diff --git a/MatrixElement/DIS/DISBase.cc b/MatrixElement/DIS/DISBase.cc --- a/MatrixElement/DIS/DISBase.cc +++ b/MatrixElement/DIS/DISBase.cc @@ -1,1361 +1,1359 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the DISBase class. // #include "DISBase.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/MatrixElement/Tree2toNDiagram.h" #include "Herwig/Utilities/Maths.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/PDT/StandardMatchers.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Repository/CurrentGenerator.h" #include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h" #include "Herwig/PDT/StandardMatchers.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include #include "Herwig/Shower/Base/ShowerProgenitor.h" #include "Herwig/Shower/Base/ShowerTree.h" #include "Herwig/Shower/Base/Branching.h" #include "Herwig/Shower/Base/HardTree.h" using namespace Herwig; using namespace ThePEG::Helicity; // namespace { // using namespace Herwig; // using namespace ThePEG::Helicity; // // void debuggingMatrixElement(bool BGF,const Lorentz5Momentum & pin, // const Lorentz5Momentum & p1, // const Lorentz5Momentum & p2, // tcPDPtr gluon, // const Lorentz5Momentum & pl1, // const Lorentz5Momentum & pl2, // const Lorentz5Momentum & pq1, // const Lorentz5Momentum & pq2, // tcPDPtr lepton1,tcPDPtr lepton2, // tcPDPtr quark1 ,tcPDPtr quark2, // Energy2 Q2,double phi, double x2, double x3, // double xperp, double zp, double xp, // const vector & azicoeff, // bool normalize) { // tcHwSMPtr hwsm=ThePEG::dynamic_ptr_cast // (CurrentGenerator::current().standardModel()); // assert(hwsm); // vector weakVertex; // vector bosons; // AbstractFFVVertexPtr strongVertex = hwsm->vertexFFG(); // if(lepton1->id()==lepton2->id()) { // weakVertex.push_back(hwsm->vertexFFZ()); // bosons.push_back(hwsm->getParticleData(ParticleID::Z0)); // weakVertex.push_back(hwsm->vertexFFP()); // bosons.push_back(hwsm->getParticleData(ParticleID::gamma)); // } // else { // weakVertex.push_back(hwsm->vertexFFW()); // bosons.push_back(hwsm->getParticleData(ParticleID::Wplus)); // } // if(!BGF) { // SpinorWaveFunction l1,q1,qp1; // SpinorBarWaveFunction l2,q2,qp2; // VectorWaveFunction gl(p2,gluon,outgoing); // if(lepton1->id()>0) { // l1 = SpinorWaveFunction (pl1,lepton1,incoming); // l2 = SpinorBarWaveFunction(pl2,lepton2,outgoing); // } // else { // l1 = SpinorWaveFunction (pl2,lepton2,outgoing); // l2 = SpinorBarWaveFunction(pl1,lepton1,incoming); // } // if(quark1->id()>0) { // q1 = SpinorWaveFunction (pq1,quark1,incoming); // q2 = SpinorBarWaveFunction(pq2,quark2,outgoing); // qp1 = SpinorWaveFunction (pin,quark1,incoming); // qp2 = SpinorBarWaveFunction(p1 ,quark2,outgoing); // } // else { // q1 = SpinorWaveFunction (pq2,quark2,outgoing); // q2 = SpinorBarWaveFunction(pq1,quark1,incoming); // qp1 = SpinorWaveFunction (p1 ,quark2,outgoing); // qp2 = SpinorBarWaveFunction(pin,quark1,incoming); // } // double lome(0.),realme(0.); // for(unsigned int lhel1=0;lhel1<2;++lhel1) { // l1.reset(lhel1); // for(unsigned int lhel2=0;lhel2<2;++lhel2) { // l2.reset(lhel2); // for(unsigned int qhel1=0;qhel1<2;++qhel1) { // q1.reset(qhel1); // qp1.reset(qhel1); // for(unsigned int qhel2=0;qhel2<2;++qhel2) { // q2.reset(qhel2); // qp2.reset(qhel2); // // leading order matrix element // Complex diagLO(0.); // for(unsigned int ix=0;ixevaluate(Q2,3,bosons[ix],l1,l2); // diagLO += weakVertex[ix]->evaluate(Q2,q1,q2,inter); // } // lome += norm(diagLO); // // real emission matrix element // for(unsigned int ghel=0;ghel<2;++ghel) { // gl.reset(2*ghel); // Complex diagReal(0.); // for(unsigned int ix=0;ixevaluate(Q2,3,bosons[ix],l1,l2); // SpinorWaveFunction off1 = // strongVertex->evaluate(Q2,5,qp1.particle(),qp1,gl); // Complex diag1 = weakVertex[ix]->evaluate(Q2,off1,qp2,inter); // SpinorBarWaveFunction off2 = // strongVertex->evaluate(Q2,5,qp2.particle(),qp2,gl); // Complex diag2 = weakVertex[ix]->evaluate(Q2,qp1,off2,inter); // diagReal += diag1+diag2; // } // realme += norm(diagReal); // } // } // } // } // } // double test1 = realme/lome/hwsm->alphaS(Q2)*Q2*UnitRemoval::InvE2; // double cphi(cos(phi)); // double test2; // if(normalize) { // test2 = 8.*Constants::pi/(1.-xp)/(1.-zp)* // (azicoeff[0]+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi))* // (1.+sqr(xp)*(sqr(x2)+1.5*sqr(xperp))); // } // else { // test2 = 8.*Constants::pi/(1.-xp)/(1.-zp)* // (azicoeff[0]+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi)); // } // cerr << "testing RATIO A " << test1/test2 << "\n"; // } // else { // SpinorWaveFunction l1,q1,qp1; // SpinorBarWaveFunction l2,q2,qp2; // VectorWaveFunction gl(pin,gluon,incoming); // if(lepton1->id()>0) { // l1 = SpinorWaveFunction (pl1,lepton1,incoming); // l2 = SpinorBarWaveFunction(pl2,lepton2,outgoing); // } // else { // l1 = SpinorWaveFunction (pl2,lepton2,outgoing); // l2 = SpinorBarWaveFunction(pl1,lepton1,incoming); // } // if(quark1->id()>0) { // q1 = SpinorWaveFunction (pq1,quark1 ,incoming); // q2 = SpinorBarWaveFunction(pq2,quark2 ,outgoing); // qp2 = SpinorBarWaveFunction(p1 ,quark2 ,outgoing); // qp1 = SpinorWaveFunction (p2 ,quark1->CC(),outgoing); // } // else { // q1 = SpinorWaveFunction (pq2,quark2 ,outgoing); // q2 = SpinorBarWaveFunction(pq1,quark1 ,incoming); // qp2 = SpinorBarWaveFunction(p2 ,quark1->CC(),outgoing); // qp1 = SpinorWaveFunction (p1 ,quark2 ,outgoing); // } // double lome(0.),realme(0.); // for(unsigned int lhel1=0;lhel1<2;++lhel1) { // l1.reset(lhel1); // for(unsigned int lhel2=0;lhel2<2;++lhel2) { // l2.reset(lhel2); // for(unsigned int qhel1=0;qhel1<2;++qhel1) { // q1.reset(qhel1); // qp1.reset(qhel1); // for(unsigned int qhel2=0;qhel2<2;++qhel2) { // q2.reset(qhel2); // qp2.reset(qhel2); // // leading order matrix element // Complex diagLO(0.); // for(unsigned int ix=0;ixevaluate(Q2,3,bosons[ix],l1,l2); // diagLO += weakVertex[ix]->evaluate(Q2,q1,q2,inter); // } // lome += norm(diagLO); // // real emission matrix element // for(unsigned int ghel=0;ghel<2;++ghel) { // gl.reset(2*ghel); // Complex diagReal(0.); // for(unsigned int ix=0;ixevaluate(Q2,3,bosons[ix],l1,l2); // SpinorWaveFunction off1 = // strongVertex->evaluate(Q2,5,qp1.particle(),qp1,gl); // Complex diag1 = weakVertex[ix]->evaluate(Q2,off1,qp2,inter); // SpinorBarWaveFunction off2 = // strongVertex->evaluate(Q2,5,qp2.particle(),qp2,gl); // Complex diag2 = weakVertex[ix]->evaluate(Q2,qp1,off2,inter); // diagReal += diag1+diag2; // } // realme += norm(diagReal); // } // } // } // } // } // double test1 = realme/lome/hwsm->alphaS(Q2)*Q2*UnitRemoval::InvE2; // double cphi(cos(phi)); // double test2; // if(normalize) { // test2 = 8.*Constants::pi/zp/(1.-zp)* // (azicoeff[0]+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi))* // sqr(xp)*(sqr(x3)+sqr(x2)+3.*sqr(xperp)); // } // else { // test2 = 8.*Constants::pi/zp/(1.-zp)* // (azicoeff[0]+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi)); // } // cerr << "testing RATIO B " << test1/test2 << "\n"; // } // } // // } DISBase::DISBase() : initial_(6.), final_(3.), procProb_(0.35), comptonInt_(0.), bgfInt_(0.), comptonWeight_(50.), BGFWeight_(150.), pTmin_(0.1*GeV), scaleOpt_(1), muF_(100.*GeV), scaleFact_(1.), contrib_(0), power_(0.1) {} DISBase::~DISBase() {} void DISBase::persistentOutput(PersistentOStream & os) const { os << comptonInt_ << bgfInt_ << procProb_ << initial_ << final_ << alpha_ << ounit(pTmin_,GeV) << comptonWeight_ << BGFWeight_ << gluon_ << ounit(muF_,GeV) << scaleFact_ << scaleOpt_ << contrib_<< power_; } void DISBase::persistentInput(PersistentIStream & is, int) { is >> comptonInt_ >> bgfInt_ >> procProb_ >> initial_ >> final_ >> alpha_ >> iunit(pTmin_,GeV) >> comptonWeight_ >> BGFWeight_ >> gluon_ >> iunit(muF_,GeV) >> scaleFact_ >> scaleOpt_ >> contrib_ >> power_; } AbstractClassDescription DISBase::initDISBase; // Definition of the static class description member. void DISBase::Init() { static ClassDocumentation documentation ("The DISBase class provides the base class for the " "implementation of DIS type processes including the " "hard corrections in either the old-fashioned matrix " "element correction of POWHEG approaches"); static Parameter interfaceProcessProbability ("ProcessProbability", "The probabilty of the QCD compton process for the process selection", &DISBase::procProb_, 0.3, 0.0, 1., false, false, Interface::limited); static Reference interfaceCoupling ("Coupling", "Pointer to the object to calculate the coupling for the correction", &DISBase::alpha_, false, false, true, false, false); static Parameter interfacepTMin ("pTMin", "The minimum pT", &DISBase::pTmin_, GeV, 1.*GeV, 0.0*GeV, 10.0*GeV, false, false, Interface::limited); static Parameter interfaceComptonWeight ("ComptonWeight", "Weight for the overestimate ofthe compton channel", &DISBase::comptonWeight_, 50.0, 0.0, 100.0, false, false, Interface::limited); static Parameter interfaceBGFWeight ("BGFWeight", "Weight for the overestimate of the BGF channel", &DISBase::BGFWeight_, 100.0, 0.0, 1000.0, false, false, Interface::limited); static Switch interfaceContribution ("Contribution", "Which contributions to the cross section to include", &DISBase::contrib_, 0, 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 Switch interfaceScaleOption ("ScaleOption", "Option for the choice of factorization (and renormalization) scale", &DISBase::scaleOpt_, 1, false, false); static SwitchOption interfaceDynamic (interfaceScaleOption, "Dynamic", "Dynamic factorization scale equal to the current sqrt(sHat())", 1); static SwitchOption interfaceFixed (interfaceScaleOption, "Fixed", "Use a fixed factorization scale set with FactorizationScaleValue", 2); static Parameter interfaceFactorizationScale ("FactorizationScale", "Value to use in the event of a fixed factorization scale", &DISBase::muF_, GeV, 100.0*GeV, 1.0*GeV, 500.0*GeV, true, false, Interface::limited); static Parameter interfaceScaleFactor ("ScaleFactor", "The factor used before Q2 if using a running scale", &DISBase::scaleFact_, 1.0, 0.0, 10.0, false, false, Interface::limited); static Parameter interfaceSamplingPower ("SamplingPower", "Power for the sampling of xp", &DISBase::power_, 0.6, 0.0, 1., false, false, Interface::limited); } void DISBase::doinit() { HwMEBase::doinit(); // integrals of me over phase space double r5=sqrt(5.),darg((r5-1.)/(r5+1.)),ath(0.5*log((1.+1./r5)/(1.-1./r5))); comptonInt_ = 2.*(-21./20.-6./(5.*r5)*ath+sqr(Constants::pi)/3. -2.*Math::ReLi2(1.-darg)-2.*Math::ReLi2(1.-1./darg)); bgfInt_ = 121./9.-56./r5*ath; // extract the gluon ParticleData objects gluon_ = getParticleData(ParticleID::g); } void DISBase::initializeMECorrection(ShowerTreePtr tree, double & initial, double & final) { initial = initial_; final = final_; // incoming particles for(map::const_iterator cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) { if(QuarkMatcher::Check(cit->first->progenitor()->data())) { partons_[0] = cit->first->progenitor()->dataPtr(); pq_[0] = cit->first->progenitor()->momentum(); } else if(LeptonMatcher::Check(cit->first->progenitor()->data())) { leptons_[0] = cit->first->progenitor()->dataPtr(); pl_[0] = cit->first->progenitor()->momentum(); } } // outgoing particles for(map::const_iterator cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) { if(QuarkMatcher::Check(cit->first->progenitor()->data())) { partons_[1] = cit->first->progenitor()->dataPtr(); pq_[1] = cit->first->progenitor()->momentum(); } else if(LeptonMatcher::Check(cit->first->progenitor()->data())) { leptons_[1] = cit->first->progenitor()->dataPtr(); pl_[1] = cit->first->progenitor()->momentum(); } } // extract the born variables q_ =pl_[0]-pl_[1]; q2_ = -q_.m2(); double yB = (q_*pq_[0])/(pl_[0]*pq_[0]); l_ = 2./yB-1.; // calculate the A coefficient for the correlations acoeff_ = A(leptons_[0],leptons_[1], partons_[0],partons_[1],q2_); } void DISBase::applyHardMatrixElementCorrection(ShowerTreePtr tree) { static const double eps=1e-6; // find the incoming and outgoing quarks and leptons ShowerParticlePtr quark[2],lepton[2]; PPtr hadron; // incoming particles for(map::const_iterator cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) { if(QuarkMatcher::Check(cit->first->progenitor()->data())) { hadron = cit->first->original()->parents()[0]; quark [0] = cit->first->progenitor(); beam_ = cit->first->beam(); } else if(LeptonMatcher::Check(cit->first->progenitor()->data())) { lepton[0] = cit->first->progenitor(); } } pdf_ = beam_->pdf(); assert(beam_&&pdf_&&quark[0]&&lepton[0]); // outgoing particles for(map::const_iterator cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) { if(QuarkMatcher::Check(cit->first->progenitor()->data())) quark [1] = cit->first->progenitor(); else if(LeptonMatcher::Check(cit->first->progenitor()->data())) { lepton[1] = cit->first->progenitor(); } } // momentum fraction assert(quark[1]&&lepton[1]); xB_ = quark[0]->x(); // calculate the matrix element vector azicoeff; // select the type of process bool BGF = UseRandom::rnd()>procProb_; double xp,zp,wgt,x1,x2,x3,xperp; // generate a QCD compton process if(!BGF) { wgt = generateComptonPoint(xp,zp); if(xpvalue(scale)/procProb_; // PDF piece wgt *= pdf_->xfx(beam_,quark[0]->dataPtr(),scale,xB_/xp)/ pdf_->xfx(beam_,quark[0]->dataPtr(),q2_ ,xB_); // other bits xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp); x1 = -1./xp; x2 = 1.-(1.-zp)/xp; x3 = 2.+x1-x2; // matrix element pieces azicoeff = ComptonME(xp,x2,xperp,true); } // generate a BGF process else { wgt = generateBGFPoint(xp,zp); if(xpvalue(scale)/(1.-procProb_); // PDF piece wgt *= pdf_->xfx(beam_,gluon_ ,scale,xB_/xp)/ pdf_->xfx(beam_,quark[0]->dataPtr(),q2_ ,xB_); // other bits xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp); x1 = -1./xp; x2 = 1.-(1.-zp)/xp; x3 = 2.+x1-x2; // matrix element pieces azicoeff = BGFME(xp,x2,x3,xperp,true); } // compute the azimuthal average of the weight wgt *= (azicoeff[0]+0.5*azicoeff[2]); // decide whether or not to accept the weight if(UseRandom::rnd()>wgt) return; // if generate generate phi unsigned int itry(0); double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.); double phiwgt,phi; do { phi = UseRandom::rnd()*Constants::twopi; double cphi(cos(phi)); phiwgt = azicoeff[0]+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi); ++itry; } while (phimax*UseRandom::rnd() > phiwgt && itry<200); if(itry==200) throw Exception() << "Too many tries in DISMECorrection" << "::applyHardMatrixElementCorrection() to" << " generate phi" << Exception::eventerror; // construct lorentz transform from lab to breit frame Lorentz5Momentum phadron = hadron->momentum(); phadron.setMass(0.*GeV); phadron.rescaleEnergy(); Lorentz5Momentum pcmf = phadron+0.5/xB_*q_; pcmf.rescaleMass(); LorentzRotation rot(-pcmf.boostVector()); Lorentz5Momentum pbeam = rot*phadron; Axis axis(pbeam.vect().unit()); double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); rot.rotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); Lorentz5Momentum pl = rot*pl_[0]; rot.rotateZ(-atan2(pl.y(),pl.x())); pl_[0] *= rot; pl_[1] *= rot; pq_[0] *= rot; pq_[1] *= rot; // compute the new incoming and outgoing momenta Energy Q(sqrt(q2_)); Lorentz5Momentum p1 = Lorentz5Momentum( 0.5*Q*xperp*cos(phi), 0.5*Q*xperp*sin(phi), -0.5*Q*x2,0.*GeV,0.*GeV); p1.rescaleEnergy(); Lorentz5Momentum p2 = Lorentz5Momentum(-0.5*Q*xperp*cos(phi),-0.5*Q*xperp*sin(phi), -0.5*Q*x3,0.*GeV,0.*GeV); p2.rescaleEnergy(); Lorentz5Momentum pin(0.*GeV,0.*GeV,-0.5*x1*Q,-0.5*x1*Q,0.*GeV); // debuggingMatrixElement(BGF,pin,p1,p2,gluon_,pl_[0],pl_[1],pq_[0],pq_[1], // lepton[0]->dataPtr(),lepton[1]->dataPtr(), // quark [0]->dataPtr(),quark [1]->dataPtr(), // q2_,phi,x2,x3,xperp,zp,xp,azicoeff,true); // we need the Lorentz transform back to the lab rot.invert(); // transform the momenta to lab frame pin *= rot; p1 *= rot; p2 *= rot; // test to ensure outgoing particles can be put on-shell if(!BGF) { if(p1.e()dataPtr()->constituentMass()) return; if(p2.e()constituentMass()) return; } else { if(p1.e()dataPtr() ->constituentMass()) return; if(p2.e()dataPtr()->CC()->constituentMass()) return; } // create the new particles and add to ShowerTree bool isquark = quark[0]->colourLine(); if(!BGF) { PPtr newin = new_ptr(Particle(*quark[0])); newin->set5Momentum(pin); PPtr newg = gluon_ ->produceParticle(p2 ); PPtr newout = quark[1]->dataPtr()->produceParticle(p1 ); ColinePtr col=isquark ? quark[0]->colourLine() : quark[0]->antiColourLine(); ColinePtr newline=new_ptr(ColourLine()); // final-state emission if(xp>zp) { col->removeColoured(newout,!isquark); col->addColoured(newin,!isquark); col->addColoured(newg,!isquark); newline->addColoured(newg,isquark); newline->addColoured(newout,!isquark); } // initial-state emission else { col->removeColoured(newin ,!isquark); col->addColoured(newout,!isquark); col->addColoured(newg,isquark); newline->addColoured(newg,!isquark); newline->addColoured(newin,!isquark); } PPtr orig; for(map::const_iterator cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) { if(cit->first->progenitor()!=quark[0]) continue; // remove old particles from colour line col->removeColoured(cit->first->copy(),!isquark); col->removeColoured(cit->first->progenitor(),!isquark); // insert new particles cit->first->copy(newin); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newin,1,false))); cit->first->progenitor(sp); tree->incomingLines()[cit->first]=sp; sp->x(xB_/xp); cit->first->perturbative(xp>zp); if(xp<=zp) orig=cit->first->original(); } for(map::const_iterator cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) { if(cit->first->progenitor()!=quark[1]) continue; // remove old particles from colour line col->removeColoured(cit->first->copy(),!isquark); col->removeColoured(cit->first->progenitor(),!isquark); // insert new particles cit->first->copy(newout); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newout,1,true))); cit->first->progenitor(sp); tree->outgoingLines()[cit->first]=sp; cit->first->perturbative(xp<=zp); if(xp>zp) orig=cit->first->original(); } assert(orig); // add the gluon ShowerParticlePtr sg=new_ptr(ShowerParticle(*newg,1,true)); ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(orig,newg,sg)); gluon->perturbative(false); tree->outgoingLines().insert(make_pair(gluon,sg)); tree->hardMatrixElementCorrection(true); } else { PPtr newin = gluon_ ->produceParticle(pin); PPtr newqbar = quark[0]->dataPtr()->CC()->produceParticle(p2 ); PPtr newout = quark[1]->dataPtr() ->produceParticle(p1 ); ColinePtr col=isquark ? quark[0]->colourLine() : quark[0]->antiColourLine(); ColinePtr newline=new_ptr(ColourLine()); col ->addColoured(newin ,!isquark); newline->addColoured(newin , isquark); col ->addColoured(newout ,!isquark); newline->addColoured(newqbar, isquark); PPtr orig; for(map::const_iterator cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) { if(cit->first->progenitor()!=quark[0]) continue; // remove old particles from colour line col->removeColoured(cit->first->copy(),!isquark); col->removeColoured(cit->first->progenitor(),!isquark); // insert new particles cit->first->copy(newin); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newin,1,false))); cit->first->progenitor(sp); tree->incomingLines()[cit->first]=sp; sp->x(xB_/xp); cit->first->perturbative(false); orig=cit->first->original(); } for(map::const_iterator cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) { if(cit->first->progenitor()!=quark[1]) continue; // remove old particles from colour line col->removeColoured(cit->first->copy(),!isquark); col->removeColoured(cit->first->progenitor(),!isquark); // insert new particles cit->first->copy(newout); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newout,1,true))); cit->first->progenitor(sp); tree->outgoingLines()[cit->first]=sp; cit->first->perturbative(true); } assert(orig); // add the (anti)quark ShowerParticlePtr sqbar=new_ptr(ShowerParticle(*newqbar,1,true)); ShowerProgenitorPtr qbar=new_ptr(ShowerProgenitor(orig,newqbar,sqbar)); qbar->perturbative(false); tree->outgoingLines().insert(make_pair(qbar,sqbar)); tree->hardMatrixElementCorrection(true); } } bool DISBase::softMatrixElementVeto(ShowerProgenitorPtr initial, ShowerParticlePtr parent, Branching br) { bool veto = !UseRandom::rndbool(parent->isFinalState() ? 1./final_ : 1./initial_); // check if me correction should be applied long id[2]={initial->id(),parent->id()}; if(id[0]!=id[1]||id[1]==ParticleID::g) return veto; // get the pT Energy pT=br.kinematics->pT(); // check if hardest so far if(pThighestpT()) return veto; double kappa(sqr(br.kinematics->scale())/q2_),z(br.kinematics->z()); double zk((1.-z)*kappa); // final-state double wgt(0.); if(parent->isFinalState()) { double zp=z,xp=1./(1.+z*zk); double xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp); double x2 = 1.-(1.-zp)/xp; vector azicoeff = ComptonME(xp,x2,xperp,false); wgt = (azicoeff[0]+0.5*azicoeff[2])*xp/(1.+sqr(z))/final_; if(wgt<.0||wgt>1.) { ostringstream wstring; wstring << "Soft ME correction weight too large or " << "negative for FSR in DISBase::" << "softMatrixElementVeto() soft weight " << " xp = " << xp << " zp = " << zp << " weight = " << wgt << "\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } else { double xp = 2.*z/(1.+zk+sqrt(sqr(1.+zk)-4.*z*zk)); double zp = 0.5* (1.-zk+sqrt(sqr(1.+zk)-4.*z*zk)); double xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp); double x1 = -1./xp, x2 = 1.-(1.-zp)/xp, x3 = 2.+x1-x2; // compton if(br.ids[0]!=ParticleID::g) { vector azicoeff = ComptonME(xp,x2,xperp,false); wgt = (azicoeff[0]+0.5*azicoeff[2])*xp*(1.-z)/(1.-xp)/(1.+sqr(z))/ (1.-zp+xp-2.*xp*(1.-zp)); } // BGF else { vector azicoeff = BGFME(xp,x2,x3,xperp,true); wgt = (azicoeff[0]+0.5*azicoeff[2])*xp/(1.-zp+xp-2.*xp*(1.-zp))/(sqr(z)+sqr(1.-z)); } wgt /=initial_; if(wgt<.0||wgt>1.) { ostringstream wstring; wstring << "Soft ME correction weight too large or " << "negative for ISR in DISBase::" << "softMatrixElementVeto() soft weight " << " xp = " << xp << " zp = " << zp << " weight = " << wgt << "\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } // if not vetoed if(UseRandom::rndbool(wgt)) return false; // otherwise parent->vetoEmission(br.type,br.kinematics->scale()); return true; } double DISBase::generateComptonPoint(double &xp, double & zp) { static const double maxwgt = 1.; double wgt; do { xp = UseRandom::rnd(); double zpmin = xp, zpmax = 1./(1.+xp*(1.-xp)); zp = 1.-pow((1.-zpmin)/(1.-zpmax),UseRandom::rnd())*(1.-zpmax); wgt = log((1.-zpmin)/(1.-zpmax))*(1.-zp); if(UseRandom::rndbool()) swap(xp,zp); double xperp2 = 4.*(1.-xp)*(1.-zp)*zp/xp,x2=1.-(1.-zp)/xp; wgt *= 2.*(1.+sqr(xp)*(sqr(x2)+1.5*xperp2))/(1.-xp)/(1.-zp); if(wgt>maxwgt) { ostringstream wstring; wstring << "DISBase::generateComptonPoint " << "Weight greater than maximum " << "wgt = " << wgt << " maxwgt = 1\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } while(wgtmaxwgt) { ostringstream wstring; wstring << "DISBase::generateBGFPoint " << "Weight greater than maximum " << "wgt = " << wgt << " maxwgt = 1\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } while(wgt1.+ac) cerr << "testing violates BGF maxA " << wgt << "\n"; // } // while(wgtmaxwgt*zpwgt) cerr << "testing violates BGF maxB " << wgt/xpwgt << "\n"; // } // while(wgt DISBase::ComptonME(double xp, double x2, double xperp, bool norm) { vector output(3,0.); double cos2 = x2 /sqrt(sqr(x2)+sqr(xperp)); double sin2 = xperp/sqrt(sqr(x2)+sqr(xperp)); double root = sqrt(sqr(l_)-1.); output[0] = sqr(cos2)+acoeff_*cos2*l_+sqr(l_); output[1] = -acoeff_*cos2*root*sin2-2.*l_*root*sin2; output[2] = sqr(root)*sqr(sin2); double lo(1+acoeff_*l_+sqr(l_)); double denom = norm ? 1.+sqr(xp)*(sqr(x2)+1.5*sqr(xperp)) : 1.; double fact = sqr(xp)*(sqr(x2)+sqr(xperp))/lo; for(unsigned int ix=0;ix DISBase::BGFME(double xp, double x2, double x3, double xperp, bool norm) { vector output(3,0.); double cos2 = x2 /sqrt(sqr(x2)+sqr(xperp)); double sin2 = xperp/sqrt(sqr(x2)+sqr(xperp)); double fact2 = sqr(xp)*(sqr(x2)+sqr(xperp)); double cos3 = x3 /sqrt(sqr(x3)+sqr(xperp)); double sin3 = xperp/sqrt(sqr(x3)+sqr(xperp)); double fact3 = sqr(xp)*(sqr(x3)+sqr(xperp)); double root = sqrt(sqr(l_)-1.); output[0] = fact2*(sqr(cos2)+acoeff_*cos2*l_+sqr(l_)) + fact3*(sqr(cos3)-acoeff_*cos3*l_+sqr(l_)); output[1] = - fact2*(acoeff_*cos2*root*sin2+2.*l_*root*sin2) - fact3*(acoeff_*cos3*root*sin3-2.*l_*root*sin3); output[2] = fact2*(sqr(root)*sqr(sin2)) + fact3*(sqr(root)*sqr(sin3)); double lo(1+acoeff_*l_+sqr(l_)); double denom = norm ? sqr(xp)*(sqr(x3)+sqr(x2)+3.*sqr(xperp))*lo : lo; for(unsigned int ix=0;ix inter) { - bool found = false; + ShowerInteraction::Type inter) { // check if generating QCD radiation - for(unsigned int ix=0;ix::const_iterator cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) { if(QuarkMatcher::Check(cit->first->progenitor()->data())) { hadron = cit->first->original()->parents()[0]; quark [0] = cit->first->progenitor(); beam_ = cit->first->beam(); } else if(LeptonMatcher::Check(cit->first->progenitor()->data())) { lepton[0] = cit->first->progenitor(); leptons_[0] = lepton[0]->dataPtr(); } } pdf_=beam_->pdf(); assert(beam_&&pdf_&&quark[0]&&lepton[0]); // outgoing particles for(map::const_iterator cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) { if(QuarkMatcher::Check(cit->first->progenitor()->data())) quark [1] = cit->first->progenitor(); else if(LeptonMatcher::Check(cit->first->progenitor()->data())) { lepton[1] = cit->first->progenitor(); leptons_[1] = lepton[1]->dataPtr(); } } assert(quark[1]&&lepton[1]); // Particle data objects for(unsigned int ix=0;ix<2;++ix) partons_[ix] = quark[ix]->dataPtr(); // extract the born variables q_ =lepton[0]->momentum()-lepton[1]->momentum(); q2_ = -q_.m2(); xB_ = quark[0]->x(); double yB = ( q_*quark[0]->momentum())/ (lepton[0]->momentum()*quark[0]->momentum()); l_ = 2./yB-1.; // construct lorentz transform from lab to breit frame Lorentz5Momentum phadron = hadron->momentum(); phadron.setMass(0.*GeV); phadron.rescaleRho(); Lorentz5Momentum pb = quark[0]->momentum(); Axis axis(q_.vect().unit()); double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); LorentzRotation 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()); pb *= rot_; if(pb.perp2()/GeV2>1e-20) { Boost trans = -1./pb.e()*pb.vect(); trans.setZ(0.); rot_.boost(trans); } Lorentz5Momentum pl = rot_*lepton[0]->momentum(); rot_.rotateZ(-atan2(pl.y(),pl.x())); // momenta of the particles pl_[0]=rot_*lepton[0]->momentum(); pl_[1]=rot_*lepton[1]->momentum(); pq_[0]=rot_* quark[0]->momentum(); pq_[1]=rot_* quark[1]->momentum(); q_ *= rot_; // coefficient for the matrix elements acoeff_ = A(lepton[0]->dataPtr(),lepton[1]->dataPtr(), quark [0]->dataPtr(),quark [1]->dataPtr(),q2_); // generate a compton point generateCompton(); generateBGF(); // no valid emission, return if(pTCompton_pTBGF_; // // find the sudakov for the branching // SudakovPtr sudakov; // // ISR // if(ComptonISFS_||!isCompton) { // BranchingList branchings=evolver()->splittingGenerator()->initialStateBranchings(); // long index = abs(partons_[0]->id()); // IdList br(3); // if(isCompton) { // br[0] = index; // br[1] = index; // br[2] = ParticleID::g; // } // else { // br[0] = ParticleID::g; // br[1] = abs(partons_[0]->id()); // br[2] = -abs(partons_[0]->id()); // } // for(BranchingList::const_iterator cit = branchings.lower_bound(index); // cit != branchings.upper_bound(index); ++cit ) { // IdList ids = cit->second.second; // if(ids[0]==br[0]&&ids[1]==br[1]&&ids[2]==br[2]) { // sudakov=cit->second.first; // break; // } // } // } // // FSR // else { // BranchingList branchings = // evolver()->splittingGenerator()->finalStateBranchings(); // long index=abs(partons_[1]->id()); // for(BranchingList::const_iterator cit = branchings.lower_bound(index); // cit != branchings.upper_bound(index); ++cit ) { // IdList ids = cit->second.second; // if(ids[0]==index&&ids[1]==index&&ids[2]==ParticleID::g) { // sudakov = cit->second.first; // break; // } // } // } // if(!sudakov) throw Exception() << "Can't find Sudakov for the hard emission in " // << "DISBase::generateHardest()" // << Exception::runerror; // add the leptons vector spaceBranchings,allBranchings; spaceBranchings.push_back(new_ptr(HardBranching(lepton[0],SudakovPtr(), HardBranchingPtr(), HardBranching::Incoming))); allBranchings.push_back(spaceBranchings.back()); allBranchings.push_back(new_ptr(HardBranching(lepton[1],SudakovPtr(), HardBranchingPtr(), HardBranching::Outgoing))); // compton hardest if(isCompton) { rot_.invert(); for(unsigned int ix=0;ixset5Momentum(ComptonMomenta_[1]); ShowerParticlePtr newg(new_ptr(ShowerParticle(gluon_,true))); newg->set5Momentum(ComptonMomenta_[2]); ShowerParticlePtr newqin (new_ptr(ShowerParticle(partons_[0],false ))); newqin->set5Momentum(ComptonMomenta_[0]); if(ComptonISFS_) { ShowerParticlePtr newspace(new_ptr(ShowerParticle(partons_[0],false))); newspace->set5Momentum(ComptonMomenta_[0]-ComptonMomenta_[2]); HardBranchingPtr spaceBranch(new_ptr(HardBranching(newqin,SudakovPtr(), HardBranchingPtr(), HardBranching::Incoming))); HardBranchingPtr offBranch(new_ptr(HardBranching(newspace,SudakovPtr(), spaceBranch, HardBranching::Incoming))); spaceBranch->addChild(offBranch); HardBranchingPtr g(new_ptr(HardBranching(newg,SudakovPtr(),spaceBranch, HardBranching::Outgoing))); spaceBranch->addChild(g); spaceBranch->type(offBranch->branchingParticle()->id()>0 ? ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine); HardBranchingPtr outBranch(new_ptr(HardBranching(newqout,SudakovPtr(), HardBranchingPtr(), HardBranching::Outgoing))); spaceBranchings.push_back(spaceBranch); allBranchings.push_back(offBranch); allBranchings.push_back(outBranch); ColinePtr newin(new_ptr(ColourLine())),newout(new_ptr(ColourLine())); newin ->addColoured(newqin ,partons_[0]->id()<0); newin ->addColoured(newg ,partons_[0]->id()<0); newout->addColoured(newspace,partons_[0]->id()<0); newout->addColoured(newqout ,partons_[1]->id()<0); newout->addColoured(newg ,partons_[1]->id()>0); } else { ShowerParticlePtr newtime(new_ptr(ShowerParticle(partons_[1],true))); newtime->set5Momentum(ComptonMomenta_[1]+ComptonMomenta_[2]); HardBranchingPtr spaceBranch(new_ptr(HardBranching(newqin,SudakovPtr(), HardBranchingPtr(), HardBranching::Incoming))); HardBranchingPtr offBranch(new_ptr(HardBranching(newtime,SudakovPtr(), HardBranchingPtr(), HardBranching::Outgoing))); HardBranchingPtr g(new_ptr(HardBranching(newg,SudakovPtr(),offBranch, HardBranching::Outgoing))); HardBranchingPtr outBranch(new_ptr(HardBranching(newqout,SudakovPtr(),offBranch, HardBranching::Outgoing))); offBranch->addChild(outBranch); offBranch->addChild(g); offBranch->type(offBranch->branchingParticle()->id()>0 ? ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine); spaceBranchings.push_back(spaceBranch); allBranchings.push_back(spaceBranch); allBranchings.push_back(offBranch); ColinePtr newin(new_ptr(ColourLine())),newout(new_ptr(ColourLine())); newin ->addColoured(newqin ,newqin->dataPtr()->iColour()!=PDT::Colour3); newin ->addColoured(newtime,newqin->dataPtr()->iColour()!=PDT::Colour3); newin ->addColoured(newg ,newqin->dataPtr()->iColour()!=PDT::Colour3); newout->addColoured(newg ,newqin->dataPtr()->iColour()==PDT::Colour3); newout->addColoured(newqout,newqin->dataPtr()->iColour()!=PDT::Colour3); } } // BGF hardest else { rot_.invert(); for(unsigned int ix=0;ixset5Momentum(BGFMomenta_[1]); ShowerParticlePtr newqbar(new_ptr(ShowerParticle(partons_[0]->CC(),true))); newqbar->set5Momentum(BGFMomenta_[2]); ShowerParticlePtr newg (new_ptr(ShowerParticle(gluon_,false))); newg->set5Momentum(BGFMomenta_[0]); ShowerParticlePtr newspace(new_ptr(ShowerParticle(partons_[0],false))); newspace->set5Momentum(BGFMomenta_[0]-BGFMomenta_[2]); HardBranchingPtr spaceBranch(new_ptr(HardBranching(newg,SudakovPtr(),HardBranchingPtr(), HardBranching::Incoming))); HardBranchingPtr offBranch(new_ptr(HardBranching(newspace,SudakovPtr(),spaceBranch, HardBranching::Incoming))); HardBranchingPtr qbar(new_ptr(HardBranching(newqbar,SudakovPtr(),spaceBranch, HardBranching::Outgoing))); spaceBranch->addChild(offBranch); spaceBranch->addChild(qbar); spaceBranch->type(offBranch->branchingParticle()->id()>0 ? ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine); HardBranchingPtr outBranch(new_ptr(HardBranching(newq,SudakovPtr(), HardBranchingPtr(), HardBranching::Outgoing))); spaceBranchings.push_back(spaceBranch); allBranchings.push_back(offBranch); allBranchings.push_back(outBranch); ColinePtr newin(new_ptr(ColourLine())),newout(new_ptr(ColourLine())); newout->addColoured(newspace,newspace->dataPtr()->iColour()!=PDT::Colour3); newout->addColoured(newq ,newspace->dataPtr()->iColour()!=PDT::Colour3); newout->addColoured(newg ,newspace->dataPtr()->iColour()!=PDT::Colour3); newin ->addColoured(newg ,newspace->dataPtr()->iColour()==PDT::Colour3); newin ->addColoured(newqbar ,newspace->dataPtr()->iColour()==PDT::Colour3); } allBranchings[2]->colourPartner(allBranchings[3]); allBranchings[3]->colourPartner(allBranchings[2]); HardTreePtr newTree(new_ptr(HardTree(allBranchings,spaceBranchings, ShowerInteraction::QCD))); // Set the maximum pt for all other emissions and connect hard and shower tree Energy pT = isCompton ? pTCompton_ : pTBGF_; // incoming particles for(map::const_iterator cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) { // set maximum pT if(QuarkMatcher::Check(cit->first->progenitor()->data())) cit->first->maximumpT(pT,ShowerInteraction::QCD); for(set::iterator cjt=newTree->branchings().begin(); cjt!=newTree->branchings().end();++cjt) { if(!(*cjt)->branchingParticle()->isFinalState()&& (*cjt)->branchingParticle()->id()==cit->first->progenitor()->id()) { newTree->connect(cit->first->progenitor(),*cjt); tPPtr beam =cit->first->original(); if(!beam->parents().empty()) beam=beam->parents()[0]; (*cjt)->beam(beam); HardBranchingPtr parent=(*cjt)->parent(); while(parent) { parent->beam(beam); parent=parent->parent(); }; } } } // outgoing particles for(map::const_iterator cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) { // set maximum pT if(QuarkMatcher::Check(cit->first->progenitor()->data())) cit->first->maximumpT(pT,ShowerInteraction::QCD); for(set::iterator cjt=newTree->branchings().begin(); cjt!=newTree->branchings().end();++cjt) { if((*cjt)->branchingParticle()->isFinalState()&& (*cjt)->branchingParticle()->id()==cit->first->progenitor()->id()) { newTree->connect(cit->first->progenitor(),*cjt); } } } return newTree; } void DISBase::generateCompton() { // maximum value of the xT double xT = sqrt((1.-xB_)/xB_); double xTMin = 2.*pTmin_/sqrt(q2_); double zp; // prefactor double a = alpha_->overestimateValue()*comptonWeight_/Constants::twopi; // loop to generate kinematics double wgt(0.),xp(0.); vector azicoeff; do { wgt = 0.; // intergration variables dxT/xT^3 xT *= 1./sqrt(1.-2.*log(UseRandom::rnd())/a*sqr(xT)); // zp zp = UseRandom::rnd(); xp = 1./(1.+0.25*sqr(xT)/zp/(1.-zp)); // check allowed if(xp1.) continue; // phase-space piece of the weight wgt = 8.*(1.-xp)*zp/comptonWeight_; // PDF piece of the weight Energy2 scale = q2_*((1.-xp)*(1-zp)*zp/xp+1.); wgt *= pdf_->xfx(beam_,partons_[0],scale,xB_/xp)/ pdf_->xfx(beam_,partons_[0],q2_ ,xB_); // me piece of the weight double x2 = 1.-(1.-zp)/xp; azicoeff = ComptonME(xp,x2,xT,false); wgt *= 4./3.*alpha_->ratio(0.25*q2_*sqr(xT))*(azicoeff[0]+0.5*azicoeff[2]); if(wgt>1.||wgt<0.) { ostringstream wstring; wstring << "DISBase::generateCompton() " << "Weight greater than one or less than zero" << "wgt = " << wgt << "\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } while(xT>xTMin&&UseRandom::rnd()>wgt); if(xT<=xTMin) { pTCompton_=-GeV; return; } // generate phi unsigned int itry(0); double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.); double phiwgt,phi; do { phi = UseRandom::rnd()*Constants::twopi; double cphi(cos(phi)); phiwgt = azicoeff[0]+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi); ++itry; } while (phimax*UseRandom::rnd() > phiwgt && itry<200); if(itry==200) throw Exception() << "Too many tries in DISMECorrection" << "::generateCompton() to" << " generate phi" << Exception::eventerror; // momenta for the configuration Energy Q(sqrt(q2_)); double x1 = -1./xp; double x2 = 1.-(1.-zp)/xp; double x3 = 2.+x1-x2; Lorentz5Momentum p1( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi), -0.5*Q*x2, 0.5*Q*sqrt(sqr(xT)+sqr(x2))); Lorentz5Momentum p2(-0.5*Q*xT*cos(phi), -0.5*Q*xT*sin(phi), -0.5*Q*x3, 0.5*Q*sqrt(sqr(xT)+sqr(x3))); Lorentz5Momentum p0(ZERO,ZERO,-0.5*Q*x1,-0.5*Q*x1); pTCompton_ = 0.5*Q*xT; ComptonMomenta_.resize(3); ComptonMomenta_[0] = p0; ComptonMomenta_[1] = p1; ComptonMomenta_[2] = p2; ComptonISFS_ = zp>xp; // debuggingMatrixElement(false,p0,p1,p2,gluon_,pl_[0],pl_[1],pq_[0],pq_[1], // leptons_[0],leptons_[1], // partons_[0],partons_[1], // q2_,phi,x2,x3,xT,zp,xp,azicoeff,false); } void DISBase::generateBGF() { // maximum value of the xT double xT = (1.-xB_)/xB_; double xTMin = 2.*max(pTmin_,pTCompton_)/sqrt(q2_); double zp; // prefactor double a = alpha_->overestimateValue()*BGFWeight_/Constants::twopi; // loop to generate kinematics double wgt(0.),xp(0.); vector azicoeff; do { wgt = 0.; // intergration variables dxT/xT^3 xT *= 1./sqrt(1.-2.*log(UseRandom::rnd())/a*sqr(xT)); // zp zp = UseRandom::rnd(); xp = 1./(1.+0.25*sqr(xT)/zp/(1.-zp)); // check allowed if(xp1.) continue; // phase-space piece of the weight wgt = 8.*sqr(1.-xp)*zp/BGFWeight_; // PDF piece of the weight Energy2 scale = q2_*((1.-xp)*(1-zp)*zp/xp+1.); wgt *= pdf_->xfx(beam_,gluon_ ,scale,xB_/xp)/ pdf_->xfx(beam_,partons_[0],q2_ ,xB_); // me piece of the weight double x1 = -1./xp; double x2 = 1.-(1.-zp)/xp; double x3 = 2.+x1-x2; azicoeff = BGFME(xp,x2,x3,xT,false); wgt *= 0.5*alpha_->ratio(0.25*q2_*sqr(xT))* (azicoeff[0]+0.5*azicoeff[2]); if(wgt>1.||wgt<0.) { ostringstream wstring; wstring << "DISBase::generateBGF() " << "Weight greater than one or less than zero" << "wgt = " << wgt << "\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } while(xT>xTMin&&UseRandom::rnd()>wgt); if(xT<=xTMin) { pTBGF_=-GeV; return; } // generate phi unsigned int itry(0); double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.); double phiwgt,phi; do { phi = UseRandom::rnd()*Constants::twopi; double cphi(cos(phi)); phiwgt = azicoeff[0]+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi); ++itry; } while (phimax*UseRandom::rnd() > phiwgt && itry<200); if(itry==200) throw Exception() << "Too many tries in DISMECorrection" << "::generateBGF() to" << " generate phi" << Exception::eventerror; // momenta for the configuration Energy Q(sqrt(q2_)); double x1 = -1./xp; double x2 = 1.-(1.-zp)/xp; double x3 = 2.+x1-x2; Lorentz5Momentum p1( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi), -0.5*Q*x2, 0.5*Q*sqrt(sqr(xT)+sqr(x2))); Lorentz5Momentum p2(-0.5*Q*xT*cos(phi), -0.5*Q*xT*sin(phi), -0.5*Q*x3, 0.5*Q*sqrt(sqr(xT)+sqr(x3))); Lorentz5Momentum p0(ZERO,ZERO,-0.5*Q*x1,-0.5*Q*x1); pTBGF_=0.5*Q*xT; BGFMomenta_.resize(3); BGFMomenta_[0]=p0; BGFMomenta_[1]=p1; BGFMomenta_[2]=p2; // debuggingMatrixElement(true,p0,p1,p2,gluon_,pl_[0],pl_[1],pq_[0],pq_[1], // leptons_[0],leptons_[1], // partons_[0],partons_[1], // q2_,phi,x2,x3,xT,zp,xp,azicoeff,false); } int DISBase::nDim() const { return HwMEBase::nDim() + (contrib_>0 ? 1 : 0 ); } bool DISBase::generateKinematics(const double * r) { // Born kinematics if(!HwMEBase::generateKinematics(r)) return false; if(contrib_!=0) { // hadron and momentum fraction if(HadronMatcher::Check(*lastParticles().first->dataPtr())) { hadron_ = dynamic_ptr_cast(lastParticles().first->dataPtr()); xB_ = lastX1(); } else { hadron_ = dynamic_ptr_cast(lastParticles().second->dataPtr()); xB_ = lastX2(); } // Q2 q2_ = -(meMomenta()[0]-meMomenta()[2]).m2(); // xp int ndim=nDim(); double rhomin = pow(1.-xB_,1.-power_); double rho = r[ndim-1]*rhomin; xp_ = 1.-pow(rho,1./(1.-power_)); jac_ = rhomin/(1.-power_)*pow(1.-xp_,power_); jacobian(jacobian()*jac_); } return true; } Energy2 DISBase::scale() const { return scaleOpt_ == 1 ? -sqr(scaleFact_)*tHat() : sqr(scaleFact_*muF_); } CrossSection DISBase::dSigHatDR() const { return NLOWeight()*HwMEBase::dSigHatDR(); } double DISBase::NLOWeight() const { // If only leading order is required return 1: if(contrib_==0) return 1.; // scale and prefactors Energy2 mu2(scale()); double aS = SM().alphaS(mu2); double CFfact = 4./3.*aS/Constants::twopi; double TRfact = 1./2.*aS/Constants::twopi; // LO + dipole subtracted virtual + collinear quark bit with LO pdf double virt = 1.+CFfact*(-4.5-1./3.*sqr(Constants::pi)+1.5*log(q2_/mu2/(1.-xB_)) +2.*log(1.-xB_)*log(q2_/mu2)+sqr(log(1.-xB_))); virt /= jac_; // PDF from leading-order double loPDF = hadron_->pdf()->xfx(hadron_,mePartonData()[1],mu2,xB_)/xB_; // NLO gluon PDF tcPDPtr gluon = getParticleData(ParticleID::g); double gPDF = hadron_->pdf()->xfx(hadron_,gluon,mu2,xB_/xp_)*xp_/xB_; // NLO quark PDF double qPDF = hadron_->pdf()->xfx(hadron_,mePartonData()[1],mu2,xB_/xp_)*xp_/xB_; // collinear counterterms // gluon double collg = TRfact/xp_*gPDF*(2.*xp_*(1.-xp_)+(sqr(xp_)+sqr(1.-xp_))*log((1.-xp_)*q2_/xp_/mu2)); // quark double collq = CFfact/xp_*qPDF*(1-xp_-2./(1.-xp_)*log(xp_)-(1.+xp_)*log((1.-xp_)/xp_*q2_/mu2))+ CFfact/xp_*(qPDF-xp_*loPDF)*(2./(1.-xp_)*log(q2_*(1.-xp_)/mu2)-1.5/(1.-xp_)); // calculate the A coefficient for the real pieces double a(A(mePartonData()[0],mePartonData()[2], mePartonData()[1],mePartonData()[3],q2_)); // cacluate lepton kinematic variables Lorentz5Momentum q = meMomenta()[0]-meMomenta()[2]; double yB = (q*meMomenta()[1])/(meMomenta()[0]*meMomenta()[1]); double l = 2./yB-1.; // q -> qg term double realq = CFfact/xp_/(1.+a*l+sqr(l))*qPDF/loPDF* (2.+2.*sqr(l)-xp_+3.*xp_*sqr(l)+a*l*(2.*xp_+1.)); // g -> q qbar term double realg =-TRfact/xp_/(1.+a*l+sqr(l))*gPDF/loPDF* ((1.+sqr(l)+2.*(1.-3.*sqr(l))*xp_*(1.-xp_)) +2.*a*l*(1.-2.*xp_*(1.-xp_))); // return the full result double wgt = virt+((collq+collg)/loPDF+realq+realg); // double f2g = gPDF/xp_*TRfact*((sqr(1-xp_)+sqr(xp_))*log((1-xp_)/xp_)+ // 8*xp_*(1.-xp_)-1.); // double f2q = // loPDF/jac_*(1.+CFfact*(-1.5*log(1.-xB_)+sqr(log(1.-xB_)) // -sqr(Constants::pi)/3.-4.5)) // +qPDF *CFfact/xp_*(3.+2.*xp_-(1.+xp_)*log(1.-xp_) // -(1.+sqr(xp_))/(1.-xp_)*log(xp_)) // +(qPDF-xp_*loPDF)*CFfact/xp_*(2.*log(1.-xp_)/(1.-xp_)-1.5/(1.-xp_)); // double wgt = (f2g+f2q)/loPDF; return contrib_ == 1 ? max(0.,wgt) : max(0.,-wgt); } diff --git a/MatrixElement/DIS/DISBase.h b/MatrixElement/DIS/DISBase.h --- a/MatrixElement/DIS/DISBase.h +++ b/MatrixElement/DIS/DISBase.h @@ -1,468 +1,468 @@ // -*- C++ -*- #ifndef HERWIG_DISBase_H #define HERWIG_DISBase_H // // This is the declaration of the DISBase class. // #include "Herwig/MatrixElement/HwMEBase.h" #include "Herwig/Shower/Couplings/ShowerAlpha.h" namespace Herwig { using namespace ThePEG; /** * The DISBase class is the base class for the implementation * of DIS type processes including corrections in both the old * fashioned matrix element and POWHEG approaches * * @see \ref DISBaseInterfaces "The interfaces" * defined for DISBase. */ class DISBase: public HwMEBase { public: /** * The default constructor. */ DISBase(); /** * The default constructor. */ virtual ~DISBase(); /** * Members for the old-fashioned matrix element correction */ //@{ /** * Has an old fashioned ME correction */ virtual bool hasMECorrection() {return true;} /** * Initialize the ME correction */ virtual void initializeMECorrection(ShowerTreePtr, double &, double & ); /** * Apply the hard matrix element correction to a given hard process or decay */ virtual void applyHardMatrixElementCorrection(ShowerTreePtr); /** * Apply the soft matrix element correction * @param initial The particle from the hard process which started the * shower * @param parent The initial particle in the current branching * @param br The branching struct * @return If true the emission should be vetoed */ virtual bool softMatrixElementVeto(ShowerProgenitorPtr, ShowerParticlePtr,Branching); //@} /** * Members for the POWHEG stype correction */ //@{ /** * Has a POWHEG style correction */ virtual POWHEGType hasPOWHEGCorrection() {return Both;} /** * Apply the POWHEG style correction */ - virtual HardTreePtr generateHardest(ShowerTreePtr,vector); + virtual HardTreePtr generateHardest(ShowerTreePtr,ShowerInteraction::Type); //@} public: /** @name Virtual functions required by the MEBase class. */ //@{ /** * Return the scale associated with the last set phase space point. */ virtual Energy2 scale() const; /** * The number of internal degrees of freedom used in the matrix * element. */ virtual int nDim() const; /** * Generate internal degrees of freedom given nDim() uniform * random numbers in the interval \f$ ]0,1[ \f$. To help the phase space * generator, the dSigHatDR should be a smooth function of these * numbers, although this is not strictly necessary. * @param r a pointer to the first of nDim() consecutive random numbers. * @return true if the generation succeeded, otherwise false. */ virtual bool generateKinematics(const double * r); /** * Return the matrix element squared differential in the variables * given by the last call to generateKinematics(). */ virtual CrossSection dSigHatDR() const; //@} 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(); //@} private: /** * The static object used to initialize the description of this class. * Indicates that this is an abstract class with persistent data. */ static AbstractClassDescription initDISBase; /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ DISBase & operator=(const DISBase &); protected: /** * The NLO weight */ double NLOWeight() const; /** * Calculate the coefficient A for the correlations */ virtual double A(tcPDPtr lin, tcPDPtr lout, tcPDPtr qin, tcPDPtr qout, Energy2 scale) const =0; /** * Members for the matrix element correction */ //@{ /** * Generate the values of \f$x_p\f$ and \f$z_p\f$ * @param xp The value of xp, output * @param zp The value of zp, output */ double generateComptonPoint(double &xp, double & zp); /** * Generate the values of \f$x_p\f$ and \f$z_p\f$ * @param xp The value of xp, output * @param zp The value of zp, output */ double generateBGFPoint(double &xp, double & zp); /** * Return the coefficients for the matrix element piece for * the QCD compton case. The output is the \f$a_i\f$ coefficients to * give the function as * \f$a_0+a_1\cos\phi+a_2\sin\phi+a_3\cos^2\phi+a_4\sin^2\phi\f$ * @param xp \f$x_p\f$ * @param x2 \f$x_2\f$ * @param xperp \f$x_\perp\f$ * @param norm Normalise to the large $l$ value of the ME */ vector ComptonME(double xp, double x2, double xperp, bool norm); /** * Return the coefficients for the matrix element piece for * the QCD compton case. The output is the \f$a_i\f$ coefficients to * give the function as * \f$a_0+a_1\cos\phi+a_2\sin\phi+a_3\cos^2\phi+a_4\sin^2\phi\f$ * @param xp \f$x_p\f$ * @param x2 \f$x_3\f$ * @param x3 \f$x_2\f$ * @param xperp \f$x_\perp\f$ * @param norm Normalise to the large $l$ value of the ME */ vector BGFME(double xp, double x2, double x3, double xperp, bool norm); //@} /** * Members for the POWHEG correction */ //@{ /** * Generate a Compton process */ void generateCompton(); /** * Generate a BGF process */ void generateBGF(); //@} private: /** * Parameters for the matrix element correction */ //@{ /** * Enchancement factor for ISR */ double initial_; /** * Enchancement factor for FSR */ double final_; /** * Relative fraction of compton and BGF processes to generate */ double procProb_; /** * Integral for compton process */ double comptonInt_; /** * Integral for BGF process */ double bgfInt_; //@} /** * Parameters for the POWHEG correction */ //@{ /** * Weight for the compton channel */ double comptonWeight_; /** * Weight for the BGF channel */ double BGFWeight_; /** * Minimum value of \f$p_T\f$ */ Energy pTmin_; //@} /** * Parameters for the point being generated */ //@{ /** * \f$Q^2\f$ */ Energy2 q2_; /** * */ double l_; /** * Borm momentum fraction */ double xB_; /** * Beam particle */ tcBeamPtr beam_; /** * Partons */ tcPDPtr partons_[2]; /** * Leptons */ tcPDPtr leptons_[2]; /** * PDF object */ tcPDFPtr pdf_; /** * Rotation to the Breit frame */ LorentzRotation rot_; /** * Lepton momenta */ Lorentz5Momentum pl_[2]; /** * Quark momenta */ Lorentz5Momentum pq_[2]; /** * q */ Lorentz5Momentum q_; /** * Compton parameters */ Energy pTCompton_; bool ComptonISFS_; vector ComptonMomenta_; /** * BGF parameters */ Energy pTBGF_; vector BGFMomenta_; //@} /** * The coefficient for the correlations */ double acoeff_; /** * Coupling */ ShowerAlphaPtr alpha_; /** * Gluon particle data object */ PDPtr gluon_; private: /** * The radiative variables */ //@{ /** * The \f$x_p\f$ or \f$z\f$ real integration variable */ double xp_; //@} /** * The hadron */ tcBeamPtr hadron_; /** * Selects a dynamic or fixed factorization scale */ unsigned int scaleOpt_; /** * The factorization scale */ Energy muF_; /** * Prefactor if variable scale used */ double scaleFact_; /** * Whether to generate the positive, negative or leading order contribution */ unsigned int contrib_; /** * Power for sampling \f$x_p\f$ */ double power_; /** * Jacobian for \f$x_p\f$ integral */ double jac_; }; } #include "ThePEG/Utilities/ClassTraits.h" namespace ThePEG { /** @cond TRAITSPECIALIZATIONS */ /** This template specialization informs ThePEG about the * base classes of DISBase. */ template <> struct BaseClassTrait { /** Typedef of the first base class of DISBase. */ typedef Herwig::HwMEBase NthBase; }; /** This template specialization informs ThePEG about the name of * the DISBase 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::DISBase"; } /** * The name of a file containing the dynamic library where the class * MENeutralCurrentDIS is implemented. It may also include several, space-separated, * libraries if the class MENeutralCurrentDIS depends on other classes (base classes * excepted). In this case the listed libraries will be dynamically * linked in the order they are specified. */ static string library() { return "HwMEDIS.so"; } }; /** @endcond */ } #endif /* HERWIG_DISBase_H */ diff --git a/MatrixElement/DrellYanBase.cc b/MatrixElement/DrellYanBase.cc --- a/MatrixElement/DrellYanBase.cc +++ b/MatrixElement/DrellYanBase.cc @@ -1,1062 +1,1060 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the DrellYanBase class. // #include "DrellYanBase.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Interface/ClassDocumentation.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 "Herwig/Shower/Base/ShowerTree.h" #include "Herwig/Shower/Base/HardTree.h" #include "Herwig/Shower/Base/ShowerProgenitor.h" #include "Herwig/Shower/Base/ShowerParticle.h" #include "Herwig/Shower/Base/Branching.h" using namespace Herwig; DrellYanBase::DrellYanBase() : _channelwgtA(0.12), _channelwgtB(2.00), _nover(0), _maxwgt(0.), _power(2.0),_preqqbar(6.5),_preqg(4.0),_pregqbar(4.0), _min_pt(2.*GeV) {} void DrellYanBase::persistentOutput(PersistentOStream & os) const { os << _channelwgtA << _channelwgtB << _channelweights << _alpha << _power << _preqqbar << _preqg << _pregqbar << ounit( _min_pt, GeV ) << _prefactor; } void DrellYanBase::persistentInput(PersistentIStream & is, int) { is >> _channelwgtA >> _channelwgtB >> _channelweights >> _alpha >> _power >> _preqqbar >> _preqg >> _pregqbar >> iunit( _min_pt, GeV ) >> _prefactor; } AbstractClassDescription DrellYanBase::initDrellYanBase; // Definition of the static class description member. void DrellYanBase::Init() { static ClassDocumentation documentation ("The DrellYanBase class provides a base class for the" " corrections to Drell-Yan type processes"); static Parameter interfaceQQbarChannelWeight ("QQbarChannelWeight", "The relative weights of the q qbar abd q g channels for selection." " This is a technical parameter for the phase-space generation and " "should not affect the results only the efficiency and fraction" " of events with weight > 1.", &DrellYanBase::_channelwgtA, 0.12, 0.01, 100., false, false, Interface::limited); static Parameter interfaceQGChannelWeight ("QGChannelWeight", "The relative weights of the qg abd qbar g channels for selection." " This is a technical parameter for the phase-space generation and " "should not affect the results only the efficiency and fraction", &DrellYanBase::_channelwgtB, 2., 0.01, 100., false, false, Interface::limited); static Reference interfaceCoupling ("Coupling", "Pointer to the object to calculate the coupling for the correction", &DrellYanBase::_alpha, false, false, true, false, false); static Parameter interfacePower ("Power", "The power for the sampling of the matrix elements", &DrellYanBase::_power, 2.0, 1.0, 10.0, false, false, Interface::limited); static Parameter interfacePrefactorqqbar ("Prefactorqqbar", "The prefactor for the sampling of the q qbar channel", &DrellYanBase::_preqqbar, 5.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacePrefactorqg ("Prefactorqg", "The prefactor for the sampling of the q g channel", &DrellYanBase::_preqg, 3.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacePrefactorgqbar ("Prefactorgqbar", "The prefactor for the sampling of the g qbar channel", &DrellYanBase::_pregqbar, 3.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacePtMin ("minPt", "The pt cut on hardest emision generation" "2*(1-Beta)*exp(-sqr(intrinsicpT/RMS))/sqr(RMS)", &DrellYanBase::_min_pt, GeV, 2.*GeV, ZERO, 100000.0*GeV, false, false, Interface::limited); } void DrellYanBase::doinit() { HwMEBase::doinit(); _channelweights.push_back(_channelwgtA/(1.+_channelwgtA)); _channelweights.push_back(_channelweights[0]+1./(1.+_channelwgtA)/(1+_channelwgtB)); _channelweights.push_back(1.0); _prefactor.push_back(_preqqbar); _prefactor.push_back(_preqg); _prefactor.push_back(_pregqbar); } void DrellYanBase::dofinish() { HwMEBase::dofinish(); if(_nover==0) return; generator()->log() << "DrellYanBase when applying the hard correction " << _nover << " weights larger than one were generated of which" << " the largest was " << _maxwgt << "\n"; } void DrellYanBase::applyHardMatrixElementCorrection(ShowerTreePtr tree) { // get the quark,antiquark and the gauge boson // get the quarks map::const_iterator cit; ShowerParticleVector incoming; vector beams; for(cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) { incoming.push_back(cit->first->progenitor()); beams.push_back(cit->first->beam()); } // ensure that the quark is first if(incoming[0]->id()id()) { swap(incoming[0],incoming[1]); swap(beams[0],beams[1]); } Lorentz5Momentum pboson; for( map::const_iterator cjt= tree->outgoingLines().begin(); cjt != tree->outgoingLines().end();++cjt ) { pboson += cjt->first->original()->momentum(); } pboson.rescaleMass(); // calculate the momenta unsigned int iemit,itype; vector pnew; LorentzRotation trans; pair xnew; // if not accepted return if(!applyHard(incoming,beams,pboson,iemit,itype,pnew,trans,xnew)) return; // if applying ME correction create the new particles if(itype==0) { // get the momenta of the new particles Lorentz5Momentum pquark(pnew[0]),panti(pnew[1]),pgluon(pnew[2]); if(iemit==2) swap(pquark,panti); // ensure gluon can be put on shell Lorentz5Momentum ptest(pgluon); if(ptest.boost(-(pquark+panti).boostVector()).e() < getParticleData(ParticleID::g)->constituentMass()) return; // create the new gluon PPtr newg= getParticleData(ParticleID::g)->produceParticle(pgluon); PPtr newq,newa; ColinePtr col; // make the new particles if(iemit==1) { col=incoming[0]->colourLine(); newq = getParticleData(incoming[0]->id())->produceParticle(pquark); newa = new_ptr(Particle(*incoming[1])); col->removeAntiColoured(newa); newa->set5Momentum(panti); } else { col=incoming[1]->antiColourLine(); newa = getParticleData(incoming[1]->id())->produceParticle(panti); newq = new_ptr(Particle(*incoming[0])); col->removeColoured(newq); newq->set5Momentum(pquark); } // set the colour lines ColinePtr newline=new_ptr(ColourLine()); if(iemit==1) { newline->addColoured(newq); newline->addColoured(newg); col->addAntiColoured(newg); col->addAntiColoured(newa); } else { newline->addAntiColoured(newa); newline->addAntiColoured(newg); col->addColoured(newg); col->addColoured(newq); } // change the existing quark and antiquark PPtr orig; for(cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) { if(cit->first->progenitor()->id()==newq->id()) { // remove old particles from colour line col->removeColoured(cit->first->copy()); col->removeColoured(cit->first->progenitor()); // insert new particles cit->first->copy(newq); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newq,1,false))); sp->x(xnew.first); cit->first->progenitor(sp); tree->incomingLines()[cit->first]=sp; cit->first->perturbative(iemit!=1); if(iemit==1) orig=cit->first->original(); } else { // remove old particles from colour line col->removeAntiColoured(cit->first->copy()); col->removeColoured(cit->first->progenitor()); // insert new particles cit->first->copy(newa); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newa,1,false))); sp->x(xnew.second); cit->first->progenitor(sp); tree->incomingLines()[cit->first]=sp; cit->first->perturbative(iemit==1); if(iemit==2) orig=cit->first->original(); } } // fix the momentum of the gauge boson Boost boostv=pboson.findBoostToCM(); trans *=LorentzRotation(boostv); for( map::const_iterator cjt= tree->outgoingLines().begin(); cjt != tree->outgoingLines().end();++cjt ) { cjt->first->progenitor()->transform(trans); cjt->first->copy()->transform(trans); } tree->hardMatrixElementCorrection(true); // add the gluon ShowerParticlePtr sg=new_ptr(ShowerParticle(*newg,1,true)); ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(orig,newg,sg)); gluon->perturbative(false); tree->outgoingLines().insert(make_pair(gluon,sg)); } else if(itype==1) { Lorentz5Momentum pin(pnew[0]),pout(pnew[1]),pgluon(pnew[2]); if(iemit==2) swap(pin,pout); // ensure outgoing quark can be put on-shell Lorentz5Momentum ptest(pout); if(ptest.boost(-(pin+pgluon).boostVector()).e() < incoming[1]->dataPtr()->constituentMass()) return; // create the new gluon PPtr newg = getParticleData(ParticleID::g)->produceParticle(pgluon); // create the new outgoing quark PPtr newout= getParticleData(-incoming[1]->id())->produceParticle(pout); // create the new incoming quark PPtr newin = new_ptr(Particle(*incoming[0])); newin->set5Momentum(pin); // colour info ColinePtr col=incoming[0]->colourLine(); col->removeColoured(newin); ColinePtr newline=new_ptr(ColourLine()); newline->addColoured(newout); newline->addColoured(newg); col->addAntiColoured(newg); col->addColoured(newin); // change the existing incoming partons PPtr orig; for(cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) { if(cit->first->progenitor()->id()==newin->id()) { // remove old particles from colour line col->removeColoured(cit->first->copy()); col->removeColoured(cit->first->progenitor()); // insert new particles cit->first->copy(newin); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newin,1,false))); sp->x(xnew.first); cit->first->progenitor(sp); tree->incomingLines()[cit->first]=sp; cit->first->perturbative(true); } else { // remove old particles from colour line col->removeAntiColoured(cit->first->copy()); col->removeColoured(cit->first->progenitor()); // insert new particles cit->first->copy(newg); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newg,1,false))); sp->x(xnew.second); cit->first->progenitor(sp); tree->incomingLines()[cit->first]=sp; cit->first->perturbative(false); orig=cit->first->original(); } } // fix the momentum of the gauge boson Boost boostv=pboson.findBoostToCM(); trans *=LorentzRotation(boostv); for( map::const_iterator cjt= tree->outgoingLines().begin(); cjt != tree->outgoingLines().end();++cjt ) { cjt->first->progenitor()->transform(trans); cjt->first->copy()->transform(trans); } tree->hardMatrixElementCorrection(true); // add the outgoing quark ShowerParticlePtr sout=new_ptr(ShowerParticle(*newout,1,true)); ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(orig,newout,sout)); out->perturbative(false); tree->outgoingLines().insert(make_pair(out,sout)); } else if(itype==2) { Lorentz5Momentum pin(pnew[0]),pout(pnew[1]),pgluon(pnew[2]); if(iemit==2) swap(pin,pout); // ensure outgoing antiquark can be put on-shell Lorentz5Momentum ptest(pout); if(ptest.boost(-(pin+pgluon).boostVector()).e() < incoming[0]->dataPtr()->constituentMass()) return; // create the new gluon PPtr newg = getParticleData(ParticleID::g)->produceParticle(pgluon); // create the new outgoing antiquark PPtr newout= getParticleData(-incoming[0]->id())->produceParticle(pout); // create the new incoming antiquark PPtr newin = new_ptr(Particle(*incoming[1])); newin->set5Momentum(pin); // colour info ColinePtr col=incoming[0]->colourLine(); col->removeAntiColoured(newin); ColinePtr newline=new_ptr(ColourLine()); newline->addAntiColoured(newout); newline->addAntiColoured(newg); col->addColoured(newg); col->addAntiColoured(newin); // change the existing incoming partons PPtr orig; for(cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) { if(cit->first->progenitor()->id()==newin->id()) { // remove old particles from colour line col->removeAntiColoured(cit->first->copy()); col->removeAntiColoured(cit->first->progenitor()); // insert new particles cit->first->copy(newin); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newin,1,false))); sp->x(xnew.second); cit->first->progenitor(sp); tree->incomingLines()[cit->first]=sp; cit->first->perturbative(true); } else { // remove old particles from colour line col->removeColoured(cit->first->copy()); col->removeColoured(cit->first->progenitor()); // insert new particles cit->first->copy(newg); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newg,1,false))); sp->x(xnew.first); cit->first->progenitor(sp); tree->incomingLines()[cit->first]=sp; cit->first->perturbative(false); orig=cit->first->original(); } } // fix the momentum of the gauge boson Boost boostv=pboson.findBoostToCM(); trans *=LorentzRotation(boostv); for( map::const_iterator cjt= tree->outgoingLines().begin(); cjt != tree->outgoingLines().end();++cjt ) { cjt->first->progenitor()->transform(trans); cjt->first->copy()->transform(trans); } tree->hardMatrixElementCorrection(true); // add the outgoing antiquark ShowerParticlePtr sout=new_ptr(ShowerParticle(*newout,1,true)); ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(orig,newout,sout)); out->perturbative(false); tree->outgoingLines().insert(make_pair(out,sout)); } } bool DrellYanBase::applyHard(ShowerParticleVector quarks, vector beams, Lorentz5Momentum boson, unsigned int & iemit,unsigned int & itype, vector & pnew, LorentzRotation & trans, pair & xout) { // check that quark along +z and qbar along -z bool quarkplus=quarks[0]->momentum().z()>quarks[1]->momentum().z(); // calculate the limits on s Energy mb = sqrt(mb2_); Energy2 smin=mb2_; Energy2 s= (generator()->currentEvent()->incoming().first ->momentum()+ generator()->currentEvent()->incoming().second->momentum()).m2(); Energy2 smax(s); // calculate the rapidity of the boson double yB=0.5*log((boson.e()+boson.z())/ (boson.e()-boson.z())); if(!quarkplus) yB=-yB; // if no phase-space return if(smaxx(); assert(beams[ix]); pdf[ix]=beams[ix]->pdf(); assert(pdf[ix]); fx[ix]=pdf[ix]->xfx(beams[ix],quarks[ix]->dataPtr(),mb2_,x[ix]); } // select the type of process and generate the kinematics double rn(UseRandom::rnd()); Energy2 shat(ZERO),uhat(ZERO),that(ZERO); double weight(0.),xnew[2]={1.,1.}; // generate the value of s according to 1/s^2 shat = smax*smin/(smin+UseRandom::rnd()*(smax-smin)); Energy2 jacobian = sqr(shat)*(1./smin-1./smax); double sbar=shat/mb2_; // calculate limits on that Energy2 tmax=mb2_*kappa[0]*(1.-sbar)/(kappa[0]+sbar); Energy2 tmin=shat*(1.-sbar)/(kappa[1]+sbar); // calculate the limits on uhat Energy2 umax(mb2_-shat-tmin),umin(mb2_-shat-tmax); // check inside phase space if(tmax g V if(rn<_channelweights[0]) { // generate t and u according to 1/t+1/u // generate in 1/t if(UseRandom::rndbool(0.5)) { that=tmax*pow(tmin/tmax,UseRandom::rnd()); uhat=mb2_-shat-that; jacobian *=log(tmin/tmax); } // generate in 1/u else { uhat=umax*pow(umin/umax,UseRandom::rnd()); that=mb2_-shat-uhat; jacobian *=log(umin/umax); } Energy4 jacobian2 = jacobian * 2.*uhat*that/(shat-mb2_); // new scale (this is mt^2=pt^2+mb^2) Energy2 scale(uhat*that/shat+mb2_); // the PDF's with the emitted gluon double fxnew[2]; xnew[0]=exp(yB)/sqrt(s)*sqrt(shat*(mb2_-uhat)/(mb2_-that)); xnew[1]=shat/(s*xnew[0]); for(unsigned int ix=0;ix<2;++ix) {fxnew[ix]=pdf[ix]->xfx(beams[ix],quarks[ix]->dataPtr(),scale,xnew[ix]);} // jacobian and me parts of the weight weight=jacobian2*(sqr(mb2_-that)+sqr(mb2_-uhat))/(sqr(shat)*that*uhat); // pdf part of the weight weight *=fxnew[0]*fxnew[1]*x[0]*x[1]/(fx[0]*fx[1]*xnew[0]*xnew[1]); // finally coupling, colour factor and different channel pieces weight *= 2./3./Constants::pi/_channelweights[0]*_alpha->value(scale); // select the emiting particle iemit=1; if(UseRandom::rnd()_channelweights[1]) { swap(tmax,tmin); tmax=mb2_-shat-tmax; tmin=mb2_-shat-tmin; } that=tmax*pow(tmin/tmax,UseRandom::rnd()); uhat=mb2_-shat-that; Energy4 jacobian2 = jacobian * that*log(tmax/tmin); // new scale (this is mt^2=pt^2+mb^2) Energy2 scale(uhat*that/shat+mb2_); // g qbar -> qbar V double fxnew[2]; if(rn<_channelweights[1]) { itype=2; xnew[0]=exp(yB)/sqrt(s)*sqrt(shat*(mb2_-uhat)/(mb2_-that)); xnew[1]=shat/(s*xnew[0]); fxnew[0]=pdf[0]->xfx(beams[0],getParticleData(ParticleID::g),scale,xnew[0]); fxnew[1]=pdf[1]->xfx(beams[1],quarks[1]->dataPtr(),scale,xnew[1]); jacobian2/=(_channelweights[1]-_channelweights[0]); } // q g -> q V else { itype=1; xnew[0]=exp(yB)/sqrt(s)*sqrt(shat*(mb2_-that)/(mb2_-uhat)); xnew[1]=shat/(s*xnew[0]); fxnew[0]=pdf[0]->xfx(beams[0],quarks[0]->dataPtr(),scale,xnew[0]); fxnew[1]=pdf[1]->xfx(beams[1],getParticleData(ParticleID::g),scale,xnew[1]); jacobian2/=(_channelweights[2]-_channelweights[1]); } // jacobian and me parts of the weight weight=-jacobian2*(sqr(mb2_-that)+sqr(mb2_-shat))/(sqr(shat)*shat*that); // pdf part of the weight weight *=fxnew[0]*fxnew[1]*x[0]*x[1]/(fx[0]*fx[1]*xnew[0]*xnew[1]); // finally coupling, colour factor and different channel pieces weight *= 0.25/Constants::pi*_alpha->value(scale); // select the emiting particle iemit=1; if(UseRandom::rnd()1.) { ++_nover; _maxwgt=max(_maxwgt,weight); weight=1.; } if(UseRandom::rnd()>weight) return false; // construct the momenta in the rest frame of the boson Lorentz5Momentum pb(ZERO,ZERO,ZERO,mb,mb),pspect,pg,pemit; double cos3 = 0.0; if(itype==0) { pg = Lorentz5Momentum(ZERO,ZERO,ZERO,0.5*(shat-mb2_)/mb,ZERO); Energy2 tp(that),up(uhat); double zsign(-1.); if(iemit==2) { tp=uhat; up=that; zsign=1.; } pspect = Lorentz5Momentum(ZERO,ZERO,zsign*0.5*(mb2_-tp)/mb, 0.5*(mb2_-tp)/mb,ZERO); Energy eemit=0.5*(mb2_-up)/mb; cos3 = 0.5/pspect.z()/pg.e()*(sqr(pspect.e())+sqr(pg.e())-sqr(eemit)); } else { pg=Lorentz5Momentum(ZERO,ZERO,ZERO,0.5*(mb2_-uhat)/mb,ZERO); double zsign(1.); if(iemit==1) { if(itype==1) zsign=-1.; pspect=Lorentz5Momentum(ZERO,ZERO,0.5*zsign*(shat-mb2_)/mb, 0.5*(shat-mb2_)/mb); Energy eemit=0.5*(mb2_-that)/mb; cos3 = 0.5/pspect.z()/pg.e()*(sqr(pspect.e())+sqr(pg.e())-sqr(eemit)); } else { if(itype==2) zsign=-1.; pspect=Lorentz5Momentum(ZERO,ZERO,0.5*zsign*(mb2_-that)/mb, 0.5*(mb2_-that)/mb); Energy eemit=0.5*(shat-mb2_)/mb; cos3 = 0.5/pspect.z()/pg.e()*(-sqr(pspect.e())-sqr(pg.e())+sqr(eemit)); } } // rotate the gluon double sin3(sqrt(1.-sqr(cos3))); double phi(Constants::twopi*UseRandom::rnd()); pg.setX(pg.e()*sin3*cos(phi)); pg.setY(pg.e()*sin3*sin(phi)); pg.setZ(pg.e()*cos3); if(itype==0) { pemit=pb+pg-pspect; } else { if(iemit==1) pemit=pb+pspect-pg; else pemit=pspect+pg-pb; } pemit.rescaleMass(); // find the new CMF Lorentz5Momentum pp[2]; if(itype==0) { if(iemit==1) { pp[0]=pemit; pp[1]=pspect; } else { pp[0]=pspect; pp[1]=pemit; } } else if(itype==1) { pp[1]=pg; if(iemit==1) pp[0]=pemit; else pp[0]=pspect; } else { pp[0]=pg; if(iemit==1) pp[1]=pemit; else pp[1]=pspect; } Lorentz5Momentum pz= quarkplus ? pp[0] : pp[1]; pp[0]/=xnew[0]; pp[1]/=xnew[1]; Lorentz5Momentum plab(pp[0]+pp[1]); plab.rescaleMass(); // construct the boost to rest frame of plab trans=LorentzRotation(plab.findBoostToCM()); pz.transform(trans); // rotate so emitting particle along z axis // rotate so in x-z plane trans.rotateZ(-atan2(pz.y(),pz.x())); // rotate so along trans.rotateY(-acos(pz.z()/pz.vect().mag())); // undo azimuthal rotation trans.rotateZ(atan2(pz.y(),pz.x())); // perform the transforms pb .transform(trans); pspect.transform(trans); pg .transform(trans); pemit .transform(trans); // momenta to be returned pnew.push_back(pemit); pnew.push_back(pspect); pnew.push_back(pg); pnew.push_back(pb); xout.first=xnew[0]; xout.second=xnew[1]; return true; } bool DrellYanBase::softMatrixElementVeto(ShowerProgenitorPtr initial, ShowerParticlePtr parent,Branching br) { if(parent->isFinalState()) return false; // check if me correction should be applied long id[2]={initial->id(),parent->id()}; if(id[0]!=id[1]||id[1]==ParticleID::g) return false; // get the pT Energy pT=br.kinematics->pT(); // check if hardest so far if(pThighestpT()) return false; // compute the invariants double kappa(sqr(br.kinematics->scale())/mb2_),z(br.kinematics->z()); Energy2 shat(mb2_/z*(1.+(1.-z)*kappa)),that(-(1.-z)*kappa*mb2_),uhat(-(1.-z)*shat); // check which type of process // g qbar double wgt(1.); if(id[0]>0&&br.ids[0]==ParticleID::g) wgt=mb2_/(shat+uhat)*(sqr(mb2_-that)+sqr(mb2_-shat))/(sqr(shat+uhat)+sqr(uhat)); else if(id[0]>0&&br.ids[0]==id[0]) wgt=mb2_/(shat+uhat)*(sqr(mb2_-uhat)+sqr(mb2_-that))/(sqr(shat)+sqr(shat+uhat)); else if(id[0]<0&&br.ids[0]==ParticleID::g) wgt=mb2_/(shat+uhat)*(sqr(mb2_-that)+sqr(mb2_-shat))/(sqr(shat+uhat)+sqr(uhat)); else if(id[0]<0&&br.ids[0]==-id[0]) wgt=mb2_/(shat+uhat)*(sqr(mb2_-uhat)+sqr(mb2_-that))/(sqr(shat)+sqr(shat+uhat)); else return false; if(wgt<.0||wgt>1.) generator()->log() << "Soft ME correction weight too large or " << "negative in DrellYanBase::" << "softMatrixElementVeto()soft weight " << " sbar = " << shat/mb2_ << " tbar = " << that/mb2_ << "weight = " << wgt << "\n"; // if not vetoed if(UseRandom::rndbool(wgt)) return false; // otherwise parent->vetoEmission(br.type,br.kinematics->scale()); return true; } HardTreePtr DrellYanBase::generateHardest(ShowerTreePtr tree, - vector inter) { - bool found = false; + ShowerInteraction::Type inter) { // check if generating QCD radiation - for(unsigned int ix=0;ix::const_iterator cit; _quarkplus = true; 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() ); // check that quark is along +ve z direction if(cit->first->progenitor()->id() > 0 && cit->first->progenitor()->momentum().z() < ZERO ) _quarkplus = false; particlesToShower.push_back( cit->first ); } Lorentz5Momentum pboson; for( map::const_iterator cjt= tree->outgoingLines().begin(); cjt != tree->outgoingLines().end();++cjt ) { pboson += cjt->first->original()->momentum(); } pboson.rescaleMass(); // calculate the rapidity of the boson _yb = 0.5 * log((pboson.e()+pboson.z())/(pboson.e()-pboson.z())); _yb *= _quarkplus ? 1. : -1.; _mass = pboson.mass(); // we are assuming quark first, swap order to ensure this // if antiquark first if(_partons[0]->id()<_partons[1]->id()) { swap(_partons[0],_partons[1]); swap(_beams[0],_beams[1]); } vector pnew; int emission_type(-1); // generate the hard emission and return if no emission if(!getEvent(pnew,emission_type)) { for(unsigned int ix=0;ixmaximumpT(_min_pt,ShowerInteraction::QCD); return HardTreePtr(); } // construct the HardTree object needed to perform the showers ShowerParticleVector newparticles; // make the particles for the HardTree tcPDPtr gluon=getParticleData(ParticleID::g); // create the partons int iemit; // q qbar -> g V ColinePtr newline[2]={new_ptr(ColourLine()),new_ptr(ColourLine())}; if(emission_type==0) { newparticles.push_back(new_ptr(ShowerParticle(_partons[0] ,false))); newparticles.push_back(new_ptr(ShowerParticle(_partons[1] ,false))); newparticles.push_back(new_ptr(ShowerParticle(gluon , true))); newline[1]->addColoured(newparticles[0]); newline[1]->addColoured(newparticles[2]); newline[0]->addAntiColoured(newparticles[1]); newline[0]->addAntiColoured(newparticles[2]); iemit = (pnew[0]-pnew[2]).m2()>(pnew[1]-pnew[2]).m2() ? 0 : 1; } // q g -> q V else if(emission_type==1) { iemit=1; newparticles.push_back(new_ptr(ShowerParticle(_partons[0] ,false))); newparticles.push_back(new_ptr(ShowerParticle(gluon ,false))); newparticles.push_back(new_ptr(ShowerParticle(_partons[1]->CC(), true))); newline[1]->addColoured(newparticles[0]); newline[1]->addAntiColoured(newparticles[1]); newline[0]->addColoured(newparticles[1]); newline[0]->addColoured(newparticles[2]); } // g qbar -> qbar V else { iemit=0; newparticles.push_back(new_ptr(ShowerParticle(gluon ,false))); newparticles.push_back(new_ptr(ShowerParticle(_partons[1] ,false))); newparticles.push_back(new_ptr(ShowerParticle(_partons[0]->CC(), true))); newline[0]->addAntiColoured(newparticles[1]); newline[0]->addColoured(newparticles[0]); newline[1]->addAntiColoured(newparticles[0]); newline[1]->addAntiColoured(newparticles[2]); } // set the momenta for(unsigned int ix=0;ix<3;++ix) newparticles[ix]->set5Momentum(pnew[ix]); // create the off-shell particle Lorentz5Momentum poff=pnew[iemit]-pnew[2]; poff.rescaleMass(); newparticles.push_back(new_ptr(ShowerParticle(_partons[iemit],false))); newparticles.back()->set5Momentum(poff); if(iemit==0) { newline[0]->addColoured(newparticles.back()); } else { newline[1]->addAntiColoured(newparticles.back()); } // compute the boost for the bosons LorentzRotation boost(pboson.findBoostToCM()); boost.boost(pnew[3].boostVector()); for( map::const_iterator cjt= tree->outgoingLines().begin(); cjt != tree->outgoingLines().end();++cjt ) { newparticles.push_back(new_ptr(ShowerParticle(cjt->first->original()->dataPtr(), true))); newparticles.back()->set5Momentum(boost*cjt->first->original()->momentum()); } 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],HardBranching::Incoming))); inBranch[iemit]->addChild(hardBranch.back()); inBranch[iemit]->type(hardBranch.back()->branchingParticle()->id()>0 ? ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine); // create the branching for the emitted jet inBranch[iemit]->addChild(new_ptr(HardBranching(newparticles[2],SudakovPtr(), inBranch[iemit],HardBranching::Outgoing))); // set the colour partners hardBranch.back()->colourPartner(inBranch[iemit==0 ? 1 : 0]); inBranch[iemit==0 ? 1 : 0]->colourPartner(hardBranch.back()); // add other particle hardBranch.push_back(inBranch[iemit==0 ? 1 : 0]); // outgoing particles for(unsigned int ix=4;ix hard=hardtree->branchings(); for(unsigned int ix=0;ixmaximumpT(_min_pt,ShowerInteraction::QCD); else particlesToShower[ix]->maximumpT(_pt,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(); }; } } } // return the tree return hardtree; } double DrellYanBase::getResult(int emis_type, Energy pt, double yj) { Energy2 s=sqr(generator()->maximumCMEnergy()); Energy2 m2(sqr(_mass)); Energy2 scale = m2+sqr(pt); Energy et=sqrt(scale); // longitudinal real correction fractions double x = pt*exp( yj)/sqrt(s)+et*exp( _yb)/sqrt(s); double y = pt*exp(-yj)/sqrt(s)+et*exp(-_yb)/sqrt(s); // reject if outside region if(x<0.||x>1.||y<0.||y>1.||x*ypdf()->xfx(_beams[0],_partons[0],m2,x1); pdf[1]=_beams[1]->pdf()->xfx(_beams[1],_partons[1],m2,y1); //qqbar2Zg using Constants::pi; if(emis_type==0) { pdf[2]=_beams[0]->pdf()->xfx(_beams[0],_partons[0],scale,x); pdf[3]=_beams[1]->pdf()->xfx(_beams[1],_partons[1],scale,y); res = 4./3./pi*(sqr(th-m2)+sqr(uh-m2))*pt/(sh*uh*th)*GeV; } //qg2Zq else if(emis_type==1) { pdf[2]=_beams[0]->pdf()->xfx(_beams[0],_partons[0],scale,x); pdf[3]=_beams[1]->pdf()->xfx(_beams[1],getParticleData(ParticleID::g),scale,y); res = -1./2./pi*(sqr(uh-m2)+sqr(sh-m2))*pt/(sh*sh*uh)*GeV; } //qbarg2Zqbar else { pdf[2]=_beams[0]->pdf()->xfx(_beams[0],getParticleData(ParticleID::g),scale,x); pdf[3]=_beams[1]->pdf()->xfx(_beams[1],_partons[1],scale,y); res =- 1./2./pi*(sqr(th-m2)+sqr(sh-m2))*pt/(sh*sh*th)*GeV; } //deals with pdf zero issue at large x if(pdf[0]<=0.||pdf[1]<=0.||pdf[2]<=0.||pdf[3]<=0.) { res=0.; } else { res*=pdf[2]*pdf[3]/pdf[0]/pdf[1]*m2/sh; } res*=_alpha->ratio(sqr(pt)); return res; } bool DrellYanBase::getEvent(vector & pnew, int & emis_type){ // pt cut-off // Energy minp = 0.1*GeV; // maximum pt (half of centre-of-mass energy) Energy maxp = 0.5*generator()->maximumCMEnergy(); // set pt of emission to zero _pt=ZERO; //Working Variables Energy pt; double yj; // limits on the rapidity of the jet double minyj = -8.0,maxyj = 8.0; bool reject; double wgt; emis_type=-1; for(int j=0;j<3;j++) { pt=maxp; double a = _alpha->overestimateValue()*_prefactor[j]*(maxyj-minyj)/(_power-1.); do { // generate next pt pt=GeV/pow(pow(GeV/pt,_power-1)-log(UseRandom::rnd())/a,1./(_power-1.)); // generate rapidity of the jet yj=UseRandom::rnd()*(maxyj-minyj)+ minyj; // calculate rejection weight wgt=getResult(j,pt,yj); wgt/= _prefactor[j]*pow(GeV/pt,_power); reject = UseRandom::rnd()>wgt; //no emission event if p goes past p min - basically set to outside //of the histogram bounds (hopefully hist object just ignores it) if(pt<_min_pt){ pt=ZERO; reject = false; } if(wgt>1.0) { ostringstream s; s << "DrellYanBase::getEvent weight for channel " << j << "is " << wgt << " which is greater than 1"; generator()->logWarning( Exception(s.str(), Exception::warning) ); } } while(reject); // set pt of emission etc if(pt>_pt){ emis_type = j; _pt=pt; _yj=yj; } } //was this an (overall) no emission event? if(_pt<_min_pt){ _pt=ZERO; emis_type = 3; } if(emis_type==3) return false; // generate the momenta of the particles // hadron-hadron cmf Energy2 s=sqr(generator()->maximumCMEnergy()); // transverse energy Energy2 m2(sqr(_mass)); Energy et=sqrt(m2+sqr(_pt)); // first calculate all the kinematic variables // longitudinal real correction fractions double x = _pt*exp( _yj)/sqrt(s)+et*exp( _yb)/sqrt(s); double y = _pt*exp(-_yj)/sqrt(s)+et*exp(-_yb)/sqrt(s); // that and uhat Energy2 th = -sqrt(s)*x*_pt*exp(-_yj); Energy2 uh = -sqrt(s)*y*_pt*exp( _yj); Energy2 sh = x*y*s; if(emis_type==1) swap(th,uh); // decide which was the emitting particle unsigned int iemit=1; // from q qbar if(emis_type==0) { if(UseRandom::rnd()); + virtual HardTreePtr generateHardest(ShowerTreePtr, ShowerInteraction::Type); /** * Set the typed and momenta of the incoming and outgoing partons to * be used in subsequent calls to me() and colourGeometries() * according to the associated XComb object. */ virtual void setKinematics() { HwMEBase::setKinematics(); mb2_ = sHat(); } protected: /** * Return the momenta and type of hard matrix element correction * @param quarks The original incoming particles. * @param beams The BeamParticleData objects * @param boson The momentum of the original outgoing gauge boson * @param iemit Whether the first (0) or second (1) particle emitted * the radiation * @param itype The type of radiated particle (0 is gluon, 1 is quark * and 2 is antiquark) * @param pnew The momenta of the new particles * @param trans The LorentzRotation from the boson rest frame to the new lab * @param xnew The new values of the momentuym fractions * @return Whether or not the matrix element correction needs to be applied */ bool applyHard(ShowerParticleVector quarks, vector beams, Lorentz5Momentum boson,unsigned int & iemit, unsigned int & itype,vector & pnew, LorentzRotation & trans, pair & xnew); /** * Returns the matrix element for a given type of process, * rapidity of the jet \f$y_j\f$ and transverse momentum \f$p_T\f$ * @param emis_type the type of emission, * (0 is \f$q\bar{q}\to Vg\f$, 1 is \f$qg\to Vq\f$ and 2 is \f$g\bar{q}\to V\bar{q}\f$) * @param pt The transverse momentum of the jet * @param yj The rapidity of the jet */ double getResult(int emis_type, Energy pt, double yj); /** * generates the hardest emission (yj,p) * @param pnew The momenta of the new particles * @param emissiontype The type of emission, as for getResult * @return Whether not an emission was generated */ bool getEvent(vector & pnew,int & emissiontype); 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(); /** * Finalize this object. Called in the run phase just after a * run has ended. Used eg. to write out statistics. */ virtual void dofinish(); //@} private: /** * The static object used to initialize the description of this class. * Indicates that this is an abstract class with persistent data. */ static AbstractClassDescription initDrellYanBase; /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ DrellYanBase & operator=(const DrellYanBase &); private: /** * Mass squared of the vector boson */ Energy2 mb2_; /** * Parameters for the old-style ME correction */ //@{ /** * Relative weight for the \f$q\bar{q}\f$ and \f$q/\bar{q}g\f$ channels */ double _channelwgtA; /** * Relative weight for the \f$qg\f$ and \f$\bar{q}g\f$ channels */ double _channelwgtB; /** * Weights for the channels as a vector */ vector _channelweights; /** * Number of weights greater than 1 */ unsigned int _nover; /** * Maximum weight */ double _maxwgt; //@} /** * Constants for the sampling. The distribution is assumed to have the * form \f$\frac{c}{{\rm GeV}}\times\left(\frac{{\rm GeV}}{p_T}\right)^n\f$ */ //@{ /** * The power, \f$n\f$, for the sampling */ double _power; /** * The prefactor, \f$c\f$ for the \f$q\bar{q}\f$ channel */ double _preqqbar; /** * The prefactor, \f$c\f$ for the \f$qg\f$ channel */ double _preqg; /** * The prefactor, \f$c\f$ for the \f$g\bar{q}\f$ channel */ double _pregqbar; /** * The prefactors as a vector for easy use */ vector _prefactor; //@} /** * Properties of the incoming particles */ //@{ /** * Pointers to the BeamParticleData objects */ vector _beams; /** * Pointers to the ParticleDataObjects for the partons */ vector _partons; //@} /** * Properties of the boson and jets */ //@{ /** * The rapidity of the gauge boson */ double _yb; /** * The mass of the gauge boson */ Energy _mass; /** * Whether the quark is in the + or - z direction */ bool _quarkplus; /** * the rapidity of the jet */ double _yj; /** * The transverse momentum of the jet */ Energy _pt; //@} /** * The transverse momentum of the jet */ Energy _min_pt; /** * Pointer to the object calculating the strong coupling */ ShowerAlphaPtr _alpha; }; } #include "ThePEG/Utilities/ClassTraits.h" namespace ThePEG { /** @cond TRAITSPECIALIZATIONS */ /** This template specialization informs ThePEG about the * base classes of DrellYanBase. */ template <> struct BaseClassTrait { /** Typedef of the first base class of DrellYanBase. */ typedef Herwig::HwMEBase NthBase; }; /** This template specialization informs ThePEG about the name of * the DrellYanBase 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::DrellYanBase"; } }; /** @endcond */ } #endif /* HERWIG_DrellYanBase_H */ diff --git a/MatrixElement/Hadron/MEPP2Higgs.cc b/MatrixElement/Hadron/MEPP2Higgs.cc --- a/MatrixElement/Hadron/MEPP2Higgs.cc +++ b/MatrixElement/Hadron/MEPP2Higgs.cc @@ -1,1629 +1,1627 @@ // -*- C++ -*- // // MEPP2Higgs.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 MEPP2Higgs class. // #include "MEPP2Higgs.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.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/Handlers/StandardXComb.h" #include "ThePEG/Cuts/Cuts.h" #include "Herwig/MatrixElement/HardVertex.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "Herwig/Utilities/Maths.h" #include "Herwig/Shower/Base/ShowerProgenitor.h" #include "Herwig/Shower/Base/ShowerTree.h" #include "Herwig/Shower/Base/Branching.h" #include "Herwig/Shower/Base/HardTree.h" using namespace Herwig; const complex MEPP2Higgs::epsi_ = complex(ZERO,-1.e-10*GeV2); MEPP2Higgs::MEPP2Higgs() : scaleopt_(1), mu_F_(100.*GeV), shapeOption_(2), processOption_(1), minFlavour_(4), maxFlavour_(5), mh_(ZERO), wh_(ZERO), minLoop_(6),maxLoop_(6),massOption_(0), mu_R_opt_(1),mu_F_opt_(1), channelwgtA_(0.45),channelwgtB_(0.15), ggPow_(1.6), qgPow_(1.6), enhance_(1.1), nover_(0), ntry_(0), ngen_(0), maxwgt_(0.), power_(2.0), pregg_(7.), preqg_(3.), pregqbar_(3.), minpT_(2.*GeV), spinCorrelations_(true) {} ClassDescription MEPP2Higgs::initMEPP2Higgs; // Definition of the static class description member. void MEPP2Higgs::persistentOutput(PersistentOStream & os) const { os << HGGVertex_ << HFFVertex_ << shapeOption_ << processOption_ << minFlavour_ << maxFlavour_ << hmass_ << ounit(mh_,GeV) << ounit(wh_,GeV) << minLoop_ << maxLoop_ << massOption_ << alpha_ << prefactor_ << power_ << pregg_ << preqg_ << pregqbar_ << ounit( minpT_, GeV ) << ggPow_ << qgPow_ << enhance_ << channelwgtA_ << channelwgtB_ << channelWeights_ << mu_R_opt_ << mu_F_opt_ << spinCorrelations_; } void MEPP2Higgs::persistentInput(PersistentIStream & is, int) { is >> HGGVertex_ >> HFFVertex_ >> shapeOption_ >> processOption_ >> minFlavour_ >> maxFlavour_ >> hmass_ >> iunit(mh_,GeV) >> iunit(wh_,GeV) >> minLoop_ >> maxLoop_ >> massOption_ >> alpha_ >> prefactor_ >> power_ >> pregg_ >> preqg_ >> pregqbar_ >> iunit( minpT_, GeV ) >> ggPow_ >> qgPow_ >> enhance_ >> channelwgtA_ >> channelwgtB_ >> channelWeights_ >> mu_R_opt_ >> mu_F_opt_ >> spinCorrelations_; } void MEPP2Higgs::Init() { static ClassDocumentation documentation ("The MEPP2Higgs class implements the matrix elements for" " Higgs production (with decay H->W-W+) in hadron-hadron collisions" " including the generation of additional hard QCD radiation in " "gg to h0 processes in the POWHEG scheme", "Hard QCD radiation for $gg\\to h^0$ processes in the" " POWHEG scheme \\cite{Hamilton:2009za}.", "%\\cite{Hamilton:2009za}\n" "\\bibitem{Hamilton:2009za}\n" " K.~Hamilton, P.~Richardson and J.~Tully,\n" " ``A Positive-Weight Next-to-Leading Order Monte Carlo Simulation for Higgs\n" " Boson Production,''\n" " JHEP {\\bf 0904}, 116 (2009)\n" " [arXiv:0903.4345 [hep-ph]].\n" " %%CITATION = JHEPA,0904,116;%%\n"); static Switch interfaceFactorizationScaleOption ("FactorizationScaleOption", "Option for the choice of factorization scale", &MEPP2Higgs::scaleopt_, 1, false, false); static SwitchOption interfaceDynamic (interfaceFactorizationScaleOption, "Dynamic", "Dynamic factorization scale equal to the current sqrt(sHat())", 1); static SwitchOption interfaceFixed (interfaceFactorizationScaleOption, "Fixed", "Use a fixed factorization scale set with FactorizationScaleValue", 2); static Parameter interfaceFactorizationScaleValue ("FactorizationScaleValue", "Value to use in the event of a fixed factorization scale", &MEPP2Higgs::mu_F_, GeV, 100.0*GeV, 50.0*GeV, 500.0*GeV, true, false, Interface::limited); static Reference interfaceCoupling ("Coupling", "Pointer to the object to calculate the coupling for the correction", &MEPP2Higgs::alpha_, false, false, true, false, false); static Switch interfaceShapeOption ("ShapeScheme", "Option for the treatment of the Higgs resonance shape", &MEPP2Higgs::shapeOption_, 1, false, false); static SwitchOption interfaceStandardShapeFixed (interfaceShapeOption, "FixedBreitWigner", "Breit-Wigner s-channel resonanse", 1); static SwitchOption interfaceStandardShapeRunning (interfaceShapeOption, "MassGenerator", "Use the mass generator to give the shape", 2); static Switch interfaceProcess ("Process", "Which subprocesses to include", &MEPP2Higgs::processOption_, 1, false, false); static SwitchOption interfaceProcessAll (interfaceProcess, "All", "Include all subprocesses", 1); static SwitchOption interfaceProcess1 (interfaceProcess, "qqbar", "Only include the incoming q qbar subprocess", 2); static SwitchOption interfaceProcessgg (interfaceProcess, "gg", "Only include the incoming gg subprocess", 3); static Parameter interfaceMinimumInLoop ("MinimumInLoop", "The minimum flavour of the quarks to include in the loops", &MEPP2Higgs::minLoop_, 6, 5, 6, false, false, Interface::limited); static Parameter interfaceMaximumInLoop ("MaximumInLoop", "The maximum flavour of the quarks to include in the loops", &MEPP2Higgs::maxLoop_, 6, 5, 6, false, false, Interface::limited); static Switch interfaceMassOption ("MassOption", "Option for the treatment of the masses in the loop diagrams", &MEPP2Higgs::massOption_, 0, false, false); static SwitchOption interfaceMassOptionFull (interfaceMassOption, "Full", "Include the full mass dependence", 0); static SwitchOption interfaceMassOptionLarge (interfaceMassOption, "Large", "Use the heavy mass limit", 1); static Parameter interfaceMinimumFlavour ("MinimumFlavour", "The minimum flavour of the incoming quarks in the hard process", &MEPP2Higgs::minFlavour_, 4, 3, 5, false, false, Interface::limited); static Parameter interfaceMaximumFlavour ("MaximumFlavour", "The maximum flavour of the incoming quarks in the hard process", &MEPP2Higgs::maxFlavour_, 5, 3, 5, false, false, Interface::limited); static Parameter interfaceQGChannelWeight ("QGChannelWeight", "The relative weights of the g g and q g channels for selection." " This is a technical parameter for the phase-space generation and " "should not affect the results only the efficiency and fraction" " of events with weight > 1.", &MEPP2Higgs::channelwgtA_, 0.45, 0., 1.e10, false, false, Interface::limited); static Parameter interfaceQbarGChannelWeight ("QbarGChannelWeight", "The relative weights of the g g abd qbar g channels for selection." " This is a technical parameter for the phase-space generation and " "should not affect the results only the efficiency and fraction", &MEPP2Higgs::channelwgtB_, 0.15, 0., 1.e10, false, false, Interface::limited); static Parameter interfaceGGPower ("GGPower", "Power for the phase-space sampling of the gg channel", &MEPP2Higgs::ggPow_, 1.6, 1.0, 3.0, false, false, Interface::limited); static Parameter interfaceQGPower ("QGPower", "Power for the phase-space sampling of the qg and qbarg channels", &MEPP2Higgs::qgPow_, 1.6, 1.0, 3.0, false, false, Interface::limited); static Parameter interfaceEnhancementFactor ("InitialEnhancementFactor", "The enhancement factor for initial-state radiation in the shower to ensure" " the weight for the matrix element correction is less than one.", &MEPP2Higgs::enhance_, 1.1, 1.0, 10.0, false, false, Interface::limited); static Parameter interfacePower ("Power", "The power for the sampling of the matrix elements", &MEPP2Higgs::power_, 2.0, 1.0, 10.0, false, false, Interface::limited); static Parameter interfacePrefactorgg ("Prefactorgg", "The prefactor for the sampling of the q qbar channel", &MEPP2Higgs::pregg_, 7.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacePrefactorqg ("Prefactorqg", "The prefactor for the sampling of the q g channel", &MEPP2Higgs::preqg_, 3.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacePrefactorgqbar ("Prefactorgqbar", "The prefactor for the sampling of the g qbar channel", &MEPP2Higgs::pregqbar_, 3.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacePtMin ("minPt", "The pt cut on hardest emision generation" "2*(1-Beta)*exp(-sqr(intrinsicpT/RMS))/sqr(RMS)", &MEPP2Higgs::minpT_, GeV, 2.*GeV, ZERO, 100000.0*GeV, false, false, Interface::limited); static Switch interface_mu_R_Option ("mu_R_Option", "Option to use pT or mT as the scale in alphaS", &MEPP2Higgs::mu_R_opt_, 1, false, false); static SwitchOption interface_mu_R_Option_mT (interface_mu_R_Option, "mT", "Use mT as the scale in alpha_S", 0); static SwitchOption interface_mu_R_Option_pT (interface_mu_R_Option, "pT", "Use pT as the scale in alpha_S", 1); static Switch interface_mu_F_Option ("mu_F_Option", "Option to use pT or mT as the factorization scale in the PDFs", &MEPP2Higgs::mu_F_opt_, 1, false, false); static SwitchOption interface_mu_F_Option_mT (interface_mu_F_Option, "mT", "Use mT as the scale in the PDFs", 0); static SwitchOption interface_mu_F_Option_pT (interface_mu_F_Option, "pT", "Use pT as the scale in the PDFs", 1); static Switch interfaceSpinCorrelations ("SpinCorrelations", "Which on/off spin correlations in the hard process", &MEPP2Higgs::spinCorrelations_, true, false, false); static SwitchOption interfaceSpinCorrelationsYes (interfaceSpinCorrelations, "Yes", "Switch correlations on", true); static SwitchOption interfaceSpinCorrelationsNo (interfaceSpinCorrelations, "No", "Switch correlations off", false); } void MEPP2Higgs::doinit() { HwMEBase::doinit(); // get the vertex pointers from the SM object tcHwSMPtr theSM = dynamic_ptr_cast(standardModel()); // do the initialisation if(!theSM) { throw InitException() << "Wrong type of StandardModel object in MEPP2Higgs::doinit()," << " the Herwig version must be used" << Exception::runerror; } HGGVertex_ = theSM->vertexHGG(); HFFVertex_ = theSM->vertexFFH(); // get the mass generator for the higgs PDPtr h0 = getParticleData(ParticleID::h0); mh_ = h0->mass(); wh_ = h0->generateWidth(mh_); if(h0->massGenerator()) { hmass_=dynamic_ptr_cast(h0->massGenerator()); } if(shapeOption_==2&&!hmass_) throw InitException() << "If using the mass generator for the line shape in MEPP2Higgs::doinit()" << "the mass generator must be an instance of the GenericMassGenerator class" << Exception::runerror; // stuff for the ME correction double total = 1.+channelwgtA_+channelwgtB_; channelWeights_.push_back(1./total); channelWeights_.push_back(channelWeights_.back()+channelwgtA_/total); channelWeights_.push_back(channelWeights_.back()+channelwgtB_/total); // insert the different prefactors in the vector for easy look up prefactor_.push_back(pregg_); prefactor_.push_back(preqg_); prefactor_.push_back(preqg_); prefactor_.push_back(pregqbar_); prefactor_.push_back(pregqbar_); } void MEPP2Higgs::dofinish() { HwMEBase::dofinish(); if(ntry_==0) return; generator()->log() << "MEPP2Higgs when applying the hard correction " << "generated " << ntry_ << " trial emissions of which " << ngen_ << " were accepted\n"; if(nover_==0) return; generator()->log() << "MEPP2Higgs when applying the hard correction " << nover_ << " weights larger than one were generated of which" << " the largest was " << maxwgt_ << "\n"; } unsigned int MEPP2Higgs::orderInAlphaS() const { return 2; } unsigned int MEPP2Higgs::orderInAlphaEW() const { return 1; } Energy2 MEPP2Higgs::scale() const { return scaleopt_ == 1 ? sHat() : sqr(mu_F_); } int MEPP2Higgs::nDim() const { return 0; } bool MEPP2Higgs::generateKinematics(const double *) { Lorentz5Momentum pout = meMomenta()[0] + meMomenta()[1]; pout.rescaleMass(); meMomenta()[2].setMass(pout.mass()); meMomenta()[2] = LorentzMomentum(pout.x(),pout.y(),pout.z(),pout.t()); jacobian(1.0); // check whether it passes all the cuts: returns true if it does vector out(1,meMomenta()[2]); tcPDVector tout(1,mePartonData()[2]); return lastCuts().passCuts(tout, out, mePartonData()[0], mePartonData()[1]); } void MEPP2Higgs::getDiagrams() const { tcPDPtr h0=getParticleData(ParticleID::h0); // gg -> H process if(processOption_==1||processOption_==3) { tcPDPtr g=getParticleData(ParticleID::g); add(new_ptr((Tree2toNDiagram(2), g, g, 1, h0, -1))); } // q qbar -> H processes if(processOption_==1||processOption_==2) { for ( int i = minFlavour_; i <= maxFlavour_; ++i ) { tcPDPtr q = getParticleData(i); tcPDPtr qb = q->CC(); add(new_ptr((Tree2toNDiagram(2), q, qb, 1, h0, -2))); } } } CrossSection MEPP2Higgs::dSigHatDR() const { using Constants::pi; InvEnergy2 bwfact; if(shapeOption_==1) { bwfact = mePartonData()[2]->generateWidth(sqrt(sHat()))*sqrt(sHat())/pi/ (sqr(sHat()-sqr(mh_))+sqr(mh_*wh_)); } else { bwfact = hmass_->BreitWignerWeight(sqrt(sHat())); } double cs = me2() * jacobian() * pi * double(UnitRemoval::E4 * bwfact/sHat()); return UnitRemoval::InvE2 * sqr(hbarc) * cs; } double MEPP2Higgs::me2() const { double output(0.0); ScalarWaveFunction hout(meMomenta()[2],mePartonData()[2],outgoing); // Safety code to garantee the reliable behaviour of Higgs shape limits // (important for heavy and broad Higgs resonance). Energy hmass = meMomenta()[2].m(); tcPDPtr h0 = mePartonData()[2]; Energy mass = h0->mass(); Energy halfmass = .5*mass; if (.0*GeV > hmass) return 0.0; // stricly speaking the condition is applicable if // h0->widthUpCut() == h0->widthLoCut()... if (h0->widthLoCut() > halfmass) { if ( mass + h0->widthUpCut() < hmass || mass - h0->widthLoCut() > hmass ) return 0.0; } else { if (mass + halfmass < hmass || halfmass > hmass) return 0.0; } if (mePartonData()[0]->id() == ParticleID::g && mePartonData()[1]->id() == ParticleID::g) { VectorWaveFunction gin1(meMomenta()[0],mePartonData()[0],incoming); VectorWaveFunction gin2(meMomenta()[1],mePartonData()[1],incoming); vector g1,g2; for(unsigned int i = 0; i < 2; ++i) { gin1.reset(2*i); g1.push_back(gin1); gin2.reset(2*i); g2.push_back(gin2); } output = ggME(g1,g2,hout,false); } else { if (mePartonData()[0]->id() == -mePartonData()[1]->id()) { SpinorWaveFunction qin (meMomenta()[0],mePartonData()[0],incoming); SpinorBarWaveFunction qbin(meMomenta()[1],mePartonData()[1],incoming); vector fin; vector ain; for (unsigned int i = 0; i < 2; ++i) { qin.reset(i); fin.push_back(qin); qbin.reset(i); ain.push_back(qbin); } output = qqME(fin,ain,hout,false); } else assert(false); } return output; } Selector MEPP2Higgs::diagrams(const DiagramVector & diags) const { Selector sel; for (DiagramIndex i = 0; i < diags.size(); ++i) sel.insert(1.0, i); return sel; } Selector MEPP2Higgs::colourGeometries(tcDiagPtr diag) const { // colour lines static const ColourLines line1("1 -2,2 -1"); static const ColourLines line2("1 -2"); // select the colour flow Selector sel; if (diag->id() == -1) { sel.insert(1.0, &line1); } else { sel.insert(1.0, &line2); } // return the answer return sel; } void MEPP2Higgs::constructVertex(tSubProPtr sub) { if(!spinCorrelations_) return; // extract the particles in the hard process ParticleVector hard; hard.push_back(sub->incoming().first); hard.push_back(sub->incoming().second); hard.push_back(sub->outgoing()[0]); if(hard[0]->id() < hard[1]->id()) { swap(hard[0],hard[1]); } // identify the process and calculate the matrix element if(hard[0]->id() == ParticleID::g && hard[1]->id() == ParticleID::g) { vector g1,g2; vector q; vector qbar; VectorWaveFunction (g1,hard[0],incoming,false,true,true); VectorWaveFunction (g2,hard[1],incoming,false,true,true); ScalarWaveFunction hout(hard[2],outgoing,true); g1[1] = g1[2]; g2[1] = g2[2]; ggME(g1,g2,hout,true); } else { vector q1; vector q2; SpinorWaveFunction (q1,hard[0],incoming,false,true); SpinorBarWaveFunction (q2,hard[1],incoming,false,true); ScalarWaveFunction hout(hard[2],outgoing,true); qqME(q1,q2,hout,true); } // construct the vertex HardVertexPtr hardvertex = new_ptr(HardVertex()); // set the matrix element for the vertex hardvertex->ME(me_); // set the pointers and to and from the vertex for(unsigned int i = 0; i < 3; ++i) hard[i]->spinInfo()->productionVertex(hardvertex); } double MEPP2Higgs::ggME(vector g1, vector g2, ScalarWaveFunction & in, bool calc) const { ProductionMatrixElement newme(PDT::Spin1,PDT::Spin1,PDT::Spin0); Energy2 s(sHat()); double me2(0.0); for(int i = 0; i < 2; ++i) { for(int j = 0; j < 2; ++j) { Complex diag = HGGVertex_->evaluate(s,g1[i],g2[j],in); me2 += norm(diag); if(calc) newme(2*i, 2*j, 0) = diag; } } if(calc) me_.reset(newme); // initial colour and spin factors: colour -> (8/64) and spin -> (1/4) return me2/32.; } double MEPP2Higgs::qqME(vector & fin, vector & ain, ScalarWaveFunction & in, bool calc) const { ProductionMatrixElement newme(PDT::Spin1Half,PDT::Spin1Half,PDT::Spin0); Energy2 s(scale()); double me2(0.0); for(int i = 0; i < 2; ++i) { for(int j = 0; j < 2; ++j) { Complex diag = HFFVertex_->evaluate(s,fin[i],ain[j],in); me2+=norm(diag); if(calc) newme(i, j, 0) = diag; } } if(calc) me_.reset(newme); // final colour/spin factors return me2/12.; } void MEPP2Higgs::applyHardMatrixElementCorrection(ShowerTreePtr tree) { useMe(); assert(tree->outgoingLines().size()==1); if(tree->incomingLines().begin()->second->id()!=ParticleID::g) return; // get gluons and Higgs // get the gluons map::const_iterator cit; ShowerParticleVector incoming; vector beams; for(cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) { incoming.push_back(cit->first->progenitor()); beams.push_back(cit->first->beam()); } if(incoming[0]->momentum().z()outgoingLines().begin()->first->copy(); // calculate the momenta unsigned int iemit,itype; vector pnew; pair xnew; // if not accepted return tPDPtr out; if(!applyHard(incoming,beams,higgs,iemit,itype,pnew,xnew,out)) return; // if applying ME correction create the new particles if(itype==0) { // ensure gluon can be put on shell Lorentz5Momentum ptest(pnew[2]); if(ptest.boost(-(pnew[0]+pnew[1]).boostVector()).e() < getParticleData(ParticleID::g)->constituentMass()) return; // create the new gluon PPtr newg= getParticleData(ParticleID::g)->produceParticle(pnew[2]); PPtr newg1,newg2; ColinePtr col; bool colour = UseRandom::rndbool(); // make the new particles if(iemit==0) { newg1 = incoming[0]->dataPtr()->produceParticle(pnew[0]); if(colour) { col = incoming[0]->colourLine(); incoming[0]->antiColourLine()->addAntiColoured(newg1); } else { col = incoming[0]->antiColourLine(); incoming[0]->colourLine()->addColoured(newg1); } newg2 = new_ptr(Particle(*incoming[1])); col->removeColoured(newg2,colour); newg2->set5Momentum(pnew[1]); } else { newg2 = incoming[1]->dataPtr()->produceParticle(pnew[1]); if(colour) { col= incoming[1]->antiColourLine(); incoming[1]->colourLine()->addColoured(newg2); } else { col= incoming[1]->colourLine(); incoming[1]->antiColourLine()->addAntiColoured(newg2); } newg1 = new_ptr(Particle(*incoming[0])); col->removeColoured(newg1,!colour); newg1->set5Momentum(pnew[0]); } // set the colour lines ColinePtr newline=new_ptr(ColourLine()); if(iemit==0) { newline->addColoured(newg1,!colour); newline->addColoured(newg ,!colour); col ->addColoured(newg , colour); col ->addColoured(newg2, colour); } else { newline->addColoured(newg2, colour); newline->addColoured(newg , colour); col ->addColoured(newg ,!colour); col ->addColoured(newg1,!colour); } // change the existing gluons PPtr orig; for(cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) { // remove old particles from colour line ColinePtr l1=cit->first->copy()-> colourLine(); ColinePtr l2=cit->first->copy()->antiColourLine(); l1->removeColoured (cit->first->copy() ); l1->removeColoured (cit->first->progenitor()); l2->removeAntiColoured(cit->first->copy() ); l2->removeAntiColoured(cit->first->progenitor()); if(cit->first->progenitor()->momentum().z()/newg1->momentum().z()>0) { // insert new particles cit->first->copy(newg1); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newg1,1,false))); sp->x(xnew.first); cit->first->progenitor(sp); tree->incomingLines()[cit->first]=sp; cit->first->perturbative(iemit!=0); if(iemit==0) orig=cit->first->original(); } else { // insert new particles cit->first->copy(newg2); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newg2,1,false))); sp->x(xnew.second); cit->first->progenitor(sp); tree->incomingLines()[cit->first]=sp; cit->first->perturbative(iemit==0); if(iemit==1) orig=cit->first->original(); } } // fix the momentum of the higgs map::const_iterator cjt=tree->outgoingLines().begin(); Boost boostv=cjt->first->progenitor()->momentum().findBoostToCM(); LorentzRotation trans(pnew[3].boostVector()); trans *=LorentzRotation(boostv); cjt->first->progenitor()->transform(trans); cjt->first->copy()->transform(trans); tree->hardMatrixElementCorrection(true); // add the gluon ShowerParticlePtr sg=new_ptr(ShowerParticle(*newg,1,true)); ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(orig,newg,sg)); gluon->perturbative(false); tree->outgoingLines().insert(make_pair(gluon,sg)); } else if(itype==1) { // ensure outgoing quark can be put on-shell Lorentz5Momentum ptest(pnew[2]); if(ptest.boost(-(pnew[0]+pnew[1]).boostVector()).e() < out->constituentMass()) return; // create the new particles PPtr newqout = out->produceParticle(pnew[2]); PPtr newqin,newg; if(iemit==0) { newqin = out ->produceParticle(pnew[0]); newg = new_ptr(Particle(*incoming[1])); newg->set5Momentum(pnew[1]); incoming[0]->colourLine() ->addColoured(newqin); incoming[0]->antiColourLine()->addColoured(newqout); } else { newg = new_ptr(Particle(*incoming[0])); newg->set5Momentum(pnew[0]); newqin = out ->produceParticle(pnew[1]); incoming[1]->colourLine() ->addColoured(newqin); incoming[1]->antiColourLine()->addColoured(newqout); } // change the existing incoming partons PPtr orig; for(cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) { // remove old particles from colour line ColinePtr l1=cit->first->copy()-> colourLine(); ColinePtr l2=cit->first->copy()->antiColourLine(); l1->removeColoured (cit->first->copy() ); l1->removeColoured (cit->first->progenitor()); l2->removeAntiColoured(cit->first->copy() ); l2->removeAntiColoured(cit->first->progenitor()); if(cit->first->progenitor()->momentum().z()/newqin->momentum().z()>0.) { // insert new particles cit->first->copy(newqin); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newqin,1,false))); sp->x(iemit==0 ? xnew.first : xnew.second ); cit->first->progenitor(sp); tree->incomingLines()[cit->first]=sp; cit->first->perturbative(false); orig=cit->first->original(); } else { // insert new particles cit->first->copy(newg); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newg,1,false))); sp->x(iemit==1 ? xnew.first : xnew.second ); cit->first->progenitor(sp); tree->incomingLines()[cit->first]=sp; cit->first->perturbative(true); } } // fix the momentum of the higgs map::const_iterator cjt=tree->outgoingLines().begin(); Boost boostv=cjt->first->progenitor()->momentum().findBoostToCM(); LorentzRotation trans(pnew[3].boostVector()); trans *=LorentzRotation(boostv); cjt->first->progenitor()->transform(trans); cjt->first->copy()->transform(trans); tree->hardMatrixElementCorrection(true); // add the outgoing quark ShowerParticlePtr sout=new_ptr(ShowerParticle(*newqout,1,true)); ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(orig,newqout,sout)); out->perturbative(false); tree->outgoingLines().insert(make_pair(out,sout)); } else if(itype==2) { // ensure outgoing antiquark can be put on-shell Lorentz5Momentum ptest(pnew[2]); if(ptest.boost(-(pnew[0]+pnew[1]).boostVector()).e() < incoming[0]->dataPtr()->constituentMass()) return; // create the new particles PPtr newqout = out->produceParticle(pnew[2]); PPtr newqin,newg; if(iemit==0) { newqin = out ->produceParticle(pnew[0]); newg = new_ptr(Particle(*incoming[1])); newg->set5Momentum(pnew[1]); incoming[0]->colourLine() ->addAntiColoured(newqout); incoming[0]->antiColourLine()->addAntiColoured(newqin); } else { newg = new_ptr(Particle(*incoming[0])); newg->set5Momentum(pnew[0]); newqin = out ->produceParticle(pnew[1]); incoming[1]->colourLine() ->addAntiColoured(newqout); incoming[1]->antiColourLine()->addAntiColoured(newqin); } // change the existing incoming partons PPtr orig; for(cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) { // remove old particles from colour line ColinePtr l1=cit->first->copy()-> colourLine(); ColinePtr l2=cit->first->copy()->antiColourLine(); l1->removeColoured (cit->first->copy() ); l1->removeColoured (cit->first->progenitor()); l2->removeAntiColoured(cit->first->copy() ); l2->removeAntiColoured(cit->first->progenitor()); if(cit->first->progenitor()->momentum().z()/newqin->momentum().z()>0.) { // insert new particles cit->first->copy(newqin); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newqin,1,false))); sp->x(iemit==0 ? xnew.first : xnew.second ); cit->first->progenitor(sp); tree->incomingLines()[cit->first]=sp; cit->first->perturbative(false); orig=cit->first->original(); } else { // insert new particles cit->first->copy(newg); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newg,1,false))); sp->x(iemit==1 ? xnew.first : xnew.second ); cit->first->progenitor(sp); tree->incomingLines()[cit->first]=sp; cit->first->perturbative(true); } } // fix the momentum of the higgs map::const_iterator cjt=tree->outgoingLines().begin(); Boost boostv=cjt->first->progenitor()->momentum().findBoostToCM(); LorentzRotation trans(pnew[3].boostVector()); trans *=LorentzRotation(boostv); cjt->first->progenitor()->transform(trans); cjt->first->copy()->transform(trans); tree->hardMatrixElementCorrection(true); // add the outgoing antiquark ShowerParticlePtr sout=new_ptr(ShowerParticle(*newqout,1,true)); ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(orig,newqout,sout)); out->perturbative(false); tree->outgoingLines().insert(make_pair(out,sout)); } } bool MEPP2Higgs::softMatrixElementVeto(ShowerProgenitorPtr initial, ShowerParticlePtr parent,Branching br) { if(parent->isFinalState()) return false; // check if me correction should be applied long id[2]={initial->id(),parent->id()}; // must have started as a gluon if(id[0]!=ParticleID::g) return false; // must be a gluon going into the hard process if(br.ids[1]!=ParticleID::g) return false; // get the pT Energy pT=br.kinematics->pT(); // check if hardest so far if(pThighestpT()) return false; // compute the invariants double kappa(sqr(br.kinematics->scale())/mh2_),z(br.kinematics->z()); Energy2 shat(mh2_/z*(1.+(1.-z)*kappa)),that(-(1.-z)*kappa*mh2_),uhat(-(1.-z)*shat); // check which type of process Energy2 me; // g g if(br.ids[0]==ParticleID::g&&br.ids[2]==ParticleID::g) { double split = 6.*(z/(1.-z)+(1.-z)/z+z*(1.-z)); me = ggME(shat,that,uhat)/split; } // q g else if(br.ids[0] >= 1 && br.ids[0] <= 5 && br.ids[2]==br.ids[0]) { double split = 4./3./z*(1.+sqr(1.-z)); me = qgME(shat,uhat,that)/split; } // qbar g else if(br.ids[0] <= -1 && br.ids[0] >= -5 && br.ids[2]==br.ids[0]) { double split = 4./3./z*(1.+sqr(1.-z)); me = qbargME(shat,uhat,that)/split; } else { return false; } InvEnergy2 pre = 0.125/Constants::pi/loME()*sqr(mh2_)*that/shat/(shat+uhat); double wgt = -pre*me/enhance_; if(wgt<.0||wgt>1.) generator()->log() << "Soft ME correction weight too large or " << "negative in MEPP2Higgs::" << "softMatrixElementVeto()\n soft weight " << " sbar = " << shat/mh2_ << " tbar = " << that/mh2_ << "weight = " << wgt << " for " << br.ids[0] << " " << br.ids[1] << " " << br.ids[2] << "\n"; // if not vetoed if(UseRandom::rndbool(wgt)) return false; // otherwise parent->vetoEmission(br.type,br.kinematics->scale()); return true; } HardTreePtr MEPP2Higgs::generateHardest(ShowerTreePtr tree, - vector inter) { - bool found = false; + ShowerInteraction::Type inter) { // check if generating QCD radiation - for(unsigned int ix=0;ixincomingLines().begin()->second->id()!=ParticleID::g) return HardTreePtr(); useMe(); // get the particles to be showered beams_.clear(); partons_.clear(); // find the incoming particles ShowerParticleVector incoming; map::const_iterator cit; vector particlesToShower; 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 higgs boson PPtr higgs; if(tree->outgoingLines().size() == 1) { higgs = tree->outgoingLines().begin()->first->copy(); } else { higgs = tree->outgoingLines().begin()->first->copy()->parents()[0]; } // calculate the rapidity of the higgs yh_ = 0.5 * log((higgs->momentum().e()+higgs->momentum().z())/ (higgs->momentum().e()-higgs->momentum().z())); mass_=higgs->mass(); mh2_ = sqr(mass_); vector pnew; int emission_type(-1); // generate the hard emission and return if no emission if(!getEvent(pnew,emission_type)) { for(unsigned int ix=0;ixmaximumpT(minpT_,ShowerInteraction::QCD); return HardTreePtr(); } // construct the HardTree object needed to perform the showers ShowerParticleVector newparticles(4); // create the partons int iemit=-1; // g g -> h g if(emission_type==0) { newparticles[0] = new_ptr(ShowerParticle(partons_[0] ,false)); newparticles[1] = new_ptr(ShowerParticle(partons_[1] ,false)); iemit = pnew[0].z()/pnew[3].z()>0. ? 0 : 1; } // g q -> H q else if(emission_type==1) { newparticles[0] = new_ptr(ShowerParticle(partons_[0] ,false)); newparticles[1] = new_ptr(ShowerParticle(out_ ,false)); iemit = 1; } // q g -> H q else if(emission_type==2) { newparticles[0] = new_ptr(ShowerParticle(out_ ,false)); newparticles[1] = new_ptr(ShowerParticle(partons_[1] ,false)); iemit = 0; } // g qbar -> H qbar else if(emission_type==3) { newparticles[0] = new_ptr(ShowerParticle(partons_[0] ,false)); newparticles[1] = new_ptr(ShowerParticle(out_ ,false)); iemit = 1; } // qbar g -> H qbar else if(emission_type==4) { newparticles[0] = new_ptr(ShowerParticle(out_ ,false)); newparticles[1] = new_ptr(ShowerParticle(partons_[1] ,false)); iemit = 0; } unsigned int ispect = iemit==0 ? 1 : 0; // create the jet newparticles[3] = new_ptr(ShowerParticle(out_ , true)); // create the boson newparticles[2] = new_ptr(ShowerParticle(higgs->dataPtr(),true)); // set the momenta for(unsigned int ix=0;ix<4;++ix) newparticles[ix]->set5Momentum(pnew[ix]); // create the off-shell particle Lorentz5Momentum poff=pnew[iemit]-pnew[3]; poff.rescaleMass(); newparticles.push_back(new_ptr(ShowerParticle(partons_[iemit],false))); newparticles.back()->set5Momentum(poff); 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[4],SudakovPtr(), inBranch[iemit],HardBranching::Incoming))); inBranch[iemit]->addChild(hardBranch.back()); // create the branching for the emitted jet inBranch[iemit]->addChild(new_ptr(HardBranching(newparticles[3],SudakovPtr(), inBranch[iemit],HardBranching::Outgoing))); ColinePtr cline1 = new_ptr(ColourLine()); ColinePtr cline2 = new_ptr(ColourLine()); ColinePtr cline3 = new_ptr(ColourLine()); if(newparticles[3]->id()<0|| (newparticles[3]->id()==ParticleID::g&&UseRandom::rndbool())) { inBranch[iemit]->type(ShowerPartnerType::QCDColourLine); cline1->addAntiColoured(newparticles[3]); cline1->addColoured (newparticles[4]); cline1->addAntiColoured(newparticles[ispect]); cline2->addColoured (newparticles[ispect]); cline2->addAntiColoured(newparticles[4]); cline2->addAntiColoured(newparticles[iemit]); if(newparticles[3]->id()==ParticleID::g) { cline3->addColoured(newparticles[iemit]); cline3->addColoured(newparticles[3]); } } else { inBranch[iemit]->type(ShowerPartnerType::QCDAntiColourLine); cline1->addColoured (newparticles[3]); cline1->addAntiColoured(newparticles[4]); cline1->addColoured (newparticles[ispect]); cline2->addAntiColoured(newparticles[ispect]); cline2->addColoured (newparticles[4]); cline2->addColoured (newparticles[iemit]); if(newparticles[3]->id()==ParticleID::g) { cline3->addAntiColoured(newparticles[iemit]); cline3->addAntiColoured(newparticles[3]); } } // set the colour partners hardBranch.back()->colourPartner(inBranch[iemit==0 ? 1 : 0]); inBranch[iemit==0 ? 1 : 0]->colourPartner(hardBranch.back()); // add other particle hardBranch.push_back(inBranch[iemit==0 ? 1 : 0]); // outgoing Higgs boson hardBranch.push_back(new_ptr(HardBranching(newparticles[2],SudakovPtr(), HardBranchingPtr(),HardBranching::Outgoing))); // make the tree HardTreePtr hardtree=new_ptr(HardTree(hardBranch,inBranch,ShowerInteraction::QCD)); // connect the ShowerParticles with the branchings // and set the maximum pt for the radiation set hard=hardtree->branchings(); for(unsigned int ix=0;ixmaximumpT(minpT_,ShowerInteraction::QCD); else particlesToShower[ix]->maximumpT(pt_,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))) { if(particlesToShower[ix]->progenitor()->momentum().z()/ (*mit)->branchingParticle()->momentum().z()<0.) continue; 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(); }; } } } // return the answer return hardtree; } bool MEPP2Higgs::applyHard(ShowerParticleVector gluons, vector beams,PPtr higgs, unsigned int & iemit, unsigned int & itype, vector & pnew, pair & xout, tPDPtr & out) { ++ntry_; // calculate the limits on s Energy mh(higgs->mass()); mh2_=sqr(mh); Energy2 smin=mh2_; Energy2 s= (generator()->currentEvent()->incoming().first->momentum()+ generator()->currentEvent()->incoming().second->momentum()).m2(); Energy2 smax(s); // calculate the rapidity of the higgs double yH = 0.5*log((higgs->momentum().e()+higgs->momentum().z())/ (higgs->momentum().e()-higgs->momentum().z())); // if no phase-space return if(smaxx(); assert(beams[ix]); pdf[ix]=beams[ix]->pdf(); assert(pdf[ix]); fx[ix]=pdf[ix]->xfx(beams[ix],gluons[ix]->dataPtr(),mh2_,x[ix]); } // leading order ME Energy4 lome = loME(); // select the type of process and generate the kinematics double rn(UseRandom::rnd()); Energy2 shat(ZERO),uhat(ZERO),that(ZERO); double weight(0.),xnew[2]={1.,1.}; // gg -> H g if(rn=1.||xnew[1]<=0.||xnew[1]>=1.) return false; for(unsigned int ix=0;ix<2;++ix) fxnew[ix]=pdf[ix]->xfx(beams[ix],gluons[ix]->dataPtr(),scale,xnew[ix]); // jacobian and me parts of the weight weight = jacobian2*ggME(shat,uhat,that)/lome*mh2_/sqr(shat); // pdf part of the weight weight *=fxnew[0]*fxnew[1]*x[0]*x[1]/(fx[0]*fx[1]*xnew[0]*xnew[1]); // finally coupling and different channel pieces weight *= 1./16./sqr(Constants::pi)*alpha_->value(scale)/channelWeights_[0]; itype=0; iemit = that>uhat ? 0 : 1; out = getParticleData(ParticleID::g); } // incoming quark or antiquark else { // generate the value of s according to 1/s^n double rhomax(pow(smin/mh2_,1.-qgPow_)),rhomin(pow(smax/mh2_,1.-qgPow_)); double rho = rhomin+UseRandom::rnd()*(rhomax-rhomin); shat = mh2_*pow(rho,1./(1.-qgPow_)); Energy2 jacobian = mh2_/(qgPow_-1.)*(rhomax-rhomin)*pow(shat/mh2_,qgPow_); double sbar=shat/mh2_; // calculate limits on that Energy2 tmax=mh2_*kappa[0]*(1.-sbar)/(kappa[0]+sbar); Energy2 tmin=shat*(1.-sbar)/(kappa[1]+sbar); // calculate the limits on uhat Energy2 umax(mh2_-shat-tmin),umin(mh2_-shat-tmax); // check inside phase space if(tmax=1.||xnew[1]<=0.||xnew[1]>=1.) return false; if(rn H q if(!order) { out = quarkFlavour(pdf[0],scale,xnew[0],beams[0],fxnew[0],false); fxnew[1]=pdf[1]->xfx(beams[1],gluons[1]->dataPtr(),scale,xnew[1]); iemit = 0; mewgt = out ? qgME(shat,uhat,that)/lome*mh2_/sqr(shat) : ZERO; } // g q -> H q else { fxnew[0]=pdf[0]->xfx(beams[0],gluons[0]->dataPtr(),scale,xnew[0]); out = quarkFlavour(pdf[1],scale,xnew[1],beams[1],fxnew[1],false); iemit = 1; mewgt = out ? qgME(shat,that,uhat)/lome*mh2_/sqr(shat) : ZERO; } jacobian2 /= (channelWeights_[1]-channelWeights_[0]); } else { itype=2; // qbar g -> H qbar if(!order) { out = quarkFlavour(pdf[0],scale,xnew[0],beams[0],fxnew[0],true); fxnew[1]=pdf[1]->xfx(beams[1],gluons[1]->dataPtr(),scale,xnew[1]); iemit = 0; mewgt = out ? qbargME(shat,uhat,that)/lome*mh2_/sqr(shat) : ZERO; } // g qbar -> H qbar else { fxnew[0]=pdf[0]->xfx(beams[0],gluons[0]->dataPtr(),scale,xnew[0]); out = quarkFlavour(pdf[1],scale,xnew[1],beams[1],fxnew[1],true); iemit = 1; mewgt = out ? qbargME(shat,that,uhat)/lome*mh2_/sqr(shat) : ZERO; } jacobian2/=(channelWeights_[2]-channelWeights_[1]); } // weight (factor of 2 as pick q(bar)g or gq(bar) weight = 2.*jacobian2*mewgt; // pdf part of the weight weight *=fxnew[0]*fxnew[1]*x[0]*x[1]/(fx[0]*fx[1]*xnew[0]*xnew[1]); // finally coupling and different channel pieces weight *= 1./16./sqr(Constants::pi)*alpha_->value(scale); } // if me correction should be applied if(weight>1.) { ++nover_; maxwgt_ = max( maxwgt_ , weight); weight=1.; } if(UseRandom::rnd()>weight) return false; ++ngen_; // construct the momenta Energy roots = 0.5*sqrt(s); Energy pt = sqrt(uhat*that/shat); Energy mt = sqrt(uhat*that/shat+mh2_); Lorentz5Momentum pin[2]={Lorentz5Momentum(ZERO,ZERO, xnew[0]*roots,xnew[0]*roots), Lorentz5Momentum(ZERO,ZERO,-xnew[1]*roots,xnew[1]*roots)}; double phi = Constants::twopi*UseRandom::rnd(); Lorentz5Momentum pH(pt*cos(phi),pt*sin(phi),mt*sinh(yH),mt*cosh(yH)); Lorentz5Momentum pJ(pin[0]+pin[1]-pH); // momenta to be returned pnew.push_back(pin[0]); pnew.push_back(pin[1]); pnew.push_back(pJ); pnew.push_back(pH); xout.first = xnew[0]; xout.second = xnew[1]; return true; } Energy2 MEPP2Higgs::ggME(Energy2 s, Energy2 t, Energy2 u) { Energy2 output; if(massOption_==0) { complex me[2][2][2]; me[1][1][1] = ZERO; me[1][1][0] = ZERO; me[0][1][0] = ZERO; me[0][1][1] = ZERO; for(unsigned int ix=minLoop_; ix<=maxLoop_; ++ix ) { Energy2 mf2=sqr(getParticleData(long(ix))->mass()); bi_[1]=B(s,mf2); bi_[2]=B(u,mf2); bi_[3]=B(t,mf2); bi_[4]=B(mh2_,mf2); bi_[1]=bi_[1]-bi_[4]; bi_[2]=bi_[2]-bi_[4]; bi_[3]=bi_[3]-bi_[4]; ci_[1]=C(s,mf2); ci_[2]=C(u,mf2); ci_[3]=C(t,mf2); ci_[7]=C(mh2_,mf2); ci_[4]=(s*ci_[1]-mh2_*ci_[7])/(s-mh2_); ci_[5]=(u*ci_[2]-mh2_*ci_[7])/(u-mh2_); ci_[6]=(t*ci_[3]-mh2_*ci_[7])/(t-mh2_); di_[1]=D(t,u,s,mf2); di_[2]=D(s,t,u,mf2); di_[3]=D(s,u,t,mf2); me[1][1][1]+=me1(s,u,t,mf2,1,2,3,4,5,6); me[1][1][0]+=me2(s,u,t,mf2); me[0][1][0]+=me1(u,s,t,mf2,2,1,3,5,4,6); me[0][1][1]+=me1(t,u,s,mf2,3,2,1,6,5,4); } me[0][0][0]=-me[1][1][1]; me[0][0][1]=-me[1][1][0]; me[1][0][1]=-me[0][1][0]; me[1][0][0]=-me[0][1][1]; output = real(me[0][0][0]*conj(me[0][0][0])+ me[0][0][1]*conj(me[0][0][1])+ me[0][1][0]*conj(me[0][1][0])+ me[0][1][1]*conj(me[0][1][1])+ me[1][0][0]*conj(me[1][0][0])+ me[1][0][1]*conj(me[1][0][1])+ me[1][1][0]*conj(me[1][1][0])+ me[1][1][1]*conj(me[1][1][1])); output *= 3./8.; } else { output=32./3.* (pow<4,1>(s)+pow<4,1>(t)+pow<4,1>(u)+pow<4,1>(mh2_))/s/t/u; } // spin and colour factors return output/4./64.; } Energy2 MEPP2Higgs::qgME(Energy2 s, Energy2 t, Energy2 u) { Energy2 output; if(massOption_==0) { complex A(ZERO); Energy2 si(u-mh2_); for(unsigned int ix=minLoop_;ix<=maxLoop_;++ix) { Energy2 mf2=sqr(getParticleData(long(ix))->mass()); A += mf2*(2.+2.*double(u/si)*(B(u,mf2)-B(mh2_,mf2)) +double((4.*mf2-s-t)/si)*Complex(u*C(u,mf2)-mh2_*C(mh2_,mf2))); } output =-4.*(sqr(s)+sqr(t))/sqr(si)/u*real(A*conj(A)); } else{ output =-4.*(sqr(s)+sqr(t))/u/9.; } // final colour/spin factors return output/24.; } Energy2 MEPP2Higgs::qbargME(Energy2 s, Energy2 t, Energy2 u) { Energy2 output; if(massOption_==0) { complex A(ZERO); Energy2 si(u-mh2_); for(unsigned int ix=minLoop_;ix<=maxLoop_;++ix) { Energy2 mf2=sqr(getParticleData(long(ix))->mass()); A+=mf2*(2.+2.*double(u/si)*(B(u,mf2)-B(mh2_,mf2)) +double((4.*mf2-s-t)/si)*Complex(u*C(u,mf2)-mh2_*C(mh2_,mf2))); } output =-4.*(sqr(s)+sqr(t))/sqr(si)/u*real(A*conj(A)); } else { output =-4.*(sqr(s)+sqr(t))/u/9.; } // final colour/spin factors return output/24.; } Energy4 MEPP2Higgs::loME() const { Complex I(0); if(massOption_==0) { for(unsigned int ix=minLoop_;ix<=maxLoop_;++ix) { double x = sqr(getParticleData(long(ix))->mass())/mh2_; I += 3.*x*(2.+(4.*x-1.)*F(x)); } } else { I = 1.; } return sqr(mh2_)/576./Constants::pi*norm(I); } tPDPtr MEPP2Higgs::quarkFlavour(tcPDFPtr pdf, Energy2 scale, double x, tcBeamPtr beam, double & pdfweight, bool anti) { vector weights; vector partons; pdfweight = 0.; if(!anti) { for(unsigned int ix=1;ix<=5;++ix) { partons.push_back(getParticleData(long(ix))); weights.push_back(max(0.,pdf->xfx(beam,partons.back(),scale,x))); pdfweight += weights.back(); } } else { for(unsigned int ix=1;ix<=5;++ix) { partons.push_back(getParticleData(-long(ix))); weights.push_back(max(0.,pdf->xfx(beam,partons.back(),scale,x))); pdfweight += weights.back(); } } if(pdfweight==0.) return tPDPtr(); double wgt=UseRandom::rnd()*pdfweight; for(unsigned int ix=0;ix=ZERO&&rat<1.) output=2.-2.*sqrt(1./rat-1.)*asin(sqrt(rat)); else output=2.-sqrt(1.-1./rat)*(2.*log(sqrt(rat)+sqrt(rat-1.))-pii); return output; } complex MEPP2Higgs::C(Energy2 s,Energy2 mf2) const { complex output; Complex pii(0.,Constants::pi); double rat=s/(4.*mf2); if(s=ZERO&&rat<1.) output=-2.*sqr(asin(sqrt(rat)))/s; else { double cosh=log(sqrt(rat)+sqrt(rat-1.)); output=2.*(sqr(cosh)-sqr(Constants::pi)/4.-pii*cosh)/s; } return output; } Complex MEPP2Higgs::dIntegral(Energy2 a, Energy2 b, double y0) const { Complex output; if(b==ZERO) output=0.; else { Complex y1=0.5*(1.+sqrt(1.-4.*(a+epsi_)/b)); Complex y2=1.-y1; Complex z1=y0/(y0-y1); Complex z2=(y0-1.)/(y0-y1); Complex z3=y0/(y0-y2); Complex z4=(y0-1.)/(y0-y2); output=Math::Li2(z1)-Math::Li2(z2)+Math::Li2(z3)-Math::Li2(z4); } return output; } complex MEPP2Higgs::D(Energy2 s,Energy2 t, Energy2, Energy2 mf2) const { Complex output,pii(0.,Constants::pi); Energy4 st=s*t; Energy4 root=sqrt(sqr(st)-4.*st*mf2*(s+t-mh2_)); double xp=0.5*(st+root)/st,xm=1-xp; output = 2.*(-dIntegral(mf2,s,xp)-dIntegral(mf2,t,xp) +dIntegral(mf2,mh2_,xp)+log(-xm/xp) *(log((mf2+epsi_)/GeV2)-log((mf2+epsi_-s*xp*xm)/GeV2) +log((mf2+epsi_-mh2_*xp*xm)/GeV2)-log((mf2+epsi_-t*xp*xm)/GeV2))); return output/root; } complex MEPP2Higgs::me1(Energy2 s,Energy2 t,Energy2 u, Energy2 mf2, unsigned int i ,unsigned int j ,unsigned int k , unsigned int i1,unsigned int j1,unsigned int k1) const { Energy2 s1(s-mh2_),t1(t-mh2_),u1(u-mh2_); return mf2*4.*sqrt(2.*s*t*u)* (-4.*(1./(u*t)+1./(u*u1)+1./(t*t1)) -4.*((2.*s+t)*bi_[k]/sqr(u1)+(2.*s+u)*bi_[j]/sqr(t1))/s -(s-4.*mf2)*(s1*ci_[i1]+(u-s)*ci_[j1]+(t-s)*ci_[k1])/(s*t*u) -8.*mf2*(ci_[j1]/(t*t1)+ci_[k1]/(u*u1)) +0.5*(s-4.*mf2)*(s*t*di_[k]+u*s*di_[j]-u*t*di_[i])/(s*t*u) +4.*mf2*di_[i]/s -2.*(u*ci_[k]+t*ci_[j]+u1*ci_[k1]+t1*ci_[j1]-u*t*di_[i])/sqr(s)); } complex MEPP2Higgs::me2(Energy2 s,Energy2 t,Energy2 u, Energy2 mf2) const { Energy2 s1(s-mh2_),t1(t-mh2_),u1(u-mh2_); return mf2*4.*sqrt(2.*s*t*u)*(4.*mh2_+(mh2_-4.*mf2)*(s1*ci_[4]+t1*ci_[5]+u1*ci_[6]) -0.5*(mh2_-4.*mf2)*(s*t*di_[3]+u*s*di_[2]+u*t*di_[1]) )/ (s*t*u); } Complex MEPP2Higgs::F(double x) const { if(x<.25) { double root = sqrt(1.-4.*x); Complex pii(0.,Constants::pi); return 0.5*sqr(log((1.+root)/(1.-root))-pii); } else { return -2.*sqr(asin(0.5/sqrt(x))); } } bool MEPP2Higgs::getEvent(vector & pnew, int & emis_type){ // maximum pt (half of centre-of-mass energy) Energy maxp = 0.5*generator()->maximumCMEnergy(); // set pt of emission to zero pt_=ZERO; //Working Variables Energy pt; double yj; // limits on the rapidity of the jet double minyj = -8.0,maxyj = 8.0; bool reject; double wgt; emis_type=-1; tcPDPtr outParton; for(int j=0;j<5;++j) { pt = maxp; do { double a = alpha_->overestimateValue()*prefactor_[j]*(maxyj-minyj)/(power_-1.); // generate next pt pt=GeV/pow(pow(GeV/pt,power_-1)-log(UseRandom::rnd())/a,1./(power_-1.)); // generate rapidity of the jet yj=UseRandom::rnd()*(maxyj-minyj)+ minyj; // calculate rejection weight wgt=getResult(j,pt,yj,outParton); wgt/= prefactor_[j]*pow(GeV/pt,power_); reject = UseRandom::rnd()>wgt; //no emission event if p goes past p min - basically set to outside //of the histogram bounds (hopefully hist object just ignores it) if(pt1.0) { ostringstream s; s << "MEPP2Higgs::getEvent weight for channel " << j << "is " << wgt << " which is greater than 1"; generator()->logWarning( Exception(s.str(), Exception::warning) ); } } while(reject); // set pt of emission etc if(pt>pt_){ emis_type = j; pt_=pt; yj_=yj; out_ = outParton; } } //was this an (overall) no emission event? if(pt_maximumCMEnergy()); // transverse energy Energy et=sqrt(mh2_+sqr(pt_)); // first calculate all the kinematic variables // longitudinal real correction fractions double x = pt_*exp( yj_)/sqrt(s)+et*exp( yh_)/sqrt(s); double y = pt_*exp(-yj_)/sqrt(s)+et*exp(-yh_)/sqrt(s); // that and uhat // Energy2 th = -sqrt(s)*x*pt_*exp(-yj_); // Energy2 uh = -sqrt(s)*y*pt_*exp( yj_); // Energy2 sh = x*y*s; // reconstruct the momenta // incoming momenta pnew.push_back(Lorentz5Momentum(ZERO,ZERO, x*0.5*sqrt(s), x*0.5*sqrt(s),ZERO)); pnew.push_back(Lorentz5Momentum(ZERO,ZERO, -y*0.5*sqrt(s), y*0.5*sqrt(s),ZERO)); // outgoing momenta double phi(Constants::twopi*UseRandom::rnd()); double sphi(sin(phi)),cphi(cos(phi)); pnew.push_back(Lorentz5Momentum( cphi*pt_, sphi*pt_, et*sinh(yh_), et*cosh(yh_), mass_)); pnew.push_back(Lorentz5Momentum(-cphi*pt_,-sphi*pt_,pt_*sinh(yj_), pt_*cosh(yj_),ZERO)); return true; } double MEPP2Higgs::getResult(int emis_type, Energy pt, double yj, tcPDPtr & outParton) { Energy2 s=sqr(generator()->maximumCMEnergy()); Energy2 scale = mh2_+sqr(pt); Energy et=sqrt(scale); scale = mu_F_opt_==0 ? mh2_+sqr(pt) : sqr(pt) ; // longitudinal real correction fractions double x = pt*exp( yj)/sqrt(s)+et*exp( yh_)/sqrt(s); double y = pt*exp(-yj)/sqrt(s)+et*exp(-yh_)/sqrt(s); // reject if outside region if(x<0.||x>1.||y<0.||y>1.||x*ypdf()->xfx(beams_[0],partons_[0],mh2_,x1); pdf[1]=beams_[1]->pdf()->xfx(beams_[1],partons_[1],mh2_,y1); } else { // As in Nason and Ridolfi paper ... pdf[0]=beams_[0]->pdf()->xfx(beams_[0],partons_[0],scale,x1); pdf[1]=beams_[1]->pdf()->xfx(beams_[1],partons_[1],scale,y1); } // g g -> H g if(emis_type==0) { outParton = partons_[1]; pdf[2]=beams_[0]->pdf()->xfx(beams_[0],partons_[0],scale,x); pdf[3]=beams_[1]->pdf()->xfx(beams_[1],partons_[1],scale,y); res = ggME(sh,uh,th)/loME(); } // q g -> H q else if(emis_type==1) { outParton = quarkFlavour(beams_[0]->pdf(),scale,x,beams_[0],pdf[2],false); pdf[3]=beams_[1]->pdf()->xfx(beams_[1],partons_[1],scale,y); res = outParton ? qgME(sh,uh,th)/loME() : ZERO; } // g q -> H q else if(emis_type==2) { pdf[2]=beams_[0]->pdf()->xfx(beams_[0],partons_[0],scale,x); outParton = quarkFlavour(beams_[1]->pdf(),scale,y,beams_[1],pdf[3],false); res = outParton ? qgME(sh,th,uh)/loME() : ZERO; } // qbar g -> H qbar else if(emis_type==3) { outParton = quarkFlavour(beams_[0]->pdf(),scale,x,beams_[0],pdf[2],true); pdf[3]=beams_[1]->pdf()->xfx(beams_[1],partons_[1],scale,y); res = outParton ? qbargME(sh,uh,th)/loME() : ZERO; } // g qbar -> H qbar else if(emis_type==4) { pdf[2]=beams_[0]->pdf()->xfx(beams_[0],partons_[0],scale,x); outParton = quarkFlavour(beams_[1]->pdf(),scale,y,beams_[1],pdf[3],true); res = outParton ? qbargME(sh,th,uh)/loME() : ZERO; } //deals with pdf zero issue at large x if(pdf[0]<=0.||pdf[1]<=0.||pdf[2]<=0.||pdf[3]<=0.) { res = ZERO; } else { res *= pdf[2]*pdf[3]/pdf[0]/pdf[1]*mh2_/sh; } scale = mu_R_opt_==0 ? mh2_+sqr(pt) : sqr(pt) ; return alpha_->ratio(scale)/8./sqr(Constants::pi)*mh2_/sh*GeV*pt*res; } void MEPP2Higgs::initializeMECorrection(ShowerTreePtr tree, double & initial, double & final) { final = 1.; initial = tree->incomingLines().begin()->second->id()==ParticleID::g ? enhance_ : 1.; } diff --git a/MatrixElement/Hadron/MEPP2Higgs.h b/MatrixElement/Hadron/MEPP2Higgs.h --- a/MatrixElement/Hadron/MEPP2Higgs.h +++ b/MatrixElement/Hadron/MEPP2Higgs.h @@ -1,742 +1,741 @@ // -*- C++ -*- // // MEPP2Higgs.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_MEPP2Higgs_H #define HERWIG_MEPP2Higgs_H // // This is the declaration of the MEPP2Higgs class. // #include "Herwig/MatrixElement/HwMEBase.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h" #include "ThePEG/Helicity/Vertex/AbstractVVSVertex.h" #include "Herwig/PDT/GenericMassGenerator.h" #include "Herwig/MatrixElement/ProductionMatrixElement.h" #include "Herwig/Shower/Couplings/ShowerAlpha.h" namespace Herwig { using namespace ThePEG; using namespace ThePEG::Helicity; /** * The MEPP2Higgs class implements the matrix element for the process * pp->Higgs with different Higgs shape prescriptions (see details in hep-ph/9505211) * and the NLL corrected Higgs width (see details in the FORTRAN HERWIG manual). * * @see \ref MEPP2HiggsInterfaces "The interfaces" * defined for MEPP2Higgs. */ class MEPP2Higgs: public HwMEBase { public: /** * The default constructor. */ MEPP2Higgs(); /** * Return the matrix element for the kinematical configuation * previously provided by the last call to setKinematics(). Uses * me(). */ virtual CrossSection dSigHatDR() const; /** * Set the typed and momenta of the incoming and outgoing partons to * be used in subsequent calls to me() and colourGeometries() * according to the associated XComb object. */ virtual void setKinematics() { HwMEBase::setKinematics(); mh2_ = sHat(); } public: /** @name Member functions for the generation of hard QCD radiation */ //@{ /** * Has a POWHEG style correction */ virtual POWHEGType hasPOWHEGCorrection() {return ISR;} /** * Has an old fashioned ME correction */ virtual bool hasMECorrection() {return true;} /** * Initialize the ME correction */ virtual void initializeMECorrection(ShowerTreePtr tree, double & initial, double & final); /** * Apply the hard matrix element correction to a given hard process or decay */ virtual void applyHardMatrixElementCorrection(ShowerTreePtr); /** * Apply the soft matrix element correction * @param initial The particle from the hard process which started the * shower * @param parent The initial particle in the current branching * @param br The branching struct * @return If true the emission should be vetoed */ virtual bool softMatrixElementVeto(ShowerProgenitorPtr initial, ShowerParticlePtr parent, Branching br); /** * Apply the POWHEG style correction */ - virtual HardTreePtr generateHardest(ShowerTreePtr, - vector); + virtual HardTreePtr generateHardest(ShowerTreePtr,ShowerInteraction::Type); //@} public: /** @name Virtual functions required by the MEBase class. */ //@{ /** * Return the order in \f$\alpha_S\f$ in which this matrix * element is given. */ virtual unsigned int orderInAlphaS() const; /** * Return the order in \f$\alpha_{EW}\f$ in which this matrix * element is given. */ virtual unsigned int orderInAlphaEW() const; /** * The matrix element for the kinematical configuration * previously provided by the last call to setKinematics(), suitably * scaled by sHat() to give a dimension-less number. * @return the matrix element scaled with sHat() to give a * dimensionless number. */ virtual double me2() const; /** * Generate internal degrees of freedom given nDim() uniform * random numbers in the interval \f$ ]0,1[ \f$. To help the phase space * generator, the dSigHatDR should be a smooth function of these * numbers, although this is not strictly necessary. * @param r a pointer to the first of nDim() consecutive random numbers. * @return true if the generation succeeded, otherwise false. */ virtual bool generateKinematics(const double * r); /** * Return the scale associated with the last set phase space point. */ virtual Energy2 scale() const; /** * The number of internal degrees of freedom used in the matrix * element. */ virtual int nDim() const; /** * Add all possible diagrams with the add() function. */ virtual void getDiagrams() const; /** * Get diagram selector. With the information previously supplied with the * setKinematics method, a derived class may optionally * override this method to weight the given diagrams with their * (although certainly not physical) relative probabilities. * @param dv the diagrams to be weighted. * @return a Selector relating the given diagrams to their weights. */ virtual Selector diagrams(const DiagramVector & dv) const; /** * Return a Selector with possible colour geometries for the selected * diagram weighted by their relative probabilities. * @param diag the diagram chosen. * @return the possible colour geometries weighted by their * relative probabilities. */ virtual Selector colourGeometries(tcDiagPtr diag) const; /** * Construct the vertex of spin correlations. */ virtual void constructVertex(tSubProPtr); //@} 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 Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const { return new_ptr(*this); } /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const { return new_ptr(*this); } //@} 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(); /** * Finalize this object. Called in the run phase just after a * run has ended. Used eg. to write out statistics. */ virtual void dofinish(); //@} protected: /** * Members to calculate the real emission matrix elements */ //@{ /** * The leading-order matrix element for \f$gg\to H\f$ */ Energy4 loME() const; /** * The matrix element for \f$gg\to H g\f$ */ Energy2 ggME(Energy2 s, Energy2 t, Energy2 u); /** * The matrix element for \f$qg\to H q\f$ */ Energy2 qgME(Energy2 s, Energy2 t, Energy2 u); /** * The matrix element for \f$qbarg\to H qbar\f$ */ Energy2 qbargME(Energy2 s, Energy2 t, Energy2 u); //@} /** * Members to calculate the functions for the loop diagrams */ //@{ /** * The \f$B(s)\f$ function of NBP339 (1990) 38-66 * @param s The scale * @param mf2 The fermion mass squared. */ Complex B(Energy2 s,Energy2 mf2) const; /** * The \f$C(s)\f$ function of NBP339 (1990) 38-66 * @param s The scale * @param mf2 The fermion mass squared. */ complex C(Energy2 s,Energy2 mf2) const; /** * The \f$C(s)\f$ function of NBP339 (1990) 38-66 * @param s The \f$s\f$ invariant * @param t The \f$t\f$ invariant * @param u The \f$u\f$ invariant * @param mf2 The fermion mass squared */ complex D(Energy2 s,Energy2 t, Energy2 u,Energy2 mf2) const; /** * The integral \f$\int\frac{dy}{y-y_0}\log(a-i\epsilon-b y(1-y))\f$ * from NBP339 (1990) 38-66. * @param a The parameter \f$a\f$. * @param b The parameter \f$b\f$. * @param y0 The parameter \f$y_0\f$. */ Complex dIntegral(Energy2 a, Energy2 b, double y0) const; /** * The \f$M_{+++}\f$ matrix element of NBP339 (1990) 38-66. * @param s The \f$s\f$ invariant * @param t The \f$t\f$ invariant * @param u The \f$u\f$ invariant * @param mf2 The fermion mass squared. * @param i Which of the stored values to use for \f$D(u,t)\f$. * @param j Which of the stored values to use for \f$D(u,s)\f$. * @param k Which of the stored values to use for \f$D(s,t)\f$. * @param i1 Which of the stored values to use for \f$C_1(s)\f$. * @param j1 Which of the stored values to use for \f$C_1(t)\f$. * @param k1 Which of the stored values to use for \f$C_1(u)\f$. */ complex me1(Energy2 s,Energy2 t,Energy2 u, Energy2 mf2, unsigned int i,unsigned int j, unsigned int k, unsigned int i1,unsigned int j1, unsigned int k1) const; /** * The \f$M_{++-}\f$ matrix element of NBP339 (1990) 38-66. * @param s The \f$s\f$ invariant * @param t The \f$t\f$ invariant * @param u The \f$u\f$ invariant * @param mf2 The fermion mass squared. */ complex me2(Energy2 s,Energy2 t,Energy2 u, Energy2 mf2) const; /** * The \f$F(x)\f$ function for the leading-order result */ Complex F(double x) const; //@} /** * Method to extract the PDF weight for quark/antiquark * initiated processes and select the quark flavour */ tPDPtr quarkFlavour(tcPDFPtr pdf, Energy2 scale, double x, tcBeamPtr beam, double & pdfweight, bool anti); /** * Return the momenta and type of hard matrix element correction * @param gluons The original incoming particles. * @param beams The BeamParticleData objects * @param higgs The original outgoing higgs * @param iemit Whether the first (0) or second (1) particle emitted * the radiation * @param itype The type of radiated particle (0 is gluon, 1 is quark * and 2 is antiquark) * @param pnew The momenta of the new particles * @param xnew The new values of the momentuym fractions * @param out The ParticleData object for the outgoing parton * @return Whether or not the matrix element correction needs to be applied */ bool applyHard(ShowerParticleVector gluons, vector beams, PPtr higgs,unsigned int & iemit, unsigned int & itype,vector & pnew, pair & xnew, tPDPtr & out); /** * generates the hardest emission (yj,p) * @param pnew The momenta of the new particles * @param emissiontype The type of emission, as for getResult * @return Whether not an emission was generated */ bool getEvent(vector & pnew,int & emissiontype); /** * Returns the matrix element for a given type of process, * rapidity of the jet \f$y_j\f$ and transverse momentum \f$p_T\f$ * @param emis_type the type of emission, * (0 is \f$gg\to h^0g\f$, 1 is \f$qg\to h^0q\f$ and 2 is \f$g\bar{q}\to h^0\bar{q}\f$) * @param pt The transverse momentum of the jet * @param yj The rapidity of the jet * @param outParton the outgoing parton */ double getResult(int emis_type, Energy pt, double yj,tcPDPtr & outParton); private: /** * The static object used to initialize the description of this class. * Indicates that this is a concrete class with persistent data. */ static ClassDescription initMEPP2Higgs; /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ MEPP2Higgs & operator=(const MEPP2Higgs &); //@} /** * Members to return the matrix elements for the different subprocesses */ //@{ /** * Calculates the matrix element for the process g,g->h (via quark loops) * @param g1 a vector of wave functions of the first incoming gluon * @param g2 a vector of wave functions of the second incoming gluon * @param calc Whether or not to calculate the matrix element for spin correlations * @return the amlitude value. */ double ggME(vector g1, vector g2, ScalarWaveFunction &, bool calc) const; /** * Calculates the matrix element for the process q,qbar->h * @param fin a vector of quark spinors * @param ain a vector of anti-quark spinors * @param calc Whether or not to calculate the matrix element for spin correlations * @return the amlitude value. */ double qqME(vector & fin, vector & ain, ScalarWaveFunction &, bool calc) const; //@} private: /** * Selects a dynamic (sHat) or fixed factorization scale */ unsigned int scaleopt_; /** * The value associated to the fixed factorization scale option */ Energy mu_F_; /** * Defines the Higgs resonance shape */ unsigned int shapeOption_; /** * The processes to be included (GG->H and/or qq->H) */ unsigned int processOption_; /** * Minimum flavour of incoming quarks */ int minFlavour_; /** * Maximum flavour of incoming quarks */ int maxFlavour_; /** * Matrix element for spin correlations */ ProductionMatrixElement me_; /** * Pointer to the H-> 2 gluon vertex (used in gg->H) */ AbstractVVSVertexPtr HGGVertex_; /** * Pointer to the fermion-fermion Higgs vertex (used in qq->H) */ AbstractFFSVertexPtr HFFVertex_; /** * The mass generator for the Higgs */ GenericMassGeneratorPtr hmass_; /** * On-shell mass for the higgs */ Energy mh_; /** * On-shell width for the higgs */ Energy wh_; /** * Stuff for the ME correction */ //@{ /** * Parameters for the evaluation of the loops for the * matrix elements */ //@{ /** * Minimum flavour of quarks to include in the loops */ unsigned int minLoop_; /** * Maximum flavour of quarks to include in the loops */ unsigned int maxLoop_; /** * Option for treatment of the fermion loops */ unsigned int massOption_; /** * Option for dynamic scale choice in alpha_S (0=mT,>0=pT) */ unsigned int mu_R_opt_; /** * Option for dynamic scale choice in PDFs (0=mT,>0=pT) */ unsigned int mu_F_opt_; //@} //@} /** * Small complex number to regularize some integrals */ static const complex epsi_; /** * Storage of the loop functions */ //@{ /** * B functions */ mutable Complex bi_[5]; /** * C functions */ mutable complex ci_[8]; /** * D functions */ mutable complex di_[4]; //@} /** * Pointer to the object calculating the strong coupling */ ShowerAlphaPtr alpha_; /** * Mass squared of Higgs */ Energy2 mh2_; /** * Relative weight of the \f$qg\f$ to the \f$gg\f$ channel */ double channelwgtA_; /** * Relative weight for the \f$\bar{q}g\f$ to the \f$gg\f$ channel */ double channelwgtB_; /** * Weights for the channels as a vector */ vector channelWeights_; /** * Power for the \f$\frac{{\rm d}\hat{s}}{\hat{s}^n}\f$ importance sampling * of the \f$gg\f$ component */ double ggPow_; /** * Power for the \f$\frac{{\rm d}\hat{s}}{\hat{s}^n}\f$ importance sampling * of the \f$qg\f$ and \f$\bar{q}g\f$ components */ double qgPow_; /** * The enhancement factor for initial-state radiation */ double enhance_; /** * Number of weights greater than 1 */ unsigned int nover_; /** * Number of attempts */ unsigned int ntry_; /** * Number which suceed */ unsigned int ngen_; /** * Maximum weight */ double maxwgt_; //@} /** * Constants for the sampling. The distribution is assumed to have the * form \f$\frac{c}{{\rm GeV}}\times\left(\frac{{\rm GeV}}{p_T}\right)^n\f$ */ //@{ /** * The power, \f$n\f$, for the sampling */ double power_; /** * The prefactor, \f$c\f$ for the \f$gg\f$ channel */ double pregg_; /** * The prefactor, \f$c\f$ for the \f$qg\f$ channel */ double preqg_; /** * The prefactor, \f$c\f$ for the \f$g\bar{q}\f$ channel */ double pregqbar_; /** * The prefactors as a vector for easy use */ vector prefactor_; //@} /** * The transverse momentum of the jet */ Energy minpT_; /** * Properties of the incoming particles */ //@{ /** * Pointers to the BeamParticleData objects */ vector beams_; /** * Pointers to the ParticleDataObjects for the partons */ vector partons_; //@} /** * Properties of the boson and jets */ //@{ /** * The rapidity of the Higgs boson */ double yh_; /** * The mass of the Higgs boson */ Energy mass_; /** * the rapidity of the jet */ double yj_; /** * The transverse momentum of the jet */ Energy pt_; /** * The outgoing parton */ tcPDPtr out_; //@} /** * Whether of not to construct the vertex for spin correlations */ bool spinCorrelations_; }; } #include "ThePEG/Utilities/ClassTraits.h" namespace ThePEG { /** @cond TRAITSPECIALIZATIONS */ /** This template specialization informs ThePEG about the base classes of MEPP2Higgs. */ template <> struct BaseClassTrait { /** Typedef of the first base class of MEPP2Higgs. */ typedef Herwig::HwMEBase NthBase; }; /** This template specialization informs ThePEG about the name of * the MEPP2Higgs 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::MEPP2Higgs"; } /** * The name of a file containing the dynamic library where the class * MEPP2Higgs is implemented. It may also include several, space-separated, * libraries if the class MEPP2Higgs depends on other classes (base classes * excepted). In this case the listed libraries will be dynamically * linked in the order they are specified. */ static string library() { return "HwMEHadron.so"; } }; /** @endcond */ } #endif /* HERWIG_MEPP2Higgs_H */ diff --git a/MatrixElement/Hadron/MEPP2HiggsVBF.cc b/MatrixElement/Hadron/MEPP2HiggsVBF.cc --- a/MatrixElement/Hadron/MEPP2HiggsVBF.cc +++ b/MatrixElement/Hadron/MEPP2HiggsVBF.cc @@ -1,1634 +1,1632 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the MEPP2HiggsVBF class. // #include "MEPP2HiggsVBF.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/MatrixElement/Tree2toNDiagram.h" #include "ThePEG/PDT/StandardMatchers.h" #include #include "Herwig/Utilities/Maths.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "ThePEG/Repository/CurrentGenerator.h" #include "Herwig/Shower/Base/ShowerProgenitor.h" #include "Herwig/Shower/Base/ShowerTree.h" #include "Herwig/Shower/Base/Branching.h" #include "Herwig/Shower/Base/HardTree.h" using namespace Herwig; // namespace { // using namespace Herwig; // using namespace ThePEG; // using namespace ThePEG::Helicity; // void debuggingMatrixElement(bool BGF, // tcPDPtr partons1, tcPDPtr partons2, // tcPDPtr partons3, tcPDPtr partons4, // const Lorentz5Momentum & psystem0, // const Lorentz5Momentum & psystem1, // const Lorentz5Momentum & pother0, // const Lorentz5Momentum & pother1, // const Lorentz5Momentum & p0, // const Lorentz5Momentum & p1, // const Lorentz5Momentum & p2, // const Lorentz5Momentum & phiggs, // Energy2 Q12, Energy2 scale, // double old) { // // get the vertex and the boson // tcHwSMPtr hwsm=ThePEG::dynamic_ptr_cast // (CurrentGenerator::current().standardModel()); // assert(hwsm); // tcPDPtr boson; // AbstractFFVVertexPtr weakVertex; // AbstractFFVVertexPtr strongVertex = hwsm->vertexFFG(); // AbstractVVSVertexPtr higgsVertex = hwsm->vertexWWH(); // if(partons1->id()==partons2->id()) { // weakVertex = hwsm->vertexFFZ(); // boson = hwsm->getParticleData(ParticleID::Z0); // } // else { // weakVertex = hwsm->vertexFFW(); // boson = hwsm->getParticleData(ParticleID::Wplus); // } // tcPDPtr hdata = hwsm->getParticleData(ParticleID::h0); // tcPDPtr gluon = hwsm->getParticleData(ParticleID::g); // SpinorWaveFunction q1,q2; // SpinorBarWaveFunction qbar1,qbar2; // if(partons1->id()>0) { // q1 = SpinorWaveFunction (psystem0,partons1,incoming); // qbar1 = SpinorBarWaveFunction(psystem1,partons2,outgoing); // } // else { // q1 = SpinorWaveFunction (psystem1,partons2,outgoing); // qbar1 = SpinorBarWaveFunction(psystem0,partons1,incoming); // } // if(partons3->id()>0) { // q2 = SpinorWaveFunction (pother0,partons3,incoming); // qbar2 = SpinorBarWaveFunction(pother1,partons4,outgoing); // } // else { // q2 = SpinorWaveFunction (pother1,partons4,outgoing); // qbar2 = SpinorBarWaveFunction(pother0,partons3,incoming); // } // ScalarWaveFunction higgs(phiggs,hdata,outgoing); // if(!BGF) { // SpinorWaveFunction q1p; // SpinorBarWaveFunction qbar1p; // if(partons1->id()>0) { // q1p = SpinorWaveFunction (p0 ,partons1,incoming); // qbar1p = SpinorBarWaveFunction(p1 ,partons2,outgoing); // } // else { // q1p = SpinorWaveFunction (p1 ,partons2,outgoing); // qbar1p = SpinorBarWaveFunction(p0 ,partons1,incoming); // } // VectorWaveFunction gl(p2,gluon,outgoing); // double lome(0.),realme(0.); // for(unsigned int lhel1=0;lhel1<2;++lhel1) { // q2.reset(lhel1); // for(unsigned int lhel2=0;lhel2<2;++lhel2) { // qbar2.reset(lhel2); // VectorWaveFunction off1 // = weakVertex->evaluate(scale,3,boson,q2,qbar2); // VectorWaveFunction off2 // = higgsVertex->evaluate(scale,3,boson,off1,higgs); // for(unsigned int qhel1=0;qhel1<2;++qhel1) { // q1.reset(qhel1); // q1p.reset(qhel1); // for(unsigned int qhel2=0;qhel2<2;++qhel2) { // qbar1.reset(qhel2); // qbar1p.reset(qhel2); // Complex diag = weakVertex->evaluate(scale,q1,qbar1,off2); // lome += norm(diag); // for(unsigned int ghel=0;ghel<2;++ghel) { // gl.reset(2*ghel); // SpinorWaveFunction inter1 = // strongVertex->evaluate(Q12,5,q1p.particle(),q1p,gl); // Complex diag1 = weakVertex->evaluate(scale,inter1,qbar1p,off2); // SpinorBarWaveFunction inter2 = // strongVertex->evaluate(Q12,5,qbar1p.particle(),qbar1p,gl); // Complex diag2 = weakVertex->evaluate(scale,q1p,inter2,off2); // realme += norm(diag1+diag2); // } // } // } // } // } // double test1 = realme/lome/hwsm->alphaS(Q12)*Q12*UnitRemoval::InvE2; // cerr << "testing ratio A " << old/test1 << "\n"; // } // else { // SpinorWaveFunction q1p; // SpinorBarWaveFunction qbar1p; // if(partons1->id()>0) { // q1p = SpinorWaveFunction (p2,partons1->CC(),outgoing); // qbar1p = SpinorBarWaveFunction(p1,partons2 ,outgoing); // } // else { // q1p = SpinorWaveFunction (p1,partons2 ,outgoing); // qbar1p = SpinorBarWaveFunction(p2,partons1->CC(),outgoing); // } // VectorWaveFunction gl(p0,gluon,incoming); // double lome(0.),realme(0.); // for(unsigned int lhel1=0;lhel1<2;++lhel1) { // q2.reset(lhel1); // for(unsigned int lhel2=0;lhel2<2;++lhel2) { // qbar2.reset(lhel2); // VectorWaveFunction off1 // = weakVertex->evaluate(scale,3,boson,q2,qbar2); // VectorWaveFunction off2 // = higgsVertex->evaluate(scale,3,boson,off1,higgs); // for(unsigned int qhel1=0;qhel1<2;++qhel1) { // q1.reset(qhel1); // q1p.reset(qhel1); // for(unsigned int qhel2=0;qhel2<2;++qhel2) { // qbar1.reset(qhel2); // qbar1p.reset(qhel2); // Complex diag = weakVertex->evaluate(scale,q1,qbar1,off2); // lome += norm(diag); // for(unsigned int ghel=0;ghel<2;++ghel) { // gl.reset(2*ghel); // SpinorWaveFunction inter1 = // strongVertex->evaluate(Q12,5,q1p.particle(),q1p,gl); // Complex diag1 = weakVertex->evaluate(scale,inter1,qbar1p,off2); // SpinorBarWaveFunction inter2 = // strongVertex->evaluate(Q12,5,qbar1p.particle(),qbar1p,gl); // Complex diag2 = weakVertex->evaluate(scale,q1p,inter2,off2); // realme += norm(diag1+diag2); // } // } // } // } // } // double test1 = realme/lome/hwsm->alphaS(Q12)*Q12*UnitRemoval::InvE2; // cerr << "testing ratio B " << old/test1 << "\n"; // } // } // } MEPP2HiggsVBF::MEPP2HiggsVBF() : comptonWeight_(8.), BGFWeight_(30.), pTmin_(1.*GeV),initial_(10.),final_(8.), procProb_(0.5), comptonInt_(0.), bgfInt_(0.), nover_(0),maxwgt_(make_pair(0.,0.)) {} void MEPP2HiggsVBF::doinit() { gluon_ = getParticleData(ParticleID::g); // integrals of me over phase space double r5=sqrt(5.),darg((r5-1.)/(r5+1.)),ath(0.5*log((1.+1./r5)/(1.-1./r5))); comptonInt_ = 2.*(-21./20.-6./(5.*r5)*ath+sqr(Constants::pi)/3. -2.*Math::ReLi2(1.-darg)-2.*Math::ReLi2(1.-1./darg)); bgfInt_ = 121./9.-56./r5*ath; // get the vertex pointers from the SM object tcHwSMPtr hwsm= dynamic_ptr_cast(standardModel()); if(!hwsm) throw InitException() << "Wrong type of StandardModel object in " << "MEPP2HiggsVBF::doinit() the Herwig" << " version must be used" << Exception::runerror; // set the vertex setWWHVertex(hwsm->vertexWWH()); higgs(getParticleData(ParticleID::h0)); MEfftoffH::doinit(); } void MEPP2HiggsVBF::dofinish() { MEfftoffH::dofinish(); if(nover_==0) return; generator()->log() << "VBFMECorrection when applying the hard correction " << nover_ << " weights larger than one were generated of which" << " the largest was " << maxwgt_.first << " for the QCD compton" << " processes and " << maxwgt_.second << " for the BGF process\n"; } void MEPP2HiggsVBF::getDiagrams() const { // get the quark particle data objects as we'll be using them tcPDPtr q[6],qbar[6]; for ( int ix=0; ix<5; ++ix ) { q [ix] = getParticleData(ix+1); qbar[ix] = q[ix]->CC(); } // WW processes if(process()==0||process()==1) { std::vector > parentpair; parentpair.reserve(6); // don't even think of putting 'break' in here! switch(maxFlavour()) { case 5: if (minFlavour()<=4) parentpair.push_back(make_pair(getParticleData(ParticleID::b), getParticleData(ParticleID::c))); if (minFlavour()<=2) parentpair.push_back(make_pair(getParticleData(ParticleID::b), getParticleData(ParticleID::u))); case 4: if (minFlavour()<=3) parentpair.push_back(make_pair(getParticleData(ParticleID::s), getParticleData(ParticleID::c))); if (minFlavour()<=1) parentpair.push_back(make_pair(getParticleData(ParticleID::d), getParticleData(ParticleID::c))); case 3: if (minFlavour()<=2) parentpair.push_back(make_pair(getParticleData(ParticleID::s), getParticleData(ParticleID::u))); case 2: if (minFlavour()<=1) parentpair.push_back(make_pair(getParticleData(ParticleID::d), getParticleData(ParticleID::u))); default: ; } for(unsigned int ix=0;ix q1' q2' h if(parentpair[ix].first->id()id()) { add(new_ptr((Tree2toNDiagram(4), parentpair[ix].first, WMinus(), WPlus(), parentpair[iy].second, 1, parentpair[ix].second, 3, parentpair[iy].first, 2, higgs(),-1))); } else { add(new_ptr((Tree2toNDiagram(4), parentpair[iy].second, WPlus(), WMinus(), parentpair[ix].first, 1, parentpair[iy].first, 3, parentpair[ix].second, 2, higgs(),-1))); } // q1 qbar2 -> q1' qbar2' h add(new_ptr((Tree2toNDiagram(4), parentpair[ix].first, WMinus(), WPlus(), parentpair[iy].first->CC(), 1, parentpair[ix].second, 3, parentpair[iy].second->CC(), 2, higgs(),-1))); add(new_ptr((Tree2toNDiagram(4),parentpair[iy].second, WPlus(), WMinus(), parentpair[ix].second->CC(), 1, parentpair[iy].first, 3, parentpair[ix].first->CC(), 2, higgs(),-1))); // qbar1 qbar2 -> qbar1' qbar2' h if(parentpair[ix].first->id()id()) { add(new_ptr((Tree2toNDiagram(4), parentpair[ix].first->CC(), WPlus(), WMinus(), parentpair[iy].second->CC(), 1, parentpair[ix].second->CC(), 3, parentpair[iy].first->CC(), 2, higgs(),-1))); } else { add(new_ptr((Tree2toNDiagram(4), parentpair[iy].second->CC(), WMinus(), WPlus(), parentpair[ix].first->CC(), 1, parentpair[iy].first->CC(), 3, parentpair[ix].second->CC(), 2, higgs(),-1))); } } } } // ZZ processes if(process()==0||process()==2) { for(unsigned int ix=minFlavour()-1;ix q q H add(new_ptr((Tree2toNDiagram(4), q[ix], Z0(), Z0(), q[iy], 1, q[ix], 3, q[iy], 2, higgs(),-2))); // qbar qbar -> qbar qbar H add(new_ptr((Tree2toNDiagram(4), qbar[ix], Z0(), Z0(), qbar[iy], 1, qbar[ix], 3, qbar[iy], 2, higgs(),-2))); } // q qbar -> q qbar H for(unsigned int iy=minFlavour()-1;iy> initial_ >> final_ >> alpha_ >> iunit(pTmin_,GeV) >> comptonWeight_ >> BGFWeight_ >> gluon_ >> comptonInt_ >> bgfInt_ >> procProb_; } ClassDescription MEPP2HiggsVBF::initMEPP2HiggsVBF; // Definition of the static class description member. void MEPP2HiggsVBF::Init() { static ClassDocumentation documentation ("The MEPP2HiggsVBF class implements Higgs production via vector-boson fusion"); static Reference interfaceShowerAlphaQCD ("ShowerAlphaQCD", "The object calculating the strong coupling constant", &MEPP2HiggsVBF::alpha_, false, false, true, false, false); static Parameter interfacepTMin ("pTMin", "The minimum pT", &MEPP2HiggsVBF::pTmin_, GeV, 1.*GeV, 0.0*GeV, 10.0*GeV, false, false, Interface::limited); static Parameter interfaceComptonWeight ("ComptonWeight", "Weight for the overestimate ofthe compton channel", &MEPP2HiggsVBF::comptonWeight_, 50.0, 0.0, 100.0, false, false, Interface::limited); static Parameter interfaceBGFWeight ("BGFWeight", "Weight for the overestimate of the BGF channel", &MEPP2HiggsVBF::BGFWeight_, 100.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfaceProcessProbability ("ProcessProbability", "The probabilty of the QCD compton process for the process selection", &MEPP2HiggsVBF::procProb_, 0.3, 0.0, 1., false, false, Interface::limited); } HardTreePtr MEPP2HiggsVBF::generateHardest(ShowerTreePtr tree, - vector inter) { - bool found = false; + ShowerInteraction::Type inter) { // check if generating QCD radiation - for(unsigned int ix=0;ix first,second; pair beams; pair hadrons; // get the incoming particles for(map::const_iterator cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) { if(!first.first) { first.first = cit->first->progenitor(); beams.first = cit->first->beam(); hadrons.first = cit->first->original()->parents()[0]; } else { second.first = cit->first->progenitor(); beams.second = cit->first->beam(); hadrons.second = cit->first->original()->parents()[0]; } } // and the outgoing for(map::const_iterator cjt=tree->outgoingLines().begin();cjt!=tree->outgoingLines().end();++cjt) { if(cjt->first->progenitor()->id()==ParticleID::h0) { higgs_ = cjt->first->progenitor(); } else { if(abs(cjt->first->progenitor()->id())>5) continue; if(cjt->first->progenitor()->colourLine()&& cjt->first->progenitor()->colourLine()==first.first->colourLine()) { first.second = cjt->first->progenitor(); continue; } if(cjt->first->progenitor()->antiColourLine()&& cjt->first->progenitor()->antiColourLine()==first.first->antiColourLine()) { first.second = cjt->first->progenitor(); continue; } if(cjt->first->progenitor()->colourLine()&& cjt->first->progenitor()->colourLine()==second.first->colourLine()) { second.second = cjt->first->progenitor(); continue; } if(cjt->first->progenitor()->antiColourLine()&& cjt->first->progenitor()->antiColourLine()==second.first->antiColourLine()) { second.second = cjt->first->progenitor(); continue; } } } // loop over the two possible emitting systems q_ [0] = first .second->momentum()-first .first->momentum(); q2_[0] = -q_[0].m2(); q_ [1] = second.second->momentum()-second.first->momentum(); q2_[1] = -q_[1].m2(); for(unsigned int ix=0;ix<2;++ix) { if(ix==1) { swap(first,second); swap(beams.first,beams.second); } // check beam, all particles assert(beams.first && higgs_ && first .first && first.second && second.first && second.second); // beam and pdf beam_[ix] = beams.first; pdf_ [ix] = beam_[ix]->pdf(); assert(beam_[ix] && pdf_[ix] ); // Particle data objects partons_[ix][0] = first. first->dataPtr(); partons_[ix][1] = first.second->dataPtr(); partons_[ix][2] = second. first->dataPtr(); partons_[ix][3] = second.second->dataPtr(); // extract the born variables xB_[ix] = first.first->x(); Lorentz5Momentum pb = first.first->momentum(); Axis axis(q_[ix].vect().unit()); double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); rot_[ix] = LorentzRotation(); if(axis.perp2()>1e-20) { rot_[ix].setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); rot_[ix].rotateX(Constants::pi); } if(abs(1.-q_[ix].e()/q_[ix].vect().mag())>1e-6) rot_[ix].boostZ( q_[ix].e()/q_[ix].vect().mag()); pb *= rot_[ix]; if(pb.perp2()/GeV2>1e-20) { Boost trans = -1./pb.e()*pb.vect(); trans.setZ(0.); rot_[ix].boost(trans); } // momenta of the particles phiggs_ [ix] = rot_[ix]*higgs_->momentum(); pother_ [ix][0] = rot_[ix]*second. first->momentum(); pother_ [ix][1] = rot_[ix]*second.second->momentum(); psystem_[ix][0] = rot_[ix]* first. first->momentum(); psystem_[ix][1] = rot_[ix]* first.second->momentum(); q_[ix] *= rot_[ix]; pTCompton_[ix] = pTBGF_[ix] = ZERO; // generate a compton point generateCompton(ix); // generate a BGF point generateBGF(ix); } // no valid emissions, return if(pTCompton_[0]::const_iterator cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) { if(QuarkMatcher::Check(cit->first->progenitor()->data())) cit->first->maximumpT(pTmin_,ShowerInteraction::QCD); } for(map::const_iterator cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) { if(QuarkMatcher::Check(cit->first->progenitor()->data())) cit->first->maximumpT(pTmin_,ShowerInteraction::QCD); } return HardTreePtr(); } // find the maximum pT emission unsigned int system = 0; bool isCompton = false; Energy pTmax = -GeV; for(unsigned int ix=0;ix<2;++ix) { if(pTCompton_[ix]>pTmax) { pTmax = pTCompton_[ix]; isCompton = true; system = ix; } if(pTBGF_[ix]>pTmax) { pTmax = pTBGF_[ix]; isCompton = false; system = ix; } } if(system==0) { swap(first,second); swap(beams.first,beams.second); } // add the non emitting particles vector spaceBranchings,allBranchings; spaceBranchings.push_back(new_ptr(HardBranching(second.first,SudakovPtr(), HardBranchingPtr(), HardBranching::Incoming))); allBranchings.push_back(spaceBranchings.back()); allBranchings.push_back(new_ptr(HardBranching(second.second,SudakovPtr(), HardBranchingPtr(), HardBranching::Outgoing))); allBranchings.push_back(new_ptr(HardBranching(higgs_,SudakovPtr(), HardBranchingPtr(), HardBranching::Outgoing))); allBranchings[0]->colourPartner(allBranchings[1]); allBranchings[1]->colourPartner(allBranchings[0]); rot_[system].invert(); // compton hardest if(isCompton) { for(unsigned int ix=0;ixset5Momentum(ComptonMomenta_[system][1]); ShowerParticlePtr newg(new_ptr(ShowerParticle(gluon_,true))); newg->set5Momentum(ComptonMomenta_[system][2]); ShowerParticlePtr newqin (new_ptr(ShowerParticle(partons_[system][0],false ))); newqin->set5Momentum(ComptonMomenta_[system][0]); if(ComptonISFS_[system]) { ShowerParticlePtr newspace(new_ptr(ShowerParticle(partons_[system][0],false))); newspace->set5Momentum(ComptonMomenta_[system][0]-ComptonMomenta_[system][2]); HardBranchingPtr spaceBranch(new_ptr(HardBranching(newqin,SudakovPtr(), HardBranchingPtr(), HardBranching::Incoming))); HardBranchingPtr offBranch(new_ptr(HardBranching(newspace,SudakovPtr(), spaceBranch, HardBranching::Incoming))); spaceBranch->addChild(offBranch); HardBranchingPtr g(new_ptr(HardBranching(newg,SudakovPtr(),spaceBranch, HardBranching::Outgoing))); spaceBranch->addChild(g); spaceBranch->type(offBranch->branchingParticle()->id()>0 ? ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine); HardBranchingPtr outBranch(new_ptr(HardBranching(newqout,SudakovPtr(), HardBranchingPtr(), HardBranching::Outgoing))); spaceBranchings.push_back(spaceBranch); allBranchings.push_back(offBranch); allBranchings.push_back(outBranch); ColinePtr newin(new_ptr(ColourLine())),newout(new_ptr(ColourLine())); newin ->addColoured(newqin ,newspace->dataPtr()->iColour()!=PDT::Colour3); newin ->addColoured(newg ,newspace->dataPtr()->iColour()!=PDT::Colour3); newout->addColoured(newspace,newspace->dataPtr()->iColour()!=PDT::Colour3); newout->addColoured(newqout ,newspace->dataPtr()->iColour()!=PDT::Colour3); newout->addColoured(newg ,newspace->dataPtr()->iColour()==PDT::Colour3); } else { ShowerParticlePtr newtime(new_ptr(ShowerParticle(partons_[system][1],true))); newtime->set5Momentum(ComptonMomenta_[system][1]+ComptonMomenta_[system][2]); HardBranchingPtr spaceBranch(new_ptr(HardBranching(newqin,SudakovPtr(), HardBranchingPtr(), HardBranching::Incoming))); HardBranchingPtr offBranch(new_ptr(HardBranching(newtime,SudakovPtr(), HardBranchingPtr(), HardBranching::Outgoing))); HardBranchingPtr g(new_ptr(HardBranching(newg,SudakovPtr(),offBranch, HardBranching::Outgoing))); HardBranchingPtr outBranch(new_ptr(HardBranching(newqout,SudakovPtr(),offBranch, HardBranching::Outgoing))); offBranch->addChild(outBranch); offBranch->addChild(g); offBranch->type(offBranch->branchingParticle()->id()>0 ? ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine); spaceBranchings.push_back(spaceBranch); allBranchings.push_back(spaceBranch); allBranchings.push_back(offBranch); ColinePtr newin(new_ptr(ColourLine())),newout(new_ptr(ColourLine())); newin ->addColoured(newqin ,newqin->dataPtr()->iColour()!=PDT::Colour3); newin ->addColoured(newtime ,newqin->dataPtr()->iColour()!=PDT::Colour3); newin ->addColoured(newg ,newqin->dataPtr()->iColour()!=PDT::Colour3); newout->addColoured(newg ,newqin->dataPtr()->iColour()==PDT::Colour3); newout->addColoured(newqout ,newqin->dataPtr()->iColour()!=PDT::Colour3); } } // BGF hardest else { for(unsigned int ix=0;ixset5Momentum(BGFMomenta_[system][1]); ShowerParticlePtr newqbar(new_ptr(ShowerParticle(partons_[system][0]->CC(),true))); newqbar->set5Momentum(BGFMomenta_[system][2]); ShowerParticlePtr newg (new_ptr(ShowerParticle(gluon_,false))); newg->set5Momentum(BGFMomenta_[system][0]); ShowerParticlePtr newspace(new_ptr(ShowerParticle(partons_[system][0],false))); newspace->set5Momentum(BGFMomenta_[system][0]-BGFMomenta_[system][2]); HardBranchingPtr spaceBranch(new_ptr(HardBranching(newg,SudakovPtr(),HardBranchingPtr(), HardBranching::Incoming))); HardBranchingPtr offBranch(new_ptr(HardBranching(newspace,SudakovPtr(),spaceBranch, HardBranching::Incoming))); HardBranchingPtr qbar(new_ptr(HardBranching(newqbar,SudakovPtr(),spaceBranch, HardBranching::Outgoing))); spaceBranch->addChild(offBranch); spaceBranch->addChild(qbar); spaceBranch->type(offBranch->branchingParticle()->id()>0 ? ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine); HardBranchingPtr outBranch(new_ptr(HardBranching(newq,SudakovPtr(), HardBranchingPtr(), HardBranching::Outgoing))); spaceBranchings.push_back(spaceBranch); allBranchings.push_back(offBranch); allBranchings.push_back(outBranch); ColinePtr newin(new_ptr(ColourLine())),newout(new_ptr(ColourLine())); newout->addColoured(newspace,newspace->dataPtr()->iColour()!=PDT::Colour3); newout->addColoured(newq ,newspace->dataPtr()->iColour()!=PDT::Colour3); newout->addColoured(newg ,newspace->dataPtr()->iColour()!=PDT::Colour3); newin ->addColoured(newg ,newspace->dataPtr()->iColour()==PDT::Colour3); newin ->addColoured(newqbar ,newspace->dataPtr()->iColour()==PDT::Colour3); } allBranchings[3]->colourPartner(allBranchings[4]); allBranchings[4]->colourPartner(allBranchings[3]); HardTreePtr newTree(new_ptr(HardTree(allBranchings,spaceBranchings, ShowerInteraction::QCD))); // Set the maximum pt for all other emissions and connect hard and shower tree Energy pT = isCompton ? pTCompton_[system] : pTBGF_[system]; // incoming particles for(map::const_iterator cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) { // set maximum pT if(QuarkMatcher::Check(cit->first->progenitor()->data())) cit->first->maximumpT(pT,ShowerInteraction::QCD); set::iterator cjt=newTree->branchings().begin(); if(cit->first->progenitor()==first.first) { ++cjt;++cjt;++cjt; } newTree->connect(cit->first->progenitor(),*cjt); tPPtr beam =cit->first->original(); if(!beam->parents().empty()) beam=beam->parents()[0]; (*cjt)->beam(beam); HardBranchingPtr parent=(*cjt)->parent(); while(parent) { parent->beam(beam); parent=parent->parent(); }; } // outgoing particles for(map::const_iterator cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) { // set maximum pT if(QuarkMatcher::Check(cit->first->progenitor()->data())) cit->first->maximumpT(pT,ShowerInteraction::QCD); for(set::iterator cjt=newTree->branchings().begin(); cjt!=newTree->branchings().end();++cjt) { if((*cjt)->branchingParticle()->isFinalState()&& (*cjt)->branchingParticle()->id()==cit->first->progenitor()->id()) { newTree->connect(cit->first->progenitor(),*cjt); } } } // set the evolution partners and scales ShowerParticleVector particles; for(set::iterator cit=newTree->branchings().begin(); cit!=newTree->branchings().end();++cit) { particles.push_back((*cit)->branchingParticle()); } for(set::iterator cjt=newTree->branchings().begin(); cjt!=newTree->branchings().end();++cjt) { if(cjt==newTree->branchings().begin()) { (**cjt).showerMomentum((**cjt).branchingParticle()->momentum()); ++cjt; (**cjt).showerMomentum((**cjt).branchingParticle()->momentum()); ++cjt; (**cjt).showerMomentum((**cjt).branchingParticle()->momentum()); ++cjt; } } return newTree; } void MEPP2HiggsVBF::generateCompton(unsigned int system) { // calculate the A coefficient for the correlations acoeff_ = A(partons_[system][0],partons_[system][1], partons_[system][2],partons_[system][3]); // maximum value of the xT double xT = sqrt((1.-xB_[system])/xB_[system]); double xTMin = 2.*pTmin_/sqrt(q2_[system]); double zp; // prefactor double a = alpha_->overestimateValue()*comptonWeight_/Constants::twopi; // loop to generate kinematics double wgt(0.),xp(0.); l_ = 2.*pother_[system][0]/sqrt(q2_[system]); m_ = 2.*pother_[system][1]/sqrt(q2_[system]); vector azicoeff; do { wgt = 0.; // intergration variables dxT/xT^3 xT *= 1./sqrt(1.-2.*log(UseRandom::rnd())/a*sqr(xT)); // dz zp = UseRandom::rnd(); xp = 1./(1.+0.25*sqr(xT)/zp/(1.-zp)); // check allowed if(xp1.) continue; // phase-space piece of the weight wgt = 8.*(1.-xp)*zp/comptonWeight_; // PDF piece of the weight Energy2 mu2 = q2_[system]*((1.-xp)*(1-zp)*zp/xp+1.); double pdf = pdf_[system]->xfx(beam_[system],partons_[system][0], mu2 ,xB_[system]/xp)/ pdf_[system]->xfx(beam_[system],partons_[system][0], scale(),xB_[system] ); wgt *= max(pdf,0.); // me piece of the weight // double me = comptonME(system,xT,xp,zp,phi); double x2 = 1.-(1.-zp)/xp; azicoeff = ComptonME(xp,x2,xT,l_,m_); double me = 4./3.*alpha_->ratio(0.25*q2_[system]*sqr(xT))* (azicoeff[0]+0.5*azicoeff[2]+0.5*azicoeff[4]); wgt *= me; if(wgt>1.||wgt<0.) { ostringstream wstring; wstring << "MEPP2HiggsVBF::generateCompton() " << "Weight greater than one or less than zero" << "wgt = " << wgt << "\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } while(xT>xTMin&&UseRandom::rnd()>wgt); if(xT<=xTMin) { pTCompton_[system]=-GeV; return; } // generate phi unsigned int itry(0); double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.); double phiwgt,phi; do { phi = UseRandom::rnd()*Constants::twopi; double cphi(cos(phi)),sphi(sin(phi)); phiwgt = azicoeff[0]+azicoeff[5]*sphi*cphi +azicoeff[1]*cphi+azicoeff[2]*sqr(cphi) +azicoeff[3]*sphi+azicoeff[4]*sqr(sphi); ++itry; } while (phimax*UseRandom::rnd() > phiwgt && itry<200); if(itry==200) throw Exception() << "Too many tries in MEPP2HiggsVBF" << "::generateCompton() to" << " generate phi" << Exception::eventerror; // momenta for the configuration Energy Q(sqrt(q2_[system])); double x1 = -1./xp; double x2 = 1.-(1.-zp)/xp; double x3 = 2.+x1-x2; Lorentz5Momentum p1( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi), -0.5*Q*x2, 0.5*Q*sqrt(sqr(xT)+sqr(x2))); Lorentz5Momentum p2(-0.5*Q*xT*cos(phi), -0.5*Q*xT*sin(phi), -0.5*Q*x3, 0.5*Q*sqrt(sqr(xT)+sqr(x3))); Lorentz5Momentum p0(ZERO,ZERO,-0.5*Q*x1,-0.5*Q*x1); pTCompton_[system] = 0.5*Q*xT; ComptonMomenta_[system].resize(3); ComptonMomenta_[system][0] = p0; ComptonMomenta_[system][1] = p1; ComptonMomenta_[system][2] = p2; ComptonISFS_[system] = zp>xp; } double MEPP2HiggsVBF::comptonME(unsigned int system, double xT, double xp, double zp, double phi) { // scale and prefactors double CFfact = 4./3.*alpha_->ratio(0.25*q2_[system]*sqr(xT)); Energy Q(sqrt(q2_[system])); double x1 = -1./xp; double x2 = 1.-(1.-zp)/xp; double x3 = 2.+x1-x2; //set NLO momenta Lorentz5Momentum p1( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi), -0.5*Q*x2, 0.5*Q*sqrt(sqr(xT)+sqr(x2))); Lorentz5Momentum p2(-0.5*Q*xT*cos(phi), -0.5*Q*xT*sin(phi), -0.5*Q*x3, 0.5*Q*sqrt(sqr(xT)+sqr(x3))); Lorentz5Momentum p0(ZERO,ZERO,-0.5*Q*x1,-0.5*Q*x1); Lorentz5Momentum qnlo = p2+p1-p0; // Breit frame variables Lorentz5Momentum r1 = -p0/x1; Lorentz5Momentum r2 = p1/x2; // electroweak parameters double c0L,c1L,c0R,c1R; // W if(partons_[system][0]->id()!=partons_[system][1]->id()) { c0L = sqrt(0.5); c0R = 0; c1L = sqrt(0.5); c1R = 0; } // Z else { if(abs(partons_[system][0]->id())%2==0) { c0L = generator()->standardModel()->vu()+ generator()->standardModel()->au(); c0R = generator()->standardModel()->vu()- generator()->standardModel()->au(); } else { c0L = generator()->standardModel()->vd()+ generator()->standardModel()->ad(); c0R = generator()->standardModel()->vd()- generator()->standardModel()->ad(); } if(abs(partons_[system][2]->id())%2==0) { c1L = generator()->standardModel()->vu()+ generator()->standardModel()->au(); c1R = generator()->standardModel()->vu()- generator()->standardModel()->au(); } else { c1L = generator()->standardModel()->vd()+ generator()->standardModel()->ad(); c1R = generator()->standardModel()->vd()- generator()->standardModel()->ad(); } c0L *= 0.25; c0R *= 0.25; c1L *= 0.25; c1R *= 0.25; } // Matrix element variables double G1 = sqr(c0L*c1L)+sqr(c0R*c1R); double G2 = sqr(c0L*c1R)+sqr(c0R*c1L); Energy4 term1,term2,loME; if(partons_[system][0]->id()>0) { if(partons_[system][2]->id()>0) { term1 = loMatrixElement(r1 ,pother_[system][0], qnlo+r1 ,pother_[system][1],G1,G2); term2 = loMatrixElement(r2-qnlo ,pother_[system][0], r2 ,pother_[system][1],G1,G2); loME = loMatrixElement(psystem_[system][0],pother_[system][0], psystem_[system][1],pother_[system][1],G1,G2); } else { term1 = loMatrixElement(r1 ,pother_[system][1], qnlo+r1 ,pother_[system][0],G1,G2); term2 = loMatrixElement(r2-qnlo ,pother_[system][1], r2 ,pother_[system][0],G1,G2); loME = loMatrixElement(psystem_[system][0],pother_[system][1], psystem_[system][1],pother_[system][0],G1,G2); } } else { if(partons_[system][2]->id()>0) { term1 = loMatrixElement(qnlo+r1 ,pother_[system][0], r1 ,pother_[system][1],G1,G2); term2 = loMatrixElement(r2 ,pother_[system][0], r2-qnlo ,pother_[system][1],G1,G2); loME = loMatrixElement(psystem_[system][1],pother_[system][0], psystem_[system][0],pother_[system][1],G1,G2); } else { term1 = loMatrixElement(qnlo+r1,pother_[system][1],r1 , pother_[system][0],G1,G2); term2 = loMatrixElement(r2 ,pother_[system][1],r2-qnlo, pother_[system][0],G1,G2); loME = loMatrixElement(psystem_[system][1],pother_[system][1], psystem_[system][0],pother_[system][0],G1,G2); } } double R1 = term1/loME; double R2 = sqr(x2)/(sqr(x2)+sqr(xT))*(term2/loME); // debuggingMatrixElement(false, // partons_[system][0],partons_[system][1], // partons_[system][2],partons_[system][3], // psystem_[system][0],psystem_[system][1], // pother_ [system][0],pother_ [system][1], // p0,p1,p2,phiggs_[system],q2_[system],scale(), // 8.*Constants::pi/(1.-xp)/(1.-zp)*(R1+sqr(xp)*(sqr(x2)+sqr(xT))*R2)); // cerr << "testing pieces A " << R1 << " " << sqr(xp)*(sqr(x2)+sqr(xT)) << " " << R2 << "\n"; return CFfact*(R1+sqr(xp)*(sqr(x2)+sqr(xT))*R2); } void MEPP2HiggsVBF::generateBGF(unsigned int system) { // maximum value of the xT double xT = (1.-xB_[system])/xB_[system]; double xTMin = 2.*pTmin_/sqrt(q2_[system]); double zp; // prefactor double a = alpha_->overestimateValue()*BGFWeight_/Constants::twopi; // loop to generate kinematics double wgt(0.),xp(0.); l_ = 2.*pother_[system][0]/sqrt(q2_[system]); m_ = 2.*pother_[system][1]/sqrt(q2_[system]); vector azicoeff; do { wgt = 0.; // intergration variables dxT/xT^3 xT *= 1./sqrt(1.-2.*log(UseRandom::rnd())/a*sqr(xT)); // dzp zp = UseRandom::rnd(); xp = 1./(1.+0.25*sqr(xT)/zp/(1.-zp)); // check allowed if(xp1.) continue; // phase-space piece of the weight wgt = 8.*sqr(1.-xp)*zp/BGFWeight_; // PDF piece of the weight Energy2 mu2 = q2_[system]*((1.-xp)*(1-zp)*zp/xp+1.); wgt *= pdf_[system]->xfx(beam_[system],gluon_ , mu2 ,xB_[system]/xp)/ pdf_[system]->xfx(beam_[system],partons_[system][0], scale(),xB_[system]); // me piece of the weight //double me = BGFME(system,xT,xp,zp,phi); double x1 = -1./xp; double x2 = 1.-(1.-zp)/xp; double x3 = 2.+x1-x2; azicoeff = BGFME(xp,x2,x3,xT,l_,m_); double me = 0.5*alpha_->ratio(0.25*q2_[system]*sqr(xT))* (azicoeff[0]+0.5*azicoeff[2]+0.5*azicoeff[4]); wgt *= me; if(wgt>1.||wgt<0.) { ostringstream wstring; wstring << "MEPP2HiggsVBF::generateBGF() " << "Weight greater than one or less than zero" << "wgt = " << wgt << "\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } while(xT>xTMin&&UseRandom::rnd()>wgt); if(xT<=xTMin) { pTBGF_[system] = -GeV; return; } // generate phi unsigned int itry(0); double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.); double phiwgt,phi; do { phi = UseRandom::rnd()*Constants::twopi; double cphi(cos(phi)),sphi(sin(phi)); phiwgt = azicoeff[0]+azicoeff[5]*sphi*cphi +azicoeff[1]*cphi+azicoeff[2]*sqr(cphi) +azicoeff[3]*sphi+azicoeff[4]*sqr(sphi); ++itry; } while (phimax*UseRandom::rnd() > phiwgt && itry<200); if(itry==200) throw Exception() << "Too many tries in MEPP2HiggsVBF" << "::generateBGF() to" << " generate phi" << Exception::eventerror; // momenta for the configuration Energy Q(sqrt(q2_[system])); double x1 = -1./xp; double x2 = 1.-(1.-zp)/xp; double x3 = 2.+x1-x2; Lorentz5Momentum p1( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi), -0.5*Q*x2, 0.5*Q*sqrt(sqr(xT)+sqr(x2))); Lorentz5Momentum p2(-0.5*Q*xT*cos(phi), -0.5*Q*xT*sin(phi), -0.5*Q*x3, 0.5*Q*sqrt(sqr(xT)+sqr(x3))); Lorentz5Momentum p0(ZERO,ZERO,-0.5*Q*x1,-0.5*Q*x1); pTBGF_[system] = 0.5*Q*xT; BGFMomenta_[system].resize(3); BGFMomenta_[system][0] = p0; BGFMomenta_[system][1] = p1; BGFMomenta_[system][2] = p2; } double MEPP2HiggsVBF::BGFME(unsigned int system, double xT, double xp, double zp, double phi) { // scale and prefactors double TRfact = 0.5*alpha_->ratio(0.25*q2_[system]*sqr(xT)); Energy Q(sqrt(q2_[system])); double x1 = -1./xp; double x2 = 1.-(1.-zp)/xp; double x3 = 2.+x1-x2; // Set NLO momenta Lorentz5Momentum p1( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi), -0.5*Q*x2, 0.5*Q*sqrt(sqr(xT)+sqr(x2))); Lorentz5Momentum p2(-0.5*Q*xT*cos(phi), -0.5*Q*xT*sin(phi), -0.5*Q*x3, 0.5*Q*sqrt(sqr(xT)+sqr(x3))); Lorentz5Momentum p0(ZERO,ZERO,-0.5*Q*x1,-0.5*Q*x1); Lorentz5Momentum qnlo = p2+p1-p0; // Breit frame variables Lorentz5Momentum r2 = p1/x2; Lorentz5Momentum r3 = -p2/x3; // electroweak parameters double c0L,c1L,c0R,c1R; // W if(partons_[system][0]->id()!=partons_[system][1]->id()) { c0L = sqrt(0.5); c0R = 0; c1L = sqrt(0.5); c1R = 0; } // Z else { if(abs(partons_[system][0]->id())%2==0) { c0L = generator()->standardModel()->vu()+ generator()->standardModel()->au(); c0R = generator()->standardModel()->vu()- generator()->standardModel()->au(); } else { c0L = generator()->standardModel()->vd()+ generator()->standardModel()->ad(); c0R = generator()->standardModel()->vd()- generator()->standardModel()->ad(); } if(abs(partons_[system][2]->id())%2==0) { c1L = generator()->standardModel()->vu()+ generator()->standardModel()->au(); c1R = generator()->standardModel()->vu()- generator()->standardModel()->au(); } else { c1L = generator()->standardModel()->vd()+ generator()->standardModel()->ad(); c1R = generator()->standardModel()->vd()- generator()->standardModel()->ad(); } c0L *= 0.25; c0R *= 0.25; c1L *= 0.25; c1R *= 0.25; } // Matrix element variables double G1 = sqr(c0L*c1L)+sqr(c0R*c1R); double G2 = sqr(c0L*c1R)+sqr(c0R*c1L); Energy4 term2,term3,loME; if(partons_[system][0]->id()>0) { if(partons_[system][2]->id()>0) { term2 = loMatrixElement(r2-qnlo,pother_[system][0], r2 ,pother_[system][1],G1,G2); term3 = loMatrixElement(r3 ,pother_[system][0], qnlo+r3,pother_[system][1],G1,G2); loME = loMatrixElement(psystem_[system][0],pother_[system][0], psystem_[system][1],pother_[system][1],G1,G2); } else { term2 = loMatrixElement(r2-qnlo,pother_[system][1], r2 ,pother_[system][0],G1,G2); term3 = loMatrixElement(r3 ,pother_[system][1], qnlo+r3,pother_[system][0],G1,G2); loME = loMatrixElement(psystem_[system][0],pother_[system][1], psystem_[system][1],pother_[system][0],G1,G2); } } else { if(partons_[system][2]->id()>0) { term2 = loMatrixElement(r2 ,pother_[system][0], r2-qnlo,pother_[system][1],G1,G2); term3 = loMatrixElement(qnlo+r3,pother_[system][0], r3 ,pother_[system][1],G1,G2); loME = loMatrixElement(psystem_[system][1],pother_[system][0], psystem_[system][0],pother_[system][1],G1,G2); } else { term2 = loMatrixElement(r2 ,pother_[system][1], r2-qnlo,pother_[system][0],G1,G2); term3 = loMatrixElement(qnlo+r3,pother_[system][1], r3 ,pother_[system][0],G1,G2); loME = loMatrixElement(psystem_[system][1],pother_[system][1], psystem_[system][0],pother_[system][0],G1,G2); } } double R3 = sqr(x3)/(sqr(x3)+sqr(xT))*(term3/loME); double R2 = sqr(x2)/(sqr(x2)+sqr(xT))*(term2/loME); // debuggingMatrixElement(true, // partons_[system][0],partons_[system][1], // partons_[system][2],partons_[system][3], // psystem_[system][0],psystem_[system][1], // pother_ [system][0],pother_ [system][1], // p0,p1,p2,phiggs_[system],q2_[system], // 8.*Constants::pi/zp/(1.-zp)*(sqr(xp)*(sqr(x3)+sqr(xT))*R3+ // sqr(xp)*(sqr(x2)+sqr(xT))*R2)); return TRfact* (sqr(xp)*(sqr(x3)+sqr(xT))*R3+ sqr(xp)*(sqr(x2)+sqr(xT))*R2); } Energy4 MEPP2HiggsVBF::loMatrixElement(const Lorentz5Momentum &p1, const Lorentz5Momentum &p2, const Lorentz5Momentum &q1, const Lorentz5Momentum &q2, double G1, double G2) const { return G1*(p1*p2)*(q1*q2) + G2*(p1*q2)*(q1*p2); } void MEPP2HiggsVBF::initializeMECorrection(ShowerTreePtr tree, double & initial, double & final) { systems_.clear(); for(map::const_iterator cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) { if(QuarkMatcher::Check(cit->first->progenitor()->data())) { systems_.push_back(tChannelPair()); systems_.back().hadron = cit->first->original()->parents()[0]; systems_.back().beam = cit->first->beam(); systems_.back().incoming = cit->first->progenitor(); systems_.back().pdf = systems_.back().beam->pdf(); } } vector outgoing; for(map::const_iterator cjt=tree->outgoingLines().begin();cjt!=tree->outgoingLines().end();++cjt) { if(cjt->first->progenitor()->id()==ParticleID::h0) higgs_ = cjt->first->progenitor(); else if(QuarkMatcher::Check(cjt->first->progenitor()->data())) outgoing.push_back(cjt->first->progenitor()); } assert(outgoing.size()==2&&higgs_); // match up the quarks for(unsigned int ix=0;ixcolourLine()) { for(unsigned int iy=0;iycolourLine()==systems_[ix].incoming->colourLine()) { systems_[ix].outgoing=outgoing[iy]; break; } } } else { for(unsigned int iy=0;iyantiColourLine()==systems_[ix].incoming->antiColourLine()) { systems_[ix].outgoing=outgoing[iy]; break; } } } } assert(systems_[0].outgoing&&systems_[1].outgoing); assert(systems_.size()==2); initial = initial_; final = final_; } void MEPP2HiggsVBF::applyHardMatrixElementCorrection(ShowerTreePtr tree) { static const double eps = 1e-6; // select emitting line if(UseRandom::rndbool()) swap(systems_[0],systems_[1]); // extract the born variables q_[0] = systems_[0].outgoing->momentum()-systems_[0].incoming->momentum(); q2_[0] = -q_[0].m2(); Energy Q = sqrt(q2_[0]); xB_[0] = systems_[0].incoming->x(); // construct lorentz transform from lab to breit frame Lorentz5Momentum phadron = systems_[0].hadron->momentum(); phadron.setMass(0.*GeV); phadron.rescaleEnergy(); Lorentz5Momentum pcmf = phadron+0.5/xB_[0]*q_[0]; pcmf.rescaleMass(); LorentzRotation rot(-pcmf.boostVector()); Lorentz5Momentum pbeam = rot*phadron; Axis axis(pbeam.vect().unit()); double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); rot.rotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); Lorentz5Momentum pout = rot*(systems_[1].outgoing->momentum()+higgs_->momentum()); rot.rotateZ(-atan2(pout.y(),pout.x())); // calculate the A coefficient for the correlations acoeff_ = A(systems_[0].incoming->dataPtr(),systems_[0].outgoing->dataPtr(), systems_[1].incoming->dataPtr(),systems_[1].outgoing->dataPtr()); vector azicoeff; // select the type of process bool BGF = UseRandom::rnd()>procProb_; double wgt,xp,zp,x1,x2,x3,xperp; l_ = 2.*(rot*systems_[1].incoming->momentum())/Q; m_ = 2.*(rot*systems_[1].outgoing->momentum())/Q; // compton process if(!BGF) { wgt = generateComptonPoint(xp,zp); if(xpvalue(mu2)/procProb_; // PDF piece wgt *= systems_[0].pdf->xfx(systems_[0].beam, systems_[0].incoming->dataPtr(),mu2 ,xB_[0]/xp)/ systems_[0].pdf->xfx(systems_[0].beam, systems_[0].incoming->dataPtr(),scale(),xB_[0] ); // numerator factors wgt /= (1.-xp)*(1.-zp); // other bits xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp); x1 = -1./xp; x2 = 1.-(1.-zp)/xp; x3 = 2.+x1-x2; // matrix element pieces azicoeff = ComptonME(xp,x2,xperp,l_,m_); } else { wgt = generateBGFPoint(xp,zp); if(xp<1e-6) return; // common pieces Energy2 mu2 = q2_[0]*((1.-xp)*(1-zp)*zp/xp+1); wgt *= 0.25/Constants::pi*alpha_->value(mu2)/(1.-procProb_); // PDF piece wgt *= systems_[0].pdf->xfx(systems_[0].beam, gluon_ ,mu2 ,xB_[0]/xp)/ systems_[0].pdf->xfx(systems_[0].beam, systems_[0].incoming->dataPtr(),scale(),xB_[0] ); // numerator factors wgt /= (1.-zp); // other bits xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp); x1 = -1./xp; x2 = 1.-(1.-zp)/xp; x3 = 2.+x1-x2; // matrix element pieces azicoeff = BGFME(xp,x2,x3,xperp,l_,m_); } // compute the azimuthal average of the weight wgt *= azicoeff[0]+0.5*(azicoeff[2]+azicoeff[4]); // finally factor as picked one line wgt *= 2.; // decide whether or not to accept the weight if(UseRandom::rnd()>wgt) return; // if accepted generate generate phi unsigned int itry(0); double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.); double phiwgt,phi; do { phi = UseRandom::rnd()*Constants::twopi; double cphi(cos(phi)),sphi(sin(phi)); phiwgt = azicoeff[0]+azicoeff[5]*sphi*cphi +azicoeff[1]*cphi+azicoeff[2]*sqr(cphi) +azicoeff[3]*sphi+azicoeff[4]*sqr(sphi); ++itry; } while (phimax*UseRandom::rnd() > phiwgt && itry<200); if(itry==200) throw Exception() << "Too many tries in VBFMECorrection" << "::applyHardMatrixElementCorrection() to" << " generate phi" << Exception::eventerror; // compute the new incoming and outgoing momenta Lorentz5Momentum p1 = Lorentz5Momentum( 0.5*Q*xperp*cos(phi), 0.5*Q*xperp*sin(phi), -0.5*Q*x2,0.*GeV,0.*GeV); p1.rescaleEnergy(); Lorentz5Momentum p2 = Lorentz5Momentum(-0.5*Q*xperp*cos(phi),-0.5*Q*xperp*sin(phi), -0.5*Q*x3,0.*GeV,0.*GeV); p2.rescaleEnergy(); Lorentz5Momentum pin(0.*GeV,0.*GeV,-0.5*x1*Q,-0.5*x1*Q,0.*GeV); // debugging code to test vs helicity amplitude expression for matrix elements // double cphi(cos(phi)),sphi(sin(phi)); // double old = (azicoeff[0]+azicoeff[5]*sphi*cphi // +azicoeff[1]*cphi+azicoeff[2]*sqr(cphi) // +azicoeff[3]*sphi+azicoeff[4]*sqr(sphi)); // if(!BGF) { // old *= 8.*Constants::pi/(1.-xp)/(1.-zp); // } // else { // old *= 8.*Constants::pi/zp/(1.-zp); // } // debuggingMatrixElement(BGF, // systems_[0].incoming->dataPtr(), // systems_[0].outgoing->dataPtr(), // systems_[1].incoming->dataPtr(), // systems_[1].outgoing->dataPtr(), // rot*systems_[0].incoming->momentum(), // rot*systems_[0].outgoing->momentum(), // rot*systems_[1].incoming->momentum(), // rot*systems_[1].outgoing->momentum(), // pin,p1,p2,rot*higgs_->momentum(), // q2_[0],scale(),old); // we need inverse of the rotation, i.e back to lab from breit rot.invert(); // transform the momenta to lab frame pin *= rot; p1 *= rot; p2 *= rot; // test to ensure outgoing particles can be put on-shell if(!BGF) { if(p1.e()dataPtr()->constituentMass()) return; if(p2.e()constituentMass()) return; } else { if(p1.e()dataPtr() ->constituentMass()) return; if(p2.e()dataPtr()->CC()->constituentMass()) return; } // stats for weights > 1 if(wgt>1.) { ++nover_; if(!BGF) maxwgt_.first = max(maxwgt_.first ,wgt); else maxwgt_.second = max(maxwgt_.second,wgt); } // create the new particles and add to ShowerTree bool isquark = systems_[0].incoming->colourLine(); if(!BGF) { PPtr newin = new_ptr(Particle(*systems_[0].incoming)); newin->set5Momentum(pin); PPtr newg = gluon_ ->produceParticle(p2 ); PPtr newout = systems_[0].outgoing->dataPtr()->produceParticle(p1 ); ColinePtr col=isquark ? systems_[0].incoming->colourLine() : systems_[0].incoming->antiColourLine(); ColinePtr newline=new_ptr(ColourLine()); // final-state emission if(xp>zp) { col->removeColoured(newout,!isquark); col->addColoured(newin,!isquark); col->addColoured(newg,!isquark); newline->addColoured(newg,isquark); newline->addColoured(newout,!isquark); } // initial-state emission else { col->removeColoured(newin ,!isquark); col->addColoured(newout,!isquark); col->addColoured(newg,isquark); newline->addColoured(newg,!isquark); newline->addColoured(newin,!isquark); } PPtr orig; for(map::const_iterator cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) { if(cit->first->progenitor()!=systems_[0].incoming) continue; // remove old particles from colour line col->removeColoured(cit->first->copy(),!isquark); col->removeColoured(cit->first->progenitor(),!isquark); // insert new particles cit->first->copy(newin); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newin,1,false))); cit->first->progenitor(sp); tree->incomingLines()[cit->first]=sp; sp->x(xB_[0]/xp); cit->first->perturbative(xp>zp); if(xp<=zp) orig=cit->first->original(); } for(map::const_iterator cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) { if(cit->first->progenitor()!=systems_[0].outgoing) continue; // remove old particles from colour line col->removeColoured(cit->first->copy(),!isquark); col->removeColoured(cit->first->progenitor(),!isquark); // insert new particles cit->first->copy(newout); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newout,1,true))); cit->first->progenitor(sp); tree->outgoingLines()[cit->first]=sp; cit->first->perturbative(xp<=zp); if(xp>zp) orig=cit->first->original(); } assert(orig); // add the gluon ShowerParticlePtr sg=new_ptr(ShowerParticle(*newg,1,true)); ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(orig,newg,sg)); gluon->perturbative(false); tree->outgoingLines().insert(make_pair(gluon,sg)); tree->hardMatrixElementCorrection(true); } else { PPtr newin = gluon_ ->produceParticle(pin); PPtr newqbar = systems_[0].incoming->dataPtr()->CC()->produceParticle(p2 ); PPtr newout = systems_[0].outgoing->dataPtr() ->produceParticle(p1 ); ColinePtr col=isquark ? systems_[0].incoming->colourLine() : systems_[0].incoming->antiColourLine(); ColinePtr newline=new_ptr(ColourLine()); col ->addColoured(newin ,!isquark); newline->addColoured(newin , isquark); col ->addColoured(newout ,!isquark); newline->addColoured(newqbar, isquark); PPtr orig; for(map::const_iterator cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) { if(cit->first->progenitor()!=systems_[0].incoming) continue; // remove old particles from colour line col->removeColoured(cit->first->copy(),!isquark); col->removeColoured(cit->first->progenitor(),!isquark); // insert new particles cit->first->copy(newin); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newin,1,false))); cit->first->progenitor(sp); tree->incomingLines()[cit->first]=sp; sp->x(xB_[0]/xp); cit->first->perturbative(false); orig=cit->first->original(); } for(map::const_iterator cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) { if(cit->first->progenitor()!=systems_[0].outgoing) continue; // remove old particles from colour line col->removeColoured(cit->first->copy(),!isquark); col->removeColoured(cit->first->progenitor(),!isquark); // insert new particles cit->first->copy(newout); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newout,1,true))); cit->first->progenitor(sp); tree->outgoingLines()[cit->first]=sp; cit->first->perturbative(true); } assert(orig); // add the (anti)quark ShowerParticlePtr sqbar=new_ptr(ShowerParticle(*newqbar,1,true)); ShowerProgenitorPtr qbar=new_ptr(ShowerProgenitor(orig,newqbar,sqbar)); qbar->perturbative(false); tree->outgoingLines().insert(make_pair(qbar,sqbar)); tree->hardMatrixElementCorrection(true); } } double MEPP2HiggsVBF::A(tcPDPtr qin1, tcPDPtr qout1, tcPDPtr qin2, tcPDPtr ) { double output; // charged current if(qin1->id()!=qout1->id()) { output = 2; } // neutral current else { double cvl,cal,cvq,caq; if(abs(qin2->id())%2==0) { cvl = generator()->standardModel()->vu(); cal = generator()->standardModel()->au(); } else { cvl = generator()->standardModel()->vd(); cal = generator()->standardModel()->ad(); } if(abs(qin1->id())%2==0) { cvq = generator()->standardModel()->vu(); caq = generator()->standardModel()->au(); } else { cvq = generator()->standardModel()->vd(); caq = generator()->standardModel()->ad(); } output = 8.*cvl*cal*cvq*caq/(sqr(cvl)+sqr(cal))/(sqr(cvq)+sqr(caq)); } if(qin1->id()<0) output *= -1.; if(qin2->id()<0) output *= -1; return output; } double MEPP2HiggsVBF::generateComptonPoint(double &xp, double & zp) { static const double maxwgt = 50.; double wgt,xperp2,x2; do { xp = UseRandom::rnd(); double zpmin = xp, zpmax = 1./(1.+xp*(1.-xp)); zp = 1.-pow((1.-zpmin)/(1.-zpmax),UseRandom::rnd())*(1.-zpmax); wgt = log((1.-zpmin)/(1.-zpmax))*(1.-zp); if(UseRandom::rndbool()) swap(xp,zp); xperp2 = 4.*(1.-xp)*(1.-zp)*zp/xp; x2 = 1.-(1.-zp)/xp; wgt *= 2.*(1.+sqr(xp)*(sqr(x2)+1.5*xperp2))/(1.-xp)/(1.-zp); if(wgt>maxwgt) if(wgt>maxwgt) { ostringstream wstring; wstring << "MEPP2HiggsVBF::generateComptonPoint() " << "Weight greater than maximum" << "wgt = " << wgt << " maxwgt = " << maxwgt << "\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } while(wgtmaxwgt) { ostringstream wstring; wstring << "DISBase::generateBGFPoint " << "Weight greater than maximum " << "wgt = " << wgt << " maxwgt = 1\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } while(wgtisFinalState() ? 1./final_ : 1./initial_); // check if me correction should be applied long id[2]={initial->id(),parent->id()}; if(id[0]!=id[1]||id[1]==ParticleID::g) return veto; // if not from the right side if(initial->progenitor()!=systems_[0].incoming && initial->progenitor()!=systems_[0].outgoing) return veto; // get the pT Energy pT=br.kinematics->pT(); // check if hardest so far if(pThighestpT()) return veto; double kappa(sqr(br.kinematics->scale())/q2_[0]),z(br.kinematics->z()); double zk((1.-z)*kappa); // final-state double wgt(0.); if(parent->isFinalState()) { double zp=z,xp=1./(1.+z*zk); double xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp); double x2 = 1.-(1.-zp)/xp; vector azicoeff = ComptonME(xp,x2,xperp,l_,m_); wgt = (azicoeff[0]+0.5*azicoeff[2]+0.5*azicoeff[4])* xp/(1.+sqr(z))/final_; if(wgt<.0||wgt>1.) { ostringstream wstring; wstring << "Soft ME correction weight too large or " << "negative for FSR in MEPP2HiggsVBF::" << "softMatrixElementVeto() soft weight " << " xp = " << xp << " zp = " << zp << " weight = " << wgt << "\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } else { double xp = 2.*z/(1.+zk+sqrt(sqr(1.+zk)-4.*z*zk)); double zp = 0.5* (1.-zk+sqrt(sqr(1.+zk)-4.*z*zk)); double xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp); double x1 = -1./xp, x2 = 1.-(1.-zp)/xp, x3 = 2.+x1-x2; // compton if(br.ids[0]!=ParticleID::g) { vector azicoeff = ComptonME(xp,x2,xperp,l_,m_); wgt = (azicoeff[0]+0.5*azicoeff[2]+0.5*azicoeff[4])* xp*(1.-z)/(1.-xp)/(1.+sqr(z))/(1.-zp+xp-2.*xp*(1.-zp)); } // BGF else { vector azicoeff = BGFME(xp,x2,x3,xperp,l_,m_); wgt = (azicoeff[0]+0.5*azicoeff[2]+0.5*azicoeff[4])* xp/(1.-zp+xp-2.*xp*(1.-zp))/(sqr(z)+sqr(1.-z)); } wgt /=initial_; if(wgt<.0||wgt>1.) { ostringstream wstring; wstring << "Soft ME correction weight too large or " << "negative for ISR in MEPP2HiggsVBF::" << "softMatrixElementVeto() soft weight " << " xp = " << xp << " zp = " << zp << " weight = " << wgt << "\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } // if not vetoed if(UseRandom::rndbool(wgt)) return false; // otherwise parent->vetoEmission(br.type,br.kinematics->scale()); return true; } vector MEPP2HiggsVBF::ComptonME(double xp, double x2, double xperp, LorentzVector l, LorentzVector m) { vector output(6,0.); double cos2 = x2 /sqrt(sqr(x2)+sqr(xperp)); double sin2 = xperp/sqrt(sqr(x2)+sqr(xperp)); // no phi dependence output[0] = l.t()*m.t()-l.z()*m.z()*sqr(cos2)+0.5*acoeff_*cos2*(l.t()*m.z()-l.z()*m.t()); // cos(phi) output[1] = sin2*(-l.x()*m.t()-l.t()*m.x() + 0.5*acoeff_*cos2*(l.z()*m.x()-m.z()*l.x())); // cos(phi)^2 output[2] = +sqr(sin2)*l.x()*m.x(); // sin(phi) output[3] = sin2*(-l.t()*m.y()-l.y()*m.t() + 0.5*acoeff_*cos2*(l.z()*m.y()-m.z()*l.y())); // sin(phi)^2 output[4] = +sqr(sin2)*l.y()*m.y(); // sin(phi)cos(phi) output[5] = +sqr(sin2)*(m.y()*l.x()+m.x()*l.y()); // additional factors double denom = -l.z()*m.z()+l.t()*m.t()+0.5*acoeff_*(l.t()*m.z()-l.z()*m.t()); double fact = sqr(xp)*(sqr(x2)+sqr(xperp))/denom; for(unsigned int ix=0;ix MEPP2HiggsVBF::BGFME(double xp, double x2, double x3, double xperp, LorentzVector l, LorentzVector m) { vector output(6,0.); double denom = -l.z()*m.z()+l.t()*m.t()+0.5*acoeff_*(l.t()*m.z()-l.z()*m.t()); double cos2 = x2 /sqrt(sqr(x2)+sqr(xperp)); double sin2 = xperp/sqrt(sqr(x2)+sqr(xperp)); double fact2 = sqr(xp)*(sqr(x2)+sqr(xperp))/denom; double cos3 = x3 /sqrt(sqr(x3)+sqr(xperp)); double sin3 = xperp/sqrt(sqr(x3)+sqr(xperp)); double fact3 = sqr(xp)*(sqr(x3)+sqr(xperp))/denom; // no phi dependence output[0] = fact2*(l.t()*m.t()-l.z()*m.z()*sqr(cos2) + 0.5*acoeff_*cos2*(l.t()*m.z()-l.z()*m.t())) + fact3*(l.t()*m.t()-l.z()*m.z()*sqr(cos3) - 0.5*acoeff_*cos3*(l.t()*m.z()-l.z()*m.t())); // cos(phi) output[1] = fact2*sin2*( - l.x()*m.t()-l.t()*m.x() + 0.5*acoeff_*cos2*(l.z()*m.x()-m.z()*l.x())) - fact3*sin3*( - l.x()*m.t()-l.t()*m.x() - 0.5*acoeff_*cos3*(l.z()*m.x()-m.z()*l.x())) ; // cos(phi)^2 output[2] = (fact2*sqr(sin2)+fact3*sqr(sin3))*l.x()*m.x(); // sin(phi) output[3] = fact2*sin2*( - l.t()*m.y()-l.y()*m.t() + 0.5*acoeff_*cos2*(l.z()*m.y()-m.z()*l.y())) - fact3*sin3*( - l.t()*m.y()-l.y()*m.t() - 0.5*acoeff_*cos3*(l.z()*m.y()-m.z()*l.y())); // sin(phi)^2 output[4] = (fact2*sqr(sin2)+fact3*sqr(sin3))*l.y()*m.y(); // sin(phi)cos(phi) output[5] = (fact2*sqr(sin2)+fact3*sqr(sin3))*(m.y()*l.x()+m.x()*l.y()); // return the answer return output; } diff --git a/MatrixElement/Hadron/MEPP2HiggsVBF.h b/MatrixElement/Hadron/MEPP2HiggsVBF.h --- a/MatrixElement/Hadron/MEPP2HiggsVBF.h +++ b/MatrixElement/Hadron/MEPP2HiggsVBF.h @@ -1,502 +1,501 @@ // -*- C++ -*- #ifndef HERWIG_MEPP2HiggsVBF_H #define HERWIG_MEPP2HiggsVBF_H // // This is the declaration of the MEPP2HiggsVBF class. // #include "Herwig/MatrixElement/MEfftoffH.h" #include "Herwig/Shower/Couplings/ShowerAlpha.h" namespace Herwig { using namespace ThePEG; /** * The MEPP2HiggsVBF class provides the matrix elements for the * production of the Higgs boson via the vector boson fusion mechanism * in hadron collisions * * @see \ref MEPP2HiggsVBFInterfaces "The interfaces" * defined for MEPP2HiggsVBF. */ class MEPP2HiggsVBF: public MEfftoffH { /** * Struct to contain the hadronic system */ struct tChannelPair{ /** * The hadron */ PPtr hadron; /** * The beam particle data object */ tcBeamPtr beam; /** * The incoming particle */ ShowerParticlePtr incoming; /** * The outgoing particle */ ShowerParticlePtr outgoing; /** * The PDF */ tcPDFPtr pdf; }; public: /** * The default constructor. */ MEPP2HiggsVBF(); /** @name Virtual functions required by the MEBase class. */ //@{ /** * Add all possible diagrams with the add() function. */ virtual void getDiagrams() const; //@} /** * Virtual members to be overridden by inheriting classes * which implement hard corrections */ //@{ /** * Has a POWHEG style correction */ virtual POWHEGType hasPOWHEGCorrection() {return Both;} /** * Has an old fashioned ME correction */ virtual bool hasMECorrection() {return true;} /** * Initialize the ME correction */ virtual void initializeMECorrection(ShowerTreePtr , double & , double & ); /** * Apply the hard matrix element correction to a given hard process or decay */ virtual void applyHardMatrixElementCorrection(ShowerTreePtr); /** * Apply the soft matrix element correction * @param initial The particle from the hard process which started the * shower * @param parent The initial particle in the current branching * @param br The branching struct * @return If true the emission should be vetoed */ virtual bool softMatrixElementVeto(ShowerProgenitorPtr, ShowerParticlePtr,Branching); /** * Apply the POWHEG style correction */ - virtual HardTreePtr generateHardest(ShowerTreePtr, - vector); + virtual HardTreePtr generateHardest(ShowerTreePtr, ShowerInteraction::Type); //@} 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: /** * Generate the hardest emission in the POWHEG approach */ //@{ /** * Generate a Compton process */ void generateCompton(unsigned int system); /** * Generate a BGF process */ void generateBGF(unsigned int system); /** * Matrix element piece for the Compton process */ double comptonME(unsigned int system, double xT,double xp, double zp, double phi); /** * Matrix element piece for the Compton process */ double BGFME(unsigned int system, double xT,double xp, double zp, double phi); /** * Leading order matrix element */ Energy4 loMatrixElement(const Lorentz5Momentum &p1, const Lorentz5Momentum &p2, const Lorentz5Momentum &q1, const Lorentz5Momentum &q2, double G1, double G2) const; //@} /** * Generate the hard emission in the old-fashioned matrix element correction approach */ //@{ /** * Generate the values of \f$x_p\f$ and \f$z_p\f$ * @param xp The value of xp, output * @param zp The value of zp, output */ double generateComptonPoint(double &xp, double & zp); /** * Generate the values of \f$x_p\f$ and \f$z_p\f$ * @param xp The value of xp, output * @param zp The value of zp, output */ double generateBGFPoint(double &xp, double & zp); /** * Return the coefficients for the matrix element piece for * the QCD compton case. The output is the \f$a_i\f$ coefficients to * give the function as * \f$a_0+a_1\cos\phi+a_2\sin\phi+a_3\cos^2\phi+a_4\sin^2\phi\f$ * @param xp \f$x_p\f$ * @param x2 \f$x_2\f$ * @param xperp \f$x_\perp\f$ * @param l Scaled momentum of incoming spectator * @param m Scaled momentum of outgoing spectator * */ vector ComptonME(double xp, double x2, double xperp, LorentzVector l, LorentzVector m); /** * Return the coefficients for the matrix element piece for * the QCD compton case. The output is the \f$a_i\f$ coefficients to * give the function as * \f$a_0+a_1\cos\phi+a_2\sin\phi+a_3\cos^2\phi+a_4\sin^2\phi\f$ * @param xp \f$x_p\f$ * @param x2 \f$x_3\f$ * @param x3 \f$x_2\f$ * @param xperp \f$x_\perp\f$ * @param l Scaled momentum of incoming spectator * @param m Scaled momentum of outgoing spectator * */ vector BGFME(double xp, double x2, double x3, double xperp, LorentzVector l, LorentzVector m); /** * Calculate the coefficient A for the correlations */ double A(tcPDPtr qin1, tcPDPtr qout1, tcPDPtr qin2, tcPDPtr qout2); //@} 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(); /** * Finalize this object. Called in the run phase just after a * run has ended. Used eg. to write out statistics. */ virtual void dofinish(); //@} protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const { return new_ptr(*this); } /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const { return new_ptr(*this); } //@} private: /** * The static object used to initialize the description of this class. * Indicates that this is a concrete class with persistent data. */ static ClassDescription initMEPP2HiggsVBF; /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ MEPP2HiggsVBF & operator=(const MEPP2HiggsVBF &); private: /** * Parameters for the hard POWHEG emission */ //@{ /** * Pointer to the object calculating the strong coupling */ ShowerAlphaPtr alpha_; /** * Weight for the compton channel */ double comptonWeight_; /** * Weight for the BGF channel */ double BGFWeight_; /** * Minimum value of \f$p_T\f$ */ Energy pTmin_; /** * Gluon particle data object */ PDPtr gluon_; //@} /** * Properties of the emission */ //@{ /** * Beam particle */ tcBeamPtr beam_[2]; /** * PDF object */ tcPDFPtr pdf_[2]; /** * Partons */ tcPDPtr partons_[2][4]; /** * q */ Lorentz5Momentum q_[2]; /** * \f$Q^2\f$ */ Energy2 q2_[2]; /** * Coupling factor */ double acoeff_; /** * Lorentz vectors for the matrix element */ LorentzVector l_; /** * Lorentz vectors for the matrix element */ LorentzVector m_; /** * Born momentum fraction */ double xB_[2]; /** * Rotation to the Breit frame */ LorentzRotation rot_[2]; /** * Quark momenta for spectator system */ Lorentz5Momentum pother_[2][2]; /** * Quark momenta for emitting system */ Lorentz5Momentum psystem_[2][2]; /** * Higgs momenta */ Lorentz5Momentum phiggs_[2]; /** * Transverse momenta for the compton emissions */ Energy pTCompton_[2]; /** * Transverse momenta for the BGF emissions */ Energy pTBGF_[2]; /** * Whether the Compton radiation is ISR or FSR */ bool ComptonISFS_[2]; /** * Momenta of the particles for a compton emission */ vector ComptonMomenta_[2]; /** * Momenta of the particles for a BGF emission */ vector BGFMomenta_[2]; /** * the systems */ vector systems_; /** * Higgs boson */ ShowerParticlePtr higgs_; //@} /** * Parameters for the matrix element correction */ //@{ /** * Enchancement factor for ISR */ double initial_; /** * Enchancement factor for FSR */ double final_; /** * Relative fraction of compton and BGF processes to generate */ double procProb_; /** * Integral for compton process */ double comptonInt_; /** * Integral for BGF process */ double bgfInt_; /** * Number of weights greater than 1 */ unsigned int nover_; /** * Maximum weight */ pair maxwgt_; //@} }; } #include "ThePEG/Utilities/ClassTraits.h" namespace ThePEG { /** @cond TRAITSPECIALIZATIONS */ /** This template specialization informs ThePEG about the * base classes of MEPP2HiggsVBF. */ template <> struct BaseClassTrait { /** Typedef of the first base class of MEPP2HiggsVBF. */ typedef Herwig::MEfftoffH NthBase; }; /** This template specialization informs ThePEG about the name of * the MEPP2HiggsVBF 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::MEPP2HiggsVBF"; } /** * The name of a file containing the dynamic library where the class * MEPP2HiggsVBF is implemented. It may also include several, space-separated, * libraries if the class MEPP2HiggsVBF depends on other classes (base classes * excepted). In this case the listed libraries will be dynamically * linked in the order they are specified. */ static string library() { return "HwMEHadron.so"; } }; /** @endcond */ } #endif /* HERWIG_MEPP2HiggsVBF_H */ diff --git a/MatrixElement/HwMEBase.cc b/MatrixElement/HwMEBase.cc --- a/MatrixElement/HwMEBase.cc +++ b/MatrixElement/HwMEBase.cc @@ -1,289 +1,289 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the HwMEBase class. // #include "HwMEBase.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Utilities/SimplePhaseSpace.h" #include "ThePEG/PDT/EnumParticles.h" #include "Herwig/PDT/GenericMassGenerator.h" #include "ThePEG/Cuts/Cuts.h" #include "Herwig/Shower/Base/HardTree.h" #include "Herwig/Shower/Base/Branching.h" using namespace Herwig; void HwMEBase::persistentOutput(PersistentOStream & os) const { os << massOption_ << rescaleOption_; } void HwMEBase::persistentInput(PersistentIStream & is, int) { is >> massOption_ >> rescaleOption_; } AbstractClassDescription HwMEBase::initHwMEBase; // Definition of the static class description member. void HwMEBase::Init() { static ClassDocumentation documentation ("The HwMEBase class is the base class for matrix elements in Herwig" " and provides the virtual members for hard radiation corrections in the" " shower."); } int HwMEBase::nDim() const { unsigned ndim = 1; for(unsigned int ix=0;ix & masses, double & mjac, const double *r) { assert(massOption_.size()+2==mePartonData().size()); mjac = 1.; masses.clear(); masses.resize(massOption_.size(),ZERO); Energy ecm = sqrt(sHat()); Energy emin(ZERO); int noff(0); for(unsigned int ix=0;ixhardProcessMass(); emin += masses[ix]; } else if (massOption_[ix]==2) { emin += mePartonData()[ix+2]->massMin(); ++noff; } } // check allowed if(emin>ecm) return false; // if nothing off-shell return if(noff==0) return true; int iloc = nDim()-noff; emin = ecm - emin; // generate the masses for(unsigned int ix=0;ixmassMin(); emin += mmin; Energy mmax = min(mePartonData()[ix+2]->massMax(),emin); if(mmin>mmax) return false; tGenericMassGeneratorPtr gen = mePartonData()[ix+2]->massGenerator() ? dynamic_ptr_cast(mePartonData()[ix+2]->massGenerator()) : tGenericMassGeneratorPtr(); if(gen) { double jtemp(0.); masses[ix] = gen->mass(jtemp,*mePartonData()[ix+2],mmin,mmax,r[iloc]); mjac *= jtemp; } else { Energy mon(mePartonData()[ix+2]->hardProcessMass()); Energy width(mePartonData()[ix+2]->width()); double rhomin = atan2((sqr(mmin)-sqr(mon)), mon*width); double rhomax = atan2((sqr(mmax)-sqr(mon)), mon*width); masses[ix] = sqrt(mon*width*tan(rhomin+r[iloc]*(rhomax-rhomin))+sqr(mon)); mjac *= (rhomax-rhomin)/Constants::pi; } emin -= masses[ix]; if(emin masses; double mjac(0.); if(!generateMasses(masses,mjac,r)) return false; // set up the momenta for ( int i = 2, N = meMomenta().size(); i < N; ++i ) { meMomenta()[i] = Lorentz5Momentum(masses[i-2]); } double ctmin = -1.0, ctmax = 1.0; Energy q = ZERO; try { q = SimplePhaseSpace:: getMagnitude(sHat(), meMomenta()[2].mass(), meMomenta()[3].mass()); } catch ( ImpossibleKinematics ) { return false; } Energy e = sqrt(sHat())/2.0; Energy2 m22 = meMomenta()[2].mass2(); Energy2 m32 = meMomenta()[3].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) + m32); Energy2 e1e3 = 2.0*e*sqrt(sqr(q) + m32); Energy2 pq = 2.0*e*q; 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 - m32 - thmin)/pq); thmin = lastCuts().minTij(mePartonData()[0], mePartonData()[3]); if ( thmin > ZERO ) ctmin = max(ctmin, (thmin + m32 - 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, sqrt(sqr(q) + m32)*tanh(-ymin3)/q); if ( ymax3 + ytot < 0.9*Constants::MaxRapidity ) ctmin = max(ctmin, sqrt(sqr(q) + m32)*tanh(-ymax3)/q); 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(); 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; tHat(pq*cth + m22 - e0e2); uHat(m22 + m32 - sHat() - tHat()); jacobian((pq/sHat())*Constants::pi*jacobian()*mjac); // compute the rescaled momenta return rescaleMomenta(meMomenta(),mePartonData()); } bool HwMEBase::rescaleMomenta(const vector & momenta, const cPDVector & data) { assert(momenta.size()==4&&data.size()==4); // default just use the ones we generated rescaledMomenta_=momenta; if(rescaleOption_==1) return true; Energy mnew[2] = {0*MeV, ZERO}; if(rescaleOption_==0) { mnew[0] = ZERO; mnew[1] = ZERO; } else if(rescaleOption_==2) { mnew[0] = data[2]->hardProcessMass(); mnew[1] = data[3]->hardProcessMass(); } else if(rescaleOption_==3) { if(abs(data[2]->id())!=abs(data[3]->id())) return true; mnew[0] = 0.5*(momenta[2].mass()+momenta[3].mass()); mnew[1] = mnew[0]; } else { assert(false); } Lorentz5Momentum pcm(momenta[2]+momenta[3]); Energy m0=pcm.m(); if(m01e-10*(rescaledMomenta_[2].t()+rescaledMomenta_[2].mass())) rescaledMomenta_[2].rescaleRho(); else { rescaledMomenta_[2].setX(ZERO); rescaledMomenta_[2].setY(ZERO); rescaledMomenta_[2].setZ(ZERO); } rescaledMomenta_[2].boost(-bv); rescaledMomenta_[3].boost(bv); rescaledMomenta_[3].setMass(mnew[1]); rescaledMomenta_[3].setE(0.5*(sqr(m0)-sqr(mnew[0])+sqr(mnew[1]))/m0); if(rescaledMomenta_[3].t()-rescaledMomenta_[3].mass()>1e-10*(rescaledMomenta_[3].t()+rescaledMomenta_[3].mass())) rescaledMomenta_[3].rescaleRho(); else { rescaledMomenta_[3].setX(ZERO); rescaledMomenta_[3].setY(ZERO); rescaledMomenta_[3].setZ(ZERO); } rescaledMomenta_[3].boost(-bv); return true; } double HwMEBase::getCosTheta(double ctmin, double ctmax, const double r) { double cth = 0.0; static const double eps = 1.0e-6; if ( 1.0 + ctmin <= eps && 1.0 - ctmax <= eps ) { jacobian(jacobian()*(ctmax - ctmin)); cth = ctmin + r*(ctmax - ctmin); } else if ( 1.0 + ctmin <= eps ) { cth = 1.0 - (1.0 - ctmax)*pow((1.0 - ctmin)/(1.0 - ctmax), r); jacobian(jacobian()*log((1.0 - ctmin)/(1.0 - ctmax))*(1.0 - cth)); } else if ( 1.0 - ctmax <= eps ) { cth = -1.0 + (1.0 + ctmin)*pow((1.0 + ctmax)/(1.0 + ctmin), r); jacobian(jacobian()*log((1.0 + ctmax)/(1.0 + ctmin))*(1.0 + cth)); } else { double zmin = 0.5*(1.0 - ctmax); double zmax = 0.5*(1.0 - ctmin); double A1 = -ctmin/(zmax*(1.0-zmax)); double A0 = -ctmax/(zmin*(1.0-zmin)); double A = r*(A1 - A0) + A0; double z = A < 2.0? 2.0/(sqrt(sqr(A) + 4.0) + 2 - A): 0.5*(A - 2.0 + sqrt(sqr(A) + 4.0))/A; cth = 1.0 - 2.0*z; jacobian(jacobian()*2.0*(A1 - A0)*sqr(z)*sqr(1.0 - z)/(sqr(z) + sqr(1.0 - z))); } return cth; } bool HwMEBase::softMatrixElementVeto(ShowerProgenitorPtr, ShowerParticlePtr,Branching) { return false; } -HardTreePtr HwMEBase::generateHardest(ShowerTreePtr,vector) { +HardTreePtr HwMEBase::generateHardest(ShowerTreePtr,ShowerInteraction::Type) { return HardTreePtr(); } diff --git a/MatrixElement/HwMEBase.h b/MatrixElement/HwMEBase.h --- a/MatrixElement/HwMEBase.h +++ b/MatrixElement/HwMEBase.h @@ -1,319 +1,319 @@ // -*- C++ -*- #ifndef HERWIG_HwMEBase_H #define HERWIG_HwMEBase_H // // This is the declaration of the HwMEBase class. // #include "ThePEG/MatrixElement/MEBase.h" #include "Herwig/Shower/Base/ShowerParticle.fh" #include "Herwig/Shower/Base/ShowerProgenitor.fh" #include "Herwig/Shower/Base/ShowerTree.fh" #include "Herwig/Shower/Base/HardTree.fh" #include "Herwig/Shower/ShowerConfig.h" #include "ThePEG/PDF/BeamParticleData.h" #include "HwMEBase.fh" namespace Herwig { struct Branching; using namespace ThePEG; typedef Ptr::transient_const_pointer tcBeamPtr; /** * The HwMEBase class serves a number of purposes * - it implements the phase space for \f$2\to2\f$ scattering processes * - it provides virtual members for the implementation of hard radiation * - it gives us greater control over the masses of the outgoing * particles so that they can be * - set massless where required by gauge invariance * - have their off-shell masses generated using the sophisticated approaches * available in Herwig. * * @see \ref HwMEBaseInterfaces "The interfaces" * defined for HwMEBase. */ class HwMEBase: public MEBase { public: /** * Default constructor. */ HwMEBase() : lastTHat_(ZERO), lastUHat_(ZERO), lastPhi_(0.0), rescaleOption_(1) {} /** @name Virtual functions required by the MEBase class. */ //@{ /** * The number of internal degreed of freedom used in the matrix * element. */ virtual int nDim() const; /** * Generate internal degrees of freedom given 'nDim()' uniform * random numbers in the interval ]0,1[. To help the phase space * generator, the 'dSigHatDR()' should be a smooth function of these * numbers, although this is not strictly necessary. Return * false if the chosen points failed the kinematical cuts. */ virtual bool generateKinematics(const double * r); /** * Return the matrix element for the kinematical configuation * previously provided by the last call to setKinematics(). Uses * me(). */ virtual CrossSection dSigHatDR() const; /** * Set the typed and momenta of the incoming and outgoing partons to * be used in subsequent calls to me() and colourGeometries() * according to the associated XComb object. */ virtual void setKinematics(); //@} /** * Virtual members to be overridden by inheriting classes * which implement hard corrections */ //@{ /** * Type of POWHEG correction */ enum POWHEGType {No, ISR, FSR, Both}; /** * Has a POWHEG style correction */ virtual POWHEGType hasPOWHEGCorrection() {return No;} /** * Has an old fashioned ME correction */ virtual bool hasMECorrection() {return false;} /** * Initialize the ME correction */ virtual void initializeMECorrection(ShowerTreePtr , double & , double & ) {} /** * Apply the hard matrix element correction to a given hard process or decay */ virtual void applyHardMatrixElementCorrection(ShowerTreePtr) {} /** * Apply the soft matrix element correction * @param initial The particle from the hard process which started the * shower * @param parent The initial particle in the current branching * @param br The branching struct * @return If true the emission should be vetoed */ virtual bool softMatrixElementVeto(ShowerProgenitorPtr initial, ShowerParticlePtr parent, Branching br); /** * Apply the POWHEG style correction */ - virtual HardTreePtr generateHardest(ShowerTreePtr,vector); + virtual HardTreePtr generateHardest(ShowerTreePtr,ShowerInteraction::Type); //@} 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 Access cached values in of the last set phase space point. */ //@{ /** * Return the \f$\hat{t}\f$ of the last set phase space point. */ Energy2 tHat() const { return lastTHat_; } /** * Return the \f$\hat{u}\f$ of the last set phase space point. */ Energy2 uHat() const { return lastUHat_; } /** * Return the azimuth angle of the last set phase space point. */ double phi() const { return lastPhi_; } //@} /** @name Set the cached values in of the last set phase space point. */ //@{ /** * Set the \f$\hat{t}\f$ of the last set phase space point. */ void tHat(Energy2 e2) { lastTHat_ = e2; } /** * Set the \f$\hat{u}\f$ of the last set phase space point. */ void uHat(Energy2 e2) { lastUHat_ = e2; } /** * Set the azimuth angle of the last set phase space point. */ void phi(double phi) { lastPhi_ = phi; } //@} /** * Set the treatment of the outgoing masses * @param iopt The option for the treatment of the mass */ void massOption(vector iopt) { massOption_ = iopt; } /** * Rescaled momenta for the helicity ME */ //@{ /** * Set the treatment of the rescaling of the momenta for * the matrix element calculation * @param iopt The rescaling option */ void rescalingOption(unsigned int iopt) { rescaleOption_=iopt; } /** * rescale the momenta for the computation of the helicity matrix element */ bool rescaleMomenta(const vector &, const cPDVector &); /** * Access to the rescaled momenta */ const vector & rescaledMomenta() const { return rescaledMomenta_; } //@} /** * Generate the masses of the particles */ bool generateMasses(vector & masses, double & mjac, const double *r); /** * Used internally by generateKinematics, after calculating the * limits on cos(theta). */ virtual double getCosTheta(double cthmin, double cthmax, const double r); private: /** * The static object used to initialize the description of this class. * Indicates that this is an abstract class without persistent data. */ static AbstractClassDescription initHwMEBase; /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ HwMEBase & operator=(const HwMEBase &); private: /** * Option for the treatment of the particle masses */ vector massOption_; /** * The \f$\hat{t}\f$ of the last set phase space point. */ Energy2 lastTHat_; /** * The \f$\hat{u}\f$ of the last set phase space point. */ Energy2 lastUHat_; /** * The azimuth angle of the last set phase space point. */ double lastPhi_; /** * Produced to produce rescaled momenta */ unsigned int rescaleOption_; /** * Rescaled momenta for use in ME calculations */ vector rescaledMomenta_; }; } #include "ThePEG/Utilities/ClassTraits.h" namespace ThePEG { /** @cond TRAITSPECIALIZATIONS */ /** This template specialization informs ThePEG about the * base classes of HwMEBase. */ template <> struct BaseClassTrait { /** Typedef of the first base class of HwMEBase. */ typedef MEBase NthBase; }; /** This template specialization informs ThePEG about the name of * the HwMEBase 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::HwMEBase"; } }; /** @endcond */ } #endif /* HERWIG_HwMEBase_H */ diff --git a/MatrixElement/Lepton/MEee2gZ2ll.cc b/MatrixElement/Lepton/MEee2gZ2ll.cc --- a/MatrixElement/Lepton/MEee2gZ2ll.cc +++ b/MatrixElement/Lepton/MEee2gZ2ll.cc @@ -1,764 +1,758 @@ // -*- C++ -*- // // MEee2gZ2ll.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 MEee2gZ2ll class. // #include "MEee2gZ2ll.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/Helicity/WaveFunction/VectorWaveFunction.h" #include "ThePEG/Handlers/StandardXComb.h" #include "Herwig/MatrixElement/HardVertex.h" #include "ThePEG/PDF/PolarizedBeamParticleData.h" #include "ThePEG/Utilities/DescribeClass.h" #include #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" using namespace Herwig; void MEee2gZ2ll::getDiagrams() const { // specific the diagrams tcPDPtr ep = getParticleData(ParticleID::eplus); tcPDPtr em = getParticleData(ParticleID::eminus); // setup the processes for( int i =11;i<=16;++i) { if(allowed_==0 || (allowed_==1 && i%2==1) || (allowed_==2&&i==11) || (allowed_==3&&i==13) || (allowed_==4&&i==15)) { tcPDPtr lm = getParticleData(i); tcPDPtr lp = lm->CC(); add(new_ptr((Tree2toNDiagram(2), em, ep, 1, gamma_, 3, lm, 3, lp, -1))); add(new_ptr((Tree2toNDiagram(2), em, ep, 1, Z0_, 3, lm, 3, lp, -2))); } } } Energy2 MEee2gZ2ll::scale() const { return sHat(); } unsigned int MEee2gZ2ll::orderInAlphaS() const { return 0; } unsigned int MEee2gZ2ll::orderInAlphaEW() const { return 2; } Selector MEee2gZ2ll::diagrams(const DiagramVector & diags) const { double lastCont(0.5),lastBW(0.5); if ( lastXCombPtr() ) { lastCont = meInfo()[0]; lastBW = meInfo()[1]; } Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ) { if ( diags[i]->id() == -1 ) sel.insert(lastCont, i); else if ( diags[i]->id() == -2 ) sel.insert(lastBW, i); } return sel; } Selector MEee2gZ2ll::colourGeometries(tcDiagPtr) const { static ColourLines ctST(" "); Selector sel; sel.insert(1.0, &ctST); return sel; } void MEee2gZ2ll::persistentOutput(PersistentOStream & os) const { os << allowed_ << FFZVertex_ << FFPVertex_ << gamma_ << Z0_ << alphaQED_ << ounit(pTmin_,GeV) << preFactor_; } void MEee2gZ2ll::persistentInput(PersistentIStream & is, int) { is >> allowed_ >> FFZVertex_ >> FFPVertex_ >> gamma_ >> Z0_ >> alphaQED_ >> iunit(pTmin_,GeV) >> preFactor_; } // *** Attention *** The following static variable is needed for the type // description system in ThePEG. Please check that the template arguments // are correct (the class and its base class), and that the constructor // arguments are correct (the class name and the name of the dynamically // loadable library where the class implementation can be found). DescribeClass describeMEee2gZ2ll("Herwig::MEee2gZ2ll", "HwMELepton.so"); void MEee2gZ2ll::Init() { static ClassDocumentation documentation ("The MEee2gZ2ll class implements the matrix element for" "e+e- to leptons via Z and photon exchange using helicity amplitude" "techniques"); static Switch interfaceallowed ("Allowed", "Allowed outgoing leptons", &MEee2gZ2ll::allowed_, 0, false, false); static SwitchOption interfaceallowedAll (interfaceallowed, "All", "Allow all leptons as outgoing particles", 0); static SwitchOption interfaceallowedCharged (interfaceallowed, "Charged", "Only charged leptons as outgoing particles", 1); static SwitchOption interfaceallowedElectron (interfaceallowed, "Electron", "Only the electron and positron as outgoing leptons", 2); static SwitchOption interfaceallowedMuon (interfaceallowed, "Muon", "Only muons as outgoing particles", 3); static SwitchOption interfaceallowedTau (interfaceallowed, "Tau", "Only taus as outgoing particles", 4); static Parameter interfacepTMin ("pTMin", "Minimum pT for hard radiation", &MEee2gZ2ll::pTmin_, GeV, 1.0*GeV, 0.001*GeV, 10.0*GeV, false, false, Interface::limited); static Parameter interfacePrefactor ("Prefactor", "Prefactor for the overestimate of the emission probability", &MEee2gZ2ll::preFactor_, 6.0, 1.0, 100.0, false, false, Interface::limited); static Reference interfaceEMCoupling ("AlphaQED", "Pointer to the object to calculate the EM coupling for the correction", &MEee2gZ2ll::alphaQED_, false, false, true, false, false); } double MEee2gZ2ll::me2() const { return loME(mePartonData(),rescaledMomenta(),true); } double MEee2gZ2ll::loME(const vector & partons, const vector & momenta, bool first) const { vector fin,aout; vector ain,fout; SpinorWaveFunction ein (momenta[0],partons[0],incoming); SpinorBarWaveFunction pin (momenta[1],partons[1],incoming); SpinorBarWaveFunction ilmout(momenta[2],partons[2],outgoing); SpinorWaveFunction ilpout(momenta[3],partons[3],outgoing); for(unsigned int ix=0;ix<2;++ix) { ein.reset(ix) ;fin.push_back( ein ); pin.reset(ix) ;ain.push_back( pin ); ilmout.reset(ix);fout.push_back(ilmout); ilpout.reset(ix);aout.push_back(ilpout); } // compute the matrix element double me,lastCont,lastBW; HelicityME(fin,ain,fout,aout,me,lastCont,lastBW); // save the components if(first) { DVector save; save.push_back(lastCont); save.push_back(lastBW); meInfo(save); } // return the answer return me; } ProductionMatrixElement MEee2gZ2ll::HelicityME(vector & fin, vector & ain, vector & fout, vector & aout, double & me,double & cont, double & BW ) const { // the particles should be in the order // for the incoming // 0 incoming fermion (u spinor) // 1 incoming antifermion (vbar spinor) // for the outgoing // 0 outgoing fermion (ubar spinor) // 1 outgoing antifermion (v spinor) // me to be returned ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half); ProductionMatrixElement gamma (PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half); ProductionMatrixElement Zboson(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half); // // wavefunctions for the intermediate particles VectorWaveFunction interZ,interG; // temporary storage of the different diagrams Complex diag1,diag2; // sum over helicities to get the matrix element unsigned int inhel1,inhel2,outhel1,outhel2; double total[3]={0.,0.,0.}; for(inhel1=0;inhel1<2;++inhel1) { for(inhel2=0;inhel2<2;++inhel2) { // intermediate Z interZ = FFZVertex_->evaluate(sHat(),1,Z0_,fin[inhel1],ain[inhel2]); // intermediate photon interG = FFPVertex_->evaluate(sHat(),1,gamma_,fin[inhel1],ain[inhel2]); for(outhel1=0;outhel1<2;++outhel1) { for(outhel2=0;outhel2<2;++outhel2) { // first the Z exchange diagram diag1 = FFZVertex_->evaluate(sHat(),aout[outhel2],fout[outhel1], interZ); // then the photon exchange diagram diag2 = FFPVertex_->evaluate(sHat(),aout[outhel2],fout[outhel1], interG); // add up squares of individual terms total[1] += norm(diag1); Zboson(inhel1,inhel2,outhel1,outhel2) = diag1; total[2] += norm(diag2); gamma (inhel1,inhel2,outhel1,outhel2) = diag2; // the full thing including interference diag1 += diag2; total[0] += norm(diag1); output(inhel1,inhel2,outhel1,outhel2) = diag1; } } } } // results for(int ix=0;ix<3;++ix) total[ix] *= 0.25; tcPolarizedBeamPDPtr beam[2] = {dynamic_ptr_cast(mePartonData()[0]), dynamic_ptr_cast(mePartonData()[1])}; if( beam[0] || beam[1] ) { RhoDMatrix rho[2] = {beam[0] ? beam[0]->rhoMatrix() : RhoDMatrix(mePartonData()[0]->iSpin()), beam[1] ? beam[1]->rhoMatrix() : RhoDMatrix(mePartonData()[1]->iSpin())}; total[0] = output.average(rho[0],rho[1]); total[1] = Zboson.average(rho[0],rho[1]); total[2] = gamma .average(rho[0],rho[1]); } cont = total[2]; BW = total[1]; me = total[0]; return output; } void MEee2gZ2ll::constructVertex(tSubProPtr sub) { // extract the particles in the hard process ParticleVector hard; hard.push_back(sub->incoming().first);hard.push_back(sub->incoming().second); hard.push_back(sub->outgoing()[0]);hard.push_back(sub->outgoing()[1]); if(hard[0]->id()id()) swap(hard[0],hard[1]); if(hard[2]->id()id()) swap(hard[2],hard[3]); vector fin,aout; vector ain,fout; SpinorWaveFunction( fin ,hard[0],incoming,false,true); SpinorBarWaveFunction(ain ,hard[1],incoming,false,true); SpinorBarWaveFunction(fout,hard[2],outgoing,true ,true); SpinorWaveFunction( aout,hard[3],outgoing,true ,true); // calculate the matrix element double me,cont,BW; ProductionMatrixElement prodme=HelicityME(fin,ain,fout,aout,me,cont,BW); // construct the vertex HardVertexPtr hardvertex=new_ptr(HardVertex()); // set the matrix element for the vertex hardvertex->ME(prodme); // set the pointers and to and from the vertex for(unsigned int ix=0;ix<4;++ix) { tSpinPtr spin = hard[ix]->spinInfo(); if(ix<2) { tcPolarizedBeamPDPtr beam = dynamic_ptr_cast(hard[ix]->dataPtr()); if(beam) spin->rhoMatrix() = beam->rhoMatrix(); } spin->productionVertex(hardvertex); } } void MEee2gZ2ll::doinit() { HwMEBase::doinit(); // set the particle data objects Z0_=getParticleData(ThePEG::ParticleID::Z0); gamma_=getParticleData(ThePEG::ParticleID::gamma); // cast the SM pointer to the Herwig SM pointer tcHwSMPtr hwsm= dynamic_ptr_cast(standardModel()); // do the initialisation if(!hwsm) throw InitException() << "Wrong type of StandardModel object in " << "MEee2gZ2ll::doinit() the Herwig" << " version must be used" << Exception::runerror; FFZVertex_ = hwsm->vertexFFZ(); FFPVertex_ = hwsm->vertexFFP(); } void MEee2gZ2ll::rebind(const TranslationMap & trans) { FFZVertex_ = trans.translate(FFZVertex_); FFPVertex_ = trans.translate(FFPVertex_); Z0_ = trans.translate(Z0_); gamma_ = trans.translate(gamma_); HwMEBase::rebind(trans); } IVector MEee2gZ2ll::getReferences() { IVector ret = HwMEBase::getReferences(); ret.push_back(FFZVertex_); ret.push_back(FFPVertex_); ret.push_back(Z0_ ); ret.push_back(gamma_ ); return ret; } -HardTreePtr MEee2gZ2ll::generateHardest(ShowerTreePtr tree, - vector inter) { - // check if QED switched on - bool QEDon=false; - for(unsigned int ix=0;ix emmision; unsigned int iemit,ispect; Energy pTveto = generateHard(tree,emmision,iemit,ispect,false); // outgoing progenitors ShowerProgenitorPtr qkProgenitor = tree->outgoingLines().begin() ->first, qbProgenitor = tree->outgoingLines().rbegin()->first; if(qkProgenitor->id()<0) swap(qkProgenitor,qbProgenitor); // check if charged if(!qkProgenitor->progenitor()->dataPtr()->charged()) return HardTreePtr(); // maximum pT of emission if(pTveto<=ZERO) { - for(unsigned int ix=0;ixmaximumpT(pTmin_,inter[ix]); - qbProgenitor->maximumpT(pTmin_,inter[ix]); - } + qkProgenitor->maximumpT(pTmin_,ShowerInteraction::QED); + qbProgenitor->maximumpT(pTmin_,ShowerInteraction::QED); return HardTreePtr(); } else { - for(unsigned int ix=0;ixmaximumpT(pTveto,inter[ix]); - qbProgenitor->maximumpT(pTveto,inter[ix]); - } + qkProgenitor->maximumpT(pTveto,ShowerInteraction::QED); + qbProgenitor->maximumpT(pTveto,ShowerInteraction::QED); } // Make the particles for the hard tree ShowerParticleVector hardParticles; for(unsigned int ix=0;ix=2))); hardParticles.back()->set5Momentum(emmision[ix]); } ShowerParticlePtr parent(new_ptr(ShowerParticle(partons_[iemit],true))); Lorentz5Momentum parentMomentum(emmision[iemit]+emmision[4]); parentMomentum.setMass(partons_[iemit]->mass()); parent->set5Momentum(parentMomentum); // Create the vectors of HardBranchings to create the HardTree: vector spaceBranchings,allBranchings; // Incoming boson: for(unsigned int ix=0;ix<2;++ix) { spaceBranchings.push_back(new_ptr(HardBranching(hardParticles[ix],SudakovPtr(), HardBranchingPtr(), HardBranching::Incoming))); allBranchings.push_back(spaceBranchings.back()); } // Outgoing particles from hard emission: HardBranchingPtr spectatorBranch(new_ptr(HardBranching(hardParticles[ispect], SudakovPtr(),HardBranchingPtr(), HardBranching::Outgoing))); HardBranchingPtr emitterBranch(new_ptr(HardBranching(parent,SudakovPtr(), HardBranchingPtr(), HardBranching::Outgoing))); emitterBranch->addChild(new_ptr(HardBranching(hardParticles[iemit], SudakovPtr(),HardBranchingPtr(), HardBranching::Outgoing))); emitterBranch->addChild(new_ptr(HardBranching(hardParticles[4], SudakovPtr(),HardBranchingPtr(), HardBranching::Outgoing))); emitterBranch->type(ShowerPartnerType::QED); if(iemit==0) { allBranchings.push_back(emitterBranch); allBranchings.push_back(spectatorBranch); } else { allBranchings.push_back( spectatorBranch ); allBranchings.push_back( emitterBranch ); } emitterBranch ->branchingParticle()->partner(spectatorBranch->branchingParticle()); spectatorBranch->branchingParticle()->partner(emitterBranch ->branchingParticle()); spaceBranchings[0]->branchingParticle()->partner(spaceBranchings[1]->branchingParticle()); spaceBranchings[1]->branchingParticle()->partner(spaceBranchings[0]->branchingParticle()); // Make the HardTree from the HardBranching vectors. HardTreePtr hardtree = new_ptr(HardTree(allBranchings,spaceBranchings, ShowerInteraction::QED)); hardtree->partnersSet(true); // Connect the particles with the branchings in the HardTree hardtree->connect( qkProgenitor->progenitor(), allBranchings[2] ); hardtree->connect( qbProgenitor->progenitor(), allBranchings[3] ); // colour flow ColinePtr newline=new_ptr(ColourLine()); // Return the HardTree return hardtree; } double MEee2gZ2ll::meRatio(vector partons, vector momenta, unsigned int iemitter, bool subtract) const { Lorentz5Momentum q = momenta[2]+momenta[3]+momenta[4]; Energy2 Q2=q.m2(); Energy2 lambda = sqrt((Q2-sqr(momenta[2].mass()+momenta[3].mass()))* (Q2-sqr(momenta[2].mass()-momenta[3].mass()))); InvEnergy2 D[2]; double lome[2]; for(unsigned int iemit=0;iemit<2;++iemit) { unsigned int ispect = iemit==0 ? 1 : 0; Energy2 pipj = momenta[4 ] * momenta[2+iemit ]; Energy2 pipk = momenta[4 ] * momenta[2+ispect]; Energy2 pjpk = momenta[2+iemit] * momenta[2+ispect]; double y = pipj/(pipj+pipk+pjpk); double z = pipk/( pipk+pjpk); Energy mij = sqrt(2.*pipj+sqr(momenta[2+iemit].mass())); Energy2 lamB = sqrt((Q2-sqr(mij+momenta[2+ispect].mass()))* (Q2-sqr(mij-momenta[2+ispect].mass()))); Energy2 Qpk = q*momenta[2+ispect]; Lorentz5Momentum pkt = lambda/lamB*(momenta[2+ispect]-Qpk/Q2*q) +0.5/Q2*(Q2+sqr(momenta[2+ispect].mass())-sqr(momenta[2+ispect].mass()))*q; Lorentz5Momentum pijt = q-pkt; double muj = momenta[2+iemit ].mass()/sqrt(Q2); double muk = momenta[2+ispect].mass()/sqrt(Q2); double vt = sqrt((1.-sqr(muj+muk))*(1.-sqr(muj-muk)))/(1.-sqr(muj)-sqr(muk)); double v = sqrt(sqr(2.*sqr(muk)+(1.-sqr(muj)-sqr(muk))*(1.-y))-4.*sqr(muk)) /(1.-y)/(1.-sqr(muj)-sqr(muk)); // dipole term D[iemit] = 0.5/pipj*(2./(1.-(1.-z)*(1.-y)) -vt/v*(2.-z+sqr(momenta[2+iemit].mass())/pipj)); // matrix element vector lomom(4); lomom[0] = momenta[0]; lomom[1] = momenta[1]; if(iemit==0) { lomom[2] = pijt; lomom[3] = pkt ; } else { lomom[3] = pijt; lomom[2] = pkt ; } lome[iemit] = loME(partons,lomom,false); } InvEnergy2 ratio = realME(partons,momenta) *abs(D[iemitter])/(abs(D[0]*lome[0])+abs(D[1]*lome[1])); double output = Q2*ratio; if(subtract) output -= 2.*Q2*D[iemitter]; return output; } InvEnergy2 MEee2gZ2ll::realME(const vector & partons, const vector & momenta) const { // compute the spinors vector fin,aout; vector ain,fout; vector gout; SpinorWaveFunction ein (momenta[0],partons[0],incoming); SpinorBarWaveFunction pin (momenta[1],partons[1],incoming); SpinorBarWaveFunction qkout(momenta[2],partons[2],outgoing); SpinorWaveFunction qbout(momenta[3],partons[3],outgoing); VectorWaveFunction photon(momenta[4],partons[4],outgoing); for(unsigned int ix=0;ix<2;++ix) { ein.reset(ix) ; fin.push_back( ein ); pin.reset(ix) ; ain.push_back( pin ); qkout.reset(ix); fout.push_back(qkout); qbout.reset(ix); aout.push_back(qbout); photon.reset(2*ix); gout.push_back(photon); } vector diag(4,0.); ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1); double total(0.); for(unsigned int inhel1=0;inhel1<2;++inhel1) { for(unsigned int inhel2=0;inhel2<2;++inhel2) { // intermediate Z VectorWaveFunction interZ = FFZVertex_->evaluate(scale(),1,Z0_,fin[inhel1],ain[inhel2]); // intermediate photon VectorWaveFunction interG = FFPVertex_->evaluate(scale(),1,gamma_,fin[inhel1],ain[inhel2]); for(unsigned int outhel1=0;outhel1<2;++outhel1) { for(unsigned int outhel2=0;outhel2<2;++outhel2) { for(unsigned int outhel3=0;outhel3<2;++outhel3) { SpinorBarWaveFunction off1 = FFPVertex_->evaluate(scale(),3,partons[2],fout[outhel1],gout[outhel3]); diag[0] = FFZVertex_->evaluate(scale(),aout[outhel2],off1,interZ); diag[1] = FFPVertex_->evaluate(scale(),aout[outhel2],off1,interG); SpinorWaveFunction off2 = FFPVertex_->evaluate(scale(),3,partons[3],aout[outhel2],gout[outhel3]); diag[2] = FFZVertex_->evaluate(scale(),off2,fout[outhel1],interZ); diag[3] = FFPVertex_->evaluate(scale(),off2,fout[outhel1],interG); // sum of diagrams Complex sum = std::accumulate(diag.begin(),diag.end(),Complex(0.)); // matrix element output(inhel1,inhel2,outhel1,outhel2,outhel3)=sum; // me2 total += norm(sum); } } } } } // spin average total *= 0.25; tcPolarizedBeamPDPtr beam[2] = {dynamic_ptr_cast(partons[0]), dynamic_ptr_cast(partons[1])}; if( beam[0] || beam[1] ) { RhoDMatrix rho[2] = {beam[0] ? beam[0]->rhoMatrix() : RhoDMatrix(mePartonData()[0]->iSpin()), beam[1] ? beam[1]->rhoMatrix() : RhoDMatrix(mePartonData()[1]->iSpin())}; total = output.average(rho[0],rho[1]); } // divide out the coupling and charge total /= norm(FFPVertex_->norm())* sqr(double(mePartonData()[2]->iCharge())/3.); // return the total return total*UnitRemoval::InvE2; } Energy MEee2gZ2ll::generateHard(ShowerTreePtr tree, vector & emmision, unsigned int & iemit, unsigned int & ispect, bool applyVeto) { // get the momenta of the incoming and outgoing particles // incoming ShowerProgenitorPtr emProgenitor = tree->incomingLines().begin() ->first, epProgenitor = tree->incomingLines().rbegin()->first; // outgoing ShowerProgenitorPtr qkProgenitor = tree->outgoingLines().begin() ->first, qbProgenitor = tree->outgoingLines().rbegin()->first; // get the order right if(emProgenitor->id()<0) swap(emProgenitor,epProgenitor); if(qkProgenitor->id()<0) swap(qkProgenitor,qbProgenitor); loMomenta_.resize(0); // extract the momenta loMomenta_.push_back(emProgenitor->progenitor()->momentum()); loMomenta_.push_back(epProgenitor->progenitor()->momentum()); loMomenta_.push_back(qkProgenitor->progenitor()->momentum()); loMomenta_.push_back(qbProgenitor->progenitor()->momentum()); // and ParticleData objects partons_.resize(5); partons_[0]=emProgenitor->progenitor()->dataPtr(); partons_[1]=epProgenitor->progenitor()->dataPtr(); partons_[2]=qkProgenitor->progenitor()->dataPtr(); partons_[3]=qbProgenitor->progenitor()->dataPtr(); partons_[4]=gamma_; // boost from lab to CMS frame with outgoing particles // along the z axis LorentzRotation eventFrame( ( loMomenta_[2] + loMomenta_[3] ).findBoostToCM() ); Lorentz5Momentum spectator = eventFrame*loMomenta_[2]; eventFrame.rotateZ( -spectator.phi() ); eventFrame.rotateY( -spectator.theta() ); eventFrame.invert(); // mass of the final-state system Energy2 M2 = (loMomenta_[2]+loMomenta_[3]).m2(); Energy M = sqrt(M2); double mu1 = loMomenta_[2].mass()/M; double mu2 = loMomenta_[3].mass()/M; double mu12 = sqr(mu1), mu22 = sqr(mu2); double lambda = sqrt(1.+sqr(mu12)+sqr(mu22)-2.*mu12-2.*mu22-2.*mu12*mu22); // max pT Energy pTmax = 0.5*sqrt(M2)* (1.-sqr(loMomenta_[2].mass()+loMomenta_[3].mass())/M2); // max y double ymax = acosh(pTmax/pTmin_); double a = alphaQED_->overestimateValue()/Constants::twopi* 2.*ymax*preFactor_*sqr(double(mePartonData()[2]->iCharge())/3.); // variables for the emission Energy pT[2]; double y[2],phi[2],x3[2],x1[2][2],x2[2][2]; double contrib[2][2]; // storage of the real emission momenta vector realMomenta[2][2]= {{vector(5),vector(5)}, {vector(5),vector(5)}}; for(unsigned int ix=0;ix<2;++ix) for(unsigned int iy=0;iy<2;++iy) for(unsigned int iz=0;iz<2;++iz) realMomenta[ix][iy][iz] = loMomenta_[iz]; // generate the emission for(unsigned int ix=0;ix<2;++ix) { if(ix==1) { swap(mu1 ,mu2 ); swap(mu12,mu22); } pT[ix] = pTmax; y [ix] = 0.; bool reject = true; do { // generate pT pT[ix] *= pow(UseRandom::rnd(),1./a); if(pT[ix] 1. -sqr( mu1 + mu2 ) ) continue; // find the possible solutions for x1 double xT2 = sqr(2./M*pT[ix]); double root = (-sqr(x3[ix])+xT2)* (xT2*mu22+2.*x3[ix]-sqr(mu12)+2.*mu22+2.*mu12-sqr(x3[ix])-1. +2.*mu12*mu22-sqr(mu22)-2.*mu22*x3[ix]-2.*mu12*x3[ix]); double c1=2.*sqr(x3[ix])-4.*mu22-6.*x3[ix]+4.*mu12-xT2*x3[ix] +2.*xT2-2.*mu12*x3[ix]+2.*mu22*x3[ix]+4.; if(root<0.) continue; x1[ix][0] = 1./(4.-4.*x3[ix]+xT2)*(c1-2.*sqrt(root)); x1[ix][1] = 1./(4.-4.*x3[ix]+xT2)*(c1+2.*sqrt(root)); // change sign of y if 2nd particle emits if(ix==1) y[ix] *=-1.; // loop over the solutions for(unsigned int iy=0;iy<2;++iy) { contrib[ix][iy]=0.; // check x1 value allowed if(x1[ix][iy]<2.*mu1||x1[ix][iy]>1.+mu12-mu22) continue; // calculate x2 value and check allowed x2[ix][iy] = 2.-x3[ix]-x1[ix][iy]; double root = max(0.,sqr(x1[ix][iy])-4.*mu12); root = sqrt(root); double x2min = 1.+mu22-mu12 -0.5*(1.-x1[ix][iy]+mu12-mu22)/(1.-x1[ix][iy]+mu12)*(x1[ix][iy]-2.*mu12+root); double x2max = 1.+mu22-mu12 -0.5*(1.-x1[ix][iy]+mu12-mu22)/(1.-x1[ix][iy]+mu12)*(x1[ix][iy]-2.*mu12-root); if(x2[ix][iy]x2max) continue; // check the z components double z1 = sqrt(sqr(x1[ix][iy])-4.*mu12-xT2); double z2 = -sqrt(sqr(x2[ix][iy])-4.*mu22); double z3 = pT[ix]*sinh(y[ix])*2./M; if(ix==1) z3 *=-1.; if(abs(-z1+z2+z3)<1e-9) z1 *= -1.; if(abs(z1+z2+z3)>1e-5) continue; // if using as an ME correction the veto if(applyVeto) { // double xb = x1[ix][iy], xc = x2[ix][iy]; // double b = mu12, c = mu22; // double r = 0.5*(1.+b/(1.+c-xc)); // double z1 = r + (xb-(2.-xc)*r)/sqrt(sqr(xc)-4.*c); // double kt1 = (1.-b+c-xc)/z1/(1.-z1); // r = 0.5*(1.+c/(1.+b-xb)); // double z2 = r + (xc-(2.-xb)*r)/sqrt(sqr(xb)-4.*b); // double kt2 = (1.-c+b-xb)/z2/(1.-z2); // if(ix==1) { // swap(z1 ,z2); // swap(kt1,kt2); // } // // veto the shower region // if( kt1 < d_kt1_ || kt2 < d_kt2_ ) continue; } // construct the momenta realMomenta[ix][iy][4] = Lorentz5Momentum(pT[ix]*cos(phi[ix]),pT[ix]*sin(phi[ix]), pT[ix]*sinh(y[ix]) ,pT[ix]*cosh(y[ix]),ZERO); if(ix==0) { realMomenta[ix][iy][2] = Lorentz5Momentum(-pT[ix]*cos(phi[ix]),-pT[ix]*sin(phi[ix]), z1*0.5*M,x1[ix][iy]*0.5*M,M*mu1); realMomenta[ix][iy][3] = Lorentz5Momentum(ZERO,ZERO, z2*0.5*M,x2[ix][iy]*0.5*M,M*mu2); } else { realMomenta[ix][iy][2] = Lorentz5Momentum(ZERO,ZERO,-z2*0.5*M,x2[ix][iy]*0.5*M,M*mu2); realMomenta[ix][iy][3] = Lorentz5Momentum(-pT[ix]*cos(phi[ix]),-pT[ix]*sin(phi[ix]), -z1*0.5*M,x1[ix][iy]*0.5*M,M*mu1); } // boost the momenta back to the lab for(unsigned int iz=2;iz<5;++iz) realMomenta[ix][iy][iz] *= eventFrame; // jacobian and prefactors for the weight Energy J = M/sqrt(xT2)*abs(-x1[ix][iy]*x2[ix][iy]+2.*mu22*x1[ix][iy] +x2[ix][iy]+x2[ix][iy]*mu12+mu22*x2[ix][iy] -sqr(x2[ix][iy])) /pow(sqr(x2[ix][iy])-4.*mu22,1.5); // prefactors etc contrib[ix][iy] = 0.5*pT[ix]/J/preFactor_/lambda; // matrix element piece contrib[ix][iy] *= meRatio(partons_,realMomenta[ix][iy],ix,false); // coupling piece contrib[ix][iy] *= alphaQED_->ratio(sqr(pT[ix])); } if(contrib[ix][0]+contrib[ix][1]>1.) { ostringstream s; s << "MEee2gZ2qq::generateHardest weight for channel " << ix << "is " << contrib[ix][0]+contrib[ix][1] << " which is greater than 1"; generator()->logWarning( Exception(s.str(), Exception::warning) ); } reject = UseRandom::rnd() > contrib[ix][0] + contrib[ix][1]; } while (reject); if(pT[ix]pT[1]) { iemit = 2; ispect = 3; pTemit = pT[0]; if(UseRandom::rnd()(2,1)); } /** * Members for hard corrections to the emission of QCD radiation */ //@{ /** * Has a POWHEG style correction */ virtual POWHEGType hasPOWHEGCorrection() {return FSR;} /** * Has an old fashioned ME correction */ virtual bool hasMECorrection() {return false;} /** * Apply the POWHEG style correction */ - virtual HardTreePtr generateHardest(ShowerTreePtr, - vector); + virtual HardTreePtr generateHardest(ShowerTreePtr,ShowerInteraction::Type); //@} public: /** @name Virtual functions required by the MEBase class. */ //@{ /** * Return the order in \f$\alpha_S\f$ in which this matrix * element is given. */ virtual unsigned int orderInAlphaS() const; /** * Return the order in \f$\alpha_{EW}\f$ in which this matrix * element is given. */ virtual unsigned int orderInAlphaEW() const; /** * The matrix element for the kinematical configuration * previously provided by the last call to setKinematics(), suitably * scaled by sHat() to give a dimension-less number. * @return the matrix element scaled with sHat() to give a * dimensionless number. */ virtual double me2() const; /** * Return the scale associated with the last set phase space point. */ virtual Energy2 scale() const; /** * Add all possible diagrams with the add() function. */ virtual void getDiagrams() const; /** * Get diagram selector. With the information previously supplied with the * setKinematics method, a derived class may optionally * override this method to weight the given diagrams with their * (although certainly not physical) relative probabilities. * @param dv the diagrams to be weighted. * @return a Selector relating the given diagrams to their weights. */ virtual Selector diagrams(const DiagramVector & dv) const; /** * Return a Selector with possible colour geometries for the selected * diagram weighted by their relative probabilities. * @param diag the diagram chosen. * @return the possible colour geometries weighted by their * relative probabilities. */ virtual Selector colourGeometries(tcDiagPtr diag) const; /** * Construct the vertex of spin correlations. */ virtual void constructVertex(tSubProPtr); //@} 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 Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const {return new_ptr(*this);} /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const {return new_ptr(*this);} //@} 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(); /** * Rebind pointer to other Interfaced objects. Called in the setup phase * after all objects used in an EventGenerator has been cloned so that * the pointers will refer to the cloned objects afterwards. * @param trans a TranslationMap relating the original objects to * their respective clones. * @throws RebindException if no cloned object was found for a given * pointer. */ virtual void rebind(const TranslationMap & trans) ; /** * Return a vector of all pointers to Interfaced objects used in this * object. * @return a vector of pointers. */ virtual IVector getReferences(); //@} protected: /** * Calculate the matrix element for \f$e^+e^-\to \ell^+ \ell^-\f$. * @param partons The incoming and outgoing particles * @param momenta The momenta of the incoming and outgoing particles */ double loME(const vector & partons, const vector & momenta, bool first) const; /** * Member to calculate the matrix element * @param fin Spinors for incoming fermion * @param ain Spinors for incoming antifermion * @param fout Spinors for outgoing fermion * @param aout Spinors for outgong antifermion * @param me Spin summed Matrix element * @param cont The continuum piece of the matrix element * @param BW The Z piece of the matrix element */ ProductionMatrixElement HelicityME(vector & fin, vector & ain, vector & fout, vector & aout, double & me, double & cont, double & BW ) const; /** * The ratio of the matrix element for one additional jet over the * leading order result. In practice * \[\frac{\hat{s}|\overline{\mathcal{M}}|^2_2|D_{\rm emit}|}{4\pi C_F\alpha_S|\overline{\mathcal{M}}|^2_3\left(|D_{\rm emit}|+|D_{\rm spect}\right)}}\] * is returned where \f$\|\overline{\mathcal{M}}|^2\f$ is * the spin and colour summed/averaged matrix element. * @param partons The incoming and outgoing particles * @param momenta The momenta of the incoming and outgoing particles * @param iemitter Whether the quark or antiquark is regardede as the emitter * @param inter The type of interaction */ double meRatio(vector partons, vector momenta, unsigned int iemittor, bool subtract=false) const; /** * Calculate the matrix element for \f$e^-e^-\to q \bar q g$. * @param partons The incoming and outgoing particles * @param momenta The momenta of the incoming and outgoing particles * @param inter The type of interaction */ InvEnergy2 realME(const vector & partons, const vector & momenta) const; /** * Generate the momenta for a hard configuration */ Energy generateHard(ShowerTreePtr tree, vector & emission, unsigned int & iemit, unsigned int & ispect, bool applyVeto); protected: /** * Pointer to the fermion-antifermion Z vertex */ AbstractFFVVertexPtr FFZVertex() const {return FFZVertex_;} /** * Pointer to the fermion-antifermion photon vertex */ AbstractFFVVertexPtr FFPVertex() const {return FFPVertex_;} /** * Pointer to the particle data object for the Z */ PDPtr Z0() const {return Z0_;} /** * Pointer to the particle data object for the photon */ PDPtr gamma() const {return gamma_;} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ MEee2gZ2ll & operator=(const MEee2gZ2ll &); private: /** * Pointers to the vertices */ //@{ /** * Pointer to the fermion-antifermion Z vertex */ AbstractFFVVertexPtr FFZVertex_; /** * Pointer to the fermion-antifermion photon vertex */ AbstractFFVVertexPtr FFPVertex_; //@} /** * Pointer to the particle data object for the Z */ PDPtr Z0_; /** * Pointer to the particle data object for the photon */ PDPtr gamma_; /** * The allowed outgoing */ int allowed_; /** * The initial kappa-tilde values for radiation from the quark */ double d_kt1_; /** * Pointer to the EM coupling */ ShowerAlphaPtr alphaQED_; /** * Variables for the POWHEG style corrections */ //@{ /** * The cut off on pt, assuming massless quarks. */ Energy pTmin_; /** * Overestimate for the prefactor */ double preFactor_; /** * ParticleData objects for the partons */ vector partons_; /** * Momenta of the leading-order partons */ vector loMomenta_; //@} }; } #include "ThePEG/Utilities/ClassTraits.h" namespace ThePEG { /** @cond TRAITSPECIALIZATIONS */ /** This template specialization informs ThePEG about the * base classes of MEee2gZ2ll. */ template <> struct BaseClassTrait { /** Typedef of the first base class of MEee2gZ2ll. */ typedef Herwig::HwMEBase NthBase; }; /** This template specialization informs ThePEG about the name of * the MEee2gZ2ll 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::MEee2gZ2ll"; } /** * The name of a file containing the dynamic library where the class * MEee2gZ2ll is implemented. It may also include several, space-separated, * libraries if the class MEee2gZ2ll depends on other classes (base classes * excepted). In this case the listed libraries will be dynamically * linked in the order they are specified. */ static string library() { return "HwMELepton.so"; } }; /** @endcond */ } #endif /* HERWIG_MEee2gZ2ll_H */ diff --git a/MatrixElement/Lepton/MEee2gZ2qq.cc b/MatrixElement/Lepton/MEee2gZ2qq.cc --- a/MatrixElement/Lepton/MEee2gZ2qq.cc +++ b/MatrixElement/Lepton/MEee2gZ2qq.cc @@ -1,1151 +1,1169 @@ // -*- C++ -*- // // MEee2gZ2qq.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 MEee2gZ2qq class. // #include "MEee2gZ2qq.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/Handlers/StandardXComb.h" #include "Herwig/MatrixElement/HardVertex.h" #include "Herwig/Shower/Base/Evolver.h" #include "Herwig/Shower/Base/KinematicsReconstructor.h" #include "Herwig/Shower/Base/PartnerFinder.h" #include "ThePEG/PDF/PolarizedBeamParticleData.h" #include #include "ThePEG/Utilities/DescribeClass.h" using namespace Herwig; const double MEee2gZ2qq::EPS_=0.00000001; void MEee2gZ2qq::doinit() { HwMEBase::doinit(); massOption(vector(2,massopt_)); rescalingOption(3); if(minflav_>maxflav_) throw InitException() << "The minimum flavour " << minflav_ << "must be lower the than maximum flavour " << maxflav_ << " in MEee2gZ2qq::doinit() " << Exception::runerror; // set the particle data objects Z0_ = getParticleData(ParticleID::Z0); gamma_ = getParticleData(ParticleID::gamma); gluon_ = getParticleData(ParticleID::g); // cast the SM pointer to the Herwig SM pointer tcHwSMPtr hwsm= dynamic_ptr_cast(standardModel()); // do the initialisation if(!hwsm) throw InitException() << "Wrong type of StandardModel object in " << "MEee2gZ2qq::doinit() the Herwig version must be used" << Exception::runerror; FFZVertex_ = hwsm->vertexFFZ(); FFPVertex_ = hwsm->vertexFFP(); FFGVertex_ = hwsm->vertexFFG(); } void MEee2gZ2qq::getDiagrams() const { // specific the diagrams tcPDPtr ep = getParticleData(ParticleID::eplus); tcPDPtr em = getParticleData(ParticleID::eminus); tcPDPtr gamma = getParticleData(ParticleID::gamma); tcPDPtr Z0 = getParticleData(ParticleID::Z0); // setup the processes for ( int i =minflav_; i<=maxflav_; ++i ) { tcPDPtr qk = getParticleData(i); tcPDPtr qb = qk->CC(); add(new_ptr((Tree2toNDiagram(2), em, ep, 1, gamma, 3, qk, 3, qb, -1))); add(new_ptr((Tree2toNDiagram(2), em, ep, 1, Z0 , 3, qk, 3, qb, -2))); } } Energy2 MEee2gZ2qq::scale() const { return sqr(getParticleData(ParticleID::Z0)->mass()); // return sHat(); } unsigned int MEee2gZ2qq::orderInAlphaS() const { return 0; } unsigned int MEee2gZ2qq::orderInAlphaEW() const { return 2; } Selector MEee2gZ2qq::diagrams(const DiagramVector & diags) const { double lastCont(0.5),lastBW(0.5); if ( lastXCombPtr() ) { lastCont = meInfo()[0]; lastBW = meInfo()[1]; } Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ) { if ( diags[i]->id() == -1 ) sel.insert(lastCont, i); else if ( diags[i]->id() == -2 ) sel.insert(lastBW, i); } return sel; } Selector MEee2gZ2qq::colourGeometries(tcDiagPtr ) const { static const ColourLines c("-5 4"); Selector sel; sel.insert(1.0, &c); return sel; } void MEee2gZ2qq::persistentOutput(PersistentOStream & os) const { os << FFZVertex_ << FFPVertex_ << FFGVertex_ << Z0_ << gamma_ << gluon_ << minflav_ << maxflav_ << massopt_ << alphaQCD_ << alphaQED_ << ounit(pTminQED_,GeV) << ounit(pTminQCD_,GeV) << preFactor_ << spinCorrelations_; } void MEee2gZ2qq::persistentInput(PersistentIStream & is, int) { is >> FFZVertex_ >> FFPVertex_ >> FFGVertex_ >> Z0_ >> gamma_ >> gluon_ >> minflav_ >> maxflav_ >> massopt_ >> alphaQCD_ >> alphaQED_ >> iunit(pTminQED_,GeV) >> iunit(pTminQCD_,GeV) >> preFactor_ >> spinCorrelations_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeMEee2gZ2qq("Herwig::MEee2gZ2qq", "HwMELepton.so"); void MEee2gZ2qq::Init() { static ClassDocumentation documentation ("The MEee2gZ2qq class implements the matrix element for e+e- -> q qbar"); static Parameter interfaceMinimumFlavour ("MinimumFlavour", "The PDG code of the quark with the lowest PDG code to produce.", &MEee2gZ2qq::minflav_, 1, 1, 6, false, false, Interface::limited); static Parameter interfaceMaximumFlavour ("MaximumFlavour", "The PDG code of the quark with the highest PDG code to produce", &MEee2gZ2qq::maxflav_, 5, 1, 6, false, false, Interface::limited); static Switch interfaceTopMassOption ("TopMassOption", "Option for the treatment of the top quark mass", &MEee2gZ2qq::massopt_, 1, false, false); static SwitchOption interfaceTopMassOptionOnMassShell (interfaceTopMassOption, "OnMassShell", "The top is produced on its mass shell", 1); static SwitchOption interfaceTopMassOption2 (interfaceTopMassOption, "OffShell", "The top is generated off-shell using the mass and width generator.", 2); static Parameter interfacepTMinQED ("pTMinQED", "Minimum pT for hard QED radiation", &MEee2gZ2qq::pTminQED_, GeV, 1.0*GeV, 0.001*GeV, 10.0*GeV, false, false, Interface::limited); static Parameter interfacepTMinQCD ("pTMinQCD", "Minimum pT for hard QCD radiation", &MEee2gZ2qq::pTminQCD_, GeV, 1.0*GeV, 0.001*GeV, 10.0*GeV, false, false, Interface::limited); static Parameter interfacePrefactor ("Prefactor", "Prefactor for the overestimate of the emission probability", &MEee2gZ2qq::preFactor_, 6.0, 1.0, 100.0, false, false, Interface::limited); static Reference interfaceQCDCoupling ("AlphaQCD", "Pointer to the object to calculate the strong coupling for the correction", &MEee2gZ2qq::alphaQCD_, false, false, true, false, false); static Reference interfaceEMCoupling ("AlphaQED", "Pointer to the object to calculate the EM coupling for the correction", &MEee2gZ2qq::alphaQED_, false, false, true, false, false); static Switch interfaceSpinCorrelations ("SpinCorrelations", "Switch the construction of the veretx for spin correlations on/off", &MEee2gZ2qq::spinCorrelations_, true, false, false); static SwitchOption interfaceSpinCorrelationsYes (interfaceSpinCorrelations, "Yes", "Swtich On", true); static SwitchOption interfaceSpinCorrelationsNo (interfaceSpinCorrelations, "No", "Switch off", false); } double MEee2gZ2qq::me2() const { return loME(mePartonData(),rescaledMomenta(),true); } ProductionMatrixElement MEee2gZ2qq::HelicityME(vector & fin, vector & ain, vector & fout, vector & aout, double & me, double & cont, double & BW ) const { // the particles should be in the order // for the incoming // 0 incoming fermion (u spinor) // 1 incoming antifermion (vbar spinor) // for the outgoing // 0 outgoing fermion (ubar spinor) // 1 outgoing antifermion (v spinor) // me to be returned ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half); ProductionMatrixElement gamma (PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half); ProductionMatrixElement Zboson(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half); // wavefunctions for the intermediate particles VectorWaveFunction interZ,interG; // temporary storage of the different diagrams Complex diag1,diag2; // sum over helicities to get the matrix element unsigned int inhel1,inhel2,outhel1,outhel2; double total[3]={0.,0.,0.}; for(inhel1=0;inhel1<2;++inhel1) { for(inhel2=0;inhel2<2;++inhel2) { // intermediate Z interZ = FFZVertex_->evaluate(scale(),1,Z0_,fin[inhel1],ain[inhel2]); // intermediate photon interG = FFPVertex_->evaluate(scale(),1,gamma_,fin[inhel1],ain[inhel2]); for(outhel1=0;outhel1<2;++outhel1) { for(outhel2=0;outhel2<2;++outhel2) { // first the Z exchange diagram diag1 = FFZVertex_->evaluate(scale(),aout[outhel2],fout[outhel1], interZ); // then the photon exchange diagram diag2 = FFPVertex_->evaluate(scale(),aout[outhel2],fout[outhel1], interG); // add up squares of individual terms total[1] += norm(diag1); Zboson(inhel1,inhel2,outhel1,outhel2) = diag1; total[2] += norm(diag2); gamma (inhel1,inhel2,outhel1,outhel2) = diag2; // the full thing including interference diag1 += diag2; total[0] += norm(diag1); output(inhel1,inhel2,outhel1,outhel2)=diag1; } } } } for(int ix=0;ix<3;++ix) total[ix] *= 0.25; tcPolarizedBeamPDPtr beam[2] = {dynamic_ptr_cast(mePartonData()[0]), dynamic_ptr_cast(mePartonData()[1])}; if( beam[0] || beam[1] ) { RhoDMatrix rho[2] = {beam[0] ? beam[0]->rhoMatrix() : RhoDMatrix(mePartonData()[0]->iSpin()), beam[1] ? beam[1]->rhoMatrix() : RhoDMatrix(mePartonData()[1]->iSpin())}; total[0] = output.average(rho[0],rho[1]); total[1] = Zboson.average(rho[0],rho[1]); total[2] = gamma .average(rho[0],rho[1]); } // results for(int ix=0;ix<3;++ix) total[ix]*= 3.; cont = total[2]; BW = total[1]; me = total[0]; return output; } void MEee2gZ2qq::constructVertex(tSubProPtr sub) { if(!spinCorrelations_) return; // extract the particles in the hard process ParticleVector hard; hard.push_back(sub->incoming().first); hard.push_back(sub->incoming().second); hard.push_back(sub->outgoing()[0]); hard.push_back(sub->outgoing()[1]); if(hard[0]->id()id()) swap(hard[0],hard[1]); if(hard[2]->id()id()) swap(hard[2],hard[3]); vector fin,aout; vector ain,fout; // get wave functions for off-shell momenta for later on SpinorWaveFunction( fin ,hard[0],incoming,false,true); SpinorBarWaveFunction(ain ,hard[1],incoming,false,true); SpinorBarWaveFunction(fout,hard[2],outgoing,true ,true); SpinorWaveFunction( aout,hard[3],outgoing,true ,true); // now rescale the momenta and compute the matrix element with the // rescaled momenta for correlations vector momenta; cPDVector data; for(unsigned int ix=0;ix<4;++ix) { momenta.push_back(hard[ix]->momentum()); data .push_back(hard[ix]->dataPtr()); } rescaleMomenta(momenta,data); SpinorWaveFunction ein (rescaledMomenta()[0],data[0],incoming); SpinorBarWaveFunction pin (rescaledMomenta()[1],data[1],incoming); SpinorBarWaveFunction qkout(rescaledMomenta()[2],data[2],outgoing); SpinorWaveFunction qbout(rescaledMomenta()[3],data[3],outgoing); for(unsigned int ix=0;ix<2;++ix) { ein.reset(ix) ; fin [ix] = ein ; pin.reset(ix) ; ain [ix] = pin ; qkout.reset(ix); fout[ix] = qkout; qbout.reset(ix); aout[ix] = qbout; } // calculate the matrix element double me,cont,BW; ProductionMatrixElement prodme=HelicityME(fin,ain,fout,aout,me,cont,BW); // construct the vertex HardVertexPtr hardvertex=new_ptr(HardVertex()); // set the matrix element for the vertex hardvertex->ME(prodme); // set the pointers and to and from the vertex for(unsigned int ix=0;ix<4;++ix) { tSpinPtr spin = hard[ix]->spinInfo(); if(ix<2) { tcPolarizedBeamPDPtr beam = dynamic_ptr_cast(hard[ix]->dataPtr()); if(beam) spin->rhoMatrix() = beam->rhoMatrix(); } spin->productionVertex(hardvertex); } } void MEee2gZ2qq::rebind(const TranslationMap & trans) { FFZVertex_ = trans.translate(FFZVertex_); FFPVertex_ = trans.translate(FFPVertex_); FFGVertex_ = trans.translate(FFGVertex_); Z0_ = trans.translate(Z0_); gamma_ = trans.translate(gamma_); gluon_ = trans.translate(gluon_); HwMEBase::rebind(trans); } IVector MEee2gZ2qq::getReferences() { IVector ret = HwMEBase::getReferences(); ret.push_back(FFZVertex_); ret.push_back(FFPVertex_); ret.push_back(FFGVertex_); ret.push_back(Z0_ ); ret.push_back(gamma_ ); ret.push_back(gluon_ ); return ret; } void MEee2gZ2qq::initializeMECorrection(ShowerTreePtr , double & initial, double & final) { d_Q_ = sqrt(sHat()); d_m_ = 0.5*(meMomenta()[2].mass()+meMomenta()[3].mass()); // set the other parameters d_rho_ = sqr(d_m_/d_Q_); d_v_ = sqrt(1.-4.*d_rho_); // maximum evolution scale d_kt1_ = (1. + sqrt(1. - 4.*d_rho_))/2.; double num = d_rho_ * d_kt1_ + 0.25 * d_v_ *(1.+d_v_)*(1.+d_v_); double den = d_kt1_ - d_rho_; d_kt2_ = num/den; // maximums for reweighting initial = 1.; final = 1.; } void MEee2gZ2qq::applyHardMatrixElementCorrection(ShowerTreePtr tree) { vector emission; unsigned int iemit,ispect; - generateHard(tree,emission,iemit,ispect,true, - vector(1,ShowerInteraction::QCD)); + generateHard(tree,emission,iemit,ispect,true,ShowerInteraction::QCD); if(emission.empty()) return; // get the quark and antiquark ParticleVector qq; map::const_iterator cit; for(cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) qq.push_back(cit->first->copy()); // ensure quark first if(qq[0]->id()<0) swap(qq[0],qq[1]); // perform final check to ensure energy greater than constituent mass for (int i=0; i<2; i++) { if (emission[i+2].e() < qq[i]->data().constituentMass()) return; } if (emission[4].e() < gluon_->constituentMass()) return; // set masses for (int i=0; i<2; i++) emission[i+2].setMass(qq[i]->mass()); emission[4].setMass(ZERO); // decide which particle emits bool firstEmits= emission[4].vect().perp2(emission[2].vect())< emission[4].vect().perp2(emission[3].vect()); // create the new quark, antiquark and gluon PPtr newg = gluon_->produceParticle(emission[4]); PPtr newq,newa; if(firstEmits) { newq = qq[0]->dataPtr()->produceParticle(emission[2]); newa = new_ptr(Particle(*qq[1])); qq[1]->antiColourLine()->removeAntiColoured(newa); newa->set5Momentum(emission[3]); } else { newq = new_ptr(Particle(*qq[0])); qq[0]->colourLine()->removeColoured(newq); newq->set5Momentum(emission[2]); newa = qq[1]->dataPtr()->produceParticle(emission[3]); } // get the original colour line ColinePtr col; if(qq[0]->id()>0) col=qq[0]->colourLine(); else col=qq[0]->antiColourLine(); // set the colour lines if(firstEmits) { col->addColoured(newq); col->addAntiColoured(newg); newa->colourNeighbour(newg); } else { col->addAntiColoured(newa); col->addColoured(newg); newq->antiColourNeighbour(newg); } // change the existing quark and antiquark PPtr orig; for(cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) { map >::const_iterator tit; for(tit = tree->treelinks().begin(); tit != tree->treelinks().end();++tit) { if(tit->second.first && tit->second.second==cit->first->progenitor()) break; } if(cit->first->progenitor()->id()==newq->id()) { // remove old particles from colour line col->removeColoured(cit->first->copy()); col->removeColoured(cit->first->progenitor()); // insert new particles cit->first->copy(newq); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newq,1,true))); cit->first->progenitor(sp); tree->outgoingLines()[cit->first]=sp; cit->first->perturbative(!firstEmits); if(firstEmits) orig=cit->first->original(); if(tit!=tree->treelinks().end()) tree->updateLink(tit->first,make_pair(cit->first,sp)); } else { // remove old particles from colour line col->removeAntiColoured(cit->first->copy()); col->removeAntiColoured(cit->first->progenitor()); // insert new particles cit->first->copy(newa); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newa,1,true))); cit->first->progenitor(sp); tree->outgoingLines()[cit->first]=sp; cit->first->perturbative(firstEmits); if(!firstEmits) orig=cit->first->original(); if(tit!=tree->treelinks().end()) tree->updateLink(tit->first,make_pair(cit->first,sp)); } } // add the gluon ShowerParticlePtr sg=new_ptr(ShowerParticle(*newg,1,true)); ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(orig,newg,sg)); gluon->perturbative(false); tree->outgoingLines().insert(make_pair(gluon,sg)); tree->hardMatrixElementCorrection(true); } bool MEee2gZ2qq::softMatrixElementVeto(ShowerProgenitorPtr initial, ShowerParticlePtr parent,Branching br) { // check we should be applying the veto if(parent->id()!=initial->progenitor()->id()|| br.ids[0]!=br.ids[1]|| br.ids[2]!=ParticleID::g) return false; // calculate pt double d_z = br.kinematics->z(); Energy d_qt = br.kinematics->scale(); Energy2 d_m2 = parent->momentum().m2(); Energy pPerp = (1.-d_z)*sqrt( sqr(d_z*d_qt) - d_m2); // if not hardest so far don't apply veto if(pPerphighestpT()) return false; // calculate x and xb double kti = sqr(d_qt/d_Q_); double w = sqr(d_v_) + kti*(-1. + d_z)*d_z*(2. + kti*(-1. + d_z)*d_z); if (w < 0) return false; double x = (1. + sqr(d_v_)*(-1. + d_z) + sqr(kti*(-1. + d_z))*d_z*d_z*d_z + d_z*sqrt(w) - kti*(-1. + d_z)*d_z*(2. + d_z*(-2 + sqrt(w))))/ (1. - kti*(-1. + d_z)*d_z + sqrt(w)); double xb = 1. + kti*(-1. + d_z)*d_z; // calculate the weight if(parent->id()<0) swap(x,xb); // if exceptionally out of phase space, leave this emission, as there // is no good interpretation for the soft ME correction. if( x<0 || xb<0) return false; double xg = 2. - xb - x; // always return one in the soft gluon region if(xg < EPS_) return false; // check it is in the phase space if((1.-x)*(1.-xb)*(1.-xg) < d_rho_*xg*xg) { parent->vetoEmission(parent->id()>0 ? ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDColourLine,br.kinematics->scale()); return true; } double k1 = getKfromX(x, xb); double k2 = getKfromX(xb, x); double weight = 1.; // quark emission if(parent->id() > 0 && k1 < d_kt1_) { weight = MEV(x, xb)/PS(x, xb); // is it also in the anti-quark emission zone? if(k2 < d_kt2_) weight *= 0.5; } // antiquark emission if(parent->id() < 0 && k2 < d_kt2_) { weight = MEV(x, xb)/PS(xb, x); // is it also in the quark emission zone? if(k1 < d_kt1_) weight *= 0.5; } // compute veto from weight bool veto = !UseRandom::rndbool(weight); // if not vetoed reset max // if vetoing reset the scale if(veto) { parent->vetoEmission(parent->id()>0 ? ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDColourLine,br.kinematics->scale()); } // return the veto return veto; } double MEee2gZ2qq::getKfromX(double x1, double x2) { double uval = 0.5*(1. + d_rho_/(1.-x2+d_rho_)); double num = x1 - (2. - x2)*uval; double den = sqrt(x2*x2 - 4.*d_rho_); double zval = uval + num/den; return (1.-x2)/(zval*(1.-zval)); } double MEee2gZ2qq::MEV(double x1, double x2) { // Vector part double num = (x1+2.*d_rho_)*(x1+2.*d_rho_) + (x2+2.*d_rho_)*(x2+2.*d_rho_) - 8.*d_rho_*(1.+2.*d_rho_); double den = (1.+2.*d_rho_)*(1.-x1)*(1.-x2); return (num/den - 2.*d_rho_/((1.-x1)*(1.-x1)) - 2*d_rho_/((1.-x2)*(1.-x2)))/d_v_; } double MEee2gZ2qq::PS(double x, double xbar) { double u = 0.5*(1. + d_rho_ / (1.-xbar+d_rho_)); double z = u + (x - (2.-xbar)*u)/sqrt(xbar*xbar - 4.*d_rho_); double brack = (1.+z*z)/(1.-z)- 2.*d_rho_/(1-xbar); // interesting: the splitting function without the subtraction // term. Actually gives a much worse approximation in the collinear // limit. double brack = (1.+z*z)/(1.-z); double den = (1.-xbar)*sqrt(xbar*xbar - 4.*d_rho_); return brack/den; } pair MEee2gZ2qq::generateHard(ShowerTreePtr tree, vector & emmision, unsigned int & iemit, unsigned int & ispect, - bool applyVeto, - vector inter) { + bool applyVeto,ShowerInteraction::Type type) { + vector inter; + if(type==ShowerInteraction::QCD) + inter.push_back(ShowerInteraction::QCD); + else if(type==ShowerInteraction::QED) + inter.push_back(ShowerInteraction::QED); + else if(type==ShowerInteraction::QEDQCD || + type==ShowerInteraction::ALL) { + inter.push_back(ShowerInteraction::QCD); + inter.push_back(ShowerInteraction::QED); + } // get the momenta of the incoming and outgoing partons // incoming ShowerProgenitorPtr emProgenitor = tree->incomingLines().begin() ->first, epProgenitor = tree->incomingLines().rbegin()->first; // outgoing ShowerProgenitorPtr qkProgenitor = tree->outgoingLines().begin() ->first, qbProgenitor = tree->outgoingLines().rbegin()->first; // get the order right if(emProgenitor->id()<0) swap(emProgenitor,epProgenitor); if(qkProgenitor->id()<0) swap(qkProgenitor,qbProgenitor); loMomenta_.clear(); // extract the momenta loMomenta_.push_back(emProgenitor->progenitor()->momentum()); loMomenta_.push_back(epProgenitor->progenitor()->momentum()); loMomenta_.push_back(qkProgenitor->progenitor()->momentum()); loMomenta_.push_back(qbProgenitor->progenitor()->momentum()); // and ParticleData objects partons_.resize(5); partons_[0]=emProgenitor->progenitor()->dataPtr(); partons_[1]=epProgenitor->progenitor()->dataPtr(); partons_[2]=qkProgenitor->progenitor()->dataPtr(); partons_[3]=qbProgenitor->progenitor()->dataPtr(); partons_[4]=cPDPtr(); // boost from lab to CMS frame with outgoing particles // along the z axis LorentzRotation eventFrame( ( loMomenta_[2] + loMomenta_[3] ).findBoostToCM() ); Lorentz5Momentum spectator = eventFrame*loMomenta_[2]; eventFrame.rotateZ( -spectator.phi() ); eventFrame.rotateY( -spectator.theta() ); eventFrame.invert(); // mass of the final-state system Energy2 M2 = (loMomenta_[2]+loMomenta_[3]).m2(); Energy M = sqrt(M2); double mu1 = loMomenta_[2].mass()/M; double mu2 = loMomenta_[3].mass()/M; double mu12 = sqr(mu1), mu22 = sqr(mu2); double lambda = sqrt(1.+sqr(mu12)+sqr(mu22)-2.*mu12-2.*mu22-2.*mu12*mu22); // max pT Energy pTmax = 0.5*sqrt(M2)* (1.-sqr(loMomenta_[2].mass()+loMomenta_[3].mass())/M2); // max y if ( pTmax < pTminQED_ && pTmax < pTminQCD_ ) return make_pair(ZERO,ShowerInteraction::QCD); vector pTemit; vector > emittedMomenta;; vector iemitter,ispectater; for(unsigned int iinter=0;iinteroverestimateValue()/Constants::twopi* 2.*ymax*preFactor_; } else { pTmin = pTminQED_; ymax = acosh(pTmax/pTmin); partons_[4] = gamma_; a = alphaQED_->overestimateValue()/Constants::twopi* 2.*ymax*preFactor_*sqr(double(mePartonData()[2]->iCharge())/3.); } // variables for the emission Energy pT[2]; double y[2],phi[2],x3[2],x1[2][2],x2[2][2]; double contrib[2][2]; // storage of the real emission momenta vector realMomenta[2][2]= {{vector(5),vector(5)}, {vector(5),vector(5)}}; for(unsigned int ix=0;ix<2;++ix) for(unsigned int iy=0;iy<2;++iy) for(unsigned int iz=0;iz<2;++iz) realMomenta[ix][iy][iz] = loMomenta_[iz]; // generate the emission for(unsigned int ix=0;ix<2;++ix) { if(ix==1) { swap(mu1 ,mu2 ); swap(mu12,mu22); } pT[ix] = pTmax; y [ix] = 0.; bool reject = true; do { // generate pT pT[ix] *= pow(UseRandom::rnd(),1./a); if(pT[ix] 1. -sqr( mu1 + mu2 ) ) continue; // find the possible solutions for x1 double xT2 = sqr(2./M*pT[ix]); double root = (-sqr(x3[ix])+xT2)* (xT2*mu22+2.*x3[ix]-sqr(mu12)+2.*mu22+2.*mu12-sqr(x3[ix])-1. +2.*mu12*mu22-sqr(mu22)-2.*mu22*x3[ix]-2.*mu12*x3[ix]); double c1=2.*sqr(x3[ix])-4.*mu22-6.*x3[ix]+4.*mu12-xT2*x3[ix] +2.*xT2-2.*mu12*x3[ix]+2.*mu22*x3[ix]+4.; if(root<0.) continue; x1[ix][0] = 1./(4.-4.*x3[ix]+xT2)*(c1-2.*sqrt(root)); x1[ix][1] = 1./(4.-4.*x3[ix]+xT2)*(c1+2.*sqrt(root)); // change sign of y if 2nd particle emits if(ix==1) y[ix] *=-1.; // loop over the solutions for(unsigned int iy=0;iy<2;++iy) { contrib[ix][iy]=0.; // check x1 value allowed if(x1[ix][iy]<2.*mu1||x1[ix][iy]>1.+mu12-mu22) continue; // calculate x2 value and check allowed x2[ix][iy] = 2.-x3[ix]-x1[ix][iy]; double root = max(0.,sqr(x1[ix][iy])-4.*mu12); root = sqrt(root); double x2min = 1.+mu22-mu12 -0.5*(1.-x1[ix][iy]+mu12-mu22)/(1.-x1[ix][iy]+mu12)*(x1[ix][iy]-2.*mu12+root); double x2max = 1.+mu22-mu12 -0.5*(1.-x1[ix][iy]+mu12-mu22)/(1.-x1[ix][iy]+mu12)*(x1[ix][iy]-2.*mu12-root); if(x2[ix][iy]x2max) continue; // check the z components double z1 = sqrt(sqr(x1[ix][iy])-4.*mu12-xT2); double z2 = -sqrt(sqr(x2[ix][iy])-4.*mu22); double z3 = pT[ix]*sinh(y[ix])*2./M; if(ix==1) z3 *=-1.; if(abs(-z1+z2+z3)<1e-9) z1 *= -1.; if(abs(z1+z2+z3)>1e-5) continue; // if using as an ME correction the veto if(applyVeto) { double xb = x1[ix][iy], xc = x2[ix][iy]; double b = mu12, c = mu22; double r = 0.5*(1.+b/(1.+c-xc)); double z1 = r + (xb-(2.-xc)*r)/sqrt(sqr(xc)-4.*c); double kt1 = (1.-b+c-xc)/z1/(1.-z1); r = 0.5*(1.+c/(1.+b-xb)); double z2 = r + (xc-(2.-xb)*r)/sqrt(sqr(xb)-4.*b); double kt2 = (1.-c+b-xb)/z2/(1.-z2); if(ix==1) { swap(z1 ,z2); swap(kt1,kt2); } // veto the shower region if( kt1 < d_kt1_ || kt2 < d_kt2_ ) continue; } // construct the momenta realMomenta[ix][iy][4] = Lorentz5Momentum(pT[ix]*cos(phi[ix]),pT[ix]*sin(phi[ix]), pT[ix]*sinh(y[ix]) ,pT[ix]*cosh(y[ix]),ZERO); if(ix==0) { realMomenta[ix][iy][2] = Lorentz5Momentum(-pT[ix]*cos(phi[ix]),-pT[ix]*sin(phi[ix]), z1*0.5*M,x1[ix][iy]*0.5*M,M*mu1); realMomenta[ix][iy][3] = Lorentz5Momentum(ZERO,ZERO, z2*0.5*M,x2[ix][iy]*0.5*M,M*mu2); } else { realMomenta[ix][iy][2] = Lorentz5Momentum(ZERO,ZERO,-z2*0.5*M,x2[ix][iy]*0.5*M,M*mu2); realMomenta[ix][iy][3] = Lorentz5Momentum(-pT[ix]*cos(phi[ix]),-pT[ix]*sin(phi[ix]), -z1*0.5*M,x1[ix][iy]*0.5*M,M*mu1); } // boost the momenta back to the lab for(unsigned int iz=2;iz<5;++iz) realMomenta[ix][iy][iz] *= eventFrame; // jacobian and prefactors for the weight Energy J = M/sqrt(xT2)*abs(-x1[ix][iy]*x2[ix][iy]+2.*mu22*x1[ix][iy] +x2[ix][iy]+x2[ix][iy]*mu12+mu22*x2[ix][iy] -sqr(x2[ix][iy])) /pow(sqr(x2[ix][iy])-4.*mu22,1.5); // prefactors etc contrib[ix][iy] = 0.5*pT[ix]/J/preFactor_/lambda; // matrix element piece contrib[ix][iy] *= meRatio(partons_,realMomenta[ix][iy], ix,inter[iinter],false); // coupling piece if(inter[iinter]==ShowerInteraction::QCD) contrib[ix][iy] *= alphaQCD_->ratio(sqr(pT[ix])); else contrib[ix][iy] *= alphaQED_->ratio(sqr(pT[ix])); } if(contrib[ix][0]+contrib[ix][1]>1.) { ostringstream s; s << "MEee2gZ2qq::generateHardest weight for channel " << ix << "is " << contrib[ix][0]+contrib[ix][1] << " which is greater than 1"; generator()->logWarning( Exception(s.str(), Exception::warning) ); } reject = UseRandom::rnd() > contrib[ix][0] + contrib[ix][1]; } while (reject); if(pT[ix]()); iemitter .push_back(0); ispectater.push_back(0); continue; } // now pick the emission with highest pT vector emission; if(pT[0]>pT[1]) { iemitter .push_back(2); ispectater.push_back(3); pTemit.push_back(pT[0]); if(UseRandom::rnd()pTmax) { iselect = ix; pTmax = pTemit[ix]; } } // no emission return if(iselect<0) { return make_pair(ZERO,ShowerInteraction::QCD); } partons_[4] = inter[iselect]==ShowerInteraction::QCD ? gluon_ : gamma_; iemit = iemitter[iselect]; ispect = ispectater[iselect]; emmision = emittedMomenta[iselect]; // return pT of emission return make_pair(pTmax,inter[iselect]); } HardTreePtr MEee2gZ2qq::generateHardest(ShowerTreePtr tree, - vector inter) { + ShowerInteraction::Type inter) { // generate the momenta for the hard emission vector emmision; unsigned int iemit,ispect; pair output = generateHard(tree,emmision,iemit,ispect,false,inter); Energy pTveto = output.first; ShowerInteraction::Type force = output.second; // incoming progenitors ShowerProgenitorPtr ePProgenitor = tree->incomingLines().begin() ->first, eMProgenitor = tree->incomingLines().rbegin()->first; if(eMProgenitor->id()<0) swap(eMProgenitor,ePProgenitor); // outgoing progenitors ShowerProgenitorPtr qkProgenitor = tree->outgoingLines().begin() ->first, qbProgenitor = tree->outgoingLines().rbegin()->first; if(qkProgenitor->id()<0) swap(qkProgenitor,qbProgenitor); // maximum pT of emission if(emmision.empty()) { - for(unsigned int ix=0;ixmaximumpT(pTminQCD_,inter[ix]); - qbProgenitor->maximumpT(pTminQCD_,inter[ix]); - } - else { - qkProgenitor->maximumpT(pTminQED_,inter[ix]); - qbProgenitor->maximumpT(pTminQED_,inter[ix]); - } + if(inter==ShowerInteraction::QCD || + inter==ShowerInteraction::QEDQCD || + inter==ShowerInteraction::ALL) { + qkProgenitor->maximumpT(pTminQCD_,ShowerInteraction::QCD); + qbProgenitor->maximumpT(pTminQCD_,ShowerInteraction::QCD); + } + if(inter==ShowerInteraction::QED || + inter==ShowerInteraction::QEDQCD || + inter==ShowerInteraction::ALL) { + qkProgenitor->maximumpT(pTminQED_,ShowerInteraction::QED); + qbProgenitor->maximumpT(pTminQED_,ShowerInteraction::QED); } return HardTreePtr(); } else { - for(unsigned int ix=0;ixmaximumpT(pTveto,inter[ix]); - qbProgenitor->maximumpT(pTveto,inter[ix]); + if(inter==ShowerInteraction::QCD || + inter==ShowerInteraction::QEDQCD || + inter==ShowerInteraction::ALL) { + qkProgenitor->maximumpT(pTveto,ShowerInteraction::QCD); + qbProgenitor->maximumpT(pTveto,ShowerInteraction::QCD); + } + if(inter==ShowerInteraction::QED || + inter==ShowerInteraction::QEDQCD || + inter==ShowerInteraction::ALL) { + qkProgenitor->maximumpT(pTveto,ShowerInteraction::QED); + qbProgenitor->maximumpT(pTveto,ShowerInteraction::QED); } } // perform final check to ensure energy greater than constituent mass if (emmision[2].e() < qkProgenitor->progenitor()->data().constituentMass()) return HardTreePtr(); if (emmision[3].e() < qbProgenitor->progenitor()->data().constituentMass()) return HardTreePtr(); if(force!=ShowerInteraction::QED && emmision[4].e() < gluon_->constituentMass()) return HardTreePtr(); // Make the particles for the hard tree ShowerParticleVector hardParticles; for(unsigned int ix=0;ix=2))); hardParticles.back()->set5Momentum(emmision[ix]); } ShowerParticlePtr parent(new_ptr(ShowerParticle(partons_[iemit],true))); Lorentz5Momentum parentMomentum(emmision[iemit]+emmision[4]); parentMomentum.setMass(partons_[iemit]->mass()); parent->set5Momentum(parentMomentum); // Create the vectors of HardBranchings to create the HardTree: vector spaceBranchings,allBranchings; // Incoming boson: for(unsigned int ix=0;ix<2;++ix) { spaceBranchings.push_back(new_ptr(HardBranching(hardParticles[ix],SudakovPtr(), HardBranchingPtr(), HardBranching::Incoming))); allBranchings.push_back(spaceBranchings.back()); } // Outgoing particles from hard emission: HardBranchingPtr spectatorBranch(new_ptr(HardBranching(hardParticles[ispect], SudakovPtr(),HardBranchingPtr(), HardBranching::Outgoing))); HardBranchingPtr emitterBranch(new_ptr(HardBranching(parent,SudakovPtr(), HardBranchingPtr(), HardBranching::Outgoing))); if(force==ShowerInteraction::QED) { emitterBranch->type(ShowerPartnerType::QED); } else { emitterBranch->type(emitterBranch->branchingParticle()->id()>0 ? ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine); } emitterBranch->addChild(new_ptr(HardBranching(hardParticles[iemit], SudakovPtr(),HardBranchingPtr(), HardBranching::Outgoing))); emitterBranch->addChild(new_ptr(HardBranching(hardParticles[4], SudakovPtr(),HardBranchingPtr(), HardBranching::Outgoing))); if(iemit==0) { allBranchings.push_back(emitterBranch); allBranchings.push_back(spectatorBranch); } else { allBranchings.push_back( spectatorBranch ); allBranchings.push_back( emitterBranch ); } emitterBranch ->branchingParticle()->partner(spectatorBranch->branchingParticle()); spectatorBranch->branchingParticle()->partner(emitterBranch ->branchingParticle()); if(force==ShowerInteraction::QED) { spaceBranchings[0]->branchingParticle()->partner(spaceBranchings[1]->branchingParticle()); spaceBranchings[1]->branchingParticle()->partner(spaceBranchings[0]->branchingParticle()); } // Make the HardTree from the HardBranching vectors. HardTreePtr hardtree = new_ptr(HardTree(allBranchings,spaceBranchings, force)); hardtree->partnersSet(true); // Connect the particles with the branchings in the HardTree hardtree->connect( eMProgenitor->progenitor(), allBranchings[0] ); tPPtr beam = eMProgenitor->original(); if(!beam->parents().empty()) beam = beam->parents()[0]; allBranchings[0]->beam(beam); hardtree->connect( ePProgenitor->progenitor(), allBranchings[1] ); beam = ePProgenitor->original(); if(!beam->parents().empty()) beam = beam->parents()[0]; allBranchings[1]->beam(beam); hardtree->connect( qkProgenitor->progenitor(), allBranchings[2] ); hardtree->connect( qbProgenitor->progenitor(), allBranchings[3] ); // colour flow 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()); } allBranchings[2]->colourPartner(allBranchings[3]); allBranchings[3]->colourPartner(allBranchings[2]); if(hardParticles[4]->dataPtr()->iColour()==PDT::Colour8) { ColinePtr newLine2=new_ptr(ColourLine()); if(emitterBranch->branchingParticle()->dataPtr()->iColour()==PDT::Colour3) { emitterBranch->branchingParticle()->colourLine()->addColoured(hardParticles[4]); newLine2->addColoured(hardParticles[iemit]); newLine2->addAntiColoured(hardParticles[4]); } else { emitterBranch->branchingParticle()->antiColourLine()->addAntiColoured(hardParticles[4]); newLine2->addAntiColoured(hardParticles[iemit]); newLine2->addColoured(hardParticles[4]); } } else { if(emitterBranch->branchingParticle()->dataPtr()->iColour()==PDT::Colour3) { emitterBranch->branchingParticle()->colourLine()->addColoured(hardParticles[iemit]); } else { emitterBranch->branchingParticle()->antiColourLine()->addAntiColoured(hardParticles[iemit]); } } // Return the HardTree return hardtree; } double MEee2gZ2qq::meRatio(vector partons, vector momenta, unsigned int iemitter, ShowerInteraction::Type inter, bool subtract) const { Lorentz5Momentum q = momenta[2]+momenta[3]+momenta[4]; Energy2 Q2=q.m2(); Energy2 lambda = sqrt((Q2-sqr(momenta[2].mass()+momenta[3].mass()))* (Q2-sqr(momenta[2].mass()-momenta[3].mass()))); InvEnergy2 D[2]; double lome[2]; for(unsigned int iemit=0;iemit<2;++iemit) { unsigned int ispect = iemit==0 ? 1 : 0; Energy2 pipj = momenta[4 ] * momenta[2+iemit ]; Energy2 pipk = momenta[4 ] * momenta[2+ispect]; Energy2 pjpk = momenta[2+iemit] * momenta[2+ispect]; double y = pipj/(pipj+pipk+pjpk); double z = pipk/( pipk+pjpk); Energy mij = sqrt(2.*pipj+sqr(momenta[2+iemit].mass())); Energy2 lamB = sqrt((Q2-sqr(mij+momenta[2+ispect].mass()))* (Q2-sqr(mij-momenta[2+ispect].mass()))); Energy2 Qpk = q*momenta[2+ispect]; Lorentz5Momentum pkt = lambda/lamB*(momenta[2+ispect]-Qpk/Q2*q) +0.5/Q2*(Q2+sqr(momenta[2+ispect].mass())-sqr(momenta[2+ispect].mass()))*q; Lorentz5Momentum pijt = q-pkt; double muj = momenta[2+iemit ].mass()/sqrt(Q2); double muk = momenta[2+ispect].mass()/sqrt(Q2); double vt = sqrt((1.-sqr(muj+muk))*(1.-sqr(muj-muk)))/(1.-sqr(muj)-sqr(muk)); double v = sqr(2.*sqr(muk)+(1.-sqr(muj)-sqr(muk))*(1.-y))-4.*sqr(muk); if(v<=0.) return 0.; v = sqrt(v)/(1.-y)/(1.-sqr(muj)-sqr(muk)); // dipole term D[iemit] = 0.5/pipj*(2./(1.-(1.-z)*(1.-y)) -vt/v*(2.-z+sqr(momenta[2+iemit].mass())/pipj)); // matrix element vector lomom(4); lomom[0] = momenta[0]; lomom[1] = momenta[1]; if(iemit==0) { lomom[2] = pijt; lomom[3] = pkt ; } else { lomom[3] = pijt; lomom[2] = pkt ; } lome[iemit] = loME(partons,lomom,false)/3.; } InvEnergy2 ratio = realME(partons,momenta,inter) *abs(D[iemitter])/(abs(D[0]*lome[0])+abs(D[1]*lome[1])); double output = Q2*ratio; if(subtract) output -= 2.*Q2*D[iemitter]; return output; } double MEee2gZ2qq::loME(const vector & partons, const vector & momenta, bool first) const { // compute the spinors vector fin,aout; vector ain,fout; SpinorWaveFunction ein (momenta[0],partons[0],incoming); SpinorBarWaveFunction pin (momenta[1],partons[1],incoming); SpinorBarWaveFunction qkout(momenta[2],partons[2],outgoing); SpinorWaveFunction qbout(momenta[3],partons[3],outgoing); for(unsigned int ix=0;ix<2;++ix) { ein.reset(ix) ; fin.push_back( ein ); pin.reset(ix) ; ain.push_back( pin ); qkout.reset(ix); fout.push_back(qkout); qbout.reset(ix); aout.push_back(qbout); } // compute the matrix element double me,lastCont,lastBW; HelicityME(fin,ain,fout,aout,me,lastCont,lastBW); // save the components if(first) { DVector save; save.push_back(lastCont); save.push_back(lastBW); meInfo(save); } // return the answer return me; } InvEnergy2 MEee2gZ2qq::realME(const vector & partons, const vector & momenta, ShowerInteraction::Type inter) const { // compute the spinors vector fin,aout; vector ain,fout; vector gout; SpinorWaveFunction ein (momenta[0],partons[0],incoming); SpinorBarWaveFunction pin (momenta[1],partons[1],incoming); SpinorBarWaveFunction qkout(momenta[2],partons[2],outgoing); SpinorWaveFunction qbout(momenta[3],partons[3],outgoing); VectorWaveFunction gluon(momenta[4],partons[4],outgoing); for(unsigned int ix=0;ix<2;++ix) { ein.reset(ix) ; fin.push_back( ein ); pin.reset(ix) ; ain.push_back( pin ); qkout.reset(ix); fout.push_back(qkout); qbout.reset(ix); aout.push_back(qbout); gluon.reset(2*ix); gout.push_back(gluon); } AbstractFFVVertexPtr vertex = inter == ShowerInteraction::QCD ? FFGVertex_ : FFPVertex_; vector diag(4,0.); ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1); double total(0.); for(unsigned int inhel1=0;inhel1<2;++inhel1) { for(unsigned int inhel2=0;inhel2<2;++inhel2) { // intermediate Z VectorWaveFunction interZ = FFZVertex_->evaluate(scale(),1,Z0_,fin[inhel1],ain[inhel2]); // intermediate photon VectorWaveFunction interG = FFPVertex_->evaluate(scale(),1,gamma_,fin[inhel1],ain[inhel2]); for(unsigned int outhel1=0;outhel1<2;++outhel1) { for(unsigned int outhel2=0;outhel2<2;++outhel2) { for(unsigned int outhel3=0;outhel3<2;++outhel3) { SpinorBarWaveFunction off1 = vertex->evaluate(scale(),3,partons[2],fout[outhel1],gout[outhel3]); diag[0] = FFZVertex_->evaluate(scale(),aout[outhel2],off1,interZ); diag[1] = FFPVertex_->evaluate(scale(),aout[outhel2],off1,interG); SpinorWaveFunction off2 = vertex->evaluate(scale(),3,partons[3],aout[outhel2],gout[outhel3]); diag[2] = FFZVertex_->evaluate(scale(),off2,fout[outhel1],interZ); diag[3] = FFPVertex_->evaluate(scale(),off2,fout[outhel1],interG); // sum of diagrams Complex sum = std::accumulate(diag.begin(),diag.end(),Complex(0.)); // matrix element output(inhel1,inhel2,outhel1,outhel2,outhel3)=sum; // me2 total += norm(sum); } } } } } // spin average total *= 0.25; tcPolarizedBeamPDPtr beam[2] = {dynamic_ptr_cast(partons[0]), dynamic_ptr_cast(partons[1])}; if( beam[0] || beam[1] ) { RhoDMatrix rho[2] = {beam[0] ? beam[0]->rhoMatrix() : RhoDMatrix(mePartonData()[0]->iSpin()), beam[1] ? beam[1]->rhoMatrix() : RhoDMatrix(mePartonData()[1]->iSpin())}; total = output.average(rho[0],rho[1]); } // divide out the coupling total /= norm(vertex->norm()); // and charge (if needed) if(inter==ShowerInteraction::QED) total /= sqr(double(mePartonData()[2]->iCharge())/3.); // return the total return total*UnitRemoval::InvE2; } diff --git a/MatrixElement/Lepton/MEee2gZ2qq.h b/MatrixElement/Lepton/MEee2gZ2qq.h --- a/MatrixElement/Lepton/MEee2gZ2qq.h +++ b/MatrixElement/Lepton/MEee2gZ2qq.h @@ -1,503 +1,501 @@ // -*- C++ -*- // // MEee2gZ2qq.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_MEee2gZ2qq_H #define HERWIG_MEee2gZ2qq_H // // This is the declaration of the MEee2gZ2qq class. // #include "Herwig/MatrixElement/HwMEBase.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Utilities/Rebinder.h" #include "Herwig/MatrixElement/ProductionMatrixElement.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "Herwig/Shower/Couplings/ShowerAlpha.h" namespace Herwig { using namespace ThePEG; /** * The MEee2gZ2qq class implements the matrix element * for \f$e^+e^-\to Z/\gamma \to q\bar{q}\f$ including spin correlations. * The class includes greater control over the type of quark produced than is available * in the corresponding matrix element from ThePEG, in addition to spin correlations. * * @see \ref MEee2gZ2qqInterfaces "The interfaces" * defined for MEee2gZ2qq. */ class MEee2gZ2qq: public HwMEBase { public: /** * The default constructor. */ MEee2gZ2qq() : minflav_(1), maxflav_(5), massopt_(1), spinCorrelations_(true), pTminQED_(GeV), pTminQCD_(GeV), preFactor_(6.) {} /** * Members for hard corrections to the emission of QCD radiation */ //@{ /** * Has a POWHEG style correction */ virtual POWHEGType hasPOWHEGCorrection() {return FSR;} /** * Has an old fashioned ME correction */ virtual bool hasMECorrection() {return true;} /** * Initialize the ME correction */ virtual void initializeMECorrection(ShowerTreePtr, double &, double & ); /** * Apply the hard matrix element correction to a given hard process or decay */ virtual void applyHardMatrixElementCorrection(ShowerTreePtr); /** * Apply the soft matrix element correction * @param initial The particle from the hard process which started the * shower * @param parent The initial particle in the current branching * @param br The branching struct * @return If true the emission should be vetoed */ virtual bool softMatrixElementVeto(ShowerProgenitorPtr initial, ShowerParticlePtr parent, Branching br); /** * Apply the POWHEG style correction */ - virtual HardTreePtr generateHardest(ShowerTreePtr, - vector); + virtual HardTreePtr generateHardest(ShowerTreePtr,ShowerInteraction::Type); //@} /** @name Virtual functions required by the MEBase class. */ //@{ /** * Return the order in \f$\alpha_S\f$ in which this matrix * element is given. */ virtual unsigned int orderInAlphaS() const; /** * Return the order in \f$\alpha_{EW}\f$ in which this matrix * element is given. */ virtual unsigned int orderInAlphaEW() const; /** * The matrix element for the kinematical configuration * previously provided by the last call to setKinematics(), suitably * scaled by sHat() to give a dimension-less number. * @return the matrix element scaled with sHat() to give a * dimensionless number. */ virtual double me2() const; /** * Return the scale associated with the last set phase space point. */ virtual Energy2 scale() const; /** * Add all possible diagrams with the add() function. */ virtual void getDiagrams() const; /** * Get diagram selector. With the information previously supplied with the * setKinematics method, a derived class may optionally * override this method to weight the given diagrams with their * (although certainly not physical) relative probabilities. * @param dv the diagrams to be weighted. * @return a Selector relating the given diagrams to their weights. */ virtual Selector diagrams(const DiagramVector & dv) const; /** * Return a Selector with possible colour geometries for the selected * diagram weighted by their relative probabilities. * @param diag the diagram chosen. * @return the possible colour geometries weighted by their * relative probabilities. */ virtual Selector colourGeometries(tcDiagPtr diag) const; /** * Construct the vertex of spin correlations. */ virtual void constructVertex(tSubProPtr); //@} 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 Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const {return new_ptr(*this);} /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const {return new_ptr(*this);} //@} 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(); /** * Rebind pointer to other Interfaced objects. Called in the setup phase * after all objects used in an EventGenerator has been cloned so that * the pointers will refer to the cloned objects afterwards. * @param trans a TranslationMap relating the original objects to * their respective clones. * @throws RebindException if no cloned object was found for a given * pointer. */ virtual void rebind(const TranslationMap & trans) ; /** * Return a vector of all pointers to Interfaced objects used in this * object. * @return a vector of pointers. */ virtual IVector getReferences(); //@} protected: /** * Calculate the matrix element for \f$e^+e^-\to q \bar{q}\f$. * @param partons The incoming and outgoing particles * @param momenta The momenta of the incoming and outgoing particles * @param first Whether or not to calculate the spin correlations */ double loME(const vector & partons, const vector & momenta, bool first) const; /** * Member to calculate the matrix element * @param fin Spinors for incoming fermion * @param ain Spinors for incoming antifermion * @param fout Spinors for outgoing fermion * @param aout Spinors for outgong antifermion * @param me Spin summed Matrix element * @param cont The continuum piece of the matrix element * @param BW The Z piece of the matrix element */ ProductionMatrixElement HelicityME(vector & fin, vector & ain, vector & fout, vector & aout, double & me, double & cont, double & BW ) const; /** * The ratio of the matrix element for one additional jet over the * leading order result. In practice * \f[\frac{\hat{s}|\overline{\mathcal{M}}|^2_2|D_{\rm emit}|}{4\pi C_F\alpha_S|\overline{\mathcal{M}}|^2_3\left(|D_{\rm emit}|+|D_{\rm spect}|\right)}\f] * is returned where \f$\|\overline{\mathcal{M}}|^2\f$ is * the spin and colour summed/averaged matrix element. * @param partons The incoming and outgoing particles * @param momenta The momenta of the incoming and outgoing particles * @param iemitter Whether the quark or antiquark is regardede as the emitter * @param inter The type of interaction * @param subtract Whether or not to subtract the relevant dipole term */ double meRatio(vector partons, vector momenta, unsigned int iemitter, ShowerInteraction::Type inter, bool subtract =false) const; /** * Calculate the matrix element for \f$e^-e^-\to q \bar q g\f$. * @param partons The incoming and outgoing particles * @param momenta The momenta of the incoming and outgoing particles * @param inter The type of interaction */ InvEnergy2 realME(const vector & partons, const vector & momenta, ShowerInteraction::Type inter) const; private: /** * Generate the momenta for a hard configuration */ pair generateHard(ShowerTreePtr tree, vector & emission, unsigned int & iemit, unsigned int & ispect, - bool applyVeto, - vector); + bool applyVeto,ShowerInteraction::Type); /** * Calculate \f$\tilde{\kappa}\f$. */ double getKfromX(double, double); /** * Vector and axial vector parts of the matrix element */ //@{ /** * Vector part of the matrix element */ double MEV(double, double); /** * The matrix element, given \f$x_1\f$, \f$x_2\f$. * @param x1 \f$x_1\f$ * @param x2 \f$x_2\f$ */ double PS(double x1, double x2); //@} protected: /** * Pointer to the fermion-antifermion Z vertex */ AbstractFFVVertexPtr FFZVertex() const {return FFZVertex_;} /** * Pointer to the fermion-antifermion photon vertex */ AbstractFFVVertexPtr FFPVertex() const {return FFPVertex_;} /** * Pointer to the particle data object for the Z */ PDPtr Z0() const {return Z0_;} /** * Pointer to the particle data object for the photon */ PDPtr gamma() const {return gamma_;} /** * Pointer to the particle data object for the gluon */ PDPtr gluon() const {return gluon_;} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ MEee2gZ2qq & operator=(const MEee2gZ2qq &); private: /** * Parameters controlling the leading-order process */ //@{ /** * The minimum PDG of the quarks to be produced */ int minflav_; /** * The maximum PDG of the quarks to be produced */ int maxflav_; /** * Option for the treatment of the top quark mass */ unsigned int massopt_; //@} /** * Pointers to the vertices */ //@{ /** * Pointer to the fermion-antifermion Z vertex */ AbstractFFVVertexPtr FFZVertex_; /** * Pointer to the fermion-antifermion photon vertex */ AbstractFFVVertexPtr FFPVertex_; /** * Pointer to the fermion-antifermion photon vertex */ AbstractFFVVertexPtr FFGVertex_; //@} /** * Switch on/off the helivity vertex construction */ bool spinCorrelations_; /** * Pointer to the ParticleData objects */ //@{ /** * Pointer to the particle data object for the Z */ PDPtr Z0_; /** * Pointer to the particle data object for the photon */ PDPtr gamma_; /** * Pointer to the particle data object for the gluon */ PDPtr gluon_; //@} /** * CM energy */ Energy d_Q_; /** * Quark mass */ Energy d_m_; /** * The rho parameter */ double d_rho_; /** * The v parameter */ double d_v_; /** * The initial kappa-tilde values for radiation from the quark */ double d_kt1_; /** * The initial kappa-tilde values for radiation from the antiquark */ double d_kt2_; /** * Cut-off parameter */ static const double EPS_; /** * Pointer to the strong coupling */ ShowerAlphaPtr alphaQCD_; /** * Pointer to the EM coupling */ ShowerAlphaPtr alphaQED_; private: /** * Variables for the POWHEG style corrections */ //@{ /** * The cut off on pt for QED, assuming massless quarks. */ Energy pTminQED_; /** * The cut off on pt for QCD, assuming massless quarks. */ Energy pTminQCD_; /** * Overestimate for the prefactor */ double preFactor_; /** * ParticleData objects for the partons */ vector partons_; /** * Momenta of the leading-order partons */ vector loMomenta_; //@} }; } #endif /* HERWIG_MEee2gZ2qq_H */ diff --git a/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc b/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc --- a/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc +++ b/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc @@ -1,2201 +1,2198 @@ // -*- 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) { +generateHardest(ShowerTreePtr tree,ShowerInteraction::Type inter) { 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/MatrixElement/Powheg/MEPP2GammaGammaPowheg.h b/MatrixElement/Powheg/MEPP2GammaGammaPowheg.h --- a/MatrixElement/Powheg/MEPP2GammaGammaPowheg.h +++ b/MatrixElement/Powheg/MEPP2GammaGammaPowheg.h @@ -1,538 +1,537 @@ // -*- C++ -*- #ifndef HERWIG_MEPP2GammaGammaPowheg_H #define HERWIG_MEPP2GammaGammaPowheg_H // // This is the declaration of the MEPP2GammaGammaPowheg class. // #include "Herwig/MatrixElement/HwMEBase.h" #include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h" #include "Herwig/MatrixElement/ProductionMatrixElement.h" #include "Herwig/Shower/Couplings/ShowerAlpha.h" namespace Herwig { using namespace ThePEG; /** * Here is the documentation of the MEPP2GammaGammaPowheg class. * * @see \ref MEPP2GammaGammaPowhegInterfaces "The interfaces" * defined for MEPP2GammaGammaPowheg. */ class MEPP2GammaGammaPowheg: public HwMEBase { enum DipoleType { IIQCD1=2, IIQCD2=4, IFQED1=5, FIQED1=6, IFQED2=7, FIQED2=8 }; enum RadiationType {Subtraction,Hard,Shower}; public: /** @name Standard constructors and destructors. */ //@{ /** * The default constructor. */ MEPP2GammaGammaPowheg(); //@} /** @name Member functions for the generation of hard QCD radiation */ //@{ /** * Has a POWHEG style correction */ virtual POWHEGType hasPOWHEGCorrection() {return ISR;} /** * Apply the POWHEG style correction */ - virtual HardTreePtr generateHardest(ShowerTreePtr, - vector); + virtual HardTreePtr generateHardest(ShowerTreePtr,ShowerInteraction::Type); //@} public: /** @name Virtual functions required by the MEBase class. */ //@{ /** * Return the order in \f$\alpha_S\f$ in which this matrix * element is given. */ virtual unsigned int orderInAlphaS() const; /** * Return the order in \f$\alpha_{EW}\f$ in which this matrix * element is given. */ virtual unsigned int orderInAlphaEW() const; /** * The matrix element for the kinematical configuration * previously provided by the last call to setKinematics(), suitably * scaled by sHat() to give a dimension-less number. * @return the matrix element scaled with sHat() to give a * dimensionless number. */ virtual double me2() const; /** * Return the scale associated with the last set phase space point. */ virtual Energy2 scale() const; /** * The number of internal degrees of freedom used in the matrix * element. */ virtual int nDim() const; /** * Generate internal degrees of freedom given nDim() uniform * random numbers in the interval \f$ ]0,1[ \f$. To help the phase space * generator, the dSigHatDR should be a smooth function of these * numbers, although this is not strictly necessary. * @param r a pointer to the first of nDim() consecutive random numbers. * @return true if the generation succeeded, otherwise false. */ virtual bool generateKinematics(const double * r); /** * Return the matrix element squared differential in the variables * given by the last call to generateKinematics(). */ virtual CrossSection dSigHatDR() const; /** * Add all possible diagrams with the add() function. */ virtual void getDiagrams() const; /** * Get diagram selector. With the information previously supplied with the * setKinematics method, a derived class may optionally * override this method to weight the given diagrams with their * (although certainly not physical) relative probabilities. * @param dv the diagrams to be weighted. * @return a Selector relating the given diagrams to their weights. */ virtual Selector diagrams(const DiagramVector & dv) const; /** * Return a Selector with possible colour geometries for the selected * diagram weighted by their relative probabilities. * @param diag the diagram chosen. * @return the possible colour geometries weighted by their * relative probabilities. */ virtual Selector colourGeometries(tcDiagPtr diag) const; //@} 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: /** * Calculate of the full next-to-leading order weight */ virtual double NLOWeight() const; /** * Leading-order matrix element for \f$q\bar q\to \gamma\gamma\f$ */ double loGammaGammaME(const cPDVector & particles, const vector & momenta, bool first=false) const; /** * Leading-order matrix element for \f$qg\to \gamma q\f$ */ double loGammaqME(const cPDVector & particles, const vector & momenta, bool first=false) const; /** * Leading-order matrix element for \f$g\bar q\to \gamma \bar q\f$ */ double loGammaqbarME(const cPDVector & particles, const vector & momenta, bool first=false) const; /** * Leading-order matrix element for \f$q\bar q\to \gamma g\f$ */ double loGammagME(const cPDVector & particles, const vector & momenta, bool first=false) const; /** * Real emission matrix element for \f$q\bar q\to \gamma \gamma g\f$ */ InvEnergy2 realGammaGammagME(const cPDVector & particles, const vector & momenta, DipoleType dipole, RadiationType rad, bool first=false) const; /** * Real emission matrix element for \f$qg\to \gamma \gamma q\f$ */ InvEnergy2 realGammaGammaqME(const cPDVector & particles, const vector & momenta, DipoleType dipole, RadiationType rad, bool first=false) const; /** * Real emission matrix element for \f$g\bar q\to \gamma \gamma \bar q\f$ */ InvEnergy2 realGammaGammaqbarME(const cPDVector & particles, const vector & momenta, DipoleType dipole, RadiationType rad, bool first=false) const; /** * The dipole subtractedvirtual contribution */ double subtractedVirtual() const; /** * Subtracted real contribution */ double subtractedReal(pair x, double z, double zJac, double oldqPDF, double newqPDF, double newgPDF,bool order) const; /** * Calculate of the collinear counterterms */ //@{ /** * Quark collinear counter term */ double collinearQuark(double x, Energy2 mu2, double jac, double z, double oldPDF, double newPDF) const; /** * Gluon collinear counter term */ double collinearGluon(Energy2 mu2, double jac, double z, double oldPDF, double newPDF) const; //@} /** * The real matrix element divided by \f$2 g_S^2\f$, to be implemented in the * inheriting classes. * @param particles The ParticleData objects of the particles * @param momenta The momenta of the particles */ double realME(const cPDVector & particles, const vector & momenta) const; /** * Generate hard QCD emission */ HardTreePtr hardQCDEmission(vector); /** * Generate hard QED emission */ HardTreePtr hardQEDEmission(vector); /** * The supression function */ pair supressionFunction(Energy pT,Energy scale) const { if(supressionScale_==0) scale = lambda_; Energy2 scale2 = sqr(scale), pT2 = sqr(pT); switch( supressionFunction_ ) { case 0: return make_pair(1.,0.); case 1: if(pT < scale ) return make_pair(1.,0.); else return make_pair(0.,1.); case 2: return make_pair(scale2/(pT2+scale2),pT2/(pT2+scale2)); default: assert(false); } } protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const; /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const; //@} 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(); //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ MEPP2GammaGammaPowheg & operator=(const MEPP2GammaGammaPowheg &); private: /** * Vertices */ //@{ /** * FFPVertex */ AbstractFFVVertexPtr FFPvertex_; /** * FFGVertex */ AbstractFFVVertexPtr FFGvertex_; //@} /** * Kinematic variables for the real radiation */ //@{ /** * First variable */ mutable double zTilde_; /** * Second variable */ mutable double vTilde_; /** * Azimuthal angle */ mutable double phi_; //@} /** * Whether to generate the positive, negative or leading order contribution */ unsigned int contrib_; /** * Power for sampling \f$x_p\f$ */ double power_; /** * Pointer to the gluon ParticleData object */ tcPDPtr gluon_; /** * Processes */ unsigned int process_; /** * Processes */ unsigned int threeBodyProcess_; /** * Allowed flavours of the incoming quarks */ int maxflavour_; /** * Factor for \f$C_F\f$ dependent pieces */ mutable double CFfact_; /** * Factor for \f$T_R\f$ dependent pieces */ mutable double TRfact_; /** * Strong coupling */ mutable double alphaS_; /** * Use a fixed value of \f$\alpha_S\f$ */ bool fixedAlphaS_; /** * Electromagnetic coupling */ mutable double alphaEM_; /** * Leading-order matrix element */ mutable double loME_; /** * The matrix element */ mutable ProductionMatrixElement me_; /** * the selected dipole */ mutable DipoleType dipole_; /** * Supression Function */ //@{ /** * Choice of the supression function */ unsigned int supressionFunction_; /** * Choice for the scale in the supression function */ unsigned int supressionScale_; /** * Scalar for the supression function */ Energy lambda_; //@} /** * Hard emission stuff */ //@{ /** * Whether the quark is in the + or - z direction */ bool quarkplus_; //@} /** * Properties of the incoming particles */ //@{ /** * Pointers to the BeamParticleData objects */ vector beams_; /** * Pointers to the ParticleDataObjects for the partons */ vector partons_; //@} /** * Constants for the sampling. The distribution is assumed to have the * form \f$\frac{c}{{\rm GeV}}\times\left(\frac{{\rm GeV}}{p_T}\right)^n\f$ */ //@{ /** * The prefactor, \f$c\f$ for the \f$q\bar{q}\f$ channel */ double preQCDqqbarq_; /** * The prefactor, \f$c\f$ for the \f$q\bar{q}\f$ channel */ double preQCDqqbarqbar_; /** * The prefactor, \f$c\f$ for the \f$qg\f$ channel */ double preQCDqg_; /** * The prefactor, \f$c\f$ for the \f$g\bar{q}\f$ channel */ double preQCDgqbar_; double preQEDqqbarq_; double preQEDqqbarqbar_; double preQEDqgq_; double preQEDgqbarqbar_; /** * The prefactors as a vector for easy use */ vector prefactor_; //@} /** * The transverse momentum of the jet */ Energy minpT_; /** * Pointer to the object calculating the strong coupling */ ShowerAlphaPtr alphaQCD_; /** * Pointer to the object calculating the EM */ ShowerAlphaPtr alphaQED_; /** * Scale choice */ unsigned int scaleChoice_; /** * Scale factor */ double scalePreFactor_; }; } #endif /* HERWIG_MEPP2GammaGammaPowheg_H */ diff --git a/MatrixElement/Powheg/MEPP2VVPowheg.cc b/MatrixElement/Powheg/MEPP2VVPowheg.cc --- a/MatrixElement/Powheg/MEPP2VVPowheg.cc +++ b/MatrixElement/Powheg/MEPP2VVPowheg.cc @@ -1,5411 +1,5410 @@ // -*- C++ -*- // // MEPP2VVPowheg.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 MEPP2VVPowheg class. // #include "MEPP2VVPowheg.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/MatrixElement/Tree2toNDiagram.h" #include "ThePEG/Handlers/StandardXComb.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "Herwig/MatrixElement/HardVertex.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include "Herwig/Shower/Base/ShowerProgenitor.h" #include "Herwig/Shower/Base/ShowerTree.h" #include "Herwig/Shower/Base/Branching.h" #include "Herwig/Shower/Base/HardTree.h" using namespace Herwig; MEPP2VVPowheg::MEPP2VVPowheg() : tiny(1.e-10), CF_(4./3.), TR_(0.5), NC_(3.), contrib_(1), channels_(0), nlo_alphaS_opt_(0) , fixed_alphaS_(0.1180346226), removebr_(1), scaleopt_(1), mu_F_(100.*GeV), mu_UV_(100.*GeV), ckm_(3,vector(3,0.0)), helicityConservation_(true), realMESpinCorrelations_(true), power_(2.0), preqqbar_(3.7),preqg_(16.0),pregqbar_(11.0), b0_((11.-2./3.*5.)/4./Constants::pi), LambdaQCD_(91.118*GeV*exp(-1./2./((11.-2./3.*5.)/4./Constants::pi)/0.118)), min_pT_(2.*GeV){ massOption(vector(2,1)); } void MEPP2VVPowheg::persistentOutput(PersistentOStream & os) const { os << contrib_ << channels_ << nlo_alphaS_opt_ << fixed_alphaS_ << removebr_ << scaleopt_ << ounit(mu_F_,GeV) << ounit(mu_UV_,GeV) << ckm_ << helicityConservation_ << FFPvertex_ << FFWvertex_ << FFZvertex_ << WWWvertex_ << FFGvertex_ << realMESpinCorrelations_ << showerAlphaS_ << power_ << preqqbar_ << preqg_ << pregqbar_ << prefactor_ << b0_ << ounit(LambdaQCD_,GeV) << ounit( min_pT_,GeV ); } void MEPP2VVPowheg::persistentInput(PersistentIStream & is, int) { is >> contrib_ >> channels_ >> nlo_alphaS_opt_ >> fixed_alphaS_ >> removebr_ >> scaleopt_ >> iunit(mu_F_,GeV) >> iunit(mu_UV_,GeV) >> ckm_ >> helicityConservation_ >> FFPvertex_ >> FFWvertex_ >> FFZvertex_ >> WWWvertex_ >> FFGvertex_ >> realMESpinCorrelations_ >> showerAlphaS_ >> power_ >> preqqbar_ >> preqg_ >> pregqbar_ >> prefactor_ >> b0_ >> iunit(LambdaQCD_,GeV) >> iunit( min_pT_, GeV ); } ClassDescription MEPP2VVPowheg::initMEPP2VVPowheg; // Definition of the static class description member. void MEPP2VVPowheg::Init() { static ClassDocumentation documentation ("The MEPP2VVPowheg class implements the NLO matrix elements for the production of" "pairs of electroweak vector bosons.", "The calcultaion of $W^+W^-$, $W^\\pm Z^0$ and $Z^0Z^0$ production" " in hadron collisions at next-to-leading order in the POWHEG scheme" " is described in \\cite{Hamilton:2010mb}.", "\\bibitem{Hamilton:2010mb}\n" " K.~Hamilton,\n" "%``A positive-weight next-to-leading order simulation of weak boson pair\n" "%production,''\n" "JHEP {\bf 1101} (2011) 009\n" "[arXiv:1009.5391 [hep-ph]].\n" "%%CITATION = JHEPA,1101,009;%%\n"); static Switch interfaceContribution ("Contribution", "Which contributions to the cross section to include", &MEPP2VVPowheg::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 Switch interfaceChannels ("Channels", "Which channels to include in the cross section", &MEPP2VVPowheg::channels_, 0, false, false); static SwitchOption interfaceChannelsAll (interfaceChannels, "All", "All channels required for the full NLO cross section: qqb, qg, gqb", 0); static SwitchOption interfaceChannelsAnnihilation (interfaceChannels, "Annihilation", "Only include the qqb annihilation channel, omitting qg and gqb channels", 1); static SwitchOption interfaceChannelsCompton (interfaceChannels, "Compton", "Only include the qg and gqb compton channels, omitting all qqb processes", 2); static Switch interfaceNLOalphaSopt ("NLOalphaSopt", "An option allowing you to supply a fixed value of alpha_S " "through the FixedNLOAlphaS interface.", &MEPP2VVPowheg::nlo_alphaS_opt_, 0, false, false); static SwitchOption interfaceNLOalphaSoptRunningAlphaS (interfaceNLOalphaSopt, "RunningAlphaS", "Use the usual running QCD coupling evaluated at scale mu_UV2()", 0); static SwitchOption interfaceNLOalphaSoptFixedAlphaS (interfaceNLOalphaSopt, "FixedAlphaS", "Use a constant QCD coupling for comparison/debugging purposes", 1); static Parameter interfaceFixedNLOalphaS ("FixedNLOalphaS", "The value of alphaS to use for the nlo weight if nlo_alphaS_opt_=1", &MEPP2VVPowheg::fixed_alphaS_, 0.1180346226, 0., 1.0, false, false, Interface::limited); static Switch interfaceremovebr ("removebr", "Whether to multiply the event weights by the MCFM branching ratios", &MEPP2VVPowheg::removebr_, 1, false, false); static SwitchOption interfaceProductionCrossSection (interfaceremovebr, "true", "Do not multiply in the branching ratios (default running)", 1); static SwitchOption interfaceIncludeBRs (interfaceremovebr, "false", "Multiply by MCFM branching ratios for comparison/debugging purposes", 0); static Switch interfaceScaleOption ("ScaleOption", "Option for running / fixing EW and QCD factorization & renormalization scales", &MEPP2VVPowheg::scaleopt_, 1, false, false); static SwitchOption interfaceDynamic (interfaceScaleOption, "Dynamic", "QCD factorization & renormalization scales are sqr(pV1+pV2). " "EW scale is (mV1^2+mV2^2)/2 (similar to MCatNLO)", 1); static SwitchOption interfaceFixed (interfaceScaleOption, "Fixed", "QCD factorization fixed to value by FactorizationScaleValue." "EW and QCD renormalization scales fixed by RenormalizationScaleValue.", 2); static Parameter interfaceFactorizationScaleValue ("FactorizationScaleValue", "Value to use for the QCD factorization scale if fixed scales" "have been requested with the ScaleOption interface.", &MEPP2VVPowheg::mu_F_, GeV, 100.0*GeV, 50.0*GeV, 500.0*GeV, true, false, Interface::limited); static Parameter interfaceRenormalizationScaleValue ("RenormalizationScaleValue", "Value to use for the EW and QCD renormalization scales if fixed " "scales have been requested with the ScaleOption interface.", &MEPP2VVPowheg::mu_UV_, GeV, 100.0*GeV, 50.0*GeV, 500.0*GeV, true, false, Interface::limited); static Switch interfaceSpinCorrelations ("SpinCorrelations", "Flag to select leading order spin correlations or a " "calculation taking into account the real NLO effects", &MEPP2VVPowheg::realMESpinCorrelations_, 1, false, false); static SwitchOption interfaceSpinCorrelationsLeadingOrder (interfaceSpinCorrelations, "LeadingOrder", "Decay bosons using a leading order 2->2 calculation of the " "production spin density matrix", 0); static SwitchOption interfaceSpinCorrelationsRealNLO (interfaceSpinCorrelations, "RealNLO", "Decay bosons using a production spin density matrix which " "takes into account the effects of real radiation", 1); static Reference interfaceCoupling ("Coupling", "The object calculating the strong coupling constant", &MEPP2VVPowheg::showerAlphaS_, false, false, true, false, false); static Parameter interfacePower ("Power", "The power for the sampling of the matrix elements", &MEPP2VVPowheg::power_, 2.0, 1.0, 10.0, false, false, Interface::limited); static Parameter interfacePrefactorqqbar ("Prefactorqqbar", "The prefactor for the sampling of the q qbar channel", &MEPP2VVPowheg::preqqbar_, 5.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacePrefactorqg ("Prefactorqg", "The prefactor for the sampling of the q g channel", &MEPP2VVPowheg::preqg_, 3.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacePrefactorgqbar ("Prefactorgqbar", "The prefactor for the sampling of the g qbar channel", &MEPP2VVPowheg::pregqbar_, 3.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacepTMin ("minPt", "The pT cut on hardest emision generation" "2*(1-Beta)*exp(-sqr(intrinsicpT/RMS))/sqr(RMS)", &MEPP2VVPowheg::min_pT_, GeV, 2.*GeV, ZERO, 100000.0*GeV, false, false, Interface::limited); } Energy2 MEPP2VVPowheg::scale() const { // N.B. This scale is the electroweak scale! // It is used in the evaluation of the LO code // in the MEPP2VV base class. This means it // should appear in the denominator of the // NLOweight here and all other LO parts like // the function for the lumi ratio (Lhat). It // should also be used for evaluating any EW // parameters / vertices in the numerator. // The scaleopt_ == 1 "running" option is // chosen to be like the MC@NLO one (it ought // to be more like sHat instead?). return scaleopt_ == 1 ? // 0.5*(meMomenta()[2].m2()+meMomenta()[3].m2()) : sqr(mu_UV_); sHat() : sqr(mu_UV_); } Energy2 MEPP2VVPowheg::mu_F2() const { return scaleopt_ == 1 ? // ((H_.k1r()).m2()+k1r_perp2_lab_+(H_.k2r()).m2()+k2r_perp2_lab_)/2. : sqr(mu_F_); sHat() : sqr(mu_F_); } Energy2 MEPP2VVPowheg::mu_UV2() const { return scaleopt_ == 1 ? // ((H_.k1r()).m2()+k1r_perp2_lab_+(H_.k2r()).m2()+k2r_perp2_lab_)/2. : sqr(mu_UV_); sHat() : sqr(mu_UV_); } void MEPP2VVPowheg::doinit() { MEPP2VV::doinit(); // 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() << "missing hwsm pointer in MEPP2VVPowheg::doinit()" << Exception::abortnow; // get pointers to all required Vertex objects FFPvertex_ = hwsm->vertexFFP(); FFZvertex_ = hwsm->vertexFFZ(); WWWvertex_ = hwsm->vertexWWW(); FFWvertex_ = hwsm->vertexFFW(); FFGvertex_ = hwsm->vertexFFG(); // get the ckm object Ptr::pointer theCKM=dynamic_ptr_cast::pointer>(SM().CKM()); if(!theCKM) throw InitException() << "MEPP2VVPowheg::doinit() " << "the CKM object must be the Herwig one" << Exception::runerror; unsigned int ix,iy; // get the CKM matrix (unsquared for interference) vector< vector > CKM(theCKM->getUnsquaredMatrix(SM().families())); for(ix=0;ix<3;++ix){for(iy=0;iy<3;++iy){ckm_[ix][iy]=CKM[ix][iy];}} // insert the different prefactors in the vector for easy look up prefactor_.push_back(preqqbar_); prefactor_.push_back(preqg_); prefactor_.push_back(pregqbar_); } int MEPP2VVPowheg::nDim() const { int output = MEPP2VV::nDim(); // See related comment in MEPP2VVPowheg::generateKinematics! if(contrib_>0) output += 2; return output; } bool MEPP2VVPowheg::generateKinematics(const double * r) { // N.B. A fix was made to make theta2 a radiative // variable in r4532. Originally theta2 was take to // be the azimuthal angle coming from the generation // of the Born kinematics inherited from MEPP2VV i.e. // before the change theta2 was a random number between // 0 and 2pi. On changing theta2 was set to be // theta2 = (*(r+3)) * 2.*Constants::pi; // and nDim returned if(contrib_>0) output += 3; // In the months following it was noticed that agreement // with MCFM was per mille at Tevatron energies but got // close to 1 percent for LHC energies (for all VV // processes). After searching back up the svn branch // running 2M events each time, the change was spotted // to occur on r4532. Changing: // if(contrib_>0) output += 3; // in ::nDim() and also, // xt = (*(r +nDim() -3)); // y = (*(r +nDim() -2)) * 2. - 1.; // theta2 = (*(r +nDim() -1)) * 2.*Constants::pi; // did not fix the problem. The following code gives the // same good level of agreement at LHC and TVT: double xt( -999.); double y( -999.); double theta2( -999.); if(contrib_>0) { // Generate the radiative integration variables: xt = (*(r +nDim() -2)); y = (*(r +nDim() -1)) * 2. - 1.; // KH 19th August - next line changed for phi in 0->pi not 0->2pi // theta2 = UseRandom::rnd() * 2.*Constants::pi; theta2 = UseRandom::rnd() *Constants::pi; } // Continue with lo matrix element code: bool output(MEPP2VV::generateKinematics(r)); // Work out the kinematics for the leading order / virtual process // and also get the leading order luminosity function: getKinematics(xt,y,theta2); return output; } double MEPP2VVPowheg::me2() const { double output(0.0); useMe(); output = MEPP2VV::me2(); double mcfm_brs(1.); if(!removebr_) { switch(MEPP2VV::process()) { case 1: // W+(->e+,nu_e) W-(->e-,nu_ebar) (MCFM: 61 [nproc]) mcfm_brs *= 0.109338816; mcfm_brs *= 0.109338816; break; case 2: // W+/-(mu+,nu_mu / mu-,nu_mubar) Z(nu_e,nu_ebar) // (MCFM: 72+77 [nproc]) mcfm_brs *= 0.109338816; mcfm_brs *= 0.06839002; break; case 3: // Z(mu-,mu+) Z(e-,e+) (MCFM: 86 [nproc]) mcfm_brs *= 0.034616433; mcfm_brs *= 0.034616433; mcfm_brs *= 2.; // as identical particle factor 1/2 is now obsolete. break; case 4: // W+(mu+,nu_mu) Z(nu_e,nu_ebar) (MCFM: 72 [nproc]) mcfm_brs *= 0.109338816; mcfm_brs *= 0.06839002; break; case 5: // W-(mu-,nu_mubar) Z(nu_e,nu_ebar) (MCFM: 77 [nproc]) mcfm_brs *= 0.109338816; mcfm_brs *= 0.06839002; break; } } // Store the value of the leading order squared matrix element: lo_me2_ = output; output *= NLOweight(); output *= mcfm_brs; return output; } void MEPP2VVPowheg::getKinematics(double xt, double y, double theta2) { // In this member we want to get the lo_lumi_ as this is a // common denominator in the NLO weight. We want also the // bornVVKinematics object and all of the realVVKinematics // objects needed for the NLO weight. // Check if the W- is first in W+W- production. Already confirmed // mePartonData()[0] is a quark, and mePartonData()[1] is an antiquark. // We assume mePartonData[2] and mePartonData[3] are, respectively, // W+/- Z, W+/- W-/+, or Z Z. bool wminus_first(false); if((mePartonData()[2]->id()==-24)&&(mePartonData()[3]->id()==24)) wminus_first=true; // Now get all data on the LO process needed for the NLO computation: // The +z hadron in the lab: hadron_A_=dynamic_ptr_cast::transient_const_pointer> (lastParticles().first->dataPtr()); // The -z hadron in the lab: hadron_B_=dynamic_ptr_cast::transient_const_pointer> (lastParticles().second->dataPtr()); // Leading order momentum fractions: double xa(lastX1()); // The +z momentum fraction in the lab. double xb(lastX2()); // The -z momentum fraction in the lab. // Particle data for incoming +z & -z QCD particles respectively: ab_ = lastPartons().first ->dataPtr(); // The +z momentum parton in the lab. bb_ = lastPartons().second->dataPtr(); // The -z momentum parton in the lab. // We checked TVT & LHC for all VV channels with 10K events: // lastParticles().first ->momentum().z() is always positive // lastParticles().second->momentum().z() is always negative // lastParticles().first ->momentum().z()*xa=lastPartons().first ->momentum().z() 1 in 10^6 // lastParticles().second->momentum().z()*xb=lastPartons().second->momentum().z() 1 in 10^6 // Set the quark and antiquark data pointers. quark_ = mePartonData()[0]; antiquark_ = mePartonData()[1]; if(quark_->id()<0) swap(quark_,antiquark_); // Now in _our_ calculation we basically define the +z axis as being // given by the direction of the incoming quark for q+qb & q+g processes // and the incoming gluon for g+qbar processes. So now we might need to // flip the values of hadron_A_, hadron_B_, ab_, bb_, xa, xb accordingly: if(ab_->id()!=quark_->id()) { swap(hadron_A_,hadron_B_); swap(ab_,bb_); swap(xa,xb); } // So hadron_A_ is the thing containing a quark (ab_) with momentum frac xa, // hadron_B_ is the thing containing an antiquark (bb_) with momentum frac xb. // Now get the partonic flux for the Born process: lo_lumi_ = hadron_A_->pdf()->xfx(hadron_A_,ab_,scale(),xa)/xa * hadron_B_->pdf()->xfx(hadron_B_,bb_,scale(),xb)/xb; // For W+W- events make sure k1 corresponds to the W+ momentum: if(MEPP2VV::process()==1&&wminus_first) swap(meMomenta()[2],meMomenta()[3]); // Create the object containing all 2->2 __kinematic__ information: B_ = bornVVKinematics(meMomenta(),xa,xb); // We checked that meMomenta()[0] (quark) is in the +z direction and meMomenta()[1] // is in the -z direction (antiquark). // Revert momentum swap in case meMomenta and mePartonData correlation // needs preserving for other things. if(MEPP2VV::process()==1&&wminus_first) swap(meMomenta()[2],meMomenta()[3]); // Check the Born kinematics objects is internally consistent: // B_.sanityCheck(); // If we are going beyond leading order then lets calculate all of // the necessary real emission kinematics. if(contrib_>0) { // Soft limit of the 2->3 real emission kinematics: S_ = realVVKinematics(B_, 1., y, theta2); // Soft-collinear limit of the 2->3 kinematics (emission in +z direction): SCp_ = realVVKinematics(B_, 1., 1., theta2); // Soft-collinear limit of the 2->3 kinematics (emission in -z direction): SCm_ = realVVKinematics(B_, 1.,-1., theta2); // Collinear limit of the 2->3 kinematics (emission in +z direction): Cp_ = realVVKinematics(B_, xt, 1., theta2); // Collinear limit of the 2->3 kinematics (emission in -z direction): Cm_ = realVVKinematics(B_, xt,-1., theta2); // The resolved 2->3 real emission kinematics: H_ = realVVKinematics(B_, xt, y, theta2); // Borrowed from VVhardGenerator (lab momenta of k1,k2): Energy pT(sqrt(H_.pT2_in_lab())); LorentzRotation yzRotation; yzRotation.setRotateX(-atan2(pT/GeV,sqrt(B_.sb())/GeV)); LorentzRotation boostFrompTisZero; boostFrompTisZero.setBoostY(-pT/sqrt(B_.sb()+pT*pT)); LorentzRotation boostFromYisZero; boostFromYisZero.setBoostZ(tanh(B_.Yb())); k1r_perp2_lab_ = (boostFromYisZero*boostFrompTisZero*yzRotation*(H_.k1r())).perp2(); k2r_perp2_lab_ = (boostFromYisZero*boostFrompTisZero*yzRotation*(H_.k2r())).perp2(); // Check all the real kinematics objects are internally consistent: // S_.sanityCheck(); // SCp_.sanityCheck(); // SCm_.sanityCheck(); // Cp_.sanityCheck(); // Cm_.sanityCheck(); // H_.sanityCheck(); } return; } double MEPP2VVPowheg::NLOweight() const { // If only leading order is required return 1: if(contrib_==0) return lo_me()/lo_me2_; // Calculate alpha_S and alpha_S/(2*pi). alphaS_ = nlo_alphaS_opt_==1 ? fixed_alphaS_ : SM().alphaS(mu_UV2()); double alsOn2pi(alphaS_/2./pi); // Particle data objects for the new plus and minus colliding partons. tcPDPtr gluon; gluon = getParticleData(ParticleID::g); // Get the all couplings. gW_ = sqrt(4.0*pi*SM().alphaEM(scale())/SM().sin2ThetaW()); sin2ThetaW_ = SM().sin2ThetaW(); double cosThetaW(sqrt(1.-sin2ThetaW_)); guL_ = gW_/2./cosThetaW*( 1.-4./3.*sin2ThetaW_); gdL_ = gW_/2./cosThetaW*(-1.+2./3.*sin2ThetaW_); guR_ = gW_/2./cosThetaW*( -4./3.*sin2ThetaW_); gdR_ = gW_/2./cosThetaW*( +2./3.*sin2ThetaW_); eZ_ = gW_*cosThetaW; eZ2_ = sqr(eZ_); // MCFM has gwsq = 0.4389585130009 -> gw = 0.662539442600115 // Here we have gW_ = 0.662888 // MCFM has xw = 0.22224653300000 -> sqrt(xw) = 0.471430306 // Here we have 0.222247 // MCFM has esq = 0.097557007645279 -> e = 0.31234117187024679 // Here we have 4.0*pi*SM().alphaEM(sqr(100.*GeV)) = 0.0976596 // If the process is W-Z instead of W+Z we must transform these // couplings as follows, according to NPB 383(1992)3-44 Eq.3.23 if(mePartonData()[2]->id()==-24&&mePartonData()[3]->id()==23) { swap(guL_,gdL_); eZ_ *= -1.; } // Get the CKM entry. Note that this code was debugged // considerably; the call to CKM(particle,particle) // did not appear to work, so we extract the elements // as follows below. The right numbers now appear to // to be associated with the right quarks. double Kij(-999.); // W+Z / W-Z if(abs(mePartonData()[2]->id())==24&&mePartonData()[3]->id()==23) { int up_id(-999),dn_id(-999); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==1) { up_id = abs(quark_->id()); dn_id = abs(antiquark_->id()); } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==0) { up_id = abs(antiquark_->id()); dn_id = abs(quark_->id()); } else { cout << "MEPP2VVPowheg:" << endl; cout << "WZ needs an up and a down type quark as incoming!" << endl; } up_id /= 2; up_id -= 1; dn_id -= 1; dn_id /= 2; Kij = sqrt(SM().CKM(up_id,dn_id)); } // W+W- else if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { int up_ida(abs(quark_->id())/2-1); int up_idb(abs(antiquark_->id())/2-1); Kij = sqrt(std::norm( CKM(up_ida,0)*CKM(up_idb,0) + CKM(up_ida,1)*CKM(up_idb,1) + CKM(up_ida,2)*CKM(up_idb,2))); } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { int dn_ida((abs(quark_->id())-1)/2); int dn_idb((abs(antiquark_->id())-1)/2); Kij = sqrt(std::norm( CKM(0,dn_ida)*CKM(0,dn_idb) + CKM(1,dn_ida)*CKM(1,dn_idb) + CKM(2,dn_ida)*CKM(2,dn_idb))); } else { cout << "MEPP2VVPowheg:" << endl; cout << "WW needs 2 down-type / 2 up-type!" << endl; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { Kij = 2.*sqrt(2.)/gW_; } else { cout << "MEPP2VVPowheg: incompatible final state particles!" << endl; } Fij2_ = sqr(gW_/2./sqrt(2.)*Kij); // Get the leading order matrix element (this is necessary!) M_Born_ = M_Born_WZ(B_); // // Get the regular part of the virtual correction (only needed for sanityCheck()!) // M_V_regular_ = M_V_regular(S_); // // Get the q + qbar real emission matrix element (only needed for sanityCheck()!) // t_u_M_R_qqb_ = t_u_M_R_qqb(H_); // Calculate the integrand double wgt(0.); double wqqb(0.); double wgqb(0.); double wqg(0.); double wqqbvirt(0.); double wqqbcollin(0.); double wqqbreal(0.); double wqgcollin(0.); double wqgreal(0.); double wgqbcollin(0.); double wgqbreal(0.); if(channels_==0||channels_==1) { // q+qb wqqbvirt = Vtilde_universal(S_) + M_V_regular(S_)/lo_me2_; wqqbcollin = alsOn2pi*( Ctilde_Ltilde_qq_on_x(quark_,antiquark_,Cp_) + Ctilde_Ltilde_qq_on_x(quark_,antiquark_,Cm_) ); wqqbreal = alsOn2pi*Rtilde_Ltilde_qqb_on_x(quark_,antiquark_); wqqb = wqqbvirt + wqqbcollin + wqqbreal; } if(channels_==0||channels_==2) { // q+g wqgcollin = alsOn2pi*Ctilde_Ltilde_gq_on_x(quark_,gluon,Cm_); wqgreal = alsOn2pi*Rtilde_Ltilde_qg_on_x(quark_,gluon); wqg = wqgreal + wqgcollin; // g+qb wgqbcollin = alsOn2pi*Ctilde_Ltilde_gq_on_x(gluon,antiquark_,Cp_); wgqbreal = alsOn2pi*Rtilde_Ltilde_gqb_on_x(gluon,antiquark_); wgqb = wgqbreal+wgqbcollin; } // total contribution wgt = 1.+(wqqb+wgqb+wqg); // If restricting to qg, gqb channels then subtract the LO contribution: if(channels_==2) wgt -= 1.; if(isnan(wgt)||isinf(wgt)) { cout << "MEPP2VVPowheg:: NLO weight " << "is bad: wgt = " << wgt << endl; cout << "MEPP2VVPowheg sanityCheck invoked!" << endl; cout << ab_->PDGName() << ", " << bb_->PDGName() << ", " << mePartonData()[2]->PDGName() << ", " << mePartonData()[3]->PDGName() << endl; cout << "lo_me2_ - M_Born_ (rel) = " << lo_me2_-M_Born_ << " (" << (lo_me2_-M_Born_)/M_Born_ << ")\n"; cout << "lo_me2_, M_Born_ " << lo_me2_ << ", " << M_Born_ << endl; cout << "xr = " << H_.xr() << " 1-xr = " << 1.-H_.xr() << " y = " << H_.y() << endl; cout << "tkr = " << H_.tkr()/GeV2 << " ukr = " << H_.ukr()/GeV2 << endl; cout << "root(sb) = " << sqrt(B_.sb())/GeV << endl; cout << "sb+tb+ub = " << B_.sb()/GeV2 << " + " << B_.tb()/GeV2 << " + " << B_.ub()/GeV2 << endl; cout << "sqrt(k12) " << sqrt(H_.k12r())/GeV << endl; cout << "sqrt(k22) " << sqrt(H_.k22r())/GeV << endl; cout << "sqr(Kij) " << Kij*Kij << endl; cout << "wqqbvirt " << wqqbvirt << endl; cout << "wqqbcollin " << wqqbcollin << endl; cout << "wqqbreal " << wqqbreal << endl; cout << "wqqb " << wqqb << endl; cout << "wqgcollin " << wqgcollin << endl; cout << "wqgreal " << wqgreal << endl; cout << "wqg " << wqg << endl; cout << "wgqbcollin " << wgqbcollin << endl; cout << "wgqbreal " << wgqbreal << endl; cout << "wgqb " << wgqb << endl; cout << "wgt " << wgt << endl; throw Exception() << "MEPP2VVPowheg:: NLO weight " << "is bad: " << wgt << Exception::eventerror; } return contrib_==1 ? max(0.,wgt) : max(0.,-wgt); } double MEPP2VVPowheg::Lhat_ab(tcPDPtr a, tcPDPtr b, realVVKinematics Kinematics) const { if(!(abs(a->id())<=6||a->id()==21)||!(abs(b->id())<=6||b->id()==21)) cout << "MEPP2VVPowheg::Lhat_ab: Error," << "particle a = " << a->PDGName() << ", " << "particle b = " << b->PDGName() << endl; double nlo_lumi(-999.); double x1(Kinematics.x1r()),x2(Kinematics.x2r()); nlo_lumi = (hadron_A_->pdf()->xfx(hadron_A_,a,mu_F2(),x1)/x1) * (hadron_B_->pdf()->xfx(hadron_B_,b,mu_F2(),x2)/x2); return nlo_lumi / lo_lumi_; } double MEPP2VVPowheg::Vtilde_universal(realVVKinematics S) const { double xbar_y = S.xbar(); double y = S.y(); double eta1b(S.bornVariables().eta1b()); double eta2b(S.bornVariables().eta2b()); Energy2 sb(S.s2r()); return alphaS_/2./pi*CF_ * ( log(sb/mu_F2()) * (3. + 4.*log(eta1b)+4.*log(eta2b)) + 8.*sqr(log(eta1b)) +8.*sqr(log(eta2b)) - 2.*sqr(pi)/3. ) + alphaS_/2./pi*CF_ * ( 8./(1.+y)*log(sqrt(1.-xbar_y)/eta2b) + 8./(1.-y)*log(sqrt(1.-xbar_y)/eta1b) ); } double MEPP2VVPowheg::Ctilde_Ltilde_qq_on_x(tcPDPtr a, tcPDPtr b, realVVKinematics C) const { if(C.y()!= 1.&&C.y()!=-1.) cout << "\nCtilde_qq::y value not allowed."; if(C.y()== 1.&&!(abs(a->id())>0&&abs(a->id())<7)) cout << "\nCtilde_qq::for Cqq^plus a must be a quark! id = " << a->id() << "\n"; if(C.y()==-1.&&!(abs(b->id())>0&&abs(b->id())<7)) cout << "\nCtilde_qq::for Cqq^minus b must be a quark! id = " << b->id() << "\n"; double xt = C.xt(); double x = C.xr(); double etab = C.y() == 1. ? C.bornVariables().eta1b() : C.bornVariables().eta2b() ; Energy2 sb(C.s2r()); if(fabs(1.-xt)<=tiny||fabs(1.-H_.xr())<=tiny) return 0.; return ( ( (1./(1.-xt))*log(sb/mu_F2()/x)+4.*log(etab)/(1.-xt) + 2.*log(1.-xt)/(1.-xt) )*CF_*(1.+sqr(x)) + sqr(etab)*CF_*(1.-x) )*Lhat_ab(a,b,C) / x - ( ( (1./(1.-xt))*log(sb/mu_F2() )+4.*log(etab)/(1.-xt) + 2.*log(1.-xt)/(1.-xt) )*CF_*2. )*Lhat_ab(a,b,S_); } double MEPP2VVPowheg::Ctilde_Ltilde_gq_on_x(tcPDPtr a, tcPDPtr b, realVVKinematics C) const { if(C.y()!= 1.&&C.y()!=-1.) cout << "\nCtilde_gq::y value not allowed."; if(C.y()== 1.&&a->id()!=21) cout << "\nCtilde_gq::for Cgq^plus a must be a gluon! id = " << a->id() << "\n"; if(C.y()==-1.&&b->id()!=21) cout << "\nCtilde_gq::for Cgq^minus b must be a gluon! id = " << b->id() << "\n"; double xt = C.xt(); double x = C.xr(); double etab = C.y() == 1. ? C.bornVariables().eta1b() : C.bornVariables().eta2b() ; Energy2 sb(C.s2r()); return ( ( (1./(1.-xt))*log(sb/mu_F2()/x)+4.*log(etab)/(1.-xt) + 2.*log(1.-xt)/(1.-xt) )*(1.-x)*TR_*(sqr(x)+sqr(1.-x)) + sqr(etab)*TR_*2.*x*(1.-x) )*Lhat_ab(a,b,C) / x; } double MEPP2VVPowheg::Rtilde_Ltilde_qqb_on_x(tcPDPtr a , tcPDPtr b) const { if(!(abs(a->id())<=6||a->id()==21)||!(abs(b->id())<=6||b->id()==21)) cout << "MEPP2VVPowheg::Rtilde_Ltilde_qqb_on_x: Error," << "particle a = " << a->PDGName() << ", " << "particle b = " << b->PDGName() << endl; double xt(H_.xt()); double y(H_.y()); Energy2 s(H_.sr()); Energy2 sCp(Cp_.sr()); Energy2 sCm(Cm_.sr()); Energy2 t_u_M_R_qqb_H (t_u_M_R_qqb(H_ )); Energy2 t_u_M_R_qqb_Cp(t_u_M_R_qqb(Cp_)); Energy2 t_u_M_R_qqb_Cm(t_u_M_R_qqb(Cm_)); // Energy2 t_u_M_R_qqb_H (t_u_M_R_qqb_hel_amp(H_)); // Energy2 t_u_M_R_qqb_Cp(8.*pi*alphaS_*Cp_.sr()/Cp_.xr() // *CF_*(1.+sqr(Cp_.xr()))*lo_me2_); // Energy2 t_u_M_R_qqb_Cm(8.*pi*alphaS_*Cm_.sr()/Cm_.xr() // *CF_*(1.+sqr(Cm_.xr()))*lo_me2_); int config(0); if(fabs(1.-xt)<=tiny||fabs(1.-H_.xr())<=tiny) return 0.; if(fabs(1.-y )<=tiny) { t_u_M_R_qqb_H = t_u_M_R_qqb_Cp ; config = 1; } if(fabs(1.+y )<=tiny) { t_u_M_R_qqb_H = t_u_M_R_qqb_Cm ; config = -1; } if(fabs(H_.tkr()/s)<=tiny) { t_u_M_R_qqb_H = t_u_M_R_qqb_Cp ; config = 1; } if(fabs(H_.ukr()/s)<=tiny) { t_u_M_R_qqb_H = t_u_M_R_qqb_Cm ; config = -1; } if(config== 0) return ( ( (t_u_M_R_qqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qqb_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) + ( (t_u_M_R_qqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qqb_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) ) / lo_me2_ / 8. / pi / alphaS_; else if(config== 1) return ( (t_u_M_R_qqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qqb_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else if(config==-1) return ( (t_u_M_R_qqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qqb_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else throw Exception() << "MEPP2VVPowheg::Rtilde_Ltilde_qqb_on_x\n" << "The configuration is not identified as hard / soft / fwd collinear or bwd collinear." << "config = " << config << "\n" << "xt = " << xt << " 1.-xt = " << 1.-xt << "\n" << "y = " << y << " 1.-y = " << 1.-y << "\n" << Exception::eventerror; } double MEPP2VVPowheg::Rtilde_Ltilde_gqb_on_x(tcPDPtr a , tcPDPtr b) const { if(!(abs(a->id())<=6||a->id()==21)||!(abs(b->id())<=6||b->id()==21)) cout << "MEPP2VVPowheg::Rtilde_Ltilde_gqb_on_x: Error," << "particle a = " << a->PDGName() << ", " << "particle b = " << b->PDGName() << endl; double xt(H_.xt()); double y(H_.y()); Energy2 s(H_.sr()); Energy2 sCp(Cp_.sr()); Energy2 sCm(Cm_.sr()); Energy2 t_u_M_R_gqb_H (t_u_M_R_gqb(H_ )); Energy2 t_u_M_R_gqb_Cp(t_u_M_R_gqb(Cp_)); Energy2 t_u_M_R_gqb_Cm(t_u_M_R_gqb(Cm_)); // Energy2 t_u_M_R_gqb_H (t_u_M_R_gqb_hel_amp(H_)); // Energy2 t_u_M_R_gqb_Cp(8.*pi*alphaS_*Cp_.sr()/Cp_.xr()*(1.-Cp_.xr()) // *TR_*(sqr(Cp_.xr())+sqr(1.-Cp_.xr()))*lo_me2_); // Energy2 t_u_M_R_gqb_Cm(t_u_M_R_gqb(Cm_)); // // Energy2 t_u_M_R_gqb_Cm(t_u_M_R_gqb_hel_amp(Cm_)); int config(0); if(fabs(1.-xt)<=tiny||fabs(1.-H_.xr())<=tiny) return 0.; if(fabs(1.-y )<=tiny) { t_u_M_R_gqb_H = t_u_M_R_gqb_Cp ; config = 1; } if(fabs(1.+y )<=tiny) { t_u_M_R_gqb_H = t_u_M_R_gqb_Cm ; config = -1; } if(fabs(H_.tkr()/s)<=tiny) { t_u_M_R_gqb_H = t_u_M_R_gqb_Cp ; config = 1; } if(fabs(H_.ukr()/s)<=tiny) { t_u_M_R_gqb_H = t_u_M_R_gqb_Cm ; config = -1; } if(config== 0) return ( ( (t_u_M_R_gqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_gqb_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) + ( (t_u_M_R_gqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_gqb_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) ) / lo_me2_ / 8. / pi / alphaS_; else if(config== 1) return ( (t_u_M_R_gqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_gqb_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else if(config==-1) return ( (t_u_M_R_gqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_gqb_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else throw Exception() << "MEPP2VVPowheg::Rtilde_Ltilde_gqb_on_x\n" << "The configuration is not identified as hard / soft / fwd collinear or bwd collinear." << "config = " << config << "\n" << "xt = " << xt << " 1.-xt = " << 1.-xt << "\n" << "y = " << y << " 1.-y = " << 1.-y << "\n" << Exception::eventerror; } double MEPP2VVPowheg::Rtilde_Ltilde_qg_on_x(tcPDPtr a , tcPDPtr b) const { if(!(abs(a->id())<=6||a->id()==21)||!(abs(b->id())<=6||b->id()==21)) cout << "MEPP2VVPowheg::Rtilde_Ltilde_qg_on_x: Error," << "particle a = " << a->PDGName() << ", " << "particle b = " << b->PDGName() << endl; double xt(H_.xt()); double y(H_.y()); Energy2 s(H_.sr()); Energy2 sCp(Cp_.sr()); Energy2 sCm(Cm_.sr()); Energy2 t_u_M_R_qg_H (t_u_M_R_qg(H_ )); Energy2 t_u_M_R_qg_Cp(t_u_M_R_qg(Cp_)); Energy2 t_u_M_R_qg_Cm(t_u_M_R_qg(Cm_)); // Energy2 t_u_M_R_qg_H (t_u_M_R_qg_hel_amp(H_)); // Energy2 t_u_M_R_qg_Cp(t_u_M_R_qg(Cp_)); // // Energy2 t_u_M_R_qg_Cp(t_u_M_R_qg_hel_amp(Cp_)); // Energy2 t_u_M_R_qg_Cm(8.*pi*alphaS_*Cm_.sr()/Cm_.xr()*(1.-Cm_.xr()) // *TR_*(sqr(Cm_.xr())+sqr(1.-Cm_.xr()))*lo_me2_); int config(0); if(fabs(1.-xt)<=tiny||fabs(1.-H_.xr())<=tiny) return 0.; if(fabs(1.-y )<=tiny) { t_u_M_R_qg_H = t_u_M_R_qg_Cp ; config = 1; } if(fabs(1.+y )<=tiny) { t_u_M_R_qg_H = t_u_M_R_qg_Cm ; config = -1; } if(fabs(H_.tkr()/s)<=tiny) { t_u_M_R_qg_H = t_u_M_R_qg_Cp ; config = 1; } if(fabs(H_.ukr()/s)<=tiny) { t_u_M_R_qg_H = t_u_M_R_qg_Cm ; config = -1; } if(config== 0) return ( ( (t_u_M_R_qg_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qg_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) + ( (t_u_M_R_qg_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qg_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) ) / lo_me2_ / 8. / pi / alphaS_; else if(config== 1) return ( (t_u_M_R_qg_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qg_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else if(config==-1) return ( (t_u_M_R_qg_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qg_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else throw Exception() << "MEPP2VVPowheg::Rtilde_Ltilde_qg_on_x\n" << "The configuration is not identified as hard / soft / fwd collinear or bwd collinear." << "config = " << config << "\n" << "xt = " << xt << " 1.-xt = " << 1.-xt << "\n" << "y = " << y << " 1.-y = " << 1.-y << "\n" << Exception::eventerror; } /***************************************************************************/ // The following three functions are identically \tilde{I}_{4,t}, // \tilde{I}_{3,WZ} and \tilde{I}_{3,W} given in Eqs. B.8,B.9,B.10 // of NPB 383(1992)3-44, respectively. They are related to / derived // from the loop integrals in Eqs. A.3, A.5 and A.8 of the same paper. InvEnergy4 TildeI4t(Energy2 s, Energy2 t, Energy2 mW2, Energy2 mZ2); InvEnergy2 TildeI3WZ(Energy2 s, Energy2 mW2, Energy2 mZ2, double beta); InvEnergy2 TildeI3W(Energy2 s, Energy2 t, Energy2 mW2); /***************************************************************************/ // The following six functions are identically I_{dd}^{(1)}, I_{ud}^{(1)}, // I_{uu}^{(1)}, F_{u}^{(1)}, F_{d}^{(1)}, H^{(1)} from Eqs. B.4, B.5, B.3, // B.3, B.6, B.7 of NPB 383(1992)3-44, respectively. They make up the // one-loop matrix element. Ixx functions correspond to the graphs // with no TGC, Fx functions are due to non-TGC graphs interfering // with TGC graphs, while the H function is due purely to TGC graphs. double Idd1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta); double Iud1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta); double Iuu1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta); Energy2 Fu1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta); Energy2 Fd1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta); Energy4 H1 (Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); /***************************************************************************/ // M_V_Regular is the regular part of the one-loop matrix element // exactly as defined in Eqs. B.1 and B.2 of of NPB 383(1992)3-44. double MEPP2VVPowheg::M_V_regular(realVVKinematics S) const { Energy2 s(S.bornVariables().sb()); Energy2 t(S.bornVariables().tb()); Energy2 u(S.bornVariables().ub()); Energy2 mW2(S.k12r()); // N.B. the diboson masses are preserved in getting Energy2 mZ2(S.k22r()); // the 2->2 from the 2->3 kinematics. double beta(S.betaxr()); // N.B. for x=1 \beta_x=\beta in NPB 383(1992)3-44. double cosThetaW(sqrt(1.-sin2ThetaW_)); double eZ2(eZ2_); double eZ(eZ_); double gdL(gdL_); double guL(guL_); double gdR(gdR_); double guR(guR_); // W+W- if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { double e2(sqr(gW_)*sin2ThetaW_); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s-mW2)/Fij2_ * (e2*e2/s/s*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s/(s-mW2/sqr(cosThetaW))) +sqr( eZ*(guL-guR)/2./e2*s/(s-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s-mW2) * (gW_*gW_*e2/4./s *( 2./3.+2.*eZ*guL/2./e2*s/(s-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } gdL = gW_/sqrt(2.); guL = 0.; } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s-mW2)/Fij2_ * (e2*e2/s/s*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s/(s-mW2/sqr(cosThetaW))) +sqr( eZ*(gdL-gdR)/2./e2*s/(s-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s-mW2) * (gW_*gW_*e2/4./s *(-1./3.+2.*eZ*gdL/2./e2*s/(s-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } guL = gW_/sqrt(2.); gdL = 0.; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { eZ = 0.; eZ2 = 0.; double gV2,gA2; gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL; else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL; else { cout << "MEPP2VVPowheg:" << endl; cout << "ZZ needs 2 down-type / 2 up-type!" << endl; } } return 4.*pi*alphaS_*Fij2_*CF_*(1./sqr(4.*pi))/NC_ * ( gdL*gdL*Idd1(s,t,u,mW2,mZ2,beta) + gdL*guL*Iud1(s,t,u,mW2,mZ2,beta) + guL*guL*Iuu1(s,t,u,mW2,mZ2,beta) - eZ/(s-mW2) * ( gdL*Fd1(s,t,u,mW2,mZ2,beta) - guL*Fu1(s,t,u,mW2,mZ2,beta) ) + eZ2/sqr(s-mW2) * H1(s,t,u,mW2,mZ2) ); } /***************************************************************************/ InvEnergy4 TildeI4t(Energy2 s, Energy2 t, Energy2 mW2, Energy2 mZ2) { double sqrBrackets; sqrBrackets = ( sqr(log(-t/mW2))/2.+log(-t/mW2)*log(-t/mZ2)/2. - 2.*log(-t/mW2)*log((mW2-t)/mW2)-2.*ReLi2(t/mW2) ); swap(mW2,mZ2); sqrBrackets+= ( sqr(log(-t/mW2))/2.+log(-t/mW2)*log(-t/mZ2)/2. - 2.*log(-t/mW2)*log((mW2-t)/mW2)-2.*ReLi2(t/mW2) ); swap(mW2,mZ2); return sqrBrackets/s/t; } InvEnergy2 TildeI3WZ(Energy2 s, Energy2 mW2, Energy2 mZ2, double beta) { Energy2 sig(mZ2+mW2); Energy2 del(mZ2-mW2); double sqrBrackets ; sqrBrackets = ( ReLi2(2.*mW2/(sig-del*(del/s+beta))) + ReLi2((1.-del/s+beta)/2.) + sqr(log((1.-del/s+beta)/2.))/2. + log((1.-del/s-beta)/2.)*log((1.+del/s-beta)/2.) ); beta *= -1; sqrBrackets -= ( ReLi2(2.*mW2/(sig-del*(del/s+beta))) + ReLi2((1.-del/s+beta)/2.) + sqr(log((1.-del/s+beta)/2.))/2. + log((1.-del/s-beta)/2.)*log((1.+del/s-beta)/2.) ); beta *= -1; swap(mW2,mZ2); del *= -1.; sqrBrackets += ( ReLi2(2.*mW2/(sig-del*(del/s+beta))) + ReLi2((1.-del/s+beta)/2.) + sqr(log((1.-del/s+beta)/2.))/2. + log((1.-del/s-beta)/2.)*log((1.+del/s-beta)/2.) ); swap(mW2,mZ2); del *= -1.; beta *= -1; swap(mW2,mZ2); del *= -1.; sqrBrackets -= ( ReLi2(2.*mW2/(sig-del*(del/s+beta))) + ReLi2((1.-del/s+beta)/2.) + sqr(log((1.-del/s+beta)/2.))/2. + log((1.-del/s-beta)/2.)*log((1.+del/s-beta)/2.) ); beta *= -1; swap(mW2,mZ2); del *= -1.; return sqrBrackets/s/beta; } InvEnergy2 TildeI3W(Energy2 s, Energy2 t, Energy2 mW2) { return 1./(mW2-t)*(sqr(log(mW2/s))/2.-sqr(log(-t/s))/2.-sqr(pi)/2.); } /***************************************************************************/ double Idd1(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) { Energy2 sig(mZ2+mW2); Energy2 del(mZ2-mW2); double Val(0.); Val += 2.*(22.*t*t+t*(19.*s-18.*sig)+18.*mW2*mZ2)/t/t - 8.*(u*t+2*s*sig)/mW2/mZ2 - 2.*sqr(t-u)/t/s/sqr(beta); Val += +( 2.*(8.*t*t+4.*t*(s-3.*sig)+4*sqr(sig)-5.*s*sig+s*s)/t/s/sqr(beta) + 4.*(t*(3.*u+s)-3.*mW2*mZ2)/t/t + 6.*(t+u)*sqr(t-u)/t/s/s/sqr(sqr(beta)) )*log(-t/s); Val += +( ( 8.*t*t*(-2.*s+del)+8.*t*(-s*s+3.*s*sig-2.*del*sig) - 2.*(s-sig)*(s*s-4.*s*sig+3.*del*sig) )/t/s/s/beta/beta + 16.*s*(t-mZ2)/(t*(u+s)-mW2*mZ2) + 2.*(4.*t*t+t*(10.*s-3.*mZ2-9.*mW2)+12.*mW2*mZ2)/t/t -6.*(s-del)*(t+u)*sqr(t-u)/t/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( - ( 4.*t*t*(2.*sig-3.*s) - 4.*t*(s-sig)*(2.*s-3.*sig) - 2.*(s-2.*sig)*sqr(s-sig) )/t/s/beta/beta + ( 4.*sig*t-3.*s*s+4.*s*sig - 4.*(mW2*mW2+mZ2*mZ2) )/t - 3.*sqr(t*t-u*u)/t/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += +( 4.*(t*u+2.*s*sig)/3./mW2/mZ2 - 4.*(t-2.*u)/3./t )*pi*pi; Val += -( 4.*s*(t*u-2.*mW2*mZ2)/t )*TildeI4t(s,t,mW2,mZ2); Val += ( 8.*(t-mW2)*(u*t-2.*mW2*mZ2)/t/t )*TildeI3W(s,t,mW2); swap(mW2,mZ2); del *= -1; Val += 2.*(22.*t*t+t*(19.*s-18.*sig)+18.*mW2*mZ2)/t/t - 8.*(u*t+2*s*sig)/mW2/mZ2 - 2.*sqr(t-u)/t/s/sqr(beta); Val += +( 2.*(8.*t*t+4.*t*(s-3.*sig)+4*sqr(sig)-5.*s*sig+s*s)/t/s/sqr(beta) + 4.*(t*(3.*u+s)-3.*mW2*mZ2)/t/t + 6.*(t+u)*sqr(t-u)/t/s/s/sqr(sqr(beta)) )*log(-t/s); Val += +( ( 8.*t*t*(-2.*s+del)+8.*t*(-s*s+3.*s*sig-2.*del*sig) - 2.*(s-sig)*(s*s-4.*s*sig+3.*del*sig) )/t/s/s/beta/beta + 16.*s*(t-mZ2)/(t*(u+s)-mW2*mZ2) + 2.*(4.*t*t+t*(10.*s-3.*mZ2-9.*mW2)+12.*mW2*mZ2)/t/t -6.*(s-del)*(t+u)*sqr(t-u)/t/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( - ( 4.*t*t*(2.*sig-3.*s) - 4.*t*(s-sig)*(2.*s-3.*sig) - 2.*(s-2.*sig)*sqr(s-sig) )/t/s/beta/beta + ( 4.*sig*t-3.*s*s+4.*s*sig - 4.*(mW2*mW2+mZ2*mZ2) )/t - 3.*sqr(t*t-u*u)/t/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += +( 4.*(t*u+2.*s*sig)/3./mW2/mZ2 - 4.*(t-2.*u)/3./t )*pi*pi; Val += -( 4.*s*(t*u-2.*mW2*mZ2)/t )*TildeI4t(s,t,mW2,mZ2); Val += ( 8.*(t-mW2)*(u*t-2.*mW2*mZ2)/t/t )*TildeI3W(s,t,mW2); swap(mW2,mZ2); del *= -1; return Val; } /***************************************************************************/ double Iud1(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) { Energy2 sig(mZ2+mW2); Energy2 del(mZ2-mW2); double Val(0.); Val += 2.*(4.*t*t+t*(9.*s-4.*sig)-18.*s*sig)/t/u + 8.*(t*u+2.*s*sig)/mW2/mZ2 + 4.*s*s*(2.*t-sig)/u/(mW2*mZ2-t*(u+s)) - 2.*sqr(t-u)/u/s/sqr(beta); Val += ( 2.*(8.*t*t-4.*t*(s+3.*sig)-(s-sig)*(3.*s+4.*sig))/u/s/sqr(beta) + 6.*(t+u)*sqr(t-u)/u/s/s/sqr(sqr(beta)) - 12.*s*(t-sig)/t/u )*log(-t/s); Val += ( (2./u/s/s/sqr(beta))*( 4.*t*t*(-2.*s+del) + 4.*t*(s*s+s*(mZ2+5.*mW2)-2.*sig*del) + (s-sig)*(3.*s*s+8.*mW2*s-3.*sig*del) ) + (2.*t*(18.*s+3.*mW2+mZ2)-24.*s*sig)/t/u - 8.*s*(2.*t*t-t*(3.*s+4.*mZ2+2.*mW2)+2.*mZ2*(s+sig)) /u/(mW2*mZ2-t*(u+s)) - 8.*s*s*t*(2.*t-sig)*(t-mZ2)/u/sqr(mW2*mZ2-t*(u+s)) + 6.*(s-del)*(s-sig)*sqr(t-u)/u/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( -2.*(2.*t*t*(2.*sig-3.*s)+6.*sig*t*(s-sig)+sqr(s-sig)*(s+2.*sig)) /u/s/sqr(beta) +3.*s*(4.*t-4.*sig-s)/u -3.*sqr(s-sig)*sqr(t-u)/u/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += ( 4.*(u+4.*s)/3./u - 4.*(u*t+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += -( 16.*s*(t-sig)*(t-mW2)/t/u )*TildeI3W(s,t,mW2); Val += ( 8.*s*s*(t-sig)/u )*TildeI4t(s,t,mW2,mZ2); swap(t,u); Val += 2.*(4.*t*t+t*(9.*s-4.*sig)-18.*s*sig)/t/u + 8.*(t*u+2.*s*sig)/mW2/mZ2 + 4.*s*s*(2.*t-sig)/u/(mW2*mZ2-t*(u+s)) - 2.*sqr(t-u)/u/s/sqr(beta); Val += ( 2.*(8.*t*t-4.*t*(s+3.*sig)-(s-sig)*(3.*s+4.*sig))/u/s/sqr(beta) + 6.*(t+u)*sqr(t-u)/u/s/s/sqr(sqr(beta)) - 12.*s*(t-sig)/t/u )*log(-t/s); Val += ( (2./u/s/s/sqr(beta))*( 4.*t*t*(-2.*s+del) + 4.*t*(s*s+s*(mZ2+5.*mW2)-2.*sig*del) + (s-sig)*(3.*s*s+8.*mW2*s-3.*sig*del) ) + (2.*t*(18.*s+3.*mW2+mZ2)-24.*s*sig)/t/u - 8.*s*(2.*t*t-t*(3.*s+4.*mZ2+2.*mW2)+2.*mZ2*(s+sig)) /u/(mW2*mZ2-t*(u+s)) - 8.*s*s*t*(2.*t-sig)*(t-mZ2)/u/sqr(mW2*mZ2-t*(u+s)) + 6.*(s-del)*(s-sig)*sqr(t-u)/u/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( -2.*(2.*t*t*(2.*sig-3.*s)+6.*sig*t*(s-sig)+sqr(s-sig)*(s+2.*sig)) /u/s/sqr(beta) +3.*s*(4.*t-4.*sig-s)/u -3.*sqr(s-sig)*sqr(t-u)/u/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += ( 4.*(u+4.*s)/3./u - 4.*(u*t+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += -( 16.*s*(t-sig)*(t-mW2)/t/u )*TildeI3W(s,t,mW2); Val += ( 8.*s*s*(t-sig)/u )*TildeI4t(s,t,mW2,mZ2); swap(t,u); swap(mW2,mZ2); del *= -1; Val += 2.*(4.*t*t+t*(9.*s-4.*sig)-18.*s*sig)/t/u + 8.*(t*u+2.*s*sig)/mW2/mZ2 + 4.*s*s*(2.*t-sig)/u/(mW2*mZ2-t*(u+s)) - 2.*sqr(t-u)/u/s/sqr(beta); Val += ( 2.*(8.*t*t-4.*t*(s+3.*sig)-(s-sig)*(3.*s+4.*sig))/u/s/sqr(beta) + 6.*(t+u)*sqr(t-u)/u/s/s/sqr(sqr(beta)) - 12.*s*(t-sig)/t/u )*log(-t/s); Val += ( (2./u/s/s/sqr(beta))*( 4.*t*t*(-2.*s+del) + 4.*t*(s*s+s*(mZ2+5.*mW2)-2.*sig*del) + (s-sig)*(3.*s*s+8.*mW2*s-3.*sig*del) ) + (2.*t*(18.*s+3.*mW2+mZ2)-24.*s*sig)/t/u - 8.*s*(2.*t*t-t*(3.*s+4.*mZ2+2.*mW2)+2.*mZ2*(s+sig)) /u/(mW2*mZ2-t*(u+s)) - 8.*s*s*t*(2.*t-sig)*(t-mZ2)/u/sqr(mW2*mZ2-t*(u+s)) + 6.*(s-del)*(s-sig)*sqr(t-u)/u/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( -2.*(2.*t*t*(2.*sig-3.*s)+6.*sig*t*(s-sig)+sqr(s-sig)*(s+2.*sig)) /u/s/sqr(beta) +3.*s*(4.*t-4.*sig-s)/u -3.*sqr(s-sig)*sqr(t-u)/u/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += ( 4.*(u+4.*s)/3./u - 4.*(u*t+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += -( 16.*s*(t-sig)*(t-mW2)/t/u )*TildeI3W(s,t,mW2); Val += ( 8.*s*s*(t-sig)/u )*TildeI4t(s,t,mW2,mZ2); swap(mW2,mZ2); del *= -1; swap(t,u); swap(mW2,mZ2); del *= -1; Val += 2.*(4.*t*t+t*(9.*s-4.*sig)-18.*s*sig)/t/u + 8.*(t*u+2.*s*sig)/mW2/mZ2 + 4.*s*s*(2.*t-sig)/u/(mW2*mZ2-t*(u+s)) - 2.*sqr(t-u)/u/s/sqr(beta); Val += ( 2.*(8.*t*t-4.*t*(s+3.*sig)-(s-sig)*(3.*s+4.*sig))/u/s/sqr(beta) + 6.*(t+u)*sqr(t-u)/u/s/s/sqr(sqr(beta)) - 12.*s*(t-sig)/t/u )*log(-t/s); Val += ( (2./u/s/s/sqr(beta))*( 4.*t*t*(-2.*s+del) + 4.*t*(s*s+s*(mZ2+5.*mW2)-2.*sig*del) + (s-sig)*(3.*s*s+8.*mW2*s-3.*sig*del) ) + (2.*t*(18.*s+3.*mW2+mZ2)-24.*s*sig)/t/u - 8.*s*(2.*t*t-t*(3.*s+4.*mZ2+2.*mW2)+2.*mZ2*(s+sig)) /u/(mW2*mZ2-t*(u+s)) - 8.*s*s*t*(2.*t-sig)*(t-mZ2)/u/sqr(mW2*mZ2-t*(u+s)) + 6.*(s-del)*(s-sig)*sqr(t-u)/u/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( -2.*(2.*t*t*(2.*sig-3.*s)+6.*sig*t*(s-sig)+sqr(s-sig)*(s+2.*sig)) /u/s/sqr(beta) +3.*s*(4.*t-4.*sig-s)/u -3.*sqr(s-sig)*sqr(t-u)/u/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += ( 4.*(u+4.*s)/3./u - 4.*(u*t+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += -( 16.*s*(t-sig)*(t-mW2)/t/u )*TildeI3W(s,t,mW2); Val += ( 8.*s*s*(t-sig)/u )*TildeI4t(s,t,mW2,mZ2); swap(t,u); swap(mW2,mZ2); del *= -1; return Val; } /***************************************************************************/ double Iuu1(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) { double Val(Idd1(s,u,t,mW2,mZ2,beta)); return Val; } /***************************************************************************/ Energy2 Fd1 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) { Energy2 sig(mZ2+mW2); Energy2 del(mZ2-mW2); Energy2 Val(0.*GeV2); Val += 4.*(17.*t*t+t*(11.*s-13.*sig)+17.*(s*sig+mW2*mZ2))/t + 16.*(s-sig)*(t*u+2.*s*sig)/mW2/mZ2 + 4*s*s*(2.*t-sig)/(t*(u+s)-mW2*mZ2); Val += ( 8.*(t-u)/sqr(beta) - 4.*(3.*t*t-t*(s+3.*sig)+3.*(s*sig+mW2*mZ2))/t )*log(-t/s); Val += ( 8.*(t*t-t*(2.*s+3.*mW2+mZ2)+3.*(s*sig+mW2*mZ2))/t + 8.*s*(t*(3.*s+2.*sig)-2.*mZ2*(s+sig))/(t*(u+s)-mW2*mZ2) + 8.*s*s*t*(2.*t-sig)*(t-mZ2)/sqr(t*(u+s)-mW2*mZ2) - 8.*(s-del)*(t-u)/s/sqr(beta) )*log(-t/mW2); Val += ( 4.*(s-sig)*(t-u)/sqr(beta) + 4.*(sig-3.*s)*t + 4.*(4.*s*sig-mZ2*mZ2-mW2*mW2) )*TildeI3WZ(s,mW2,mZ2,beta); Val += -( 8.*(3.*t*t+2.*t*(2.*s-sig)+2.*(s*sig+mW2*mZ2))/3./t + 8.*(s-sig)*(t*u+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += ( 4.*(s*t*t-s*(s+sig)*t+2.*s*(s*sig+mW2*mZ2)) )*TildeI4t(s,t,mW2,mZ2); Val += -( 8.*(t-mW2)*(t*t-t*(s+sig)+2.*(s*sig+mW2*mZ2))/t )*TildeI3W(s,t,mW2); swap(mW2,mZ2); del *= -1; Val += 4.*(17.*t*t+t*(11.*s-13.*sig)+17.*(s*sig+mW2*mZ2))/t + 16.*(s-sig)*(t*u+2.*s*sig)/mW2/mZ2 + 4*s*s*(2.*t-sig)/(t*(u+s)-mW2*mZ2); Val += ( 8.*(t-u)/sqr(beta) - 4.*(3.*t*t-t*(s+3.*sig)+3.*(s*sig+mW2*mZ2))/t )*log(-t/s); Val += ( 8.*(t*t-t*(2.*s+3.*mW2+mZ2)+3.*(s*sig+mW2*mZ2))/t + 8.*s*(t*(3.*s+2.*sig)-2.*mZ2*(s+sig))/(t*(u+s)-mW2*mZ2) + 8.*s*s*t*(2.*t-sig)*(t-mZ2)/sqr(t*(u+s)-mW2*mZ2) - 8.*(s-del)*(t-u)/s/sqr(beta) )*log(-t/mW2); Val += ( 4.*(s-sig)*(t-u)/sqr(beta) + 4.*(sig-3.*s)*t + 4.*(4.*s*sig-mZ2*mZ2-mW2*mW2) )*TildeI3WZ(s,mW2,mZ2,beta); Val += -( 8.*(3.*t*t+2.*t*(2.*s-sig)+2.*(s*sig+mW2*mZ2))/3./t + 8.*(s-sig)*(t*u+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += ( 4.*(s*t*t-s*(s+sig)*t+2.*s*(s*sig+mW2*mZ2)) )*TildeI4t(s,t,mW2,mZ2); Val += -( 8.*(t-mW2)*(t*t-t*(s+sig)+2.*(s*sig+mW2*mZ2))/t )*TildeI3W(s,t,mW2); swap(mW2,mZ2); del *= -1; return Val; } /***************************************************************************/ Energy2 Fu1 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) { Energy2 Val(Fd1(s,u,t,mW2,mZ2,beta)); return Val; } /***************************************************************************/ Energy4 H1 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { Energy2 sig(mZ2+mW2); Energy4 Val(0.*GeV2*GeV2); Val = 8.*t*t+8.*t*(s-sig)+s*s+6.*s*sig+mZ2*mZ2+10.*mW2*mZ2+mW2*mW2 - sqr(s-sig)*(t*u+2.*s*sig)/mW2/mZ2; Val *= ( 16.-8.*pi*pi/3.); return Val; } Energy2 t_u_Rdd(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1 , Energy2 q2, Energy2 mW2, Energy2 mZ2); Energy2 t_u_Rud(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1 , Energy2 q2, Energy2 q1h, Energy2 q2h, Energy2 mW2, Energy2 mZ2); Energy2 t_u_Ruu(Energy2 s , Energy2 tk , Energy2 uk, Energy2 q1h, Energy2 q2h, Energy2 mW2, Energy2 mZ2); Energy4 t_u_RZds(Energy2 s ,Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2,Energy2 mW2, Energy2 mZ2); Energy4 t_u_RZda(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2); Energy4 t_u_RZd(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1 , Energy2 q2 , Energy2 s2 , Energy2 mW2, Energy2 mZ2); Energy4 t_u_RZu(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1h, Energy2 q2h, Energy2 s2 , Energy2 mW2, Energy2 mZ2); Energy6 t_u_RZs(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2); Energy6 t_u_RZa(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2); Energy6 t_u_RZ(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2 , Energy2 mW2, Energy2 mZ2); /***************************************************************************/ // t_u_M_R_qqb is the real emission q + qb -> n + g matrix element // exactly as defined in Eqs. C.1 of NPB 383(1992)3-44, multiplied by // tk * uk! Energy2 MEPP2VVPowheg::t_u_M_R_qqb(realVVKinematics R) const { // First the Born variables: Energy2 s2(R.s2r()); Energy2 mW2(R.k12r()); Energy2 mZ2(R.k22r()); // Then the rest: Energy2 s(R.sr()); Energy2 tk(R.tkr()); Energy2 uk(R.ukr()); Energy2 q1(R.q1r()); Energy2 q2(R.q2r()); Energy2 q1h(R.q1hatr()); Energy2 q2h(R.q2hatr()); double cosThetaW(sqrt(1.-sin2ThetaW_)); double eZ2(eZ2_); double eZ(eZ_); double gdL(gdL_); double guL(guL_); double gdR(gdR_); double guR(guR_); // W+W- if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { double e2(sqr(gW_)*sin2ThetaW_); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(guL-guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *( 2./3.+2.*eZ*guL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } gdL = gW_/sqrt(2.); guL = 0.; } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(gdL-gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *(-1./3.+2.*eZ*gdL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } guL = gW_/sqrt(2.); gdL = 0.; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { eZ = 0.; eZ2 = 0.; double gV2,gA2; gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL; else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL; else { cout << "MEPP2VVPowheg:" << endl; cout << "ZZ needs 2 down-type / 2 up-type!" << endl; } } return -2.*pi*alphaS_*Fij2_*CF_/NC_ * ( gdL*gdL*t_u_Rdd(s,tk,uk,q1,q2,mW2,mZ2) + 2.*gdL*guL*t_u_Rud(s,tk,uk,q1,q2,q1h,q2h,mW2,mZ2) + guL*guL*t_u_Ruu(s,tk,uk,q1h,q2h,mW2,mZ2) - 2.*eZ/(s2-mW2) * ( gdL * t_u_RZd(s,tk,uk,q1 ,q2 ,s2,mW2,mZ2) - guL * t_u_RZu(s,tk,uk,q1h,q2h,s2,mW2,mZ2) ) + eZ2/sqr(s2-mW2) *t_u_RZ(s,tk,uk,q1,q2,s2,mW2,mZ2) ); } Energy2 t_u_Rdd(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1,Energy2 q2, Energy2 mW2, Energy2 mZ2) { Energy2 Val(0.*GeV2); Val += 4.*(q2*(uk+2.*s+q2)+q1*(s+q1))/mW2/mZ2*uk + 16.*(uk+s)/q2*uk - 4.*(2.*uk+4.*s+q2)/mW2*uk - 4.*(2.*uk+5.*s+q2+2.*q1-mW2)/mZ2*uk + 4.*q1*s*(s+q1)/mW2/mZ2 + 16.*s*(s+q2-mZ2-mW2)/q1 - 4.*s*(4.*s+q2+q1)/mW2 + 16.*mW2*mZ2*s/q1/q2 + 4.*s + 16.*mZ2*(tk-2.*mW2)/q1/q2/q2*tk*uk + 16.*(2.*mZ2+mW2-tk)/q1/q2*tk*uk + 16.*mW2*(s-mZ2-mW2)/q1/q2*uk + 16.*mZ2*(q1-2.*mW2)/q2/q2*uk + 32.*mW2*mW2*mZ2/q1/q2/q2*uk + 16.*mW2/q1*uk + 4.*uk + 8./q2*tk*uk + 4.*q1/mW2/mZ2*tk*uk - 24./q1*tk*uk - 4./mW2*tk*uk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); Val += 4.*(q2*(uk+2.*s+q2)+q1*(s+q1))/mW2/mZ2*uk + 16.*(uk+s)/q2*uk - 4.*(2.*uk+4.*s+q2)/mW2*uk - 4.*(2.*uk+5.*s+q2+2.*q1-mW2)/mZ2*uk + 4.*q1*s*(s+q1)/mW2/mZ2 + 16.*s*(s+q2-mZ2-mW2)/q1 - 4.*s*(4.*s+q2+q1)/mW2 + 16.*mW2*mZ2*s/q1/q2 + 4.*s + 16.*mZ2*(tk-2.*mW2)/q1/q2/q2*tk*uk + 16.*(2.*mZ2+mW2-tk)/q1/q2*tk*uk + 16.*mW2*(s-mZ2-mW2)/q1/q2*uk + 16.*mZ2*(q1-2.*mW2)/q2/q2*uk + 32.*mW2*mW2*mZ2/q1/q2/q2*uk + 16.*mW2/q1*uk + 4.*uk + 8./q2*tk*uk + 4.*q1/mW2/mZ2*tk*uk - 24./q1*tk*uk - 4./mW2*tk*uk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); return Val; } Energy2 t_u_Rud(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1,Energy2 q2, Energy2 q1h,Energy2 q2h,Energy2 mW2, Energy2 mZ2) { Energy2 Val(0.*GeV2); Val += (uk*s*(uk+3.*s+q1h)+s*s*(s+mZ2)-(s+uk)*(2.*mZ2*s+3.*mW2*s+mW2*q1h) ) * 8./q1/q2h/q2*uk - (uk*(uk+3.*s+q1h-mW2)-(q2+s)*(q2-s)+s*(q2-mW2)+q1h*(q2-mW2)+mW2*q2 ) * 4.*s/mZ2/q1/q2h*uk - 4.*((s+uk+q2h-2.*mZ2)*(s+q1h-mZ2)-mZ2*q1)/mW2/q2*uk + 4.*(2.*s*uk+2.*mW2*uk+5.*s*s+2.*q1h*s-2.*mZ2*s)/q1/q2h*uk + 4.*(2.*s*uk-s*s-2.*q1h*s+2.*mW2*s+2.*mW2*q1h)/q1/q2h/q2*tk*uk + ((2.*uk+s)*(s+q1h)+s*(q2+q2h)+2.*q2*(s+q2h)-q1*s+q1*q2+q1h*q2h ) /mW2/mZ2*uk + 8.*s*(uk-q1h+mZ2)/q1/q2*uk + 4.*s*(-uk+s-q2+q1+q1h)/mZ2/q2h*uk + 4.*s*(-uk-q2+q1h)/mZ2/q1*uk + 8.*(mZ2*uk-s*s+mW2*s-2.*mZ2*q1-2.*mZ2*q1h)/q2h/q2*uk + 2.*(-uk-9.*s-4.*q2-5.*q2h-3.*q1-4.*q1h+8.*mZ2)/mW2*uk + 2.*(-4.*uk+3.*s+5.*q1+4.*q1h)/q2h*uk + 2.*(s*tk+q2*tk+s*s-q2*q2+q1h*q2)/mW2/mZ2*tk - 8.*s*(tk+s+q1h)/mW2/q2*tk + 2.*(-tk+3.*s+q2-q1h)/mW2*tk - 8.*s*s*s/q1h/q2 - 2.*s*q2*(s+q2)/mW2/mZ2 + 2.*s*(2.*s+q2)/mZ2 + 2.*s*(2.*s+q2)/mW2 - 16.*s*s/q1h - 2.*s - 16.*s*s/q1h/q2*tk - 8.*s/q2*tk - 16.*s/q1h*tk + 6.*s/mZ2*tk + 4.*s/q1*uk + 4.*s/mZ2*uk + 12.*uk + 4.*s*(tk+q1h-mW2)/mZ2/q1/q2h*tk*uk + 2.*(s+4.*q1+5.*q1h-4.*mZ2)/q2*uk - 4.*s*s*s/q1h/q1/q2h/q2*tk*uk - 4.*s*s/q1h/q2h/q2*tk*uk - 4.*s*s/q1h/q1/q2*tk*uk + 8.*s*s/mW2/q1h/q2*tk*uk - 4.*s*s/q1h/q1/q2h*tk*uk + 4.*(s+mZ2)/mW2/q2*tk*uk - 4.*s/q1h/q2h*tk*uk - 4.*s/q1h/q1*tk*uk + 12.*s/mW2/q1h*tk*uk - (s+4.*q2)/mW2/mZ2*tk*uk - 4.*(s+2.*mZ2)/q2h/q2*tk*uk - 4.*(3.*s+2.*q1h)/q1/q2*tk*uk - 8.*mW2/q1/q2h*tk*uk + 8./q2h*tk*uk + 8./q1*tk*uk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); swap(q1h,q2h); // Note this swap is done in accordance with MC@NLO. // It is not in NPB 383(1992)3-44 Eq.C.4! Val += (uk*s*(uk+3.*s+q1h)+s*s*(s+mZ2)-(s+uk)*(2.*mZ2*s+3.*mW2*s+mW2*q1h) ) * 8./q1/q2h/q2*uk - (uk*(uk+3.*s+q1h-mW2)-(q2+s)*(q2-s)+s*(q2-mW2)+q1h*(q2-mW2)+mW2*q2 ) * 4.*s/mZ2/q1/q2h*uk - 4.*((s+uk+q2h-2.*mZ2)*(s+q1h-mZ2)-mZ2*q1)/mW2/q2*uk + 4.*(2.*s*uk+2.*mW2*uk+5.*s*s+2.*q1h*s-2.*mZ2*s)/q1/q2h*uk + 4.*(2.*s*uk-s*s-2.*q1h*s+2.*mW2*s+2.*mW2*q1h)/q1/q2h/q2*tk*uk + ((2.*uk+s)*(s+q1h)+s*(q2+q2h)+2.*q2*(s+q2h)-q1*s+q1*q2+q1h*q2h ) /mW2/mZ2*uk + 8.*s*(uk-q1h+mZ2)/q1/q2*uk + 4.*s*(-uk+s-q2+q1+q1h)/mZ2/q2h*uk + 4.*s*(-uk-q2+q1h)/mZ2/q1*uk + 8.*(mZ2*uk-s*s+mW2*s-2.*mZ2*q1-2.*mZ2*q1h)/q2h/q2*uk + 2.*(-uk-9.*s-4.*q2-5.*q2h-3.*q1-4.*q1h+8.*mZ2)/mW2*uk + 2.*(-4.*uk+3.*s+5.*q1+4.*q1h)/q2h*uk + 2.*(s*tk+q2*tk+s*s-q2*q2+q1h*q2)/mW2/mZ2*tk - 8.*s*(tk+s+q1h)/mW2/q2*tk + 2.*(-tk+3.*s+q2-q1h)/mW2*tk - 8.*s*s*s/q1h/q2 - 2.*s*q2*(s+q2)/mW2/mZ2 + 2.*s*(2.*s+q2)/mZ2 + 2.*s*(2.*s+q2)/mW2 - 16.*s*s/q1h - 2.*s - 16.*s*s/q1h/q2*tk - 8.*s/q2*tk - 16.*s/q1h*tk + 6.*s/mZ2*tk + 4.*s/q1*uk + 4.*s/mZ2*uk + 12.*uk + 4.*s*(tk+q1h-mW2)/mZ2/q1/q2h*tk*uk + 2.*(s+4.*q1+5.*q1h-4.*mZ2)/q2*uk - 4.*s*s*s/q1h/q1/q2h/q2*tk*uk - 4.*s*s/q1h/q2h/q2*tk*uk - 4.*s*s/q1h/q1/q2*tk*uk + 8.*s*s/mW2/q1h/q2*tk*uk - 4.*s*s/q1h/q1/q2h*tk*uk + 4.*(s+mZ2)/mW2/q2*tk*uk - 4.*s/q1h/q2h*tk*uk - 4.*s/q1h/q1*tk*uk + 12.*s/mW2/q1h*tk*uk - (s+4.*q2)/mW2/mZ2*tk*uk - 4.*(s+2.*mZ2)/q2h/q2*tk*uk - 4.*(3.*s+2.*q1h)/q1/q2*tk*uk - 8.*mW2/q1/q2h*tk*uk + 8./q2h*tk*uk + 8./q1*tk*uk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); swap(q1h,q2h); // Note this swap is done in accordance with MC@NLO. // It is not in NPB 383(1992)3-44 Eq.C.4! swap(tk,uk); swap(q1,q2h); swap(q2,q1h); Val += (uk*s*(uk+3.*s+q1h)+s*s*(s+mZ2)-(s+uk)*(2.*mZ2*s+3.*mW2*s+mW2*q1h) ) * 8./q1/q2h/q2*uk - (uk*(uk+3.*s+q1h-mW2)-(q2+s)*(q2-s)+s*(q2-mW2)+q1h*(q2-mW2)+mW2*q2 ) * 4.*s/mZ2/q1/q2h*uk - 4.*((s+uk+q2h-2.*mZ2)*(s+q1h-mZ2)-mZ2*q1)/mW2/q2*uk + 4.*(2.*s*uk+2.*mW2*uk+5.*s*s+2.*q1h*s-2.*mZ2*s)/q1/q2h*uk + 4.*(2.*s*uk-s*s-2.*q1h*s+2.*mW2*s+2.*mW2*q1h)/q1/q2h/q2*tk*uk + ((2.*uk+s)*(s+q1h)+s*(q2+q2h)+2.*q2*(s+q2h)-q1*s+q1*q2+q1h*q2h ) /mW2/mZ2*uk + 8.*s*(uk-q1h+mZ2)/q1/q2*uk + 4.*s*(-uk+s-q2+q1+q1h)/mZ2/q2h*uk + 4.*s*(-uk-q2+q1h)/mZ2/q1*uk + 8.*(mZ2*uk-s*s+mW2*s-2.*mZ2*q1-2.*mZ2*q1h)/q2h/q2*uk + 2.*(-uk-9.*s-4.*q2-5.*q2h-3.*q1-4.*q1h+8.*mZ2)/mW2*uk + 2.*(-4.*uk+3.*s+5.*q1+4.*q1h)/q2h*uk + 2.*(s*tk+q2*tk+s*s-q2*q2+q1h*q2)/mW2/mZ2*tk - 8.*s*(tk+s+q1h)/mW2/q2*tk + 2.*(-tk+3.*s+q2-q1h)/mW2*tk - 8.*s*s*s/q1h/q2 - 2.*s*q2*(s+q2)/mW2/mZ2 + 2.*s*(2.*s+q2)/mZ2 + 2.*s*(2.*s+q2)/mW2 - 16.*s*s/q1h - 2.*s - 16.*s*s/q1h/q2*tk - 8.*s/q2*tk - 16.*s/q1h*tk + 6.*s/mZ2*tk + 4.*s/q1*uk + 4.*s/mZ2*uk + 12.*uk + 4.*s*(tk+q1h-mW2)/mZ2/q1/q2h*tk*uk + 2.*(s+4.*q1+5.*q1h-4.*mZ2)/q2*uk - 4.*s*s*s/q1h/q1/q2h/q2*tk*uk - 4.*s*s/q1h/q2h/q2*tk*uk - 4.*s*s/q1h/q1/q2*tk*uk + 8.*s*s/mW2/q1h/q2*tk*uk - 4.*s*s/q1h/q1/q2h*tk*uk + 4.*(s+mZ2)/mW2/q2*tk*uk - 4.*s/q1h/q2h*tk*uk - 4.*s/q1h/q1*tk*uk + 12.*s/mW2/q1h*tk*uk - (s+4.*q2)/mW2/mZ2*tk*uk - 4.*(s+2.*mZ2)/q2h/q2*tk*uk - 4.*(3.*s+2.*q1h)/q1/q2*tk*uk - 8.*mW2/q1/q2h*tk*uk + 8./q2h*tk*uk + 8./q1*tk*uk; swap(tk,uk); swap(q1,q2h); swap(q2,q1h); swap(mW2,mZ2); swap(q1,q1h); swap(q2,q2h); Val += (uk*s*(uk+3.*s+q1h)+s*s*(s+mZ2)-(s+uk)*(2.*mZ2*s+3.*mW2*s+mW2*q1h) ) * 8./q1/q2h/q2*uk - (uk*(uk+3.*s+q1h-mW2)-(q2+s)*(q2-s)+s*(q2-mW2)+q1h*(q2-mW2)+mW2*q2 ) * 4.*s/mZ2/q1/q2h*uk - 4.*((s+uk+q2h-2.*mZ2)*(s+q1h-mZ2)-mZ2*q1)/mW2/q2*uk + 4.*(2.*s*uk+2.*mW2*uk+5.*s*s+2.*q1h*s-2.*mZ2*s)/q1/q2h*uk + 4.*(2.*s*uk-s*s-2.*q1h*s+2.*mW2*s+2.*mW2*q1h)/q1/q2h/q2*tk*uk + ((2.*uk+s)*(s+q1h)+s*(q2+q2h)+2.*q2*(s+q2h)-q1*s+q1*q2+q1h*q2h ) /mW2/mZ2*uk + 8.*s*(uk-q1h+mZ2)/q1/q2*uk + 4.*s*(-uk+s-q2+q1+q1h)/mZ2/q2h*uk + 4.*s*(-uk-q2+q1h)/mZ2/q1*uk + 8.*(mZ2*uk-s*s+mW2*s-2.*mZ2*q1-2.*mZ2*q1h)/q2h/q2*uk + 2.*(-uk-9.*s-4.*q2-5.*q2h-3.*q1-4.*q1h+8.*mZ2)/mW2*uk + 2.*(-4.*uk+3.*s+5.*q1+4.*q1h)/q2h*uk + 2.*(s*tk+q2*tk+s*s-q2*q2+q1h*q2)/mW2/mZ2*tk - 8.*s*(tk+s+q1h)/mW2/q2*tk + 2.*(-tk+3.*s+q2-q1h)/mW2*tk - 8.*s*s*s/q1h/q2 - 2.*s*q2*(s+q2)/mW2/mZ2 + 2.*s*(2.*s+q2)/mZ2 + 2.*s*(2.*s+q2)/mW2 - 16.*s*s/q1h - 2.*s - 16.*s*s/q1h/q2*tk - 8.*s/q2*tk - 16.*s/q1h*tk + 6.*s/mZ2*tk + 4.*s/q1*uk + 4.*s/mZ2*uk + 12.*uk + 4.*s*(tk+q1h-mW2)/mZ2/q1/q2h*tk*uk + 2.*(s+4.*q1+5.*q1h-4.*mZ2)/q2*uk - 4.*s*s*s/q1h/q1/q2h/q2*tk*uk - 4.*s*s/q1h/q2h/q2*tk*uk - 4.*s*s/q1h/q1/q2*tk*uk + 8.*s*s/mW2/q1h/q2*tk*uk - 4.*s*s/q1h/q1/q2h*tk*uk + 4.*(s+mZ2)/mW2/q2*tk*uk - 4.*s/q1h/q2h*tk*uk - 4.*s/q1h/q1*tk*uk + 12.*s/mW2/q1h*tk*uk - (s+4.*q2)/mW2/mZ2*tk*uk - 4.*(s+2.*mZ2)/q2h/q2*tk*uk - 4.*(3.*s+2.*q1h)/q1/q2*tk*uk - 8.*mW2/q1/q2h*tk*uk + 8./q2h*tk*uk + 8./q1*tk*uk; swap(mW2,mZ2); swap(q1,q1h); swap(q2,q2h); return Val; } Energy2 t_u_Ruu(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1h,Energy2 q2h, Energy2 mW2, Energy2 mZ2) { return t_u_Rdd(s,tk,uk,q1h,q2h,mZ2,mW2); } Energy4 t_u_RZds(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1,Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2) { Energy4 Val(0.*GeV2*GeV2); Energy2 sig(mZ2+mW2); Val += ( q1*q2*(5./2.*s*s+5.*s*tk+3.*tk*tk)+(tk*uk*uk+q1*q1*q2)*(tk+s) + q1*(tk*tk*uk+s*uk*uk-s*s*tk+s*s*uk)+q1*q1*q1*(uk+s)-q1*q1*s*s2 ) * 8./q1/q2 - ( tk*tk*(4.*uk+s+q1-2.*q2)+tk*(sqr(q1+q2)-q1*s-3.*q2*s-2.*q1*q1) - q1*s*(4.*s-2.*q1-q2)+tk*uk*(q1+3.*s) ) * 4.*sig/q1/q2 - 4.*sig*sig*(s*(2.*s+q1)+tk*(uk+5./2.*tk+5.*s+q1+q2) )/mW2/mZ2 + 2.*sig*s2*(4.*sqr(s+tk)+tk*(uk+s+4.*q1+2.*q2)+2.*q1*(2.*s+q1) )/mW2/mZ2 + 4.*sig*sig*(s2+s-q1+q2)/q1/q2*tk - 16.*mW2*mZ2*(tk*uk/2.+q2*tk-q1*s)/q1/q2 - 4.*s2*s2*q1*(tk+s+q1)/mW2/mZ2 + sig*sig*sig*(uk+tk)/mW2/mZ2 + 4.*mW2*mZ2*sig*(uk+tk)/q1/q2; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); Val += ( q1*q2*(5./2.*s*s+5.*s*tk+3.*tk*tk)+(tk*uk*uk+q1*q1*q2)*(tk+s) + q1*(tk*tk*uk+s*uk*uk-s*s*tk+s*s*uk)+q1*q1*q1*(uk+s)-q1*q1*s*s2 ) * 8./q1/q2 - ( tk*tk*(4.*uk+s+q1-2.*q2)+tk*(sqr(q1+q2)-q1*s-3.*q2*s-2.*q1*q1) - q1*s*(4.*s-2.*q1-q2)+tk*uk*(q1+3.*s) ) * 4.*sig/q1/q2 - 4.*sig*sig*(s*(2.*s+q1)+tk*(uk+5./2.*tk+5.*s+q1+q2) )/mW2/mZ2 + 2.*sig*s2*(4.*sqr(s+tk)+tk*(uk+s+4.*q1+2.*q2)+2.*q1*(2.*s+q1) )/mW2/mZ2 + 4.*sig*sig*(s2+s-q1+q2)/q1/q2*tk - 16.*mW2*mZ2*(tk*uk/2.+q2*tk-q1*s)/q1/q2 - 4.*s2*s2*q1*(tk+s+q1)/mW2/mZ2 + sig*sig*sig*(uk+tk)/mW2/mZ2 + 4.*mW2*mZ2*sig*(uk+tk)/q1/q2; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); return Val; } Energy4 t_u_RZda(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1,Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2) { Energy4 Val(0.*GeV2*GeV2); Val += 4.*mZ2*(2.*uk*uk-s*tk+q1*(uk-tk-s+q1+0.5*q2)+q2*(s-3.*q2) ) /q1/q2*tk - 4.*mZ2*mZ2*(q1-tk-2.*s-q2)/q1/q2*tk - 2.*mZ2*(tk+2.*s+2.*q2)/mW2*tk - 2.*s2*(s+2.*q2)/mZ2*tk + 8.*mW2*mZ2*mZ2/q1/q2*tk + 2.*mZ2*mZ2/mW2*tk; swap(mW2,mZ2); // N.B. Here we subtract! Val -= 4.*mZ2*(2.*uk*uk-s*tk+q1*(uk-tk-s+q1+0.5*q2)+q2*(s-3.*q2) ) /q1/q2*tk - 4.*mZ2*mZ2*(q1-tk-2.*s-q2)/q1/q2*tk - 2.*mZ2*(tk+2.*s+2.*q2)/mW2*tk - 2.*s2*(s+2.*q2)/mZ2*tk + 8.*mW2*mZ2*mZ2/q1/q2*tk + 2.*mZ2*mZ2/mW2*tk; swap(mW2,mZ2); swap(q1,q2); // N.B. Here we subtract! swap(tk,uk); Val -= 4.*mZ2*(2.*uk*uk-s*tk+q1*(uk-tk-s+q1+0.5*q2)+q2*(s-3.*q2) ) /q1/q2*tk - 4.*mZ2*mZ2*(q1-tk-2.*s-q2)/q1/q2*tk - 2.*mZ2*(tk+2.*s+2.*q2)/mW2*tk - 2.*s2*(s+2.*q2)/mZ2*tk + 8.*mW2*mZ2*mZ2/q1/q2*tk + 2.*mZ2*mZ2/mW2*tk; swap(q1,q2); swap(tk,uk); swap(mW2,mZ2); // N.B. Here we add! swap(q1,q2); swap(tk,uk); Val += 4.*mZ2*(2.*uk*uk-s*tk+q1*(uk-tk-s+q1+0.5*q2)+q2*(s-3.*q2) ) /q1/q2*tk - 4.*mZ2*mZ2*(q1-tk-2.*s-q2)/q1/q2*tk - 2.*mZ2*(tk+2.*s+2.*q2)/mW2*tk - 2.*s2*(s+2.*q2)/mZ2*tk + 8.*mW2*mZ2*mZ2/q1/q2*tk + 2.*mZ2*mZ2/mW2*tk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); return Val; } Energy4 t_u_RZd(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1 , Energy2 q2 , Energy2 s2, Energy2 mW2, Energy2 mZ2) { Energy4 Val(0.*GeV2*GeV2); Val = t_u_RZds(s,tk,uk,q1,q2,s2,mW2,mZ2) + t_u_RZda(s,tk,uk,q1,q2,s2,mW2,mZ2); return Val; } Energy4 t_u_RZu(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1h, Energy2 q2h, Energy2 s2, Energy2 mW2, Energy2 mZ2) { Energy4 Val(0.*GeV2*GeV2); Val = t_u_RZd(s,tk,uk,q1h,q2h,s2,mZ2,mW2); return Val; } Energy6 t_u_RZs(Energy2 s,Energy2 tk,Energy2 uk,Energy2 q1,Energy2 q2, Energy2 s2,Energy2 mW2,Energy2 mZ2) { Energy6 Val(0.*GeV2*GeV2*GeV2); Energy2 sig(mZ2+mW2); Val += 2.*sig*sig*s2*( tk*(3.*uk+9.*tk+19.*s+6.*q1+4.*q2)+8.*s*s+6.*q1*s + 2.*q1*q1 )/mW2/mZ2 - 2.*sig*sig*sig*(tk*(3.*uk+6.*tk+11.*s+2.*q1+2.*q2)+2.*s*(2.*s+q1)) / mW2/mZ2 - 2.*sig*s2*s2*(tk*(uk+4.*tk+9.*s+6.*q1+2.*q2)+4.*sqr(s+q1)-2.*q1*s) /mW2/mZ2 - 16.*sig*(2.*tk*(uk/2.-tk-s+q1+q2)-s*(3.*s/2.-2.*q1)) + 8.*s2*(s*(s/2.+tk)+4.*q1*(tk+s+q1)) + 4.*s2*s2*s2*q1*(tk+s+q1)/mW2/mZ2 + 8.*sig*sig*(2.*tk+s/2.) + 2.*sig*sig*sig*sig*tk/mW2/mZ2 + 32.*mW2*mZ2*s; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); Val += 2.*sig*sig*s2*( tk*(3.*uk+9.*tk+19.*s+6.*q1+4.*q2)+8.*s*s+6.*q1*s + 2.*q1*q1 )/mW2/mZ2 - 2.*sig*sig*sig*(tk*(3.*uk+6.*tk+11.*s+2.*q1+2.*q2)+2.*s*(2.*s+q1)) / mW2/mZ2 - 2.*sig*s2*s2*(tk*(uk+4.*tk+9.*s+6.*q1+2.*q2)+4.*sqr(s+q1)-2.*q1*s) /mW2/mZ2 - 16.*sig*(2.*tk*(uk/2.-tk-s+q1+q2)-s*(3.*s/2.-2.*q1)) + 8.*s2*(s*(s/2.+tk)+4.*q1*(tk+s+q1)) + 4.*s2*s2*s2*q1*(tk+s+q1)/mW2/mZ2 + 8.*sig*sig*(2.*tk+s/2.) + 2.*sig*sig*sig*sig*tk/mW2/mZ2 + 32.*mW2*mZ2*s; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); return Val; } Energy6 t_u_RZa(Energy2 s,Energy2 tk,Energy2 uk,Energy2 q1,Energy2 q2, Energy2 s2,Energy2 mW2,Energy2 mZ2) { Energy6 Val(0.*GeV2*GeV2*GeV2); Val += - 2.*mZ2*(2.*tk+11.*s+18.*q2)*tk - 2.*mZ2*mZ2*(2.*tk+3.*s+2.*q2)/mW2*tk + 2.*mZ2*s2*(tk+3.*s+4.*q2)/mW2*tk - 2.*s2*s2*(s+2.*q2)/mW2*tk + 2.*mZ2*mZ2*mZ2/mW2*tk + 20.*mZ2*mZ2*tk; swap(mW2,mZ2); Val -= - 2.*mZ2*(2.*tk+11.*s+18.*q2)*tk - 2.*mZ2*mZ2*(2.*tk+3.*s+2.*q2)/mW2*tk + 2.*mZ2*s2*(tk+3.*s+4.*q2)/mW2*tk - 2.*s2*s2*(s+2.*q2)/mW2*tk + 2.*mZ2*mZ2*mZ2/mW2*tk + 20.*mZ2*mZ2*tk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); Val -= - 2.*mZ2*(2.*tk+11.*s+18.*q2)*tk - 2.*mZ2*mZ2*(2.*tk+3.*s+2.*q2)/mW2*tk + 2.*mZ2*s2*(tk+3.*s+4.*q2)/mW2*tk - 2.*s2*s2*(s+2.*q2)/mW2*tk + 2.*mZ2*mZ2*mZ2/mW2*tk + 20.*mZ2*mZ2*tk; swap(q1,q2); swap(tk,uk); swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); Val += - 2.*mZ2*(2.*tk+11.*s+18.*q2)*tk - 2.*mZ2*mZ2*(2.*tk+3.*s+2.*q2)/mW2*tk + 2.*mZ2*s2*(tk+3.*s+4.*q2)/mW2*tk - 2.*s2*s2*(s+2.*q2)/mW2*tk + 2.*mZ2*mZ2*mZ2/mW2*tk + 20.*mZ2*mZ2*tk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); return Val; } Energy6 t_u_RZ(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2) { Energy6 Val(0.*GeV2*GeV2*GeV2); Val = t_u_RZs(s,tk,uk,q1,q2,s2,mW2,mZ2) + t_u_RZa(s,tk,uk,q1,q2,s2,mW2,mZ2); return Val; } /***************************************************************************/ // t_u_M_R_qg is the real emission q + qb -> n + g matrix element // exactly as defined in Eqs. C.9 of NPB 383(1992)3-44, multiplied by // tk * uk! Energy2 MEPP2VVPowheg::t_u_M_R_qg(realVVKinematics R) const { // First the Born variables: Energy2 s2(R.s2r()); Energy2 mW2(R.k12r()); Energy2 mZ2(R.k22r()); // Then the rest: Energy2 s(R.sr()); Energy2 tk(R.tkr()); Energy2 uk(R.ukr()); Energy2 q1(R.q1r()); Energy2 q2(R.q2r()); Energy2 q1h(R.q1hatr()); Energy2 q2h(R.q2hatr()); Energy2 w1(R.w1r()); Energy2 w2(R.w2r()); double cosThetaW(sqrt(1.-sin2ThetaW_)); double eZ2(eZ2_); double eZ(eZ_); double gdL(gdL_); double guL(guL_); double gdR(gdR_); double guR(guR_); // W+W- if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { double e2(sqr(gW_)*sin2ThetaW_); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(guL-guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *( 2./3.+2.*eZ*guL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } gdL = gW_/sqrt(2.); guL = 0.; } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(gdL-gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *(-1./3.+2.*eZ*gdL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } guL = gW_/sqrt(2.); gdL = 0.; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { eZ = 0.; eZ2 = 0.; double gV2,gA2; gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL; else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL; else { cout << "MEPP2VVPowheg:" << endl; cout << "ZZ needs 2 down-type / 2 up-type!" << endl; } } Energy2 Val(0.*GeV2); swap(s,tk); swap(q2,w2); swap(q2h,w1); Val = -2.*pi*alphaS_*Fij2_*CF_/NC_ * ( gdL*gdL*t_u_Rdd(s,tk,uk,q1,q2,mW2,mZ2) + 2.*gdL*guL*t_u_Rud(s,tk,uk,q1,q2,q1h,q2h,mW2,mZ2) + guL*guL*t_u_Ruu(s,tk,uk,q1h,q2h,mW2,mZ2) - 2.*eZ/(s2-mW2) * ( gdL * t_u_RZd(s,tk,uk,q1 ,q2 ,s2,mW2,mZ2) - guL * t_u_RZu(s,tk,uk,q1h,q2h,s2,mW2,mZ2) ) + eZ2/sqr(s2-mW2) *t_u_RZ(s,tk,uk,q1,q2,s2,mW2,mZ2) ); swap(s,tk); swap(q2,w2); swap(q2h,w1); Val *= -tk/s * TR_/CF_; return Val; } /***************************************************************************/ // t_u_M_R_gqb is the real emission g + qb -> n + q matrix element // exactly as defined in Eqs. C.9 of NPB 383(1992)3-44, multiplied by // tk * uk! Energy2 MEPP2VVPowheg::t_u_M_R_gqb(realVVKinematics R) const { // First the Born variables: Energy2 s2(R.s2r()); Energy2 mW2(R.k12r()); Energy2 mZ2(R.k22r()); // Then the rest: Energy2 s(R.sr()); Energy2 tk(R.tkr()); Energy2 uk(R.ukr()); Energy2 q1(R.q1r()); Energy2 q2(R.q2r()); Energy2 q1h(R.q1hatr()); Energy2 q2h(R.q2hatr()); Energy2 w1(R.w1r()); Energy2 w2(R.w2r()); double cosThetaW(sqrt(1.-sin2ThetaW_)); double eZ2(eZ2_); double eZ(eZ_); double gdL(gdL_); double guL(guL_); double gdR(gdR_); double guR(guR_); // W+W- if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { double e2(sqr(gW_)*sin2ThetaW_); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(guL-guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *( 2./3.+2.*eZ*guL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } gdL = gW_/sqrt(2.); guL = 0.; } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(gdL-gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *(-1./3.+2.*eZ*gdL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } guL = gW_/sqrt(2.); gdL = 0.; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { eZ = 0.; eZ2 = 0.; double gV2,gA2; gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL; else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL; else { cout << "MEPP2VVPowheg:" << endl; cout << "ZZ needs 2 down-type / 2 up-type!" << endl; } } Energy2 Val(0.*GeV2); swap(s,uk); swap(q1,w1); swap(q1h,w2); Val = -2.*pi*alphaS_*Fij2_*CF_/NC_ * ( gdL*gdL*t_u_Rdd(s,tk,uk,q1,q2,mW2,mZ2) + 2.*gdL*guL*t_u_Rud(s,tk,uk,q1,q2,q1h,q2h,mW2,mZ2) + guL*guL*t_u_Ruu(s,tk,uk,q1h,q2h,mW2,mZ2) - 2.*eZ/(s2-mW2) * ( gdL * t_u_RZd(s,tk,uk,q1 ,q2 ,s2,mW2,mZ2) - guL * t_u_RZu(s,tk,uk,q1h,q2h,s2,mW2,mZ2) ) + eZ2/sqr(s2-mW2) *t_u_RZ(s,tk,uk,q1,q2,s2,mW2,mZ2) ); swap(s,uk); swap(q1,w1); swap(q1h,w2); Val *= -uk/s * TR_/CF_; return Val; } /***************************************************************************/ // The following six functions are I_{dd}^{(0)}, I_{ud}^{(0)}, // I_{uu}^{(0)}, F_{u}^{(0)}, F_{d}^{(0)}, H^{(0)} from Eqs. 3.9 - 3.14 // They make up the Born matrix element. Ixx functions correspond to the // graphs with no TGC, Fx functions are due to non-TGC graphs interfering // with TGC graphs, while the H function is due purely to TGC graphs. double Idd0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); double Iud0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); double Iuu0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); Energy2 Fu0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); Energy2 Fd0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); Energy4 H0 (Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); /***************************************************************************/ // M_Born_WZ is the Born matrix element exactly as defined in Eqs. 3.3-3.14 // of of NPB 383(1992)3-44 (with a spin*colour averaging factor 1./4./NC_/NC_). double MEPP2VVPowheg::M_Born_WZ(bornVVKinematics B) const { Energy2 s(B.sb()); Energy2 t(B.tb()); Energy2 u(B.ub()); Energy2 mW2(B.k12b()); // N.B. the diboson masses are preserved in getting Energy2 mZ2(B.k22b()); // the 2->2 from the 2->3 kinematics. double cosThetaW(sqrt(1.-sin2ThetaW_)); double eZ2(eZ2_); double eZ(eZ_); double gdL(gdL_); double guL(guL_); double gdR(gdR_); double guR(guR_); // W+W- if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { double e2(sqr(gW_)*sin2ThetaW_); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s-mW2)/Fij2_ * (e2*e2/s/s*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s/(s-mW2/sqr(cosThetaW))) +sqr( eZ*(guL-guR)/2./e2*s/(s-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s-mW2) * (gW_*gW_*e2/4./s *( 2./3.+2.*eZ*guL/2./e2*s/(s-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } gdL = gW_/sqrt(2.); guL = 0.; } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s-mW2)/Fij2_ * (e2*e2/s/s*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s/(s-mW2/sqr(cosThetaW))) +sqr( eZ*(gdL-gdR)/2./e2*s/(s-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s-mW2) * (gW_*gW_*e2/4./s *(-1./3.+2.*eZ*gdL/2./e2*s/(s-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } guL = gW_/sqrt(2.); gdL = 0.; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { eZ = 0.; eZ2 = 0.; double gV2,gA2; gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL; else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL; else { cout << "MEPP2VVPowheg:" << endl; cout << "ZZ needs 2 down-type / 2 up-type!" << endl; } } return Fij2_/2./NC_ * ( gdL*gdL*Idd0(s,t,u,mW2,mZ2) + 2.*gdL*guL*Iud0(s,t,u,mW2,mZ2) + guL*guL*Iuu0(s,t,u,mW2,mZ2) - 2.*eZ/(s-mW2) * ( gdL*Fd0(s,t,u,mW2,mZ2) - guL*Fu0(s,t,u,mW2,mZ2) ) + eZ2/sqr(s-mW2) * H0(s,t,u,mW2,mZ2) ); } /***************************************************************************/ double Idd0(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return 8.*((u*t/mW2/mZ2-1.)/4.+s/2.*(mW2+mZ2)/mW2/mZ2) + 8.*(u/t-mW2*mZ2/t/t); } /***************************************************************************/ double Iud0(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return - 8.*((u*t/mW2/mZ2-1.)/4.+s/2.*(mW2+mZ2)/mW2/mZ2) + 8.*s/t/u*(mW2+mZ2); } /***************************************************************************/ double Iuu0(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return Idd0(s,u,t,mW2,mZ2); } /***************************************************************************/ Energy2 Fd0 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return - 8.*s*( (u*t/mW2/mZ2-1.)*(1.-(mW2+mZ2)/s-4.*mW2*mZ2/s/t)/4. + (mW2+mZ2)/2./mW2/mZ2*(s-mW2-mZ2+2.*mW2*mZ2/t) ); } /***************************************************************************/ Energy2 Fu0 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return Fd0(s,u,t,mW2,mZ2); } /***************************************************************************/ Energy4 H0 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return 8.*s*s*(u*t/mW2/mZ2-1.)*( 1./4.-(mW2+mZ2)/2./s + (sqr(mW2+mZ2)+8.*mW2*mZ2)/4./s/s ) + 8.*s*s*(mW2+mZ2)/mW2/mZ2*(s/2.-mW2-mZ2+sqr(mW2-mZ2)/2./s); } /***************************************************************************/ bool MEPP2VVPowheg::sanityCheck() const { bool alarm(false); Energy2 prefacs(8.*pi*alphaS_*S_.sr() /S_.xr() ); Energy2 prefacsp(8.*pi*alphaS_*SCp_.sr() /SCp_.xr() ); Energy2 prefacsm(8.*pi*alphaS_*SCm_.sr() /SCm_.xr() ); Energy2 prefacp(8.*pi*alphaS_*Cp_.sr()/Cp_.xr()); Energy2 prefacm(8.*pi*alphaS_*Cm_.sr()/Cm_.xr()); double xp(Cp_.xr()); double xm(Cm_.xr()); double M_B_WW(M_Born_WW(B_)); double M_B_ZZ(M_Born_ZZ(B_)); double M_V_reg_WW(M_V_regular_WW(S_)); double M_V_reg_ZZ(M_V_regular_ZZ(S_)); Energy2 t_u_qqb_WW(t_u_M_R_qqb_WW(H_)); Energy2 t_u_qqb_ZZ(t_u_M_R_qqb_ZZ(H_)); // Check that the native leading order Herwig matrix // element is equivalent to the WZ leading order matrix // element in NPB 383 (1992) 3-44, with the relevant WZ->WW // WZ->ZZ transformation applied (M_Born_). // if(fabs((lo_me2_ - M_Born_)/M_Born_)>1.e-2) { // alarm=true; // cout << "lo_me2_ - M_Born_ (%) = " // << lo_me2_ - M_Born_ << " (" // << (lo_me2_ - M_Born_)/M_Born_*100. << ")\n"; // } // Check that the transformation from NPB 383 (1992) 3-44 WZ // matrix elements to WW matrix elements actually works, by // comparing them to the explicit WW matrix elements in // NPB 410 (1993) 280-324. if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { if(fabs((M_Born_ -M_B_WW )/M_B_WW )>1.e-6) { alarm=true; cout << "WZ->WW transformation error!\n"; cout << "M_Born_ - M_B_WW (rel) = " << M_Born_ - M_B_WW << " (" << (M_Born_ - M_B_WW)/M_B_WW << ")\n"; cout << "M_Born_ = " << M_Born_ << endl; cout << "M_B_WW = " << M_B_WW << endl; } if(fabs((M_V_regular_-M_V_reg_WW)/M_V_reg_WW)>1.e-6) { alarm=true; cout << "WZ->WW transformation error!\n"; cout << "M_V_regular_ - M_V_reg_WW (rel) = " << M_V_regular_ - M_V_reg_WW << " (" << (M_V_regular_ - M_V_reg_WW)/M_V_reg_WW << ")\n"; cout << "M_V_regular_ = " << M_V_regular_ << endl; cout << "M_V_reg_WW = " << M_V_reg_WW << endl; } if(fabs((t_u_M_R_qqb_-t_u_qqb_WW)/t_u_qqb_WW)>1.e-6) { alarm=true; cout << "WZ->WW transformation error!\n"; cout << "t_u_M_R_qqb_ - t_u_qqb_WW (rel) = " << (t_u_M_R_qqb_ - t_u_qqb_WW)/GeV2 << " (" << (t_u_M_R_qqb_ - t_u_qqb_WW)/t_u_qqb_WW << ")\n"; cout << "t_u_M_R_qqb_ = " << t_u_M_R_qqb_/GeV2 << endl; cout << "t_u_qqb_WW = " << t_u_qqb_WW /GeV2 << endl; } } // Check that the transformation from NPB 383 (1992) 3-44 WZ // matrix elements to ZZ matrix elements actually works, by // comparing them to the explicit ZZ matrix elements in // NPB 357 (1991) 409-438. if(abs(mePartonData()[2]->id())==23&&abs(mePartonData()[3]->id())==23) { if(fabs((M_Born_ -M_B_ZZ )/M_B_ZZ )>1.e-6) { alarm=true; cout << "WZ->ZZ transformation error!\n"; cout << "M_Born_ - M_B_ZZ (rel) = " << M_Born_ - M_B_ZZ << " (" << (M_Born_ - M_B_ZZ)/M_B_ZZ << ")\n"; cout << "M_Born_ = " << M_Born_ << endl; cout << "M_B_ZZ = " << M_B_ZZ << endl; } if(fabs((M_V_regular_-M_V_reg_ZZ)/M_V_reg_ZZ)>1.e-6) { alarm=true; cout << "WZ->ZZ transformation error!\n"; cout << "M_V_regular_ - M_V_reg_ZZ (rel) = " << M_V_regular_ - M_V_reg_ZZ << " (" << (M_V_regular_ - M_V_reg_ZZ)/M_V_reg_ZZ << ")\n"; cout << "M_V_regular_ = " << M_V_regular_ << endl; cout << "M_V_reg_ZZ = " << M_V_reg_ZZ << endl; } if(fabs((t_u_M_R_qqb_-t_u_qqb_ZZ)/t_u_qqb_ZZ)>1.e-6) { alarm=true; cout << "WZ->ZZ transformation error!\n"; cout << "t_u_M_R_qqb_ - t_u_qqb_ZZ (rel) = " << (t_u_M_R_qqb_ - t_u_qqb_ZZ)/GeV2 << " (" << (t_u_M_R_qqb_ - t_u_qqb_ZZ)/t_u_qqb_ZZ << ")\n"; cout << "t_u_M_R_qqb_ = " << t_u_M_R_qqb_/GeV2 << endl; cout << "t_u_qqb_ZZ = " << t_u_qqb_ZZ /GeV2 << endl; } } // Check the soft limit of the q + qbar matrix element. Energy2 absDiff_qqbs = t_u_M_R_qqb(S_) - prefacs*2.*CF_*M_Born_; double relDiff_qqbs = absDiff_qqbs / t_u_M_R_qqb(S_); if(fabs(relDiff_qqbs)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qqb(S_) " << t_u_M_R_qqb(S_) /GeV2 << endl; cout << "t_u_M_R_qqb(S_)-8*pi*alphaS*sHat/x*2*Cab*M_Born_ (rel):\n" << absDiff_qqbs / GeV2 << " (" << relDiff_qqbs << ")\n"; } // Check the positive soft-collinearlimit of the q + qbar matrix element. Energy2 absDiff_qqbsp = t_u_M_R_qqb(SCp_) - prefacsp*2.*CF_*M_Born_; double relDiff_qqbsp = absDiff_qqbsp / t_u_M_R_qqb(SCp_); if(fabs(relDiff_qqbsp)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qqb(SCp_) " << t_u_M_R_qqb(SCp_)/GeV2 << endl; cout << "t_u_M_R_qqb(SCp_)-8*pi*alphaS*sHat/x*2*Cab*M_Born_ (rel):\n" << absDiff_qqbsp / GeV2 << " (" << relDiff_qqbsp << ")\n"; } // Check the negative soft-collinearlimit of the q + qbar matrix element. Energy2 absDiff_qqbsm = t_u_M_R_qqb(SCm_) - prefacsm*2.*CF_*M_Born_; double relDiff_qqbsm = absDiff_qqbsm / t_u_M_R_qqb(SCm_); if(fabs(relDiff_qqbsm)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qqb(SCm_) " << t_u_M_R_qqb(SCm_)/GeV2 << endl; cout << "t_u_M_R_qqb(SCm_)-8*pi*alphaS*sHat/x*2*Cab*M_Born_ (rel):\n" << absDiff_qqbsm / GeV2 << " (" << relDiff_qqbsm << ")\n"; } // Check the positive collinearlimit of the q + qbar matrix element. Energy2 absDiff_qqbp = t_u_M_R_qqb(Cp_) - prefacp*CF_*(1.+xp*xp)*M_Born_; double relDiff_qqbp = absDiff_qqbp / t_u_M_R_qqb(Cp_); if(fabs(relDiff_qqbp)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qqb(Cp_) " << t_u_M_R_qqb(Cp_) /GeV2 << endl; cout << "t_u_M_R_qqb(Cp_)-8*pi*alphaS*sHat/x*(1-x)*Pqq*M_Born_ (rel):\n" << absDiff_qqbp / GeV2 << " (" << relDiff_qqbp << ")\n"; } // Check the negative collinearlimit of the q + qbar matrix element. Energy2 absDiff_qqbm = t_u_M_R_qqb(Cm_) - prefacm*CF_*(1.+xm*xm)*M_Born_; double relDiff_qqbm = absDiff_qqbm / t_u_M_R_qqb(Cm_); if(fabs(relDiff_qqbm)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qqb(Cm_) " << t_u_M_R_qqb(Cm_) /GeV2 << endl; cout << "t_u_M_R_qqb(Cm_)-8*pi*alphaS*sHat/x*(1-x)*Pqq*M_Born_ (rel):\n" << absDiff_qqbm / GeV2 << " (" << relDiff_qqbm << ")\n"; } // Check the positive collinear limit of the g + qbar matrix element. Energy2 absDiff_gqbp = t_u_M_R_gqb(Cp_) - prefacp*(1.-xp)*TR_*(xp*xp+sqr(1.-xp))*M_Born_; double relDiff_gqbp = absDiff_gqbp/ t_u_M_R_gqb(Cp_); if(fabs(relDiff_gqbp)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_gqb(Cp_) " << t_u_M_R_gqb(Cp_) /GeV2 << endl; cout << "t_u_M_R_gqb(Cp_)-8*pi*alphaS*sHat/x*(1-x)*Pgq*M_Born_ (rel):\n" << absDiff_gqbp / GeV2 << " (" << relDiff_gqbp << ")\n"; } // Check the negative collinear limit of the q + g matrix element. Energy2 absDiff_qgm = t_u_M_R_qg(Cm_) - prefacm*(1.-xm)*TR_*(xm*xm+sqr(1.-xm))*M_Born_; double relDiff_qgm = absDiff_qgm / t_u_M_R_qg(Cm_); if(fabs(relDiff_qgm)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qg(Cm_) " << t_u_M_R_qg(Cm_) /GeV2 << endl; cout << "t_u_M_R_qg(Cm_)-8*pi*alphaS*sHat/x*(1-x)*Pgq*M_Born_ (rel):\n" << absDiff_qgm / GeV2 << " (" << relDiff_qgm << ")\n"; } return alarm; } /***************************************************************************/ // M_Born_ZZ is the Born matrix element exactly as defined in Eqs. 2.18-2.19 // of of NPB 357(1991)409-438. double MEPP2VVPowheg::M_Born_ZZ(bornVVKinematics B) const { Energy2 s(B.sb()); Energy2 t(B.tb()); Energy2 u(B.ub()); Energy2 mZ2(B.k22b()); // the 2->2 from the 2->3 kinematics. double cosThetaW(sqrt(1.-sin2ThetaW_)); double gV2,gA2,gX,gY,gZ; gV2 = sqr(guL_/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL_/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); gX = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL_/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL_/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gY = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gZ = gX; if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) gZ = gY; return 1./NC_*sqr(gZ*2.)*(t/u+u/t+4.*mZ2*s/t/u-mZ2*mZ2*(1./t/t+1./u/u)); } /***************************************************************************/ // M_V_regular_ZZ is the one-loop ZZ matrix element exactly as defined in // Eqs. B.1 & B.2 of NPB 357(1991)409-438. double MEPP2VVPowheg::M_V_regular_ZZ(realVVKinematics S) const { Energy2 s(S.bornVariables().sb()); Energy2 t(S.bornVariables().tb()); Energy2 u(S.bornVariables().ub()); Energy2 mZ2(S.k22r()); // the 2->2 from the 2->3 kinematics. double beta(S.betaxr()); // N.B. for x=1 \beta_x=\beta in NPB 383(1992)3-44. double cosThetaW(sqrt(1.-sin2ThetaW_)); double gV2,gA2,gX,gY,gZ; gV2 = sqr(guL_/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL_/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); gX = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL_/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL_/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gY = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gZ = gX; if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) gZ = gY; double M_V_reg(0.); M_V_reg = 2.*s*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/sqr(4.*pi)/2. *( 2.*sqr(t+mZ2)/sqr(beta)/s/t/u + 4.*s/(t-mZ2)/u - ( 16.*t*t*t+(28.*s-68.*mZ2)*t*t+(18.*s*s-36.*mZ2*s+88.*mZ2*mZ2)*t + 18.*mZ2*mZ2*s-36.*mZ2*mZ2*mZ2 )/t/t/s/u + ( 12.*s/(t-mZ2)/u-4.*mZ2*s/sqr(t-mZ2)/u+2.*(t+4.*s)/s/u - 6.*(s*s+mZ2*mZ2)/s/t/u+6.*mZ2*mZ2*(2.*mZ2-s)/t/t/s/u )*log(-t/mZ2) + ( - ( 5.*t*t*t+(8.*s-18.*mZ2)*t*t+(6.*s*s+25.*mZ2*mZ2)*t + 6.*mZ2*mZ2*s-12.*mZ2*mZ2*mZ2 )/t/t/s/u - 12.*mZ2*sqr(t+mZ2)/sqr(sqr(beta))/s/s/t/u + ( 3.*t*t-26.*mZ2*t-25.*mZ2*mZ2)/sqr(beta)/s/t/u )*log(s/mZ2) + ( (-2.*t*t+8.*mZ2*t-2.*s*s-12.*mZ2*mZ2)/u + 4.*mZ2*mZ2*(2.*mZ2-s)/t/u) / (s*t) * ( 2.*sqr(log(-t/mZ2))-4.*log(-t/mZ2)*log((mZ2-t)/mZ2)-4.*ReLi2(t/mZ2)) + ( 4.*(t*t-5.*mZ2*t+s*s+10.*mZ2*mZ2)/s/u + 4.*mZ2*(-s*s+2.*mZ2*s-10.*mZ2*mZ2)/s/t/u + 8.*mZ2*mZ2*mZ2*(2.*mZ2-s)/t/t/s/u ) / (t-mZ2) * (pi*pi/2.+log(-t/mZ2)*log(-t/s)-1./2.*sqr(log(-t/mZ2))) + ( ( (2.*s-3.*mZ2)*t*t+(6.*mZ2*mZ2-8.*mZ2*s)*t+2.*s*s*s-4.*mZ2*s*s + 12.*mZ2*mZ2*s-3.*mZ2*mZ2*mZ2 ) /s/t/u + 12.*mZ2*mZ2*sqr(t+mZ2)/sqr(sqr(beta))/s/s/t/u - (mZ2*t*t-30.*mZ2*mZ2*t-27.*mZ2*mZ2*mZ2)/beta/beta/s/t/u ) / (beta*s) * (pi*pi/3.+sqr(log((1.-beta)/(1.+beta)))+4.*ReLi2(-(1.-beta)/(1.+beta))) + (4.*(t+4.*s-4.*mZ2)/3./s/u+4.*sqr(s-2.*mZ2)/3./s/t/u)*pi*pi ); swap(t,u); M_V_reg += 2.*s*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/sqr(4.*pi)/2. *( 2.*sqr(t+mZ2)/sqr(beta)/s/t/u + 4.*s/(t-mZ2)/u - ( 16.*t*t*t+(28.*s-68.*mZ2)*t*t+(18.*s*s-36.*mZ2*s+88.*mZ2*mZ2)*t + 18.*mZ2*mZ2*s-36.*mZ2*mZ2*mZ2 )/t/t/s/u + ( 12.*s/(t-mZ2)/u-4.*mZ2*s/sqr(t-mZ2)/u+2.*(t+4.*s)/s/u - 6.*(s*s+mZ2*mZ2)/s/t/u+6.*mZ2*mZ2*(2.*mZ2-s)/t/t/s/u )*log(-t/mZ2) + ( - ( 5.*t*t*t+(8.*s-18.*mZ2)*t*t+(6.*s*s+25.*mZ2*mZ2)*t + 6.*mZ2*mZ2*s-12.*mZ2*mZ2*mZ2 )/t/t/s/u - 12.*mZ2*sqr(t+mZ2)/sqr(sqr(beta))/s/s/t/u + ( 3.*t*t-26.*mZ2*t-25.*mZ2*mZ2)/sqr(beta)/s/t/u )*log(s/mZ2) + ( (-2.*t*t+8.*mZ2*t-2.*s*s-12.*mZ2*mZ2)/u + 4.*mZ2*mZ2*(2.*mZ2-s)/t/u) / (s*t) * ( 2.*sqr(log(-t/mZ2))-4.*log(-t/mZ2)*log((mZ2-t)/mZ2)-4.*ReLi2(t/mZ2)) + ( 4.*(t*t-5.*mZ2*t+s*s+10.*mZ2*mZ2)/s/u + 4.*mZ2*(-s*s+2.*mZ2*s-10.*mZ2*mZ2)/s/t/u + 8.*mZ2*mZ2*mZ2*(2.*mZ2-s)/t/t/s/u ) / (t-mZ2) * (pi*pi/2.+log(-t/mZ2)*log(-t/s)-1./2.*sqr(log(-t/mZ2))) + ( ( (2.*s-3.*mZ2)*t*t+(6.*mZ2*mZ2-8.*mZ2*s)*t+2.*s*s*s-4.*mZ2*s*s + 12.*mZ2*mZ2*s-3.*mZ2*mZ2*mZ2 ) /s/t/u + 12.*mZ2*mZ2*sqr(t+mZ2)/sqr(sqr(beta))/s/s/t/u - (mZ2*t*t-30.*mZ2*mZ2*t-27.*mZ2*mZ2*mZ2)/beta/beta/s/t/u ) / (beta*s) * (pi*pi/3.+sqr(log((1.-beta)/(1.+beta)))+4.*ReLi2(-(1.-beta)/(1.+beta))) + (4.*(t+4.*s-4.*mZ2)/3./s/u+4.*sqr(s-2.*mZ2)/3./s/t/u)*pi*pi ); return M_V_reg; } /***************************************************************************/ // t_u_M_R_qqb_ZZ is the real emission q + qb -> n + g matrix element // exactly as defined in Eqs. C.1 of NPB 357(1991)409-438, multiplied by // tk * uk! Energy2 MEPP2VVPowheg::t_u_M_R_qqb_ZZ(realVVKinematics R) const { // First the Born variables: Energy2 mZ2(R.k22r()); // Then the rest: Energy2 s(R.sr()); Energy2 tk(R.tkr()); Energy2 uk(R.ukr()); Energy2 q1(R.q1r()); Energy2 q2(R.q2r()); Energy2 q1h(R.q1hatr()); Energy2 q2h(R.q2hatr()); double cosThetaW(sqrt(1.-sin2ThetaW_)); double gV2,gA2,gX,gY,gZ; gV2 = sqr(guL_/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL_/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); gX = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL_/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL_/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gY = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gZ = gX; if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) gZ = gY; Energy2 t_u_qqb(0.*GeV2); t_u_qqb = (2.*s)*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/2. * ( - ( tk*uk*uk+2.*s*uk*uk-tk*tk*uk - 2.*s*tk*uk+mZ2*(tk*tk-uk*uk+2.*s*uk-2.*s*tk-2.*s*s) )/q1h/q1/q2h/s*tk + 2.*(tk*uk*uk-mZ2*uk*(s+3.*tk)+mZ2*mZ2*(2.*uk-s))/q1/q2/s + ( tk*uk*(uk+s)-mZ2*(uk*uk+3.*tk*uk+3.*s*uk+s*tk) + 2.*mZ2*mZ2*(uk+tk+2.*s) )/q1h/q1/q2/s*tk + ( tk*(uk*uk+tk*uk-s*s)+mZ2*(4.*s*uk-3.*tk*uk-tk*tk+4.*s*s) )/q1h/q2/s - ( tk*uk+s*uk-s*tk-s*s+2.*mZ2*(s-tk) ) /q1h/q1/s*tk + q2*(tk*uk-s*uk-2.*s*tk-2.*s*s)/q1/q2h/s + 2.*(tk*uk-tk*tk-s*tk-s*s+mZ2*(2.*s-uk))/q1/s - 2.*mZ2*(uk*uk-2.*mZ2*uk+2.*mZ2*mZ2)/q1/q1/q2/s*tk + (2.*s*uk+tk*tk+3.*s*tk+2*s*s)/q1h/s + q1*(uk+s)*(uk+tk)/q1h/q2h/s + (tk*uk+s*uk+3.*s*tk+2.*s*s-mZ2*(uk+tk+2.*s))/q1h/q2h/s*uk + (uk-tk)/2./q1h/q2h/s*(q1*(uk+s)/q2/tk-q2*(tk+s)/q1/uk)*tk*uk + (tk-2.*mZ2)*(uk-2.*mZ2)/q1h/q1/q2h/q2*tk*uk - (q1*q1+q2*q2)/q1/q2 - 2.*mZ2*(q2-2.*mZ2)/q1/q1/s*tk ); swap(tk ,uk ); swap(q1 ,q2 ); swap(q1h,q2h); t_u_qqb += (2.*s)*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/2. * ( - ( tk*uk*uk+2.*s*uk*uk-tk*tk*uk - 2.*s*tk*uk+mZ2*(tk*tk-uk*uk+2.*s*uk-2.*s*tk-2.*s*s) )/q1h/q1/q2h/s*tk + 2.*(tk*uk*uk-mZ2*uk*(s+3.*tk)+mZ2*mZ2*(2.*uk-s))/q1/q2/s + ( tk*uk*(uk+s)-mZ2*(uk*uk+3.*tk*uk+3.*s*uk+s*tk) + 2.*mZ2*mZ2*(uk+tk+2.*s) )/q1h/q1/q2/s*tk + ( tk*(uk*uk+tk*uk-s*s)+mZ2*(4.*s*uk-3.*tk*uk-tk*tk+4.*s*s) )/q1h/q2/s - ( tk*uk+s*uk-s*tk-s*s+2.*mZ2*(s-tk) ) /q1h/q1/s*tk + q2*(tk*uk-s*uk-2.*s*tk-2.*s*s)/q1/q2h/s + 2.*(tk*uk-tk*tk-s*tk-s*s+mZ2*(2.*s-uk))/q1/s - 2.*mZ2*(uk*uk-2.*mZ2*uk+2.*mZ2*mZ2)/q1/q1/q2/s*tk + (2.*s*uk+tk*tk+3.*s*tk+2*s*s)/q1h/s + q1*(uk+s)*(uk+tk)/q1h/q2h/s + (tk*uk+s*uk+3.*s*tk+2.*s*s-mZ2*(uk+tk+2.*s))/q1h/q2h/s*uk + (uk-tk)/2./q1h/q2h/s*(q1*(uk+s)/q2/tk-q2*(tk+s)/q1/uk)*tk*uk + (tk-2.*mZ2)*(uk-2.*mZ2)/q1h/q1/q2h/q2*tk*uk - (q1*q1+q2*q2)/q1/q2 - 2.*mZ2*(q2-2.*mZ2)/q1/q1/s*tk ); swap(tk ,uk ); swap(q1 ,q2 ); swap(q1h,q2h); swap(q1 ,q1h); swap(q2 ,q2h); t_u_qqb += (2.*s)*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/2. * ( - ( tk*uk*uk+2.*s*uk*uk-tk*tk*uk - 2.*s*tk*uk+mZ2*(tk*tk-uk*uk+2.*s*uk-2.*s*tk-2.*s*s) )/q1h/q1/q2h/s*tk + 2.*(tk*uk*uk-mZ2*uk*(s+3.*tk)+mZ2*mZ2*(2.*uk-s))/q1/q2/s + ( tk*uk*(uk+s)-mZ2*(uk*uk+3.*tk*uk+3.*s*uk+s*tk) + 2.*mZ2*mZ2*(uk+tk+2.*s) )/q1h/q1/q2/s*tk + ( tk*(uk*uk+tk*uk-s*s)+mZ2*(4.*s*uk-3.*tk*uk-tk*tk+4.*s*s) )/q1h/q2/s - ( tk*uk+s*uk-s*tk-s*s+2.*mZ2*(s-tk) ) /q1h/q1/s*tk + q2*(tk*uk-s*uk-2.*s*tk-2.*s*s)/q1/q2h/s + 2.*(tk*uk-tk*tk-s*tk-s*s+mZ2*(2.*s-uk))/q1/s - 2.*mZ2*(uk*uk-2.*mZ2*uk+2.*mZ2*mZ2)/q1/q1/q2/s*tk + (2.*s*uk+tk*tk+3.*s*tk+2*s*s)/q1h/s + q1*(uk+s)*(uk+tk)/q1h/q2h/s + (tk*uk+s*uk+3.*s*tk+2.*s*s-mZ2*(uk+tk+2.*s))/q1h/q2h/s*uk + (uk-tk)/2./q1h/q2h/s*(q1*(uk+s)/q2/tk-q2*(tk+s)/q1/uk)*tk*uk + (tk-2.*mZ2)*(uk-2.*mZ2)/q1h/q1/q2h/q2*tk*uk - (q1*q1+q2*q2)/q1/q2 - 2.*mZ2*(q2-2.*mZ2)/q1/q1/s*tk ); swap(q1 ,q1h); swap(q2 ,q2h); swap(tk ,uk ); swap(q1 ,q2h); swap(q2 ,q1h); t_u_qqb += (2.*s)*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/2. * ( - ( tk*uk*uk+2.*s*uk*uk-tk*tk*uk - 2.*s*tk*uk+mZ2*(tk*tk-uk*uk+2.*s*uk-2.*s*tk-2.*s*s) )/q1h/q1/q2h/s*tk + 2.*(tk*uk*uk-mZ2*uk*(s+3.*tk)+mZ2*mZ2*(2.*uk-s))/q1/q2/s + ( tk*uk*(uk+s)-mZ2*(uk*uk+3.*tk*uk+3.*s*uk+s*tk) + 2.*mZ2*mZ2*(uk+tk+2.*s) )/q1h/q1/q2/s*tk + ( tk*(uk*uk+tk*uk-s*s)+mZ2*(4.*s*uk-3.*tk*uk-tk*tk+4.*s*s) )/q1h/q2/s - ( tk*uk+s*uk-s*tk-s*s+2.*mZ2*(s-tk) ) /q1h/q1/s*tk + q2*(tk*uk-s*uk-2.*s*tk-2.*s*s)/q1/q2h/s + 2.*(tk*uk-tk*tk-s*tk-s*s+mZ2*(2.*s-uk))/q1/s - 2.*mZ2*(uk*uk-2.*mZ2*uk+2.*mZ2*mZ2)/q1/q1/q2/s*tk + (2.*s*uk+tk*tk+3.*s*tk+2*s*s)/q1h/s + q1*(uk+s)*(uk+tk)/q1h/q2h/s + (tk*uk+s*uk+3.*s*tk+2.*s*s-mZ2*(uk+tk+2.*s))/q1h/q2h/s*uk + (uk-tk)/2./q1h/q2h/s*(q1*(uk+s)/q2/tk-q2*(tk+s)/q1/uk)*tk*uk + (tk-2.*mZ2)*(uk-2.*mZ2)/q1h/q1/q2h/q2*tk*uk - (q1*q1+q2*q2)/q1/q2 - 2.*mZ2*(q2-2.*mZ2)/q1/q1/s*tk ); swap(tk ,uk ); swap(q1 ,q2h); swap(q2 ,q1h); return t_u_qqb; } /***************************************************************************/ // M_B_WW is the Born matrix element exactly as defined in Eqs. 3.2-3.8 // of of NPB 410(1993)280-384. double MEPP2VVPowheg::M_Born_WW(bornVVKinematics B) const { Energy2 s(B.sb()); Energy2 t(B.tb()); Energy2 u(B.ub()); Energy2 mW2(B.k12b()); // N.B. the diboson masses are preserved in getting bool up_type = abs(quark_->id())%2==0 ? true : false; double Qi = up_type ? 2./3. : -1./3. ; double giL = up_type ? guL_/2. : gdL_/2.; double giR = up_type ? guR_/2. : gdR_/2.; double e2 = sqr(gW_)*sin2ThetaW_; double cos2ThetaW(1.-sin2ThetaW_); double ctt_i(gW_*gW_*gW_*gW_/16.); InvEnergy2 cts_i(gW_*gW_*e2/4./s *(Qi+2.*eZ_*giL/e2*s/(s-mW2/cos2ThetaW))); InvEnergy4 css_i(e2*e2/s/s*(sqr(Qi+eZ_*(giL+giR)/e2*s/(s-mW2/cos2ThetaW)) +sqr( eZ_*(giL-giR)/e2*s/(s-mW2/cos2ThetaW))) ); ctt_i *= 8.*Fij2_/gW_/gW_; cts_i *= sqrt(8.*Fij2_/gW_/gW_); if(quark_->id()!=-antiquark_->id()) { cts_i = 0./GeV2; css_i = 0./GeV2/GeV2; } if(!up_type) swap(t,u); double signf = up_type ? 1. : -1.; return 1./4./NC_ * ( ctt_i*( 16.*(u*t/mW2/mW2-1.)*(1./4.+mW2*mW2/t/t)+16.*s/mW2) - cts_i*( 16.*(u*t/mW2/mW2-1.)*(s/4.-mW2/2.-mW2*mW2/t) + 16.*s*(s/mW2-2.+2.*mW2/t) ) *signf + css_i*( 8.*(u*t/mW2/mW2-1.)*(s*s/4.-s*mW2+3.*mW2*mW2) + 8.*s*s*(s/mW2-4.) ) ); } /***************************************************************************/ // M_V_regular_WW is the regular part of the one-loop WW matrix element // exactly as defined in Eqs. C.1 - C.7 of of NPB 410(1993)280-324 *** // modulo a factor 1/(2s) ***, which is a flux factor that those authors // absorb in the matrix element. double MEPP2VVPowheg::M_V_regular_WW(realVVKinematics S) const { Energy2 s(S.bornVariables().sb()); Energy2 t(S.bornVariables().tb()); Energy2 u(S.bornVariables().ub()); Energy2 mW2(S.k12r()); // N.B. the diboson masses are preserved in getting double beta(S.betaxr()); // N.B. for x=1 \beta_x=\beta in NPB 383(1992)3-44. bool up_type = abs(quark_->id())%2==0 ? true : false; double Qi = up_type ? 2./3. : -1./3.; double giL = up_type ? guL_/2. : gdL_/2.; double giR = up_type ? guR_/2. : gdR_/2.; double e2 = sqr(gW_)*sin2ThetaW_; double cos2ThetaW(1.-sin2ThetaW_); double ctt_i(gW_*gW_*gW_*gW_/16.); InvEnergy2 cts_i(gW_*gW_*e2/4./s *(Qi+2.*eZ_*giL/e2*s/(s-mW2/cos2ThetaW))); InvEnergy4 css_i(e2*e2/s/s*(sqr(Qi+eZ_*(giL+giR)/e2*s/(s-mW2/cos2ThetaW)) +sqr( eZ_*(giL-giR)/e2*s/(s-mW2/cos2ThetaW))) ); ctt_i *= 8.*Fij2_/gW_/gW_; cts_i *= sqrt(8.*Fij2_/gW_/gW_); if(quark_->id()!=-antiquark_->id()) { cts_i = 0./GeV2; css_i = 0./GeV2/GeV2; } if(!up_type) swap(t,u); double signf = up_type ? 1. : -1.; InvEnergy4 TildeI4 = ( 2.*sqr(log(-t/mW2))-4.*log((mW2-t)/mW2)*log(-t/mW2) - 4.*ReLi2(t/mW2) )/s/t; InvEnergy2 TildeI3t = 1./(mW2-t) *(sqr(log(mW2/s))/2.-sqr(log(-t/s))/2.-pi*pi/2.); InvEnergy2 TildeI3l = 1./s/beta*( 4.*ReLi2((beta-1.)/(beta+1.)) + sqr(log((1.-beta)/(1.+beta))) + pi*pi/3.); double Fup1_st(0.); Fup1_st = 4.*(80.*t*t+73.*s*t-140.*mW2*t+72.*mW2*mW2)/t/t - 4.*sqr(4.*t+s)/s/beta/beta/t - 128.*(t+2.*s)/mW2 + 64.*t*(t+s)/mW2/mW2 - (32.*(t*t-3.*s*t-3.*mW2*mW2)/t/t+128.*s/(t-mW2))*log(-t/mW2) + ( 8.*(6.*t*t+8.*s*t-19.*mW2*t+12.*mW2*mW2)/t/t - (32.*t*t-128.*s*t-26.*s*s)/s/beta/beta/t + 6.*sqr(4.*t+s)/s/sqr(sqr(beta))/t )*log(s/mW2) + 32.*s*(2.*mW2*mW2/t-u)*TildeI4 - 64.*(t-mW2)*(2.*mW2*mW2/t/t-u/t)*TildeI3t + ( (16.*t*(4.*mW2-u)-49.*s*s+72.*mW2*s-48.*mW2*mW2)/2./t + 2.*(8.*t*t-14.*s*t-3.*s*s)/beta/beta/t - 3.*sqr(4.*t+s)/2./sqr(sqr(beta))/t )*TildeI3l + 32./3.*( 2.*(t+2.*s)/mW2 - (3.*t+2.*s-4.*mW2)/t - t*(t+s)/mW2/mW2 )*pi*pi; Energy2 Jup1_st(0.*GeV2); Jup1_st = -128.*(t*t+2.*s*t+2.*s*s)/mW2 - 16.*(t*t-21.*s*t-26.*mW2*t+34.*mW2*s+17.*mW2*mW2)/t + 64.*s*t*(t+s)/mW2/mW2 +32.*s*s/(t-mW2) + ( 16.*(t-5.*s+2.*mW2)-48.*mW2*(2.*s+mW2)/t + 64.*s*(2.*t+s)/(t-mW2) - 32.*s*s*t/sqr(t-mW2) )*log(-t/mW2) + ( 16.*(4.*t+s)/beta/beta - 16.*(3.*t-2.*s) + 48.*mW2*(2.*t-2.*s-mW2)/t )*log(s/mW2) + 16.*s*(t*(2.*s+u)-2.*mW2*(2.*s+mW2))*TildeI4 + 32.*(t-mW2)*(2.*mW2*(2.*s+mW2)/t-2.*s-u)*TildeI3t + ( 32.*s*t-12.*s*s+32.*mW2*mW2 - 16.*mW2*(2.*t+7.*s)-4.*s*(4.*t+s)/beta/beta )*TildeI3l + 32./3.*( 2.*(t*t+2.*s*t+2.*s*s)/mW2 - s*t*(t+s)/mW2/mW2-2.*mW2*(2.*t-2.*s-mW2)/t-t-4.*s )*pi*pi; Energy4 Kup1_st(0.*GeV2*GeV2); Kup1_st = 16.*( 12.*t*t+20.*s*t-24.*mW2*t+17.*s*s-4.*mW2*s+12.*mW2*mW2 + s*s*t*(t+s)/mW2/mW2-2.*s*(2.*t*t+3.*s*t+2.*s*s)/mW2) *(2.-pi*pi/3.); return pi*alphaS_*CF_/NC_/(sqr(4.*pi)) * ( ctt_i*Fup1_st - cts_i*Jup1_st*signf + css_i*Kup1_st ); } /***************************************************************************/ // t_u_M_R_qqb is the real emission q + qb -> n + g matrix element // exactly as defined in Eqs. C.1 of NPB 383(1992)3-44, multiplied by // tk * uk! Energy2 MEPP2VVPowheg::t_u_M_R_qqb_WW(realVVKinematics R) const { // First the Born variables: Energy2 s2(R.s2r()); Energy2 mW2(R.k12r()); // Then the rest: Energy2 s(R.sr()); Energy2 tk(R.tkr()); Energy2 uk(R.ukr()); Energy2 q1(R.q1r()); Energy2 q2(R.q2r()); Energy2 q1h(R.q1hatr()); Energy2 q2h(R.q2hatr()); bool up_type = abs(quark_->id())%2==0 ? true : false; double Qi = up_type ? 2./3. : -1./3.; double giL = up_type ? guL_/2. : gdL_/2.; double giR = up_type ? guR_/2. : gdR_/2.; double e2 = sqr(gW_)*sin2ThetaW_; double cos2ThetaW(1.-sin2ThetaW_); double ctt_i(gW_*gW_*gW_*gW_/16.); InvEnergy2 cts_i(gW_*gW_*e2/4./s2*(Qi+2.*eZ_*giL/e2*s2/(s2-mW2/cos2ThetaW))); InvEnergy4 css_i(e2*e2/s2/s2*(sqr(Qi+eZ_*(giL+giR)/e2*s2/(s2-mW2/cos2ThetaW)) +sqr( eZ_*(giL-giR)/e2*s2/(s2-mW2/cos2ThetaW))) ); ctt_i *= 8.*Fij2_/gW_/gW_; cts_i *= sqrt(8.*Fij2_/gW_/gW_); if(quark_->id()!=-antiquark_->id()) { cts_i = 0./GeV2; css_i = 0./GeV2/GeV2; } if(!up_type) { swap(q1,q1h); swap(q2,q2h); } double signf = up_type ? 1. : -1.; Energy2 t_u_Xup(0.*GeV2); Energy4 t_u_Yup(0.*GeV2*GeV2); Energy6 t_u_Zup(0.*GeV2*GeV2*GeV2); t_u_Xup = 32.*mW2*(tk*uk+3.*q2*uk+q2*s+q1*q2)/q1/q2/q2*tk + 32.*mW2*q1/q2/q2*uk - 64.*mW2*s/q2 - 32.*tk*(uk-q2)/q1/q2*tk + 64.*mW2*mW2*mW2/q1/q1/q2*tk - 16.*(2.*tk-2.*s-q2)/q2*uk + 16.*s*(2.*s+2.*q1+q2/2.)/q2 - 8.*(4.*tk+uk+9.*s+2.*q2+2.*q1)/mW2*tk - 16.*s*(2.*s+q1)/mW2 - 64.*mW2*mW2*(tk*uk+q2*tk+q1*uk-q2*s/2.)/q1/q2/q2 + 8.*s2*q1*(tk+s+q1)/mW2/mW2; swap(tk,uk); swap(q1,q2); t_u_Xup += 32.*mW2*(tk*uk+3.*q2*uk+q2*s+q1*q2)/q1/q2/q2*tk + 32.*mW2*q1/q2/q2*uk - 64.*mW2*s/q2 - 32.*tk*(uk-q2)/q1/q2*tk + 64.*mW2*mW2*mW2/q1/q1/q2*tk - 16.*(2.*tk-2.*s-q2)/q2*uk + 16.*s*(2.*s+2.*q1+q2/2.)/q2 - 8.*(4.*tk+uk+9.*s+2.*q2+2.*q1)/mW2*tk - 16.*s*(2.*s+q1)/mW2 - 64.*mW2*mW2*(tk*uk+q2*tk+q1*uk-q2*s/2.)/q1/q2/q2 + 8.*s2*q1*(tk+s+q1)/mW2/mW2; swap(tk,uk); swap(q1,q2); t_u_Yup = - 16.*tk*(uk*(uk+s+q1)+q2*(s-2.*q1))/q1/q2*tk - 32.*mW2*mW2*s/q2 - 32.*mW2*mW2*mW2/q1/q2*tk + 16.*(2.*q2*uk+s*s+q1*s+5.*q2*s+q1*q2+2.*q2*q2)/q2*tk - 16.*(q2*q2+s*s-q2*s)/q1*tk + 16.*s*(q1*s+3./2.*q2*s+q1*q2-q1*q1)/q2 + 16.*mW2*tk*(4.*uk+s+q1-2.*q2)/q1/q2*tk + 16.*mW2*(3.*s*uk+q1*uk-q1*s-3.*q2*s-q1*q1+q2*q2)/q1/q2*tk + 16.*mW2*s*(q2-4.*s+2.*q1)/q2 - 8.*s2*(4.*tk+uk+9.*s+4.*q1+2.*q2)/mW2*tk - 16.*s2*(2.*s*s+2.*q1*s+q1*q1)/mW2 - 32.*mW2*mW2*(tk+uk/2.+2.*s-q1)/q1/q2*tk + 8.*s2*s2*q1*(tk+s+q1)/mW2/mW2; swap(tk,uk); swap(q1,q2); t_u_Yup += - 16.*tk*(uk*(uk+s+q1)+q2*(s-2.*q1))/q1/q2*tk - 32.*mW2*mW2*s/q2 - 32.*mW2*mW2*mW2/q1/q2*tk + 16.*(2.*q2*uk+s*s+q1*s+5.*q2*s+q1*q2+2.*q2*q2)/q2*tk - 16.*(q2*q2+s*s-q2*s)/q1*tk + 16.*s*(q1*s+3./2.*q2*s+q1*q2-q1*q1)/q2 + 16.*mW2*tk*(4.*uk+s+q1-2.*q2)/q1/q2*tk + 16.*mW2*(3.*s*uk+q1*uk-q1*s-3.*q2*s-q1*q1+q2*q2)/q1/q2*tk + 16.*mW2*s*(q2-4.*s+2.*q1)/q2 - 8.*s2*(4.*tk+uk+9.*s+4.*q1+2.*q2)/mW2*tk - 16.*s2*(2.*s*s+2.*q1*s+q1*q1)/mW2 - 32.*mW2*mW2*(tk+uk/2.+2.*s-q1)/q1/q2*tk + 8.*s2*s2*q1*(tk+s+q1)/mW2/mW2; swap(tk,uk); swap(q1,q2); t_u_Zup = 8.*s2*(9.*tk+3.*uk+20.*s+10.*q1+4.*q2)*tk + 8.*s2*(17./2.*s*s+10.*q1*s+6.*q1*q1) - 4.*s2*s2*(4.*tk+uk+9.*s+6.*q1+2.*q2)/mW2*tk - 8.*s2*s2*(2.*s*s+3.*q1*s+2.*q1*q1)/mW2 - 16.*mW2*(2.*tk+5.*uk+7.*s+6.*q1+6.*q2)*tk - 16.*mW2*s*(s+6.*q1) + 4.*s2*s2*s2*q1*(tk+s+q1)/mW2/mW2 + 48.*mW2*mW2*s2; swap(tk,uk); swap(q1,q2); t_u_Zup += 8.*s2*(9.*tk+3.*uk+20.*s+10.*q1+4.*q2)*tk + 8.*s2*(17./2.*s*s+10.*q1*s+6.*q1*q1) - 4.*s2*s2*(4.*tk+uk+9.*s+6.*q1+2.*q2)/mW2*tk - 8.*s2*s2*(2.*s*s+3.*q1*s+2.*q1*q1)/mW2 - 16.*mW2*(2.*tk+5.*uk+7.*s+6.*q1+6.*q2)*tk - 16.*mW2*s*(s+6.*q1) + 4.*s2*s2*s2*q1*(tk+s+q1)/mW2/mW2 + 48.*mW2*mW2*s2; swap(tk,uk); swap(q1,q2); return -pi*alphaS_*CF_/NC_ * ( ctt_i*t_u_Xup - cts_i*t_u_Yup*signf + css_i*t_u_Zup ); } /***************************************************************************/ // The game here is to get this helicity amplitude squared to return all the // same values as t_u_M_R_qqb above, TIMES a further factor tk*uk! Energy2 MEPP2VVPowheg::t_u_M_R_qqb_hel_amp(realVVKinematics R) const { using namespace ThePEG::Helicity; // qqb_hel_amps_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half, // PDT::Spin1,PDT::Spin1, // PDT::Spin1)); double sum_hel_amps_sqr(0.); tcPDPtr p1data(quark_); tcPDPtr p2data(antiquark_); tcPDPtr k1data(mePartonData()[2]); tcPDPtr k2data(mePartonData()[3]); tcPDPtr kdata(getParticleData(ParticleID::g)); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorWaveFunction qSpinor(R.p1r(),p1data,incoming); SpinorBarWaveFunction qbSpinor(R.p2r(),p2data,incoming); vector q; vector qb; for(unsigned int ix=0;ix<2;ix++) { qSpinor.reset(ix); qbSpinor.reset(ix); q.push_back(qSpinor); qb.push_back(qbSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.kr(),kdata,outgoing); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(p2data); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorWaveFunction p1_k = ffg->evaluate(mu_UV2(),5,p1data,q[p1hel],g[khel]); SpinorBarWaveFunction p2_k = ffg->evaluate(mu_UV2(),5,p2data,qb[p2hel],g[khel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p1hel=p2hel // but if the production ME is required first fill it with (0.,0.). if((p1hel==p2hel)&&helicityConservation_) { // if(getMatrix) { // if(khel==0) // qqb_hel_amps_(p1hel,p2hel,k1hel,k2hel,0) = Complex(0.,0.); // else // qqb_hel_amps_(p1hel,p2hel,k1hel,k2hel,2) = Complex(0.,0.); // } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_t; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? p2data : tc[ix]; SpinorWaveFunction p1_v1 = ffv1->evaluate(scale(),5,intermediate_t,q[p1hel],v1[k1hel]); SpinorBarWaveFunction p2_v2 = ffv2->evaluate(scale(),5,intermediate_t,qb[p2hel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 t-channel diagrams // q+qb->g+v1+v2, q+qb->v1+g+v2, q+qb->v1+v2+g if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) { diagrams.push_back(ffv1->evaluate(scale(),p1_k,p2_v2,v1[k1hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),p1_v1,p2_v2,g[khel])); diagrams.push_back(ffv2->evaluate(scale(),p1_v1,p2_k,v2[k2hel])); } intermediate_t = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(scale(),5,intermediate_t,q[p1hel],v2[k2hel]); SpinorBarWaveFunction p2_v1 = ffv1->evaluate(scale(),5,intermediate_t,qb[p2hel],v1[k1hel]); // q+qb->g+v2+v1, q+qb->v2+g+v1, q+qb->v2+v1+g if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) { diagrams.push_back(ffv2->evaluate(scale(),p1_k,p2_v1,v2[k2hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),p1_v2,p2_v1,g[khel])); diagrams.push_back(ffv1->evaluate(scale(),p1_v2,p2_k,v1[k1hel])); } } // Note: choosing 3 as the second argument in WWWvertex_->evaluate() // sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which // means the propagator does not contain a width factor (which is // good re. gauge invariance). // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(scale(),3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(scale(),p1_k,qb[p2hel],k1_k2)); diagrams.push_back(ffv1->evaluate(scale(),q[p1hel],p2_k,k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==-p2data->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(scale(),3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(scale(),p1_k,qb[p2hel],k1_k2)); diagrams.push_back(FFZvertex_->evaluate(scale(),q[p1hel],p2_k,k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(scale(),3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(scale(),p1_k,qb[p2hel],k1_k2)); diagrams.push_back(FFPvertex_->evaluate(scale(),q[p1hel],p2_k,k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } /***************************************************************************/ // The game here is to get this helicity amplitude squared to return all the // same values as t_u_M_R_qg above, TIMES a further factor tk*uk! Energy2 MEPP2VVPowheg::t_u_M_R_qg_hel_amp(realVVKinematics R) const { using namespace ThePEG::Helicity; // qg_hel_amps_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1, // PDT::Spin1,PDT::Spin1, // PDT::Spin1Half)); double sum_hel_amps_sqr(0.); tcPDPtr p1data(quark_); tcPDPtr p2data(getParticleData(ParticleID::g)); tcPDPtr k1data(mePartonData()[2]); tcPDPtr k2data(mePartonData()[3]); tcPDPtr kdata (antiquark_->CC()); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorWaveFunction qinSpinor(R.p1r(),p1data,incoming); SpinorBarWaveFunction qoutSpinor(R.kr(),kdata,outgoing); vector qin; vector qout; for(unsigned int ix=0;ix<2;ix++) { qinSpinor.reset(ix); qoutSpinor.reset(ix); qin.push_back(qinSpinor); qout.push_back(qoutSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.p2r(),p2data,incoming); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(kdata->CC()); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorWaveFunction p1_p2 = ffg->evaluate(mu_UV2(),5,p1data,qin[p1hel],g[p2hel]); SpinorBarWaveFunction p2_k = ffg->evaluate(mu_UV2(),5,kdata->CC(),qout[khel],g[p2hel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p1hel!=khel // but if the production ME is required first fill it with (0.,0.). if((p1hel!=khel)&&helicityConservation_) { // if(getMatrix) { // if(p2hel==0) // qg_hel_amps_(p1hel,0,k1hel,k2hel,khel) = Complex(0.,0.); // else // qg_hel_amps_(p1hel,2,k1hel,k2hel,khel) = Complex(0.,0.); // } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_q; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? antiquark_ : tc[ix]; SpinorWaveFunction p1_v1 = ffv1->evaluate(scale(),5,intermediate_q,qin[p1hel],v1[k1hel]); SpinorBarWaveFunction k_v2 = ffv2->evaluate(scale(),5,intermediate_q,qout[khel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 abelian diagrams // q+g->v1+v2+q with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) { diagrams.push_back(ffv2->evaluate(scale(),p1_v1,p2_k,v2[k2hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),p1_v1,k_v2,g[p2hel])); diagrams.push_back(ffv1->evaluate(scale(),p1_p2,k_v2,v1[k1hel])); } intermediate_q = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(scale(),5,intermediate_q,qin[p1hel],v2[k2hel]); SpinorBarWaveFunction k_v1 = ffv1->evaluate(scale(),5,intermediate_q,qout[khel],v1[k1hel]); // q+g->v2+v1+q, with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) { diagrams.push_back(ffv1->evaluate(scale(),p1_v2,p2_k,v1[k1hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),p1_v2,k_v1,g[p2hel])); diagrams.push_back(ffv2->evaluate(scale(),p1_p2,k_v1,v2[k2hel])); } } // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(scale(),3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(scale(),p1_p2,qout[khel],k1_k2)); diagrams.push_back(ffv1->evaluate(scale(),qin[p1hel],p2_k,k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==kdata->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(scale(),3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(scale(),p1_p2,qout[khel],k1_k2)); diagrams.push_back(FFZvertex_->evaluate(scale(),qin[p1hel],p2_k,k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(scale(),3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(scale(),p1_p2,qout[khel],k1_k2)); diagrams.push_back(FFPvertex_->evaluate(scale(),qin[p1hel],p2_k,k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } /***************************************************************************/ // The game here is to get this helicity amplitude squared to return all the // same values as t_u_M_R_gqb above, TIMES a further factor tk*uk! Energy2 MEPP2VVPowheg::t_u_M_R_gqb_hel_amp(realVVKinematics R) const { using namespace ThePEG::Helicity; // gqb_hel_amps_.reset(ProductionMatrixElement(PDT::Spin1,PDT::Spin1Half, // PDT::Spin1,PDT::Spin1, // PDT::Spin1Half)); double sum_hel_amps_sqr(0.); tcPDPtr p1data(getParticleData(ParticleID::g)); tcPDPtr p2data(antiquark_); tcPDPtr k1data(mePartonData()[2]); tcPDPtr k2data(mePartonData()[3]); tcPDPtr kdata (quark_->CC()); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorBarWaveFunction qbinSpinor(R.p2r(),p2data,incoming); SpinorWaveFunction qboutSpinor(R.kr(),kdata,outgoing); vector qbin; vector qbout; for(unsigned int ix=0;ix<2;ix++) { qbinSpinor.reset(ix); qboutSpinor.reset(ix); qbin.push_back(qbinSpinor); qbout.push_back(qboutSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.p1r(),p1data,incoming); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p2data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p2data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(kdata->CC()); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorBarWaveFunction p1_p2 = ffg->evaluate(mu_UV2(),5,p2data,qbin[p2hel],g[p1hel]); SpinorWaveFunction p1_k = ffg->evaluate(mu_UV2(),5,kdata->CC(),qbout[khel],g[p1hel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p2hel!=khel // but if the production ME is required first fill it with (0.,0.). if((p2hel!=khel)&&helicityConservation_) { // if(getMatrix) { // if(p1hel==0) // gqb_hel_amps_(0,p2hel,k1hel,k2hel,khel) = Complex(0.,0.); // else // gqb_hel_amps_(2,p2hel,k1hel,k2hel,khel) = Complex(0.,0.); // } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_q; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? quark_ : tc[ix]; SpinorBarWaveFunction p2_v1 = ffv1->evaluate(scale(),5,intermediate_q,qbin[p2hel],v1[k1hel]); SpinorWaveFunction k_v2 = ffv2->evaluate(scale(),5,intermediate_q,qbout[khel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 abelian diagrams q+g->v1+v2+q // with 2 t-channel propagators, 1 s- and 1 t-channel // and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p2data->id())%2==0))) { diagrams.push_back(ffv2->evaluate(scale(),p1_k,p2_v1,v2[k2hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),k_v2,p2_v1,g[p1hel])); diagrams.push_back(ffv1->evaluate(scale(),k_v2,p1_p2,v1[k1hel])); } intermediate_q = (!(k1data->id()==24&&k2data->id()==-24)) ? p2data : tc[ix]; SpinorBarWaveFunction p2_v2 = ffv2->evaluate(scale(),5,intermediate_q,qbin[p2hel],v2[k2hel]); SpinorWaveFunction k_v1 = ffv1->evaluate(scale(),5,intermediate_q,qbout[khel],v1[k1hel]); // q+g->v2+v1+q, with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p2data->id())%2==1))) { diagrams.push_back(ffv1->evaluate(scale(),p1_k,p2_v2,v1[k1hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),k_v1,p2_v2,g[p1hel])); diagrams.push_back(ffv2->evaluate(scale(),k_v1,p1_p2,v2[k2hel])); } } // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(scale(),3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(scale(),qbout[khel],p1_p2,k1_k2)); diagrams.push_back(ffv1->evaluate(scale(),p1_k,qbin[p2hel],k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p2data->id()==kdata->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(scale(),3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(scale(),qbout[khel],p1_p2,k1_k2)); diagrams.push_back(FFZvertex_->evaluate(scale(),p1_k,qbin[p2hel],k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(scale(),3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(scale(),qbout[khel],p1_p2,k1_k2)); diagrams.push_back(FFPvertex_->evaluate(scale(),p1_k,qbin[p2hel],k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } double MEPP2VVPowheg::lo_me() const { using namespace ThePEG::Helicity; double sum_hel_amps_sqr(0.); tcPDPtr p1data(quark_); tcPDPtr p2data(antiquark_); tcPDPtr k1data(mePartonData()[2]); tcPDPtr k2data(mePartonData()[3]); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); // Should never actually occur. SpinorWaveFunction qSpinor(B_.p1b(),p1data,incoming); SpinorBarWaveFunction qbSpinor(B_.p2b(),p2data,incoming); vector q; vector qb; for(unsigned int ix=0;ix<2;ix++) { qSpinor.reset(ix); qbSpinor.reset(ix); q.push_back(qSpinor); qb.push_back(qbSpinor); } VectorWaveFunction v1Polarization(B_.k1b(),k1data,outgoing); VectorWaveFunction v2Polarization(B_.k2b(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(p2data); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { if((p1hel==p2hel)&&helicityConservation_) continue; for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_t; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? p2data : tc[ix]; SpinorWaveFunction p1_v1 = ffv1->evaluate(scale(),5,intermediate_t,q[p1hel],v1[k1hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 t-channel diagrams // q+qb->v1+v2 if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) diagrams.push_back(ffv2->evaluate(scale(),p1_v1,qb[p2hel],v2[k2hel])); intermediate_t = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(scale(),5,intermediate_t,q[p1hel],v2[k2hel]); // q+qb->v2+v1 if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) diagrams.push_back(ffv1->evaluate(scale(),p1_v2,qb[p2hel],v1[k1hel])); } // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(scale(),3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->v1*->v1+v2 diagrams.push_back(ffv1->evaluate(scale(),q[p1hel],qb[p2hel],k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==-p2data->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->Z0*->v1+v2 tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(scale(),3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(scale(),q[p1hel],qb[p2hel],k1_k2)); // q+qb->gamma*->v1+v2 tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(scale(),3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(scale(),q[p1hel],qb[p2hel],k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr; } HardTreePtr MEPP2VVPowheg::generateHardest(ShowerTreePtr tree, - vector inter) { - // check QCD emission switched on - bool QCD=false; - for(unsigned int ix=0;ix2 hard collision: vector particlesToShower; for(map::const_iterator cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit ) particlesToShower.push_back(cit->first); qProgenitor_ = particlesToShower[0]; qbProgenitor_ = particlesToShower[1]; showerQuark_ = particlesToShower[0]->progenitor(); showerAntiquark_ = particlesToShower[1]->progenitor(); qHadron_ = particlesToShower[0]->beam(); qbHadron_ = particlesToShower[1]->beam(); if(showerQuark_->id()<0) { swap(qProgenitor_,qbProgenitor_); swap(showerQuark_,showerAntiquark_); swap(qHadron_,qbHadron_); } // In _our_ calculation we basically define the +z axis as being given // by the direction of the incoming quark for q+qb & q+g processes and // the incoming gluon for g+qbar processes. So now we might need to flip // the beams, bjorken x values, colliding partons accordingly: flipped_ = showerQuark_->momentum().z()outgoingLines().size()==2); for(map::const_iterator cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit ) particlesToShower.push_back(cit->first); V1_ = particlesToShower[2]->progenitor(); V2_ = particlesToShower[3]->progenitor(); gluon_ = getParticleData(ParticleID::g)->produceParticle(); // Abort the run if V1_ and V2_ are not just pointers to different gauge bosons if(!V1_||!V2_) throw Exception() << "MEPP2VVPowheg::generateHardest()\n" << "one or both of the gauge boson pointers is null." << Exception::abortnow; if(!(abs(V1_->id())==24||V1_->id()==23)||!(abs(V2_->id())==24||V2_->id()==23)) throw Exception() << "MEPP2VVPowheg::generateHardest()\nmisidentified gauge bosons" << "V1_ = " << V1_->PDGName() << "\n" << "V2_ = " << V2_->PDGName() << "\n" << Exception::abortnow; // Order the gauge bosons in the same way as in the NLO calculation // (the same way as in the NLO matrix element): // W+(->e+,nu_e) W-(->e-,nu_ebar) (MCFM: 61 [nproc]) if(V1_->id()==-24&&V2_->id()== 24) swap(V1_,V2_); // W+/-(mu+,nu_mu / mu-,nu_mubar) Z(nu_e,nu_ebar) (MCFM: 72+77 [nproc]) if(V1_->id()== 23&&abs(V2_->id())== 24) swap(V1_,V2_); // *** N.B. *** // We should not have to do a swap in the ZZ case, even if the different // (off-shell) masses of the Z's are taken into account by generating // the Born variables using the WZ LO/NLO matrix element(s), because // those transformed matrix elements are, according to mathematica, // symmetric in the momenta (and therefore also the masses) of the 2 Z's. // If the vector bosons have decayed already then we may want to // to get the children_ (and any associated photons) to correct // spin correlations: StepPtr theSubProcess = generator()->eventHandler()->currentStep(); tPVector outgoing = theSubProcess->getFinalState(); children_.clear(); photons_.clear(); if(outgoing.size()>=4) { for(unsigned int ix=0;ixparents()[0]&& (abs(outgoing[ix]->parents()[0]->id())==24|| abs(outgoing[ix]->parents()[0]->id())==23)) { if(outgoing[ix]->id()!=ParticleID::gamma) children_.push_back(outgoing[ix]); else photons_.push_back(outgoing[ix]); } assert(children_.size()==4); if(children_[0]->parents()[0]!=children_[1]->parents()[0]) swap(children_[0],children_[2]); if(children_[0]->parents()[0]!=children_[1]->parents()[0]) swap(children_[0],children_[3]); if(children_[0]->parents()[0]->id()!=V1_->id()) { swap(children_[0],children_[2]); swap(children_[1],children_[3]); } if(children_[0]->id()<0) swap(children_[0],children_[1]); if(children_[2]->id()<0) swap(children_[2],children_[3]); assert(children_[0]->parents()[0]==children_[1]->parents()[0]); assert(children_[2]->parents()[0]==children_[3]->parents()[0]); } // Now we want to construct a bornVVKinematics object. The // constructor for that needs all 4 momenta, q, qbar, V1_, V2_ // in that order, as well as the Bjorken xq and xqbar. // Get the momenta first: vector theBornMomenta; theBornMomenta.push_back(showerQuark_->momentum()); theBornMomenta.push_back(showerAntiquark_->momentum()); theBornMomenta.push_back(V1_->momentum()); theBornMomenta.push_back(V2_->momentum()); // N.B. if the showerQuark_ travels in the -z direction the born kinematics object // will detect this and rotate all particles by pi about the y axis! // Leading order momentum fractions: tcPPtr qHadron = generator()->currentEvent()->primaryCollision()->incoming().first; tcPPtr qbHadron = generator()->currentEvent()->primaryCollision()->incoming().second; assert(qHadron->children().size()>0&&qbHadron->children().size()>0); if(qHadron->children()[0]->id()<0) swap(qHadron,qbHadron); // quark and antiquark momentum fractions respectively double xa = showerQuark_ ->momentum().z()/qHadron ->momentum().z(); double xb = showerAntiquark_->momentum().z()/qbHadron->momentum().z(); // Create the object containing all 2->2 __kinematic__ information: B_ = bornVVKinematics(theBornMomenta,xa,xb); // lo_me_ is the colour & spin averaged n-body matrix element squared: lo_me_ = lo_me(true); // Attempt to generate some radiative variables and their kinematics: vector theRealMomenta; channel_ = 999; if(!getEvent(theRealMomenta,channel_)) return HardTreePtr(); // Set the maximum pT for subsequent emissions: pT_ < min_pT_ ? qProgenitor_ ->maximumpT(min_pT_,ShowerInteraction::QCD) : qProgenitor_ ->maximumpT(pT_ ,ShowerInteraction::QCD); pT_ < min_pT_ ? qbProgenitor_->maximumpT(min_pT_,ShowerInteraction::QCD) : qbProgenitor_->maximumpT(pT_ ,ShowerInteraction::QCD); // Determine whether the quark or antiquark emitted: fermionNumberOfMother_=0; if((channel_==0&&theRealMomenta[0].z()/theRealMomenta[4].z()>=ZERO)|| channel_==2) fermionNumberOfMother_ = 1; else if((channel_==0&&theRealMomenta[0].z()/theRealMomenta[4].z()0.1*GeV||inMinusOut.x()>0.1*GeV|| inMinusOut.y()>0.1*GeV||inMinusOut.z()>0.1*GeV) cout << "MEPP2VVPowheg::generateHardest\n" << "Momentum imbalance in V1 V2 rest frame\n" << "P_in minus P_out = " << inMinusOut/GeV << endl; // From the radiative kinematics we now have to form ShowerParticle objects: ShowerParticlePtr p1; ShowerParticlePtr p2; ShowerParticlePtr k1(new_ptr(ShowerParticle(V1_->dataPtr(),true ))); ShowerParticlePtr k2(new_ptr(ShowerParticle(V2_->dataPtr(),true ))); ShowerParticlePtr k ; // q+qbar -> V1+V2+g if(channel_==0) { p1 = new_ptr(ShowerParticle(showerQuark_->dataPtr() ,false)); p2 = new_ptr(ShowerParticle(showerAntiquark_->dataPtr() ,false)); k = new_ptr(ShowerParticle(gluon_->dataPtr() ,true )); } // q+g -> V1+V2+q else if(channel_==1) { p1 = new_ptr(ShowerParticle(showerQuark_->dataPtr() ,false)); p2 = new_ptr(ShowerParticle(gluon_->dataPtr() ,false)); k = new_ptr(ShowerParticle(showerAntiquark_->dataPtr()->CC() ,true )); } // g+qbar -> V1+V2+qbar else { p1 = new_ptr(ShowerParticle(gluon_->dataPtr() ,false)); p2 = new_ptr(ShowerParticle(showerAntiquark_->dataPtr() ,false)); k = new_ptr(ShowerParticle(showerQuark_->dataPtr()->CC() ,true )); } // Set the momenta of the ShowerParticlePtr's: p1->set5Momentum(theRealMomenta[0]); p2->set5Momentum(theRealMomenta[1]); k1->set5Momentum(theRealMomenta[2]); k2->set5Momentum(theRealMomenta[3]); k ->set5Momentum(theRealMomenta[4]); // Then construct another set of ShowerPointers that will be // useful in creating the hardTree, using this information: ShowerParticlePtr mother; ShowerParticlePtr spacelikeSon; ShowerParticlePtr timelikeSon; ShowerParticlePtr spectator; if(fermionNumberOfMother_==1) { mother = new_ptr(ShowerParticle(showerQuark_->dataPtr() ,false)); spacelikeSon = p1; timelikeSon = k; spectator = p2; } else if(fermionNumberOfMother_==-1) { mother = new_ptr(ShowerParticle(showerAntiquark_->dataPtr(),false)); spacelikeSon = p2; timelikeSon = k; spectator = p1; } else { throw Exception() << "MEPP2VVPowheg::generateHardest()" << "Failed to determine whether the q or qbar branched" << Exception::runerror; } Lorentz5Momentum motherMomentum(spacelikeSon->momentum()-timelikeSon->momentum()); motherMomentum.rescaleMass(); mother->set5Momentum(motherMomentum); // Create HardBranchingPtrs for the particles HardBranchingPtr spacelikeSonBranching = new_ptr(HardBranching(spacelikeSon,SudakovPtr(),HardBranchingPtr() ,HardBranching::Incoming )); HardBranchingPtr timelikeSonBranching = new_ptr(HardBranching(timelikeSon ,SudakovPtr(),spacelikeSonBranching,HardBranching::Outgoing)); HardBranchingPtr spectatorBranching = new_ptr(HardBranching(spectator ,SudakovPtr(),HardBranchingPtr() ,HardBranching::Incoming )); HardBranchingPtr motherBranching = new_ptr(HardBranching(mother ,SudakovPtr(),spacelikeSonBranching,HardBranching::Incoming )); HardBranchingPtr V1_Branching = new_ptr(HardBranching(k1 ,SudakovPtr(),HardBranchingPtr() ,HardBranching::Outgoing)); HardBranchingPtr V2_Branching = new_ptr(HardBranching(k2 ,SudakovPtr(),HardBranchingPtr() ,HardBranching::Outgoing)); // N.B. The DrellYanHardGenerator first adds the timelikeSonBranching as a child // child of the spacelikeSonBranching before adding the motherBranching. We do // it the other way round in accordance with PowhegEvolver::checkShowerMomentum. spacelikeSonBranching->addChild(motherBranching); spacelikeSonBranching->addChild(timelikeSonBranching); spacelikeSonBranching->type(motherBranching->branchingParticle()->id()>0 ? ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine); motherBranching->colourPartner(spectatorBranching); spectatorBranching->colourPartner(motherBranching); vector spacelikeBranchings,hardBranchings; spacelikeBranchings.push_back(fermionNumberOfMother_ == 1 ? spacelikeSonBranching : spectatorBranching); spacelikeBranchings.push_back(fermionNumberOfMother_ == -1 ? spacelikeSonBranching : spectatorBranching); hardBranchings.push_back(motherBranching); hardBranchings.push_back(spectatorBranching); hardBranchings.push_back(V1_Branching); hardBranchings.push_back(V2_Branching); // Recalculate the hard vertex for this event: // For spin correlations, if an emission occurs go calculate the relevant // combination of amplitudes for the ProductionMatrixElement. if(realMESpinCorrelations_) { // Here we reset the realVVKinematics n+1 momenta to be those // of the lab frame in order to calculate the spin correlations. // Note that these momenta are not used for anything else after // this. R_.p1r(theRealMomenta[0]); R_.p2r(theRealMomenta[1]); R_.k1r(theRealMomenta[2]); R_.k2r(theRealMomenta[3]); R_.kr (theRealMomenta[4]); if(channel_==0) t_u_M_R_qqb_hel_amp(R_,true); else if(channel_==1) t_u_M_R_qg_hel_amp (R_,true); else if(channel_==2) t_u_M_R_gqb_hel_amp(R_,true); recalculateVertex(); } // Construct the HardTree object needed to perform the showers HardTreePtr hardTree=new_ptr(HardTree(hardBranchings,spacelikeBranchings, ShowerInteraction::QCD)); if(hardTree->branchings().size()!=4) throw Exception() << "MEPP2VVPowheg::generateHardest()\n" << "The hardTree has " << hardTree->branchings().size() << "branchings\n" << hardTree << "\n" << Exception::runerror; if((motherBranching->parent()!=spacelikeSonBranching)&& spacelikeSonBranching->parent()!=HardBranchingPtr()&& spectatorBranching->parent()!=HardBranchingPtr()) throw Exception() << "MEPP2VVPowheg::generateHardest()\n" << "The parent-child relationships are not valid.\n" << "motherBranching->parent() = " << motherBranching->parent() << "\n" << "spacelikeSonBranching = " << spacelikeSonBranching << "\n" << "spectatorBranching->parent() = " << spectatorBranching->parent() << "\n" << "spacelikeSonBranching->parent() = " << spacelikeSonBranching->parent() << "\n" << Exception::runerror; if(fermionNumberOfMother_== 1) { hardTree->connect(showerQuark_ ,motherBranching ); hardTree->connect(showerAntiquark_,spectatorBranching); spacelikeSonBranching->beam(qProgenitor_ ->original()->parents()[0]); motherBranching ->beam(qProgenitor_ ->original()->parents()[0]); spectatorBranching ->beam(qbProgenitor_->original()->parents()[0]); } else if(fermionNumberOfMother_==-1) { hardTree->connect(showerAntiquark_,motherBranching ); hardTree->connect(showerQuark_ ,spectatorBranching); spacelikeSonBranching->beam(qbProgenitor_->original()->parents()[0]); motherBranching ->beam(qbProgenitor_->original()->parents()[0]); spectatorBranching ->beam(qProgenitor_ ->original()->parents()[0]); } // hardTree->connect(V1_ ,V1_Branching ); // hardTree->connect(V2_ ,V2_Branching ); // This if {...} else if {...} puts the mother and spectator on the same colour // line. If we don't do this, then when reconstructFinalStateShower calls // setInitialEvolutionScales it says it failed to set the colour partners, so // it can't set the scale and it just forgets the emission / event. This seems // like an unintrusive work-around until reconstructFinalStateShower is sorted. ColinePtr bornColourLine=new_ptr(ColourLine()); if(fermionNumberOfMother_== 1) { bornColourLine->addColoured(mother); bornColourLine->addAntiColoured(spectator); if(timelikeSon->id()==ParticleID::g) { bornColourLine->addAntiColoured(timelikeSon); ColinePtr newLine=new_ptr(ColourLine()); newLine->addColoured(timelikeSon); newLine->addColoured(spacelikeSon); } else { bornColourLine->addColoured(spacelikeSon); ColinePtr newLine=new_ptr(ColourLine()); newLine->addAntiColoured(timelikeSon); newLine->addAntiColoured(spacelikeSon); } } else if(fermionNumberOfMother_==-1) { bornColourLine->addAntiColoured(mother); bornColourLine->addColoured(spectator); if(timelikeSon->id()==ParticleID::g) { bornColourLine->addColoured(timelikeSon); ColinePtr newLine=new_ptr(ColourLine()); newLine->addAntiColoured(timelikeSon); newLine->addAntiColoured(spacelikeSon); } else { bornColourLine->addAntiColoured(spacelikeSon); ColinePtr newLine=new_ptr(ColourLine()); newLine->addColoured(timelikeSon); newLine->addColoured(spacelikeSon); } } // this is a pain but we need the boost, which we don't have yet here!! vector pin(2); vector pq (2); vector::iterator cit; pin[0] = motherBranching ->branchingParticle()->momentum(); pin[1] = spectatorBranching->branchingParticle()->momentum(); Energy etemp = motherBranching ->beam()->momentum().z(); pq[0] = Lorentz5Momentum(ZERO, ZERO,etemp, abs(etemp)); etemp = spectatorBranching->beam()->momentum().z(); pq[1] = Lorentz5Momentum(ZERO, ZERO,etemp, abs(etemp)); // decompose the momenta double alpha[2],beta[2]; Energy2 p12=pq[0]*pq[1]; Lorentz5Momentum pt[2]; for(unsigned int ix=0;ix<2;++ix) { alpha[ix] = pin[ix]*pq[1]/p12; beta [ix] = pin[ix]*pq[0]/p12; pt[ix] = pin[ix]-alpha[ix]*pq[0]-beta[ix]*pq[1]; } // parton level centre-of-mass Lorentz5Momentum pcm=pin[0]+pin[1]; pcm.rescaleMass(); double rap=pcm.rapidity(); // hadron level cmf Energy2 s = (pq[0] +pq[1] ).m2(); // calculate the x values double x[2]={sqrt(pcm.mass2()/s*exp(2.*rap)),pcm.mass2()/s/x[0]}; if(pq[0].z()branchingParticle()->momentum(), fromRest*toRest*V2_Branching->branchingParticle()->momentum()}; LorentzRotation R(-(mother->momentum()+spectator ->momentum()).boostVector()); R.boost((showerQuark_->momentum()+showerAntiquark_->momentum()).boostVector()); for(map >::const_iterator tit = tree->treelinks().begin(); tit != tree->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 == V1_ ? pv[0] : pv[1]; map::const_iterator cjt; // reset the momenta of the decay products, LorentzRotation boostToORF(newMomentum.findBoostToCM(), newMomentum.e()/newMomentum.mass()); tPPtr children[2]; if(children_[0]->parents()[0]==cit->first->original()) { children[0] = children_[0]; children[1] = children_[1]; } else { children[0] = children_[2]; children[1] = children_[3]; } if(UseRandom::rndbool()) swap(children[0],children[1]); double originalTheta0 = (boostToORF*R*children[0]->momentum()).theta(); double originalPhi0 = (boostToORF*R*children[0]->momentum()).phi(); boostToORF.rotateZ(-originalPhi0); boostToORF.rotateY(-originalTheta0); double originalPhi1 = (boostToORF*children[1]->momentum()).phi(); LorentzRotation boost(oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass()); tPPtr newChildren[2]; for(cjt=decayTree->outgoingLines().begin(); cjt!=decayTree->outgoingLines().end();++cjt) { if(cjt->first->progenitor()->id()==children[0]->id()) newChildren[0] = cjt->first->progenitor(); else if(cjt->first->progenitor()->id()==children[1]->id()) newChildren[1] = cjt->first->progenitor(); } boost.rotateZ(-(boost*newChildren[0]->momentum()).phi()); boost.rotateY(-(boost*newChildren[0]->momentum()).theta()); boost.rotateZ(-(boost*newChildren[1]->momentum()).phi()); boost.rotateZ( originalPhi1); boost.rotateY( originalTheta0); boost.rotateZ( originalPhi0); boost.boost(-oldMomentum.findBoostToCM(), oldMomentum.e()/oldMomentum.mass()); for(cjt=decayTree->outgoingLines().begin(); cjt!=decayTree->outgoingLines().end();++cjt) { cjt->first->original() ->set5Momentum(cjt->first->progenitor()->momentum()); cjt->first->progenitor()->deepTransform(boost); cjt->first->original() ->deepTransform(boost); cjt->first->copy() ->deepTransform(boost); } } return hardTree; } double MEPP2VVPowheg::getResult(int channel, realVVKinematics R, Energy pT) { // This routine should return the integrand of the exact Sudakov form factor, // defined precisely as // KH 19th August - next 2 lines changed for phi in 0->pi not 0->2pi // \Delta(pT) = exp[ - \int_{pT}^{pTmax} dpT dYk d\phi/pi * getResult(...) ] // (Where phi is in 0->pi NOT 0->2*pi !) // Get pi for the prefactor: using Constants::pi; // Get the VV invariant mass^2: Energy2 p2 = B_.sb(); // Get the momentum fractions for the n+1 body event: double x1 = R.x1r(); double x2 = R.x2r(); // Reject the event if the x1 and x2 values are outside the phase space: if(x1<0.||x1>1.||x2<0.||x2>1.||x1*x2maximumCMEnergy())) return 0.; // Get the momentum fractions for the n body event: double x1b = B_.x1b(); double x2b = B_.x2b(); // Get the mandelstam variables needed to calculate the n+1 body matrix element: Energy2 s = R.sr() ; Energy2 t_u_MR_o_MB; double lo_lumi, nlo_lumi; // The luminosity function for the leading order n-body process: lo_lumi = qHadron_ ->pdf()->xfx(qHadron_ ,showerQuark_ ->dataPtr(),PDFScale_,x1b)* qbHadron_->pdf()->xfx(qbHadron_,showerAntiquark_->dataPtr(),PDFScale_,x2b); // Now we calculate the luminosity functions (product of the two pdfs) for the // real emission process(es) and also their matrix elements: // q + qbar -> V + V + g if(channel==0) { nlo_lumi = qHadron_ ->pdf()->xfx(qHadron_ ,showerQuark_ ->dataPtr() ,PDFScale_,x1) * qbHadron_->pdf()->xfx(qbHadron_,showerAntiquark_->dataPtr() ,PDFScale_,x2); t_u_MR_o_MB = t_u_M_R_qqb_hel_amp(R,false)/lo_me_; } // q + g -> V + V + q else if(channel==1) { nlo_lumi = qHadron_ ->pdf()->xfx(qHadron_ ,showerQuark_->dataPtr() ,PDFScale_,x1) * qbHadron_->pdf()->xfx(qbHadron_,getParticleData(ParticleID::g),PDFScale_,x2); t_u_MR_o_MB = t_u_M_R_qg_hel_amp(R,false)/lo_me_; } // g + qbar -> V + V + qbar else { nlo_lumi = qHadron_ ->pdf()->xfx(qHadron_ ,getParticleData(ParticleID::g),PDFScale_,x1) * qbHadron_->pdf()->xfx(qbHadron_,showerAntiquark_->dataPtr() ,PDFScale_,x2); t_u_MR_o_MB = t_u_M_R_gqb_hel_amp(R,false)/lo_me_; } // Multiply ratio of the real emission matrix elements to the Born matrix element // by the ratio of the pdfs for the real emission and born processes to get theWeight if(lo_lumi<=0.||nlo_lumi<=0.) return 0.; else return t_u_MR_o_MB * ( nlo_lumi/lo_lumi * p2/s ) * sqr(p2/s)/8./pi/pi / pT / p2 * GeV; } bool MEPP2VVPowheg::getEvent(vector & theRealMomenta, unsigned int & channel) { // Invariant mass of the colliding hadrons: Energy2 S = sqr(generator()->maximumCMEnergy()); // Born variables which are preserved (mass and rapidity of the diboson system): Energy2 p2 = B_.sb(); double Yb = B_.Yb(); // Born variables which are not preserved but are needed (the momentum fractions): double x1b(B_.x1b()), x2b(B_.x2b()); double x12b(x1b*x1b), x22b(x2b*x2b); // Maximum jet pT (half of the hadronic C.O.M. energy. N.B. this is overestimated a lot): Energy starting_pT = sqrt(S)/2.; // Initialize the pT_ *integration limit* i.e. the pT of the generated emission: pT_ = ZERO; // The pT *integration variable*: Energy pT; // The x_1 & x_2 momentum fractions corresponding to incoming momenta p1 & p2: double x1_(-999.), x2_(-999.); double x1 (-999.), x2 (-999.); // The jet rapidity *integration variable* and its limits: double Yk, minYk(-8.0), maxYk(8.0); // The theta2 integration variable (the azimuthal angle of the gluon w.r.t // V1 in the V1 & V2 rest frame: double theta2; // The realVVKinematics object corresponding to the current integration // set of integration variables: realVVKinematics R; // The veto algorithm rejection weight and a corresponding flag: double rejectionWeight; bool rejectEmission ; // Initialize the flag indicating the selected radiation channel: channel=999; // Some product of constants used for the crude distribution: double a(0.); for(int j=0;j<3;j++) { pT=starting_pT; a =(maxYk-minYk)*prefactor_[j]/2./b0_; do { // Generate next pT according to exp[- \int^{pTold}_{pT} dpT a*(power-1)/(pT^power)] // pT = GeV/pow( pow(GeV/pT,power_-1.) - log(UseRandom::rnd())/a // , 1./(power_-1.) ); // Generate next pT according to exp[- \int^{pTold}_{pT} dpT alpha1loop*prefactor/pT ] pT = LambdaQCD_*exp( 0.5*exp( log(log(sqr(pT/LambdaQCD_)))+log(UseRandom::rnd())/a ) ); // Generate rapidity of the jet: Yk = minYk + UseRandom::rnd()*(maxYk - minYk); // Generate the theta2 radiative variable: // KH 19th August - next line changed for phi in 0->pi not 0->2pi // theta2 = UseRandom::rnd() * 2.*Constants::pi; theta2 = UseRandom::rnd() * Constants::pi; // eT of the diboson system: Energy eT = sqrt(pT*pT+p2); // Calculate the eT and then solve for x_{\oplus} & x_{\ominus}: x1 = (pT*exp( Yk)+eT*exp( Yb))/sqrt(S); x2 = (pT*exp(-Yk)+eT*exp(-Yb))/sqrt(S); // Calculate the xr radiative variable: double xr(p2/(x1*x2*S)); // Then use this to calculate the y radiative variable: double y(-((xr+1.)/(xr-1.))*(xr*sqr(x1/x1b)-1.)/(xr*sqr(x1/x1b)+1.)); // The y value above should equal the one commented out below this line: // double y( ((xr+1.)/(xr-1.))*(xr*sqr(x2/x2b)-1.)/(xr*sqr(x2/x2b)+1.)); // Now we get the lower limit on the x integration, xbar: double omy(1.-y), opy(1.+y); double xbar1 = 2.*opy*x12b/(sqrt(sqr(1.+x12b)*sqr(omy)+16.*y*x12b)+omy*(1.-x1b)*(1.+x1b)); double xbar2 = 2.*omy*x22b/(sqrt(sqr(1.+x22b)*sqr(opy)-16.*y*x22b)+opy*(1.-x2b)*(1.+x2b)); double xbar = max(xbar1,xbar2); // Now we can calculate xtilde: double xt = (xr-xbar)/(1.-xbar); // Finally we can make the realVVKinematics object: R = realVVKinematics(B_,xt,y,theta2); // The next thing we have to do is set the QCD, EW and PDF scales using R: setTheScales(pT); // ... and so calculate rejection weight: rejectionWeight = getResult(j,R,pT); // If generating according to exp[- \int^{pTold}_{pT} dpT a*(power-1)/(pT^power)] // rejectionWeight/= showerAlphaS_->overestimateValue()*prefactor_[j]*pow(GeV/pT,power_); // If generating according to exp[- \int^{pTold}_{pT} dpT alpha1loop*prefactor/pT ] rejectionWeight/= 1./b0_/log(sqr(pT/LambdaQCD_))*prefactor_[j]*GeV/pT; rejectEmission = UseRandom::rnd()>rejectionWeight; // The event is a no-emission event if pT goes past min_pT_ - basically set to // outside the histogram bounds (hopefully histogram objects just ignore it then). if(pT1.) { ostringstream stream; stream << "MEPP2VVPowheg::getEvent weight for channel " << j << " is greater than one: " << rejectionWeight << endl; generator()->logWarning( Exception(stream.str(), Exception::warning) ); } } while(rejectEmission); // set pT of emission etc if(pT>pT_) { channel = j; pT_ = pT; Yk_ = Yk; R_ = R ; x1_ = x1; x2_ = x2; } } // Was this an (overall) no emission event? if(pT_3) throw Exception() << "MEPP2VVPowheg::getEvent() channel = " << channel << " pT = " << pT/GeV << " pT_ = " << pT_/GeV << Exception::abortnow; // Work out the momenta in the lab frame, reserving the mass and rapidity // of the VV system: LorentzRotation yzRotation; yzRotation.setRotateX(-atan2(pT_/GeV,sqrt(p2)/GeV)); LorentzRotation boostFrompTisZero; boostFrompTisZero.setBoostY(-pT_/sqrt(p2+pT_*pT_)); LorentzRotation boostFromYisZero; boostFromYisZero.setBoostZ(tanh(Yb)); theRealMomenta.resize(5); theRealMomenta[0] = Lorentz5Momentum(ZERO,ZERO, x1_*sqrt(S)/2., x1_*sqrt(S)/2.,ZERO); theRealMomenta[1] = Lorentz5Momentum(ZERO,ZERO,-x2_*sqrt(S)/2., x2_*sqrt(S)/2.,ZERO); theRealMomenta[2] = boostFromYisZero*boostFrompTisZero*yzRotation*(R_.k1r()); theRealMomenta[3] = boostFromYisZero*boostFrompTisZero*yzRotation*(R_.k2r()); theRealMomenta[4] = Lorentz5Momentum(ZERO, pT_, pT_*sinh(Yk_), pT_*cosh(Yk_),ZERO); return true; } void MEPP2VVPowheg::setTheScales(Energy pT) { // Work out the scales we want to use in the matrix elements and the pdfs: // Scale for alpha_S: pT^2 of the diboson system. QCDScale_ = max(pT*pT,sqr(min_pT_)); // Scale for real emission PDF: // pT^2+mVV^2 - as mcfm does in the case of a single W/Z boson). // Energy2 PDFScale_ = max(R.pT2_in_lab(),sqr(min_pT_))+R.s2r(); // pT^2 - as advocated by Nason & Ridolfi for ZZ production & Alioli et al for gg->h: PDFScale_ = max(pT*pT,sqr(min_pT_)); // Scale of electroweak vertices: mVV^2 the invariant mass of the diboson system. // EWScale_ = B_.sb(); // ... And this choice is more like what can be seen in mcatnlo_vbmain.f (weird). EWScale_ = 0.5*(B_.k12b()+B_.k22b()); return; } /***************************************************************************/ // This is identical to the code in the Powheg matrix element. It should // equal t_u_M_R_qqb in there, which is supposed to be the real emission ME // times tk*uk. Energy2 MEPP2VVPowheg::t_u_M_R_qqb_hel_amp(realVVKinematics R, bool getMatrix) const { using namespace ThePEG::Helicity; ProductionMatrixElement qqb_hel_amps(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1 ,PDT::Spin1 , PDT::Spin1); double sum_hel_amps_sqr(0.); tcPDPtr p1data(showerQuark_->dataPtr()); tcPDPtr p2data(showerAntiquark_->dataPtr()); tcPDPtr k1data(V1_->dataPtr()); tcPDPtr k2data(V2_->dataPtr()); tcPDPtr kdata(getParticleData(ParticleID::g)); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorWaveFunction qSpinor(R.p1r(),p1data,incoming); SpinorBarWaveFunction qbSpinor(R.p2r(),p2data,incoming); vector q; vector qb; for(unsigned int ix=0;ix<2;ix++) { qSpinor.reset(ix); qbSpinor.reset(ix); q.push_back(qSpinor); qb.push_back(qbSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.kr(),kdata,outgoing); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(p2data); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorWaveFunction p1_k = ffg->evaluate(QCDScale_,5,p1data,q[p1hel],g[khel]); SpinorBarWaveFunction p2_k = ffg->evaluate(QCDScale_,5,p2data,qb[p2hel],g[khel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p1hel=p2hel // but if the production ME is required first fill it with (0.,0.). if((p1hel==p2hel)&&helicityConservation_) { if(getMatrix) { if(khel==0) qqb_hel_amps(p1hel,p2hel,k1hel,k2hel,0) = Complex(0.,0.); else qqb_hel_amps(p1hel,p2hel,k1hel,k2hel,2) = Complex(0.,0.); } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_t; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? p2data : tc[ix]; // Note: choosing 5 as the second argument ffvX_->evaluate() sets // option 5 in thepeg/Helicity/Vertex/VertexBase.cc, which makes // the (fermion) propagator denominator massless: 1/p^2. // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams SpinorWaveFunction p1_v1 = ffv1->evaluate(EWScale_,5,intermediate_t,q[p1hel],v1[k1hel]); SpinorBarWaveFunction p2_v2 = ffv2->evaluate(EWScale_,5,intermediate_t,qb[p2hel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 t-channel diagrams // q+qb->g+v1+v2, q+qb->v1+g+v2, q+qb->v1+v2+g if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) { diagrams.push_back(ffv1->evaluate(EWScale_,p1_k,p2_v2,v1[k1hel])); diagrams.push_back(ffg->evaluate(QCDScale_,p1_v1,p2_v2,g[khel])); diagrams.push_back(ffv2->evaluate(EWScale_,p1_v1,p2_k,v2[k2hel])); } intermediate_t = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(EWScale_,5,intermediate_t,q[p1hel],v2[k2hel]); SpinorBarWaveFunction p2_v1 = ffv1->evaluate(EWScale_,5,intermediate_t,qb[p2hel],v1[k1hel]); // q+qb->g+v2+v1, q+qb->v2+g+v1, q+qb->v2+v1+g if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) { diagrams.push_back(ffv2->evaluate(EWScale_,p1_k,p2_v1,v2[k2hel])); diagrams.push_back(ffg->evaluate(QCDScale_,p1_v2,p2_v1,g[khel])); diagrams.push_back(ffv1->evaluate(EWScale_,p1_v2,p2_k,v1[k1hel])); } } // Note: choosing 3 as the second argument in WWWvertex_->evaluate() // sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which // means the propagator does not contain a width factor (which is // good re. gauge invariance). // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(EWScale_,3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(EWScale_,p1_k,qb[p2hel],k1_k2)); diagrams.push_back(ffv1->evaluate(EWScale_,q[p1hel],p2_k,k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==-p2data->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(EWScale_,3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(EWScale_,p1_k,qb[p2hel],k1_k2)); diagrams.push_back(FFZvertex_->evaluate(EWScale_,q[p1hel],p2_k,k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(EWScale_,3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(EWScale_,p1_k,qb[p2hel],k1_k2)); diagrams.push_back(FFPvertex_->evaluate(EWScale_,q[p1hel],p2_k,k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } /***************************************************************************/ // This is identical to the code in the Powheg matrix element. It should // equal t_u_M_R_qg in there, which is supposed to be the real emission ME // times tk*uk. Energy2 MEPP2VVPowheg::t_u_M_R_qg_hel_amp(realVVKinematics R, bool getMatrix) const { using namespace ThePEG::Helicity; ProductionMatrixElement qg_hel_amps(PDT::Spin1Half,PDT::Spin1, PDT::Spin1,PDT::Spin1, PDT::Spin1Half); double sum_hel_amps_sqr(0.); tcPDPtr p1data(showerQuark_->dataPtr()); tcPDPtr p2data(getParticleData(ParticleID::g)); tcPDPtr k1data(V1_->dataPtr()); tcPDPtr k2data(V2_->dataPtr()); tcPDPtr kdata (showerAntiquark_->dataPtr()->CC()); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorWaveFunction qinSpinor(R.p1r(),p1data,incoming); SpinorBarWaveFunction qoutSpinor(R.kr(),kdata,outgoing); vector qin; vector qout; for(unsigned int ix=0;ix<2;ix++) { qinSpinor.reset(ix); qoutSpinor.reset(ix); qin.push_back(qinSpinor); qout.push_back(qoutSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.p2r(),p2data,incoming); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(kdata->CC()); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorWaveFunction p1_p2 = ffg->evaluate(QCDScale_,5,p1data,qin[p1hel],g[p2hel]); SpinorBarWaveFunction p2_k = ffg->evaluate(QCDScale_,5,kdata->CC(),qout[khel],g[p2hel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p1hel!=khel // but if the production ME is required first fill it with (0.,0.). if((p1hel!=khel)&&helicityConservation_) { if(getMatrix) { if(p2hel==0) qg_hel_amps(p1hel,0,k1hel,k2hel,khel) = Complex(0.,0.); else qg_hel_amps(p1hel,2,k1hel,k2hel,khel) = Complex(0.,0.); } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_q; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? showerAntiquark_->dataPtr() : tc[ix]; SpinorWaveFunction p1_v1 = ffv1->evaluate(EWScale_,5,intermediate_q,qin[p1hel],v1[k1hel]); SpinorBarWaveFunction k_v2 = ffv2->evaluate(EWScale_,5,intermediate_q,qout[khel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 abelian diagrams // q+g->v1+v2+q with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) { diagrams.push_back(ffv2->evaluate(EWScale_,p1_v1,p2_k,v2[k2hel])); diagrams.push_back(ffg->evaluate(QCDScale_,p1_v1,k_v2,g[p2hel])); diagrams.push_back(ffv1->evaluate(EWScale_,p1_p2,k_v2,v1[k1hel])); } intermediate_q = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(EWScale_,5,intermediate_q,qin[p1hel],v2[k2hel]); SpinorBarWaveFunction k_v1 = ffv1->evaluate(EWScale_,5,intermediate_q,qout[khel],v1[k1hel]); // q+g->v2+v1+q, with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) { diagrams.push_back(ffv1->evaluate(EWScale_,p1_v2,p2_k,v1[k1hel])); diagrams.push_back(ffg->evaluate(QCDScale_,p1_v2,k_v1,g[p2hel])); diagrams.push_back(ffv2->evaluate(EWScale_,p1_p2,k_v1,v2[k2hel])); } } // Note: choosing 3 as the second argument in WWWvertex_->evaluate() // sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which // means the propagator does not contain a width factor (which is // good re. gauge invariance). // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(EWScale_,3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(EWScale_,p1_p2,qout[khel],k1_k2)); diagrams.push_back(ffv1->evaluate(EWScale_,qin[p1hel],p2_k,k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==kdata->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(EWScale_,3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(EWScale_,p1_p2,qout[khel],k1_k2)); diagrams.push_back(FFZvertex_->evaluate(EWScale_,qin[p1hel],p2_k,k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(EWScale_,3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(EWScale_,p1_p2,qout[khel],k1_k2)); diagrams.push_back(FFPvertex_->evaluate(EWScale_,qin[p1hel],p2_k,k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } /***************************************************************************/ // This is identical to the code in the Powheg matrix element. It should // equal t_u_M_R_gqb in there, which is supposed to be the real emission ME // times tk*uk. Energy2 MEPP2VVPowheg::t_u_M_R_gqb_hel_amp(realVVKinematics R, bool getMatrix) const { using namespace ThePEG::Helicity; ProductionMatrixElement gqb_hel_amps(PDT::Spin1,PDT::Spin1Half, PDT::Spin1,PDT::Spin1, PDT::Spin1Half); double sum_hel_amps_sqr(0.); tcPDPtr p1data(getParticleData(ParticleID::g)); tcPDPtr p2data(showerAntiquark_->dataPtr()); tcPDPtr k1data(V1_->dataPtr()); tcPDPtr k2data(V2_->dataPtr()); tcPDPtr kdata (showerQuark_->dataPtr()->CC()); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorBarWaveFunction qbinSpinor(R.p2r(),p2data,incoming); SpinorWaveFunction qboutSpinor(R.kr(),kdata,outgoing); vector qbin; vector qbout; for(unsigned int ix=0;ix<2;ix++) { qbinSpinor.reset(ix); qboutSpinor.reset(ix); qbin.push_back(qbinSpinor); qbout.push_back(qboutSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.p1r(),p1data,incoming); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p2data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p2data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(kdata->CC()); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorBarWaveFunction p1_p2 = ffg->evaluate(QCDScale_,5,p2data,qbin[p2hel],g[p1hel]); SpinorWaveFunction p1_k = ffg->evaluate(QCDScale_,5,kdata->CC(),qbout[khel],g[p1hel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p2hel!=khel // but if the production ME is required first fill it with (0.,0.). if((p2hel!=khel)&&helicityConservation_) { if(getMatrix) { if(p1hel==0) gqb_hel_amps(0,p2hel,k1hel,k2hel,khel) = Complex(0.,0.); else gqb_hel_amps(2,p2hel,k1hel,k2hel,khel) = Complex(0.,0.); } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_q; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? showerQuark_->dataPtr() : tc[ix]; SpinorBarWaveFunction p2_v1 = ffv1->evaluate(EWScale_,5,intermediate_q,qbin[p2hel],v1[k1hel]); SpinorWaveFunction k_v2 = ffv2->evaluate(EWScale_,5,intermediate_q,qbout[khel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 abelian diagrams q+g->v1+v2+q // with 2 t-channel propagators, 1 s- and 1 t-channel // and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p2data->id())%2==0))) { diagrams.push_back(ffv2->evaluate(EWScale_,p1_k,p2_v1,v2[k2hel])); diagrams.push_back(ffg->evaluate(QCDScale_,k_v2,p2_v1,g[p1hel])); diagrams.push_back(ffv1->evaluate(EWScale_,k_v2,p1_p2,v1[k1hel])); } intermediate_q = (!(k1data->id()==24&&k2data->id()==-24)) ? p2data : tc[ix]; SpinorBarWaveFunction p2_v2 = ffv2->evaluate(EWScale_,5,intermediate_q,qbin[p2hel],v2[k2hel]); SpinorWaveFunction k_v1 = ffv1->evaluate(EWScale_,5,intermediate_q,qbout[khel],v1[k1hel]); // q+g->v2+v1+q, with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p2data->id())%2==1))) { diagrams.push_back(ffv1->evaluate(EWScale_,p1_k,p2_v2,v1[k1hel])); diagrams.push_back(ffg->evaluate(QCDScale_,k_v1,p2_v2,g[p1hel])); diagrams.push_back(ffv2->evaluate(EWScale_,k_v1,p1_p2,v2[k2hel])); } } // Note: choosing 3 as the second argument in WWWvertex_->evaluate() // sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which // means the propagator does not contain a width factor (which is // good re. gauge invariance). // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(EWScale_,3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(EWScale_,qbout[khel],p1_p2,k1_k2)); diagrams.push_back(ffv1->evaluate(EWScale_,p1_k,qbin[p2hel],k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p2data->id()==kdata->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(EWScale_,3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(EWScale_,qbout[khel],p1_p2,k1_k2)); diagrams.push_back(FFZvertex_->evaluate(EWScale_,p1_k,qbin[p2hel],k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(EWScale_,3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(EWScale_,qbout[khel],p1_p2,k1_k2)); diagrams.push_back(FFPvertex_->evaluate(EWScale_,p1_k,qbin[p2hel],k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } /***************************************************************************/ // This returns exactly the same value as lo_me2_ when you put it in MEPP2VVPowheg.cc double MEPP2VVPowheg::lo_me(bool getMatrix) const { using namespace ThePEG::Helicity; ProductionMatrixElement lo_hel_amps(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1 ,PDT::Spin1); double sum_hel_amps_sqr(0.); tcPDPtr p1data(showerQuark_->dataPtr()); tcPDPtr p2data(showerAntiquark_->dataPtr()); tcPDPtr k1data(V1_->dataPtr()); tcPDPtr k2data(V2_->dataPtr()); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); // Should never actually occur. // If you want to reproduce the spin correlations of MEPP2VV // you should evaluate this ME using the lab frame momenta // instead of the bornVVKinematics ones (partonic C.O.M. frame). SpinorWaveFunction qSpinor; SpinorBarWaveFunction qbSpinor; if(!getMatrix) { qSpinor=SpinorWaveFunction(B_.p1b(),p1data,incoming); qbSpinor=SpinorBarWaveFunction(B_.p2b(),p2data,incoming); } else { qSpinor=SpinorWaveFunction(showerQuark_->momentum(),p1data,incoming); qbSpinor=SpinorBarWaveFunction(showerAntiquark_->momentum(),p2data,incoming); } vector q; vector qb; for(unsigned int ix=0;ix<2;ix++) { qSpinor.reset(ix); qbSpinor.reset(ix); q.push_back(qSpinor); qb.push_back(qbSpinor); } // If you want to reproduce the spin correlations of MEPP2VV // you should evaluate this ME using the lab frame momenta // instead of the bornVVKinematics ones (partonic C.O.M. frame). VectorWaveFunction v1Polarization; VectorWaveFunction v2Polarization; if(!getMatrix) { v1Polarization=VectorWaveFunction(B_.k1b(),k1data,outgoing); v2Polarization=VectorWaveFunction(B_.k2b(),k2data,outgoing); } else { v1Polarization=VectorWaveFunction(V1_->momentum(),k1data,outgoing); v2Polarization=VectorWaveFunction(V2_->momentum(),k2data,outgoing); } vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(p2data); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { if((p1hel==p2hel)&&helicityConservation_) { lo_hel_amps(p1hel,p2hel,k1hel,k2hel) = Complex(0.,0.); continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_t; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? p2data : tc[ix]; SpinorWaveFunction p1_v1 = ffv1->evaluate(EWScale_,5,intermediate_t,q[p1hel],v1[k1hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 t-channel diagrams // q+qb->v1+v2 if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) diagrams.push_back(ffv2->evaluate(EWScale_,p1_v1,qb[p2hel],v2[k2hel])); intermediate_t = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(EWScale_,5,intermediate_t,q[p1hel],v2[k2hel]); // q+qb->v2+v1 if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) diagrams.push_back(ffv1->evaluate(EWScale_,p1_v2,qb[p2hel],v1[k1hel])); } // Note: choosing 3 as the second argument in WWWvertex_->evaluate() // sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which // means the propagator does not contain a width factor (which is // good re. gauge invariance). // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(EWScale_,3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->v1*->v1+v2 diagrams.push_back(ffv1->evaluate(EWScale_,q[p1hel],qb[p2hel],k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==-p2data->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->Z0*->v1+v2 tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(EWScale_,3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(EWScale_,q[p1hel],qb[p2hel],k1_k2)); // q+qb->gamma*->v1+v2 tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(EWScale_,3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(EWScale_,q[p1hel],qb[p2hel],k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr; } /***************************************************************************/ // This member selects a [2-body] decay mode and assigns children to the // vector bosons with momenta which are isotropic in their rest frames. bool MEPP2VVPowheg::isotropicDecayer() { using namespace ThePEG::Helicity; // Generate the children's momenta isotropically in // the rest frames of V1 and V2: double cth,phi; // First V1's children: cth = UseRandom::rnd()*2.-1.; phi = UseRandom::rnd()*2.*Constants::pi; Energy m1(V1_->momentum().m()); Energy m3(children_[0]->data().constituentMass()); Energy m4(children_[1]->data().constituentMass()); Energy p34(triangleFn(sqr(m1),sqr(m3),sqr(m4)) /2./m1); if(isnan(p34/GeV)||cth>1.||cth<-1.) return false; Energy pT34(p34*sqrt(1.-cth)*sqrt(1.+cth)); Lorentz5Momentum k3(pT34*sin(phi),pT34*cos(phi),p34 *cth, sqrt(p34*p34+sqr(m3)),m3); Lorentz5Momentum k4(-k3); k4.setE(sqrt(p34*p34+sqr(m4))); k4.setTau(m4); Boost boostToV1RF(R_.k1r().boostVector()); k3.boost(boostToV1RF); k3.rescaleRho(); k4.boost(boostToV1RF); k4.rescaleRho(); // Second V2's children: cth = UseRandom::rnd()*2.-1.; phi = UseRandom::rnd()*2.*Constants::pi; Energy m2(V2_->momentum().m()); Energy m5(children_[2]->data().constituentMass()); Energy m6(children_[3]->data().constituentMass()); Energy p56(triangleFn(sqr(m2),sqr(m5),sqr(m6)) /2./m2); if(isnan(p56/GeV)||cth>1.||cth<-1.) return false; Energy pT56(p56*sqrt(1.-cth)*sqrt(1.+cth)); Lorentz5Momentum k5(pT56*sin(phi),pT56*cos(phi),p56*cth, sqrt(p56*p56+sqr(m5)),m5); Lorentz5Momentum k6(-k5); k6.setE(sqrt(p56*p56+sqr(m6))); k6.setTau(m6); Boost boostToV2RF(R_.k2r().boostVector()); k5.boost(boostToV2RF); k5.rescaleRho(); k6.boost(boostToV2RF); k6.rescaleRho(); // Assign the momenta to the children: children_[0]->set5Momentum(k3); children_[1]->set5Momentum(k4); children_[2]->set5Momentum(k5); children_[3]->set5Momentum(k6); return true; } // Override 2->2 production matrix here: void MEPP2VVPowheg::recalculateVertex() { // Zero the squared amplitude; this equals sum_hel_amps_sqr if all // is working as it should: Complex productionMatrix2(0.,0.); for(unsigned int k1hel=0;k1hel<3;++k1hel) for(unsigned int k2hel=0;k2hel<3;++k2hel) productionMatrix2 += productionMatrix_[k1hel][k1hel][k2hel][k2hel]; // Get the vector wavefunctions: VectorWaveFunction v1Polarization; VectorWaveFunction v2Polarization; v1Polarization=VectorWaveFunction(R_.k1r(),V1_->dataPtr(),outgoing); v2Polarization=VectorWaveFunction(R_.k2r(),V2_->dataPtr(),outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } AbstractFFVVertexPtr ffv1 = V1_->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = V2_->id()==23 ? FFZvertex_ : FFWvertex_; bool vetoed(true); while(vetoed) { // Decay the bosons isotropically in their rest frames: isotropicDecayer(); // Get the spinor wavefunctions: SpinorWaveFunction k3Spinor(children_[0]->momentum(),children_[0]->dataPtr(),outgoing); SpinorBarWaveFunction k4Spinor(children_[1]->momentum(),children_[1]->dataPtr(),outgoing); SpinorWaveFunction k5Spinor(children_[2]->momentum(),children_[2]->dataPtr(),outgoing); SpinorBarWaveFunction k6Spinor(children_[3]->momentum(),children_[3]->dataPtr(),outgoing); vector k3,k5; vector k4,k6; for(unsigned int ix=0;ix<2;ix++) { k3Spinor.reset(ix); k4Spinor.reset(ix); k3.push_back(k3Spinor); k4.push_back(k4Spinor); k5Spinor.reset(ix); k6Spinor.reset(ix); k5.push_back(k5Spinor); k6.push_back(k6Spinor); } DecayMEPtr decayAmps(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1Half,PDT::Spin1Half))); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k3hel=0;k3hel<2;++k3hel) { for(unsigned int k4hel=0;k4hel<2;++k4hel) { (*decayAmps)(k1hel,k3hel,k4hel) = ffv1->evaluate(EWScale_,k3[k3hel],k4[k4hel],v1[k1hel]); } } } Complex V1decayMatrix[3][3]; for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k1helpr=0;k1helpr<3;++k1helpr) { Complex theElement(0.,0.); for(unsigned int k3hel=0;k3hel<2;++k3hel) { for(unsigned int k4hel=0;k4hel<2;++k4hel) { theElement += (*decayAmps)(k1hel,k3hel,k4hel) *conj((*decayAmps)(k1helpr,k3hel,k4hel)); } } V1decayMatrix[k1hel][k1helpr] = theElement; } } Complex V1decayMatrix2(0.,0.); for(unsigned int k1hel=0;k1hel<3;++k1hel) V1decayMatrix2 += V1decayMatrix[k1hel][k1hel]; for(unsigned int k2hel=0;k2hel<3;++k2hel) { for(unsigned int k5hel=0;k5hel<2;++k5hel) { for(unsigned int k6hel=0;k6hel<2;++k6hel) { (*decayAmps)(k2hel,k5hel,k6hel) = ffv2->evaluate(EWScale_,k5[k5hel],k6[k6hel],v2[k2hel]); } } } Complex V2decayMatrix[3][3]; for(unsigned int k2hel=0;k2hel<3;++k2hel) { for(unsigned int k2helpr=0;k2helpr<3;++k2helpr) { Complex theElement(0.,0.); for(unsigned int k5hel=0;k5hel<2;++k5hel) { for(unsigned int k6hel=0;k6hel<2;++k6hel) { theElement += (*decayAmps)(k2hel,k5hel,k6hel) *conj((*decayAmps)(k2helpr,k5hel,k6hel)); } } V2decayMatrix[k2hel][k2helpr] = theElement; } } Complex V2decayMatrix2(0.,0.); for(unsigned int k2hel=0;k2hel<3;++k2hel) V2decayMatrix2 += V2decayMatrix[k2hel][k2hel]; // Contract the production matrix and the decay matrices: Complex meTimesV1V2denominators(0.,0.); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k1helpr=0;k1helpr<3;++k1helpr) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { for(unsigned int k2helpr=0;k2helpr<3;++k2helpr) { meTimesV1V2denominators += productionMatrix_[k1hel][k1helpr][k2hel][k2helpr] *V1decayMatrix[k1hel][k1helpr] *V2decayMatrix[k2hel][k2helpr]; } } } } if(imag(meTimesV1V2denominators)/real(meTimesV1V2denominators)>1.e-7) cout << "MEPP2VVPowheg warning\n" << "the matrix element's imaginary part is large " << meTimesV1V2denominators << endl; if(imag(productionMatrix2)/real(productionMatrix2)>1.e-7) cout << "MEPP2VVPowheg warning\n" << "the production matrix element's imaginary part is large " << productionMatrix2 << endl; if(imag(V1decayMatrix2)/real(V1decayMatrix2)>1.e-7) cout << "MEPP2VVPowheg warning\n" << "the V1 decay matrix element's imaginary part is large " << V1decayMatrix2 << endl; if(imag(V2decayMatrix2)/real(V2decayMatrix2)>1.e-7) cout << "MEPP2VVPowheg warning\n" << "the V2 decay matrix element's imaginary part is large " << V2decayMatrix2 << endl; // Need branching ratio at least in here I would think ---> double decayWeight( real(meTimesV1V2denominators) / real(productionMatrix2*V1decayMatrix2*V2decayMatrix2)); if(decayWeight>1.) cout << "MEPP2VVPowheg::recalculateVertex decayWeight > 1., decayWeight = " << decayWeight << endl; if(decayWeight<0.) cout << "MEPP2VVPowheg::recalculateVertex decayWeight < 0., decayWeight = " << decayWeight << endl; if(UseRandom::rnd()=ZERO) { return sqrt(lambda2); } else { generator()->log() << "MEPP2VVPowheg::triangleFn " << "kinematic instability, imaginary triangle function\n"; return -999999.*GeV2; } } diff --git a/MatrixElement/Powheg/MEPP2VVPowheg.h b/MatrixElement/Powheg/MEPP2VVPowheg.h --- a/MatrixElement/Powheg/MEPP2VVPowheg.h +++ b/MatrixElement/Powheg/MEPP2VVPowheg.h @@ -1,874 +1,874 @@ // -*- C++ -*- #ifndef HERWIG_MEPP2VVPowheg_H #define HERWIG_MEPP2VVPowheg_H // // This is the declaration of the MEPP2VVPowheg class. // #include "Herwig/MatrixElement/Hadron/MEPP2VV.h" #include "Herwig/MatrixElement/Powheg/VVKinematics.h" #include "Herwig/Utilities/Maths.h" #include "Herwig/Models/StandardModel/StandardCKM.h" #include "Herwig/Shower/Couplings/ShowerAlpha.h" namespace Herwig { using namespace ThePEG; using Math::ReLi2; using Constants::pi; /** * Here is the documentation of the MEPP2VVPowheg class. * * @see \ref MEPP2VVPowhegInterfaces "The interfaces" * defined for MEPP2VVPowheg. */ class MEPP2VVPowheg: public MEPP2VV { public: /** * The default constructor. */ MEPP2VVPowheg(); /** @name Member functions for the generation of hard QCD radiation */ //@{ /** * Has a POWHEG style correction */ virtual POWHEGType hasPOWHEGCorrection() {return ISR;} /** * Apply the POWHEG style correction */ virtual HardTreePtr generateHardest(ShowerTreePtr, - vector inter); + ShowerInteraction::Type inter); //@} public: /** * Generate internal degrees of freedom given nDim() uniform * random numbers in the interval \f$ ]0,1[ \f$. To help the phase space * generator, the dSigHatDR should be a smooth function of these * numbers, although this is not strictly necessary. * @param r a pointer to the first of nDim() consecutive random numbers. * @return true if the generation succeeded, otherwise false. */ virtual bool generateKinematics(const double * r); /** * The number of internal degrees of freedom used in the matrix * element. */ virtual int nDim() const; /** * The matrix element for the kinematical configuration * previously provided by the last call to setKinematics(), suitably * scaled by sHat() to give a dimension-less number. * @return the matrix element scaled with sHat() to give a * dimensionless number. */ virtual double me2() const; /** * Return the scale associated with the last set phase space point. */ virtual Energy2 scale() const; /** * This member check the collinear limits of the * real emission matrix elements are equal to the * appropriate combinations of Born ME's multiplied * by the splitting functions. */ bool sanityCheck() const; /** * Return the CKM matrix elements. */ Complex CKM(int ix,int iy) const { return ckm_[ix][iy]; } 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(); //@} public: /** * Function to set the born variables. */ void getKinematics(double xt, double y, double theta2); /** * Calculate the correction weight with which leading-order * configurations are re-weighted. */ double NLOweight() const; /** * Calculate the ratio of the NLO luminosity to the LO * luminosity function for the \f$q\bar{q}\f$ initiated channel. */ double Lhat_ab(tcPDPtr a, tcPDPtr b, realVVKinematics Kinematics) const; /** * Calculate the universal soft-virtual contribution to the NLO weight. */ double Vtilde_universal(realVVKinematics S) const; /** * Function for calculation of the \f$q\bar{q}\f$ initiated real * contribution. */ double Ctilde_Ltilde_qq_on_x(tcPDPtr a,tcPDPtr b,realVVKinematics C) const; /** * Function for calculation of the \f$gq\f$ initiated real * contribution. */ double Ctilde_Ltilde_gq_on_x(tcPDPtr a,tcPDPtr b,realVVKinematics C) const; /** * Function for calculation of the \f$q\bar{q}\f$ initiated real * contribution. */ double Rtilde_Ltilde_qqb_on_x(tcPDPtr a,tcPDPtr b) const; /** * Function for calculation of the \f$qg\f$ initiated real * contribution. */ double Rtilde_Ltilde_qg_on_x(tcPDPtr a,tcPDPtr b) const; /** * Function for calculation of the \f$gqb\f$ initiated real * contribution. */ double Rtilde_Ltilde_gqb_on_x(tcPDPtr a,tcPDPtr b) const; /** * The regular part of the virtual correction matrix element(s). * For WZ production this is given by Equation B.2 in NPB 383 (1992) * 3-44 *** modulo a factor 1/(2s) ***, which is a flux factor that * those authors absorb in the matrix element. */ double M_V_regular(realVVKinematics S) const; /** * Member variable to store the * regular part of the virtual correction matrix element(s). * For WZ production this is given by Equation B.2 in NPB 383 (1992) * 3-44 *** modulo a factor 1/(2s) ***, which is a flux factor that * those authors absorb in the matrix element. */ mutable double M_V_regular_; /** * The matrix element q + qb -> n + g times tk*uk */ Energy2 t_u_M_R_qqb(realVVKinematics R) const; /** * Member variable to store the matrix element q + qb -> n + g times tk*uk */ mutable Energy2 t_u_M_R_qqb_; /** * The matrix element q + g -> n + q times tk*uk */ Energy2 t_u_M_R_qg(realVVKinematics R) const; /** * Member variable to store the matrix element q + g -> n + q times tk*uk */ mutable Energy2 t_u_M_R_qg_; /** * The matrix element g + qb -> n + q times tk*uk */ Energy2 t_u_M_R_gqb(realVVKinematics R) const; /** * Member variable to store the matrix element g + qb -> n + q times tk*uk */ mutable Energy2 t_u_M_R_gqb_; /** * The matrix element q + qb -> n + g times (tk*uk)^2 - using helicity amplitudes */ Energy2 t_u_M_R_qqb_hel_amp(realVVKinematics R) const; /** * Member variable to store the * matrix element q + qb -> n + g times (tk*uk)^2 - using helicity amplitudes */ mutable Energy2 t_u_M_R_qqb_hel_amp_; /** * The matrix element q + g -> n + q times (tk*uk)^2 - using helicity amplitudes */ Energy2 t_u_M_R_qg_hel_amp(realVVKinematics R) const; /** * Member variable to store the * matrix element q + g -> n + q times (tk*uk)^2 - using helicity amplitudes */ mutable Energy2 t_u_M_R_qg_hel_amp_; /** * The matrix element g + qb -> n + qb times (tk*uk)^2 - using helicity amplitudes */ Energy2 t_u_M_R_gqb_hel_amp(realVVKinematics R) const; /** * Member variable to store the * matrix element g + qb -> n + qb times (tk*uk)^2 - using helicity amplitudes */ mutable Energy2 t_u_M_R_gqb_hel_amp_; /** * The leading order matrix element - using helicity amplitudes */ double lo_me() const; /** * The Born matrix element as given in Equation 3.1 - 3.3 in NPB 383 * (1992) *** modulo a factor 1/(2s) ***, which is a flux factor that * those authors absorb in the matrix element. */ double M_Born_WZ(bornVVKinematics B) const; /** * Member variable to store the * Born matrix element as given in Equation 3.1 - 3.3 in NPB 383 * (1992) *** modulo a factor 1/(2s) ***, which is a flux factor that * those authors absorb in the matrix element. */ mutable double M_Born_; /** * The Born matrix element as given in Equation 2.18 - 2.19 in NPB 357 * (1991) *** modulo a factor 1/(2s) ***, which is a flux factor that * those authors absorb in the matrix element. */ double M_Born_ZZ(bornVVKinematics B) const; /** * M_V_regular_ZZ is the regular part of the one-loop ZZ matrix element * exactly as defined in Eqs. B.1 & B.2 of NPB 357(1991)409-438 *** * modulo a factor 1/(2s) ***, which is a flux factor that * those authors absorb in the matrix element. */ double M_V_regular_ZZ(realVVKinematics S) const; /** * t_u_M_R_qqb_ZZ is the q + qb -> n + g times tk*uk real emission * matrix element as defined in Eq. C.1 of NPB 357(1991)409-438 *** * modulo a factor 1/(2s) ***, which is a flux factor that * those authors absorb in the matrix element. */ Energy2 t_u_M_R_qqb_ZZ(realVVKinematics R) const; /** * The Born matrix element as given in Equation 3.2 - 3.8 in NPB 410 * (1993) *** modulo a factor 1/(2s) ***, which is a flux factor that * those authors absorb in the matrix element. */ double M_Born_WW(bornVVKinematics B) const; /** * M_V_regular_WW is the regular part of the one-loop WW matrix element * exactly as defined in Eqs. C.1 - C.7 of of NPB 410(1993)280-324 *** * modulo a factor 1/(2s) ***, which is a flux factor that * those authors absorb in the matrix element. */ double M_V_regular_WW(realVVKinematics S) const; /** * t_u_M_R_qqb_WW is the q + qb -> n + g times tk*uk real emission * matrix element as defined in Eq. D.1-D.5 of NPB 410(1993)280-324 *** * modulo a factor 1/(2s) ***, which is a flux factor that * those authors absorb in the matrix element. */ Energy2 t_u_M_R_qqb_WW(realVVKinematics R) const; /** * Return the factorion scale squared. */ Energy2 mu_F2() const; /** * Return the renormalisation scale squared. */ Energy2 mu_UV2() const; protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ inline virtual IBPtr clone() const { return new_ptr(*this); } /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ inline virtual IBPtr fullclone() const { return new_ptr(*this); } //@} private: /** * The static object used to initialize the description of this class. * Indicates that this is a concrete class with persistent data. */ static ClassDescription initMEPP2VVPowheg; /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ MEPP2VVPowheg & operator=(const MEPP2VVPowheg &); private: /** * Parameters for the NLO weight */ //@{ /** * Parameter to determine when to use limiting value of real emission * matrix elements, to avoid rounding error issues. */ double tiny; /** * The BeamParticleData object for the plus and minus direction hadrons */ tcBeamPtr hadron_A_; tcBeamPtr hadron_B_; /** * Born / virtual 2->2 kinematics. */ bornVVKinematics B_; /** * Soft limit of the 2->3 real emission kinematics. */ realVVKinematics S_; /** * Soft-collinear limit of the 2->3 kinematics (emission in +z direction). */ realVVKinematics SCp_; /** * The collinear limit of the 2->3 kinematics (emission in -z direction). */ realVVKinematics SCm_; /** * The collinear limit of the 2->3 kinematics (emission in +z direction). */ realVVKinematics Cp_; /** * The collinear limit of the 2->3 kinematics (emission in -z direction). */ realVVKinematics Cm_; /** * The resolved 2->3 real emission kinematics: */ realVVKinematics H_; /** * The ParticleData object for the plus and minus lo partons */ tcPDPtr ab_, bb_; /** * The ParticleData object for the quark and antiquark * (which can be in a different order to ab_ and bb_). */ tcPDPtr quark_, antiquark_; /** * Values of the PDF's before radiation */ double lo_lumi_; /** * The value of the leading order qqbar->VV matrix element */ mutable double lo_me2_; /** * The CF_ colour factor */ double CF_; /** * The TR_ colour factor */ double TR_; /** * The number of colours */ double NC_; /** * The weak coupling and the sin (squared) of the Weinberg angle */ mutable double gW_, sin2ThetaW_; /** * The up and down, left handed, quark-boson couplings */ mutable double guL_, gdL_; /** * The up and down, right handed, quark-boson couplings (for WW & ZZ) */ mutable double guR_, gdR_; /** * The TGC coupling */ mutable double eZ_; /** * The TGC coupling squared. This is useful for debugging purposes * when one wants to turn of t-channel * TGC interference contributions * but leave the pure TGC contributions intact. It is also needed in * order to transform WZ matrix elements into WW ones. */ mutable double eZ2_; /** * The CKM factor (Fij^2) */ mutable double Fij2_; /** * Whether to generate the positive, negative or leading order contribution */ unsigned int contrib_; /** * Whether to generate all channels contributions or just qqb or just * qg+gqb contributions */ unsigned int channels_; /** * Whether to use a fixed or a running QCD coupling for the NLO weight */ unsigned int nlo_alphaS_opt_; /** * The value of alphaS to use for the nlo weight if nlo_alphaS_opt_=1 */ double fixed_alphaS_; /** * Flag to remove or multiply in MCFM branching fractions for testing */ unsigned int removebr_; /** * Selects a dynamic (sHat) or fixed factorization scale */ unsigned int scaleopt_; /** * The factorization scale */ Energy mu_F_; /** * The renormalization scale */ Energy mu_UV_; /** * The pT of V1 in a radiative event in the lab frame (for scale setting only) */ Energy2 k1r_perp2_lab_; /** * The pT of V2 in a radiative event in the lab frame (for scale setting only) */ Energy2 k2r_perp2_lab_; /** * The ckm matrix elements (unsquared, to allow interference) */ vector< vector > ckm_; /** * Option to impose helicity conservation on the real NLO ME's (greatly improves evaluation time). */ bool helicityConservation_; /** * The q + qb -> v1 + v2 + g helicity amplitudes */ mutable ProductionMatrixElement qqb_hel_amps_; /** * The q + g -> v1 + v2 + q helicity amplitudes */ mutable ProductionMatrixElement qg_hel_amps_; /** * The g + qb -> v1 + v2 + qb helicity amplitudes */ mutable ProductionMatrixElement gqb_hel_amps_; //@} /** * The vertices */ //@{ /** * The photon fermion-antifermion vertex */ AbstractFFVVertexPtr FFPvertex_; /** * The W fermion-antifermion vertex */ AbstractFFVVertexPtr FFWvertex_; /** * The Z fermion-antifermionvertex */ AbstractFFVVertexPtr FFZvertex_; /** * The triple electroweak gauge boson vertex */ AbstractVVVVertexPtr WWWvertex_; /** * The quark-antiquark gluon vertex */ AbstractFFVVertexPtr FFGvertex_; //@} /** * The value of \f$\alpha_S\f$ used for the calculation */ mutable double alphaS_; protected: /** * Returns the matrix element for a given type of process, * rapidity of the jet \f$y_j\f$ and transverse momentum \f$p_T\f$ * @param emis_type the type of emission, * (0 is \f$q\bar{q}\to Vg\f$, 1 is \f$qg\to Vq\f$ and 2 is \f$g\bar{q}\to V\bar{q}\f$) * @param pT The transverse momentum of the jet * @param R The object containing the kinematics */ double getResult(int emis_type, realVVKinematics R, Energy pT); /** * generates the hardest emission (yj,p) * @param pnew The momenta of the new particles * @param emissiontype The type of emission, as for getResult * @return Whether not an emission was generated */ bool getEvent(vector & pnew,unsigned int & emissiontype); /** * sets the QCD, EW and PDF scales * @param pT The pT of the current step in the veto algorithm */ void setTheScales(Energy pT); /** * The matrix element q + qb -> n + g times tk*uk */ Energy2 t_u_M_R_qqb_hel_amp(realVVKinematics R, bool getMatrix) const; /** * The matrix element q + g -> n + q times tk*uk */ Energy2 t_u_M_R_qg_hel_amp(realVVKinematics R, bool getMatrix) const; /** * The matrix element g + qb -> n + q times tk*uk */ Energy2 t_u_M_R_gqb_hel_amp(realVVKinematics R, bool getMatrix) const; /** * The matrix element for the kinematical configuration * previously provided by the last call to setKinematics(), suitably * scaled by sHat() to give a dimension-less number. * @return the matrix element scaled with sHat() to give a * dimensionless number. */ double lo_me(bool getMatrix) const; /** * Recalculate hard vertex to include spin correlations for radiative events. */ void recalculateVertex(); /** * Member which selects a two body decay mode for each vector * boson and distributes decay products isotropically */ bool isotropicDecayer(); /** * The triangle function lambda(x,y,z)=sqrt(x^2+y^2+z^2-2*x*y-2*y*z-2*x*z) */ Energy2 triangleFn(Energy2,Energy2,Energy2); private: /** * If this boolean is true the n+1 body helicity amplitudes will be * used to calculate a hard vertex based on those kinematics for spin * correlations in the decays. */ bool realMESpinCorrelations_; /** * The colour & spin averaged n-body (leading order) matrix element squared. */ double lo_me_; /** * The resolved 2->3 real emission kinematics. */ realVVKinematics R_; /** * This specifies the emitting configuration: * 1: q + qbar -> V1 + V2 + g * 2: q + g -> V1 + V2 + q * 3: g + qbar -> V1 + V2 + qbar. */ unsigned int channel_; /** * Identifies the space-like mother of the branching * as quark (+1) or antiquark (-1): */ int fermionNumberOfMother_; /** * Pointer to the object calculating the strong coupling */ ShowerAlphaPtr showerAlphaS_; /** * Constants for the sampling. The distribution is assumed to have the * form \f$\frac{c}{{\rm GeV}}\times\left(\frac{{\rm GeV}}{p_T}\right)^n\f$ */ //@{ /** * The power, \f$n\f$, for the sampling */ double power_; /** * The prefactor, \f$c\f$ for the \f$q\bar{q}\f$ channel */ double preqqbar_; /** * The prefactor, \f$c\f$ for the \f$qg\f$ channel */ double preqg_; /** * The prefactor, \f$c\f$ for the \f$g\bar{q}\f$ channel */ double pregqbar_; /** * The QCD beta function divided by 4pi, (11-2/3*nf)/4/pi, with nf = 5. */ double b0_; /** * The fundamental QCD scale in the one-loop alpha_{S} used for the crude * (not the very crude) overestimate of the Sudakov exponent. The default * value is set so such that alphaS(MZ), neglecting all flavour threshold * effects i.e. MZ*exp(-1/2/b0_/alphaS(MZ)). */ Energy LambdaQCD_; /** * The prefactors as a vector for easy use */ vector prefactor_; //@} /** * Properties of the incoming particles */ //@{ /** * Pointers to the ShowerProgenitor objects for the partons */ ShowerProgenitorPtr qProgenitor_; ShowerProgenitorPtr qbProgenitor_; /** * Pointers to the Shower particle objects for the partons */ ShowerParticlePtr showerQuark_; ShowerParticlePtr showerAntiquark_; /** * Pointers to the BeamParticleData objects */ tcBeamPtr qHadron_; tcBeamPtr qbHadron_; //@} /** * Properties of the boson and jets */ //@{ /** * Pointers to the Shower particle objects for the partons */ PPtr gluon_; ShowerParticlePtr V1_; ShowerParticlePtr V2_; vector children_; vector photons_; /** * Flag indicating if the q & qbar are flipped or not i.e. this * is true if q enters from the -z direction in the lab frame. */ bool flipped_; /** * the rapidity of the jet */ double Yk_; /** * The transverse momentum of the jet */ Energy pT_; //@} /** * The transverse momentum of the jet */ Energy min_pT_; // Work out the scales we want to use in the matrix elements and the pdfs: /** * Scale for alpha_S: pT^2 of the diboson system. */ Energy2 QCDScale_; /** * Scale for real emission PDF: */ Energy2 PDFScale_; /** * Scale of electroweak vertices: mVV^2 the invariant mass of the diboson system. */ Energy2 EWScale_; /** * A matrix to hold the home-grown production matrix element */ mutable Complex productionMatrix_[3][3][3][3]; }; } #include "ThePEG/Utilities/ClassTraits.h" namespace ThePEG { /** @cond TRAITSPECIALIZATIONS */ /** This template specialization informs ThePEG about the * base classes of MEPP2VVPowheg. */ template <> struct BaseClassTrait { /** Typedef of the first base class of MEPP2VVPowheg. */ typedef Herwig::MEPP2VV NthBase; }; /** This template specialization informs ThePEG about the name of * the MEPP2VVPowheg 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::MEPP2VVPowheg"; } /** * The name of a file containing the dynamic library where the class * MEPP2VVPowheg is implemented. It may also include several, space-separated, * libraries if the class MEPP2VVPowheg depends on other classes (base classes * excepted). In this case the listed libraries will be dynamically * linked in the order they are specified. */ static string library() { return "HwMEHadron.so HwPowhegMEHadron.so"; } }; /** @endcond */ } #endif /* HERWIG_MEPP2VVPowheg_H */ diff --git a/Shower/Base/Evolver.cc b/Shower/Base/Evolver.cc --- a/Shower/Base/Evolver.cc +++ b/Shower/Base/Evolver.cc @@ -1,3629 +1,3214 @@ // -*- 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]); + >> ienum(interaction_) >> _maxTryFSR >> _maxFailFSR >> _fracFSR; } 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::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", + static Switch interfaceInteraction + ("Interaction", "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, + &Evolver::interaction_, ShowerInteraction::QEDQCD, false, false); + static SwitchOption interfaceInteractionQCD + (interfaceInteraction, "QCDOnly", "Only QCD", - 1); - static SwitchOption interfaceInteractionsQEDFirst - (interfaceInteractions, - "QEDFirst", - "QED first then QCD", - 2); - static SwitchOption interfaceInteractionsQEDOnly - (interfaceInteractions, + ShowerInteraction::QCD); + static SwitchOption interfaceInteractionQEDOnly + (interfaceInteraction, "QEDOnly", "Only QED", - 3); - static SwitchOption interfaceInteractionsBothAtOnce - (interfaceInteractions, - "BothAtOnce", - "Generate both at the same time", - 4); + ShowerInteraction::QED); + static SwitchOption interfaceInteractionBothAtOnce + (interfaceInteraction, + "QEDQCD", + "QED and QCD", + ShowerInteraction::QEDQCD); 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]; + ShowerInteraction::Type inter = interaction_; 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); + setEvolutionPartners(hard,interaction_,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 = 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 = 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 = 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_ ); - } + _hardtree = _hardme->generateHardest( currentTree(),interaction_); } 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 = 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) { - 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]); + // create random particle vector + vector 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); } - // 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()); - } + 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,interaction_,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; + } + // loop over particles + for(unsigned int ix=0;ixprogenitor()->isFinalState()) { + if(!isFSRadiationON()) continue; + // perform shower + progenitor()->hasEmitted(startTimeLikeShower(interaction_)); + } + // 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, + interaction_)); + } + // decay + else { + // skip colour and electrically neutral particles + if(!progenitor()->progenitor()->dataPtr()->coloured() && + !progenitor()->progenitor()->dataPtr()->charged()) { + progenitor()->hasEmitted(false); + 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])); + // 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(); } - // 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])); + 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, + interaction_)); } } - // 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; - } + // do the kinematic reconstruction, checking if it worked + reconstructed = hard ? + showerModel()->kinematicsReconstructor()-> + reconstructHardJets (currentTree(),intrinsicpT(),interaction_, + switchRecon && ntry>maximumTries()/2) : + showerModel()->kinematicsReconstructor()-> + reconstructDecayJets(currentTree(),interaction_); + } + 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 = 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 = 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/Evolver.h b/Shower/Base/Evolver.h --- a/Shower/Base/Evolver.h +++ b/Shower/Base/Evolver.h @@ -1,951 +1,917 @@ // -*- C++ -*- // // Evolver.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_Evolver_H #define HERWIG_Evolver_H // // This is the declaration of the Evolver class. // #include "ThePEG/Interface/Interfaced.h" #include "Herwig/Shower/SplittingFunctions/SplittingGenerator.h" #include "ShowerModel.h" #include "ThePEG/PDF/BeamParticleData.h" #include "ShowerTree.h" #include "ShowerProgenitor.fh" #include "Herwig/Shower/ShowerHandler.fh" #include "Branching.h" #include "ShowerVeto.h" #include "HardTree.h" #include "ThePEG/Handlers/XComb.h" #include "Evolver.fh" #include "Herwig/MatrixElement/HwMEBase.h" #include "Herwig/Decay/HwDecayerBase.h" #include "Herwig/MatrixElement/Matchbox/Matching/ShowerApproximation.h" namespace Herwig { using namespace ThePEG; /**\ingroup Shower * Exception class * used to communicate failure of QED shower */ struct InteractionVeto {}; /** \ingroup Shower * The Evolver class class performs the sohwer evolution of hard scattering * and decay processes in Herwig. * * @see \ref EvolverInterfaces "The interfaces" * defined for Evolver. */ class Evolver: public Interfaced { /** * The ShowerHandler is a friend to set some parameters at initialisation */ friend class ShowerHandler; public: /** * Pointer to an XComb object */ typedef Ptr::pointer XCPtr; public: /** * Default Constructor */ Evolver() : _maxtry(100), _meCorrMode(1), _hardVetoMode(1), _hardVetoRead(0), _reconOpt(0), _hardVetoReadOption(false), _iptrms(ZERO), _beta(0.), _gamma(ZERO), _iptmax(), _limitEmissions(0), _initialenhance(1.), _finalenhance(1.), - interaction_(1), _trunc_Mode(true), _hardEmissionMode(0), + interaction_(ShowerInteraction::QEDQCD), _trunc_Mode(true), _hardEmissionMode(0), _spinOpt(1), _softOpt(2), _hardPOWHEG(false), theFactorizationScaleFactor(1.0), theRenormalizationScaleFactor(1.0), muPt(ZERO), _maxTryFSR(100000),_maxFailFSR(100),_fracFSR(0.001), _nFSR(0), _nFailedFSR(0) {} /** * Members to perform the shower */ //@{ /** * Perform the shower of the hard process */ virtual void showerHardProcess(ShowerTreePtr,XCPtr); /** * Perform the shower of a decay */ virtual void showerDecay(ShowerTreePtr); //@} /** * Access to the flags and shower variables */ //@{ /** * Is there any showering switched on */ bool showeringON() const { return isISRadiationON() || isFSRadiationON(); } /** * It returns true/false if the initial-state radiation is on/off. */ bool isISRadiationON() const { return _splittingGenerator->isISRadiationON(); } /** * It returns true/false if the final-state radiation is on/off. */ bool isFSRadiationON() const { return _splittingGenerator->isFSRadiationON(); } /** * Get the ShowerModel */ ShowerModelPtr showerModel() const {return _model;} /** * Get the SplittingGenerator */ tSplittingGeneratorPtr splittingGenerator() const { return _splittingGenerator; } /** * Mode for hard emissions */ int hardEmissionMode() const {return _hardEmissionMode;} /** * Switch on or off hard vetoes */ void restrictPhasespace(bool yes) { if ( yes ) _hardVetoMode = 1; else _hardVetoMode = 0; } /** * Switch on or off hard veto scale from muF */ void hardScaleIsMuF(bool yes) { if ( yes ) _hardVetoRead = 1; else _hardVetoRead = 0; } //@} /** * Connect the Hard and Shower trees */ virtual void connectTrees(ShowerTreePtr showerTree, HardTreePtr hardTree, bool hard ); /** * Access to switches for spin correlations */ //@{ /** * Spin Correlations */ unsigned int spinCorrelations() const { return _spinOpt; } /** * Soft correlations */ unsigned int softCorrelations() const { return _softOpt; } /** * Any correlations */ bool correlations() const { return _spinOpt!=0||_softOpt!=0; } //@} /** * Set the factorization scale factor */ void factorizationScaleFactor(double f) { if ( f == theFactorizationScaleFactor ) return; theFactorizationScaleFactor = f; splittingGenerator()->factorizationScaleFactor(f); } /** * Set the renormalization scale factor */ void renormalizationScaleFactor(double f) { if ( f == theRenormalizationScaleFactor ) return; theRenormalizationScaleFactor = f; splittingGenerator()->renormalizationScaleFactor(f); } 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: /** * Perform the shower */ void doShowering(bool hard,XCPtr); /** * Generate the hard matrix element correction */ virtual void hardMatrixElementCorrection(bool); /** * Generate the hardest emission */ virtual void hardestEmission(bool hard); /** * Extract the particles to be showered, set the evolution scales * and apply the hard matrix element correction * @param hard Whether this is a hard process or decay * @return The particles to be showered */ virtual vector setupShower(bool hard); /** * set the colour partners */ virtual void setEvolutionPartners(bool hard,ShowerInteraction::Type, bool clear); /** * Methods to perform the evolution of an individual particle, including * recursive calling on the products */ //@{ /** * It does the forward evolution of the time-like input particle * (and recursively for all its radiation products). * accepting only emissions which conforms to the showerVariables * and soft matrix element correction. * If at least one emission has occurred then the method returns true. * @param particle The particle to be showered */ virtual bool timeLikeShower(tShowerParticlePtr particle, ShowerInteraction::Type, Branching fb, bool first); /** * It does the backward evolution of the space-like input particle * (and recursively for all its time-like radiation products). * accepting only emissions which conforms to the showerVariables. * If at least one emission has occurred then the method returns true * @param particle The particle to be showered * @param beam The beam particle */ virtual bool spaceLikeShower(tShowerParticlePtr particle,PPtr beam, ShowerInteraction::Type); /** * If does the forward evolution of the input on-shell particle * involved in a decay * (and recursively for all its time-like radiation products). * accepting only emissions which conforms to the showerVariables. * @param particle The particle to be showered * @param maxscale The maximum scale for the shower. * @param minimumMass The minimum mass of the final-state system */ virtual bool spaceLikeDecayShower(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minimumMass,ShowerInteraction::Type, Branching fb); /** * Truncated shower from a time-like particle */ virtual bool truncatedTimeLikeShower(tShowerParticlePtr particle, HardBranchingPtr branch, ShowerInteraction::Type type, Branching fb, bool first); /** * Truncated shower from a space-like particle */ virtual bool truncatedSpaceLikeShower(tShowerParticlePtr particle,PPtr beam, HardBranchingPtr branch, ShowerInteraction::Type type); /** * Truncated shower from a time-like particle */ virtual bool truncatedSpaceLikeDecayShower(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minimumMass, HardBranchingPtr branch, ShowerInteraction::Type type, Branching fb); //@} /** * Switches for matrix element corrections */ //@{ /** * Any ME correction? */ bool MECOn(bool hard) const { return ( _hardEmissionMode == 0 || (!hard && _hardEmissionMode ==-1) ) && _meCorrMode > 0; } /** * Any hard ME correction? */ bool hardMEC(bool hard) const { return ( _hardEmissionMode == 0 || (!hard && _hardEmissionMode ==-1) ) && (_meCorrMode == 1 || _meCorrMode == 2); } /** * Any soft ME correction? */ bool softMEC() const { return ( _hardEmissionMode == 0 || (_currenttree->isDecay() && _hardEmissionMode ==-1) ) && (_meCorrMode == 1 || _meCorrMode > 2); } //@} /** * Is the truncated shower on? */ bool isTruncatedShowerON() const {return _trunc_Mode;} /** * Switch for intrinsic pT */ //@{ /** * Any intrinsic pT? */ bool ipTon() const { return _iptrms != ZERO || ( _beta == 1.0 && _gamma != ZERO && _iptmax !=ZERO ); } //@} /**@name Additional shower vetoes */ //@{ /** * Insert a veto. */ void addVeto (ShowerVetoPtr v) { _vetoes.push_back(v); } /** * Remove a veto. */ void removeVeto (ShowerVetoPtr v) { vector::iterator vit = find(_vetoes.begin(),_vetoes.end(),v); if (vit != _vetoes.end()) _vetoes.erase(vit); } //@} /** * Switches for vetoing hard emissions */ //@{ /** * Vetos on? */ bool hardVetoOn() const { return _hardVetoMode > 0; } /** * veto hard emissions in IS shower? */ bool hardVetoIS() const { return _hardVetoMode == 1 || _hardVetoMode == 2; } /** * veto hard emissions in FS shower? */ bool hardVetoFS() const { return _hardVetoMode == 1 || _hardVetoMode > 2; } /** * veto hard emissions according to lastScale from XComb? */ bool hardVetoXComb() const {return (_hardVetoRead == 1);} /** * Returns true if the hard veto read-in is to be applied to only * the primary collision and false otherwise. */ bool hardVetoReadOption() const {return _hardVetoReadOption;} //@} /** * Enhancement factors for radiation needed to generate the soft matrix * element correction. */ //@{ /** * Access the enhancement factor for initial-state radiation */ double initialStateRadiationEnhancementFactor() const { return _initialenhance; } /** * Access the enhancement factor for final-state radiation */ double finalStateRadiationEnhancementFactor() const { return _finalenhance; } /** * Set the enhancement factor for initial-state radiation */ void initialStateRadiationEnhancementFactor(double in) { _initialenhance=in; } /** * Set the enhancement factor for final-state radiation */ void finalStateRadiationEnhancementFactor(double in) { _finalenhance=in; } //@} /** * Access to set/get the HardTree currently beinging showered */ //@{ /** * The HardTree currently being showered */ tHardTreePtr hardTree() {return _hardtree;} /** * The HardTree currently being showered */ void hardTree(tHardTreePtr in) {_hardtree = in;} //@} /** * Access/set the beam particle for the current initial-state shower */ //@{ /** * Get the beam particle data */ Ptr::const_pointer beamParticle() const { return _beam; } /** * Set the beam particle data */ void setBeamParticle(Ptr::const_pointer in) { _beam=in; } //@} /** * Set/Get the current tree being evolverd for inheriting classes */ //@{ /** * Get the tree */ tShowerTreePtr currentTree() { return _currenttree; } /** * Set the tree */ void currentTree(tShowerTreePtr tree) { _currenttree=tree; } //@} /** * Access the maximum number of attempts to generate the shower */ unsigned int maximumTries() const { return _maxtry; } /** * Set/Get the ShowerProgenitor for the current shower */ //@{ /** * Access the progenitor */ ShowerProgenitorPtr progenitor() { return _progenitor; } /** * Set the progenitor */ void progenitor(ShowerProgenitorPtr in) { _progenitor=in; } //@} /** * Calculate the intrinsic \f$p_T\f$. */ virtual void generateIntrinsicpT(vector); /** * Access to the intrinsic \f$p_T\f$ for inheriting classes */ map > & intrinsicpT() { return _intrinsic; } /** * find the maximally allowed pt acc to the hard process. */ void setupMaximumScales(const vector &,XCPtr); /** * find the relevant hard scales for profile scales. */ void setupHardScales(const vector &,XCPtr); /** * Return the relevant hard scale to be used in the profile scales */ Energy hardScale() const { return muPt; } /** * Convert the HardTree into an extra shower emission */ void convertHardTree(bool hard,ShowerInteraction::Type type); protected: /** * Start the shower of a timelike particle */ virtual bool startTimeLikeShower(ShowerInteraction::Type); /** * Update of the time-like stuff */ void updateHistory(tShowerParticlePtr particle); /** * Start the shower of a spacelike particle */ virtual bool startSpaceLikeShower(PPtr,ShowerInteraction::Type); /** * Start the shower of a spacelike particle */ virtual bool startSpaceLikeDecayShower(const ShowerParticle::EvolutionScales & maxScales, Energy minimumMass,ShowerInteraction::Type); /** * Select the branching for the next time-like emission */ Branching selectTimeLikeBranching(tShowerParticlePtr particle, ShowerInteraction::Type type, HardBranchingPtr branch); /** * Select the branching for the next space-like emission in a decay */ Branching selectSpaceLikeDecayBranching(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minmass,ShowerInteraction::Type type, HardBranchingPtr branch); /** * Create the timelike child of a branching */ ShowerParticleVector createTimeLikeChildren(tShowerParticlePtr particle, IdList ids); /** * Vetos for the timelike shower */ virtual bool timeLikeVetoed(const Branching &,ShowerParticlePtr); /** * Vetos for the spacelike shower */ virtual bool spaceLikeVetoed(const Branching &,ShowerParticlePtr); /** * Vetos for the spacelike shower */ virtual bool spaceLikeDecayVetoed(const Branching &,ShowerParticlePtr); /** * Only generate the hard emission, for testing only. */ bool hardOnly() const {return _limitEmissions==3;} - /** - * Members to construct the HardTree from the shower if needed - */ - //@{ - /** - * Construct the tree for a scattering process - */ - bool constructHardTree(vector & particlesToShower, - ShowerInteraction::Type inter); - - /** - * Construct the tree for a decay process - */ - bool constructDecayTree(vector & particlesToShower, - ShowerInteraction::Type inter); - - /** - * Construct a time-like line - */ - void constructTimeLikeLine(tHardBranchingPtr branch,tShowerParticlePtr particle); - - /** - * Construct a space-like line - */ - void constructSpaceLikeLine(tShowerParticlePtr particle, - HardBranchingPtr & first, HardBranchingPtr & last, - SudakovPtr sud,PPtr beam); - //@} - public: /** @name MC@NLO diagnostics */ //@{ /** * True, if Matchbox MC@NLO S-event */ bool wasMCatNLOSEvent() const { return isMCatNLOSEvent; } /** * True, if matchbox MC@NLO H-event */ bool wasMCatNLOHEvent() const { return isMCatNLOHEvent; } //@} protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const; /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const; //@} 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(); //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ Evolver & operator=(const Evolver &); private: /** * Pointer to the model for the shower evolution model */ ShowerModelPtr _model; /** * Pointer to the splitting generator */ SplittingGeneratorPtr _splittingGenerator; /** * Maximum number of tries to generate the shower of a particular tree */ unsigned int _maxtry; /** * Matrix element correction switch */ unsigned int _meCorrMode; /** * Hard emission veto switch */ unsigned int _hardVetoMode; /** * Hard veto to be read switch */ unsigned int _hardVetoRead; /** * Control of the reconstruction option */ unsigned int _reconOpt; /** * If hard veto pT scale is being read-in this determines * whether the read-in value is applied to primary and * secondary (MPI) scatters or just the primary one, with * the usual computation of the veto being performed for * the secondary (MPI) scatters. */ bool _hardVetoReadOption; /** * rms intrinsic pT of Gaussian distribution */ Energy _iptrms; /** * Proportion of inverse quadratic intrinsic pT distribution */ double _beta; /** * Parameter for inverse quadratic: 2*Beta*Gamma/(sqr(Gamma)+sqr(intrinsicpT)) */ Energy _gamma; /** * Upper bound on intrinsic pT for inverse quadratic */ Energy _iptmax; /** * Limit the number of emissions for testing */ unsigned int _limitEmissions; /** * The progenitor of the current shower */ ShowerProgenitorPtr _progenitor; /** * Matrix element */ HwMEBasePtr _hardme; /** * Decayer */ HwDecayerBasePtr _decayme; /** * The ShowerTree currently being showered */ ShowerTreePtr _currenttree; /** * The HardTree currently being showered */ HardTreePtr _hardtree; /** * Radiation enhancement factors for use with the veto algorithm * if needed by the soft matrix element correction */ //@{ /** * Enhancement factor for initial-state radiation */ double _initialenhance; /** * Enhancement factor for final-state radiation */ double _finalenhance; //@} /** * The beam particle data for the current initial-state shower */ Ptr::const_pointer _beam; /** * Storage of the intrinsic \f$p_t\f$ of the particles */ map > _intrinsic; /** * Vetoes */ vector _vetoes; /** * number of IS emissions */ unsigned int _nis; /** * Number of FS emissions */ unsigned int _nfs; /** * The option for wqhich interactions to use */ - unsigned int interaction_; - - /** - * Interactions allowed in the shower - */ - vector interactions_; + ShowerInteraction::Type interaction_; /** * Truncated shower switch */ bool _trunc_Mode; /** * Count of the number of truncated emissions */ unsigned int _truncEmissions; /** * Mode for the hard emissions */ int _hardEmissionMode; /** * Option to include spin correlations */ unsigned int _spinOpt; /** * Option for the kernal for soft correlations */ unsigned int _softOpt; /** * Option for hard radiation in POWHEG events */ bool _hardPOWHEG; /** * True, if Matchbox MC@NLO S-event */ bool isMCatNLOSEvent; /** * True, if matchbox MC@NLO H-event */ bool isMCatNLOHEvent; /** * True, if Matchbox Powheg S-event */ bool isPowhegSEvent; /** * True, if matchbox Powheg H-event */ bool isPowhegHEvent; /** * The shower approximation to provide the hard scale profile */ Ptr::tptr theShowerApproximation; /** * The factorization scale factor. */ double theFactorizationScaleFactor; /** * The renormalization scale factor. */ double theRenormalizationScaleFactor; /** * True if no warnings about incorrect hard emission * mode setting have been issued yet */ static bool _hardEmissionModeWarn; /** * True if no warnings about missing truncated shower * have been issued yet */ static bool _missingTruncWarn; /** * The relevant hard scale to be used in the profile scales */ Energy muPt; /** * Maximum number of emission attempts for FSR */ unsigned int _maxTryFSR; /** * Maximum number of failures for FSR generation */ unsigned int _maxFailFSR; /** * Failure fraction for FSR generation */ double _fracFSR; /** * Counter for number of FSR emissions */ unsigned int _nFSR; /** * Counter for the number of failed events due to FSR emissions */ unsigned int _nFailedFSR; }; } #endif /* HERWIG_Evolver_H */ diff --git a/src/defaults/Shower.in b/src/defaults/Shower.in --- a/src/defaults/Shower.in +++ b/src/defaults/Shower.in @@ -1,292 +1,292 @@ # -*- ThePEG-repository -*- ############################################################ # Setup of default parton shower # # Useful switches for users are marked near the top of # this file. # # Don't edit this file directly, but reset the switches # in your own input files! ############################################################ library HwMPI.so library HwShower.so library HwMatching.so mkdir /Herwig/Shower cd /Herwig/Shower create Herwig::ShowerHandler ShowerHandler newdef ShowerHandler:MPIHandler /Herwig/UnderlyingEvent/MPIHandler newdef ShowerHandler:RemDecayer /Herwig/Partons/RemnantDecayer # use LO PDFs for Shower, can be changed later newdef ShowerHandler:PDFA /Herwig/Partons/ShowerLOPDF newdef ShowerHandler:PDFB /Herwig/Partons/ShowerLOPDF newdef ShowerHandler:PDFARemnant /Herwig/Partons/RemnantPDF newdef ShowerHandler:PDFBRemnant /Herwig/Partons/RemnantPDF ##################################### # initial setup, don't change these! ##################################### create Herwig::SplittingGenerator SplittingGenerator create Herwig::ShowerAlphaQCD AlphaQCD create Herwig::ShowerAlphaQED AlphaQED create Herwig::Evolver Evolver create Herwig::QTildeModel ShowerModel create Herwig::QTildeFinder PartnerFinder newdef PartnerFinder:PartnerMethod 1 newdef PartnerFinder:ScaleChoice 1 create Herwig::QTildeReconstructor KinematicsReconstructor newdef KinematicsReconstructor:ReconstructionOption Colour3 newdef KinematicsReconstructor:InitialStateReconOption SofterFraction newdef KinematicsReconstructor:InitialInitialBoostOption LongTransBoost newdef /Herwig/Partons/RemnantDecayer:AlphaS AlphaQCD newdef /Herwig/Partons/RemnantDecayer:AlphaEM AlphaQED newdef ShowerHandler:Evolver Evolver newdef ShowerModel:PartnerFinder PartnerFinder newdef ShowerModel:KinematicsReconstructor KinematicsReconstructor newdef Evolver:ShowerModel ShowerModel newdef Evolver:SplittingGenerator SplittingGenerator -newdef Evolver:Interactions BothAtOnce +newdef Evolver:Interaction QEDQCD newdef Evolver:SpinCorrelations Yes newdef Evolver:SoftCorrelations Singular ################################################################## # Intrinsic pT # # Recommended: # 1.9 GeV for Tevatron W/Z production. # 2.1 GeV for LHC W/Z production at 10 TeV # 2.2 GeV for LHC W/Z production at 14 TeV # # Set all parameters to 0 to disable ################################################################## newdef Evolver:IntrinsicPtGaussian 1.3*GeV newdef Evolver:IntrinsicPtBeta 0 newdef Evolver:IntrinsicPtGamma 0*GeV newdef Evolver:IntrinsicPtIptmax 0*GeV ############################################################# # Main control switches for the parton shower. ############################################################# newdef SplittingGenerator:ISR Yes newdef SplittingGenerator:FSR Yes ############################################################# # Set up truncated shower handler. ############################################################# create Herwig::PowhegShowerHandler PowhegShowerHandler set PowhegShowerHandler:MPIHandler /Herwig/UnderlyingEvent/MPIHandler set PowhegShowerHandler:RemDecayer /Herwig/Partons/RemnantDecayer set PowhegShowerHandler:Evolver /Herwig/Shower/Evolver newdef PowhegShowerHandler:PDFA /Herwig/Partons/ShowerLOPDF newdef PowhegShowerHandler:PDFB /Herwig/Partons/ShowerLOPDF newdef PowhegShowerHandler:PDFARemnant /Herwig/Partons/RemnantPDF newdef PowhegShowerHandler:PDFBRemnant /Herwig/Partons/RemnantPDF ############################################################# ############################################################# # End of interesting user servicable section. # # Anything that follows below should only be touched if you # know what you're doing. # # Really. ############################################################# # # a few default values newdef Evolver:MECorrMode 1 newdef Evolver:ReconstructionOption OffShell3 newdef AlphaQCD:ScaleFactor 1.0 newdef AlphaQCD:NPAlphaS 2 newdef AlphaQCD:Qmin 0.935 newdef AlphaQCD:NumberOfLoops 2 newdef AlphaQCD:InputOption 1 newdef AlphaQCD:AlphaMZ 0.134 # # # Lets set up all the splittings create Herwig::HalfHalfOneSplitFn QtoQGammaSplitFn set QtoQGammaSplitFn:InteractionType QED set QtoQGammaSplitFn:ColourStructure ChargedChargedNeutral set QtoQGammaSplitFn:AngularOrdered Yes create Herwig::HalfHalfOneSplitFn QtoQGSplitFn newdef QtoQGSplitFn:InteractionType QCD newdef QtoQGSplitFn:ColourStructure TripletTripletOctet set QtoQGSplitFn:AngularOrdered Yes create Herwig::OneOneOneSplitFn GtoGGSplitFn newdef GtoGGSplitFn:InteractionType QCD newdef GtoGGSplitFn:ColourStructure OctetOctetOctet set GtoGGSplitFn:AngularOrdered Yes create Herwig::OneHalfHalfSplitFn GtoQQbarSplitFn newdef GtoQQbarSplitFn:InteractionType QCD newdef GtoQQbarSplitFn:ColourStructure OctetTripletTriplet set GtoQQbarSplitFn:AngularOrdered No create Herwig::OneHalfHalfSplitFn GammatoQQbarSplitFn newdef GammatoQQbarSplitFn:InteractionType QED newdef GammatoQQbarSplitFn:ColourStructure NeutralChargedCharged set GammatoQQbarSplitFn:AngularOrdered No create Herwig::HalfOneHalfSplitFn QtoGQSplitFn newdef QtoGQSplitFn:InteractionType QCD newdef QtoGQSplitFn:ColourStructure TripletOctetTriplet set QtoGQSplitFn:AngularOrdered Yes create Herwig::HalfOneHalfSplitFn QtoGammaQSplitFn newdef QtoGammaQSplitFn:InteractionType QED newdef QtoGammaQSplitFn:ColourStructure ChargedNeutralCharged set QtoGammaQSplitFn:AngularOrdered Yes # # Now the Sudakovs create Herwig::QTildeSudakov SudakovCommon newdef SudakovCommon:Alpha AlphaQCD newdef SudakovCommon:cutoffKinScale 0.0*GeV newdef SudakovCommon:PDFmax 1.0 newdef SudakovCommon:CutOffOption pT newdef SudakovCommon:pTmin 1.67*GeV cp SudakovCommon QtoQGSudakov newdef QtoQGSudakov:SplittingFunction QtoQGSplitFn newdef QtoQGSudakov:PDFmax 1.9 cp SudakovCommon QtoQGammaSudakov set QtoQGammaSudakov:SplittingFunction QtoQGammaSplitFn set QtoQGammaSudakov:Alpha AlphaQED set QtoQGammaSudakov:PDFmax 1.9 cp QtoQGammaSudakov LtoLGammaSudakov cp SudakovCommon GtoGGSudakov newdef GtoGGSudakov:SplittingFunction GtoGGSplitFn newdef GtoGGSudakov:PDFmax 2.0 cp SudakovCommon GtoQQbarSudakov newdef GtoQQbarSudakov:SplittingFunction GtoQQbarSplitFn newdef GtoQQbarSudakov:PDFmax 120.0 cp SudakovCommon GammatoQQbarSudakov newdef GammatoQQbarSudakov:SplittingFunction GammatoQQbarSplitFn newdef GammatoQQbarSudakov:PDFmax 120.0 cp SudakovCommon GtobbbarSudakov newdef GtobbbarSudakov:SplittingFunction GtoQQbarSplitFn newdef GtobbbarSudakov:PDFmax 40000.0 cp SudakovCommon GtoccbarSudakov newdef GtoccbarSudakov:SplittingFunction GtoQQbarSplitFn newdef GtoccbarSudakov:PDFmax 2000.0 cp SudakovCommon QtoGQSudakov newdef QtoGQSudakov:SplittingFunction QtoGQSplitFn cp SudakovCommon QtoGammaQSudakov newdef QtoGammaQSudakov:SplittingFunction QtoGammaQSplitFn cp SudakovCommon utoGuSudakov newdef utoGuSudakov:SplittingFunction QtoGQSplitFn newdef utoGuSudakov:PDFFactor OverOneMinusZ newdef utoGuSudakov:PDFmax 5.0 cp SudakovCommon dtoGdSudakov newdef dtoGdSudakov:SplittingFunction QtoGQSplitFn newdef dtoGdSudakov:PDFFactor OverOneMinusZ # # Now add the final splittings # do SplittingGenerator:AddFinalSplitting u->u,g; QtoQGSudakov do SplittingGenerator:AddFinalSplitting d->d,g; QtoQGSudakov do SplittingGenerator:AddFinalSplitting s->s,g; QtoQGSudakov do SplittingGenerator:AddFinalSplitting c->c,g; QtoQGSudakov do SplittingGenerator:AddFinalSplitting b->b,g; QtoQGSudakov do SplittingGenerator:AddFinalSplitting t->t,g; QtoQGSudakov # do SplittingGenerator:AddFinalSplitting g->g,g; GtoGGSudakov # do SplittingGenerator:AddFinalSplitting g->u,ubar; GtoQQbarSudakov do SplittingGenerator:AddFinalSplitting g->d,dbar; GtoQQbarSudakov do SplittingGenerator:AddFinalSplitting g->s,sbar; GtoQQbarSudakov do SplittingGenerator:AddFinalSplitting g->c,cbar; GtoccbarSudakov do SplittingGenerator:AddFinalSplitting g->b,bbar; GtobbbarSudakov do SplittingGenerator:AddFinalSplitting g->t,tbar; GtoQQbarSudakov # do SplittingGenerator:AddFinalSplitting gamma->u,ubar; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->d,dbar; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->s,sbar; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->c,cbar; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->b,bbar; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->t,tbar; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->e-,e+; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->mu-,mu+; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->tau-,tau+; GammatoQQbarSudakov # do SplittingGenerator:AddFinalSplitting u->u,gamma; QtoQGammaSudakov do SplittingGenerator:AddFinalSplitting d->d,gamma; QtoQGammaSudakov do SplittingGenerator:AddFinalSplitting s->s,gamma; QtoQGammaSudakov do SplittingGenerator:AddFinalSplitting c->c,gamma; QtoQGammaSudakov do SplittingGenerator:AddFinalSplitting b->b,gamma; QtoQGammaSudakov do SplittingGenerator:AddFinalSplitting t->t,gamma; QtoQGammaSudakov do SplittingGenerator:AddFinalSplitting e-->e-,gamma; LtoLGammaSudakov do SplittingGenerator:AddFinalSplitting mu-->mu-,gamma; LtoLGammaSudakov do SplittingGenerator:AddFinalSplitting tau-->tau-,gamma; LtoLGammaSudakov # # Now lets add the initial splittings. Remember the form a->b,c; means # that particle a is the particle given and we backward branch to # particle b which is initial state and particle c which is final state # do SplittingGenerator:AddInitialSplitting u->u,g; QtoQGSudakov do SplittingGenerator:AddInitialSplitting d->d,g; QtoQGSudakov do SplittingGenerator:AddInitialSplitting s->s,g; QtoQGSudakov do SplittingGenerator:AddInitialSplitting c->c,g; QtoQGSudakov do SplittingGenerator:AddInitialSplitting b->b,g; QtoQGSudakov do SplittingGenerator:AddInitialSplitting u->u,gamma; QtoQGammaSudakov do SplittingGenerator:AddInitialSplitting d->d,gamma; QtoQGammaSudakov do SplittingGenerator:AddInitialSplitting s->s,gamma; QtoQGammaSudakov do SplittingGenerator:AddInitialSplitting c->c,gamma; QtoQGammaSudakov do SplittingGenerator:AddInitialSplitting b->b,gamma; QtoQGammaSudakov do SplittingGenerator:AddInitialSplitting t->t,gamma; QtoQGammaSudakov do SplittingGenerator:AddInitialSplitting g->g,g; GtoGGSudakov # do SplittingGenerator:AddInitialSplitting g->d,dbar; GtoQQbarSudakov do SplittingGenerator:AddInitialSplitting g->u,ubar; GtoQQbarSudakov do SplittingGenerator:AddInitialSplitting g->s,sbar; GtoQQbarSudakov do SplittingGenerator:AddInitialSplitting g->c,cbar; GtoccbarSudakov do SplittingGenerator:AddInitialSplitting g->b,bbar; GtobbbarSudakov # do SplittingGenerator:AddInitialSplitting gamma->d,dbar; GammatoQQbarSudakov do SplittingGenerator:AddInitialSplitting gamma->u,ubar; GammatoQQbarSudakov do SplittingGenerator:AddInitialSplitting gamma->s,sbar; GammatoQQbarSudakov do SplittingGenerator:AddInitialSplitting gamma->c,cbar; GammatoQQbarSudakov do SplittingGenerator:AddInitialSplitting gamma->b,bbar; GammatoQQbarSudakov # do SplittingGenerator:AddInitialSplitting d->g,d; dtoGdSudakov do SplittingGenerator:AddInitialSplitting u->g,u; utoGuSudakov do SplittingGenerator:AddInitialSplitting s->g,s; QtoGQSudakov do SplittingGenerator:AddInitialSplitting c->g,c; QtoGQSudakov do SplittingGenerator:AddInitialSplitting b->g,b; QtoGQSudakov do SplittingGenerator:AddInitialSplitting dbar->g,dbar; dtoGdSudakov do SplittingGenerator:AddInitialSplitting ubar->g,ubar; utoGuSudakov do SplittingGenerator:AddInitialSplitting sbar->g,sbar; QtoGQSudakov do SplittingGenerator:AddInitialSplitting cbar->g,cbar; QtoGQSudakov do SplittingGenerator:AddInitialSplitting bbar->g,bbar; QtoGQSudakov # do SplittingGenerator:AddInitialSplitting d->gamma,d; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting u->gamma,u; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting s->gamma,s; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting c->gamma,c; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting b->gamma,b; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting dbar->gamma,dbar; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting ubar->gamma,ubar; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting sbar->gamma,sbar; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting cbar->gamma,cbar; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting bbar->gamma,bbar; QtoGammaQSudakov