diff --git a/Decay/VectorMeson/OniumToOniumPiPiDecayer.cc b/Decay/VectorMeson/OniumToOniumPiPiDecayer.cc --- a/Decay/VectorMeson/OniumToOniumPiPiDecayer.cc +++ b/Decay/VectorMeson/OniumToOniumPiPiDecayer.cc @@ -1,464 +1,464 @@ // -*- C++ -*- // // OniumToOniumPiPiDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 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 OniumToOniumPiPiDecayer class. // #include "OniumToOniumPiPiDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ParVector.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "Herwig/PDT/ThreeBodyAllOnCalculator.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; void OniumToOniumPiPiDecayer::doinitrun() { DecayIntegrator::doinitrun(); for(unsigned int ix=0;ix<_maxweight.size();++ix) { if(initialize()) _maxweight[ix] = mode(ix)->maxWeight(); } } OniumToOniumPiPiDecayer::OniumToOniumPiPiDecayer() { // Upsilon(3S)->Upsilon(1S) pi pi _incoming.push_back(200553); _outgoing.push_back( 553); _maxweight.push_back(1.); _maxweight.push_back(1.); _coupling.push_back(3.92e-6); _reA.push_back( 1. /MeV2);_imA.push_back( ZERO); _reB.push_back(-2.523/MeV2);_imB.push_back( 1.189/MeV2); _reC.push_back( ZERO);_imC.push_back( ZERO); // Upsilon(3S)->Upsilon(2S) pi pi _incoming.push_back(200553); _outgoing.push_back(100553); _maxweight.push_back(1.); _maxweight.push_back(1.); _coupling.push_back(311e-6); _reA.push_back( 1. /MeV2);_imA.push_back( ZERO); _reB.push_back(-0.395/MeV2);_imB.push_back( 0.001/MeV2); _reC.push_back( ZERO);_imC.push_back( ZERO); // Upsilon(2S)->Upsilon(1S) pi pi _incoming.push_back(100553); _outgoing.push_back( 553); _maxweight.push_back(1.); _maxweight.push_back(1.); _coupling.push_back(61.4e-6); _reA.push_back( 1. /MeV2);_imA.push_back( ZERO); _reB.push_back(-0.753/MeV2);_imB.push_back( ZERO); _reC.push_back( ZERO);_imC.push_back( ZERO); // Upsilon(4S)->Upsilon(1S) pi pi _incoming.push_back(300553); _outgoing.push_back( 553); _maxweight.push_back(1.); _maxweight.push_back(1.); _coupling.push_back(1.77e-6); _reA.push_back( 1. /MeV2);_imA.push_back( ZERO); _reB.push_back( ZERO);_imB.push_back( ZERO); _reC.push_back( ZERO);_imC.push_back( ZERO); // Upsilon(4S)->Upsilon(2S) pi pi _incoming.push_back(300553); _outgoing.push_back(100553); _maxweight.push_back(1.); _maxweight.push_back(1.); _coupling.push_back(68.8e-6); _reA.push_back( 1. /MeV2);_imA.push_back( ZERO); _reB.push_back(-2.35 /MeV2);_imB.push_back( 0.55/MeV2); _reC.push_back( ZERO);_imC.push_back( ZERO); // psi(2s)->psi(1S) pi pi _incoming.push_back(100443); _outgoing.push_back( 443); _maxweight.push_back(1.); _maxweight.push_back(1.); _coupling.push_back(66.2e-6); _reA.push_back( 1. /MeV2);_imA.push_back( ZERO); _reB.push_back(-0.336/MeV2);_imB.push_back( ZERO); _reC.push_back( ZERO);_imC.push_back( ZERO); // psi(3770)->psi(1S) pi pi _incoming.push_back(30443); _outgoing.push_back( 443); _maxweight.push_back(1.); _maxweight.push_back(1.); _coupling.push_back(20.6e-6); _reA.push_back( 1. /MeV2);_imA.push_back( ZERO); _reB.push_back( ZERO);_imB.push_back( ZERO); _reC.push_back( ZERO);_imC.push_back( ZERO); // Initial size of the vectors _initsize=_incoming.size(); // don'y generate the intermediates in the phase-space generateIntermediates(false); } void OniumToOniumPiPiDecayer::doinit() { DecayIntegrator::doinit(); // check consistency of the vectors unsigned int isize=_incoming.size(); if(_outgoing.size()!=isize||_maxweight.size()!=2*isize|| _coupling.size()!=isize|| _reA .size()!=isize||_imA.size() !=isize|| _reB .size()!=isize||_imB.size() !=isize|| _reC .size()!=isize||_imC.size() !=isize) throw InitException() << "Inconsistent size of the parameter vectors in " << "OniumToOniumPiPiDecayer" << Exception::runerror; // construct the complex couplings for(unsigned int ix=0;ix<_incoming.size();++ix) { _cA.push_back(complex(_reA[ix],_imA[ix])); _cB.push_back(complex(_reB[ix],_imB[ix])); _cC.push_back(complex(_reC[ix],_imC[ix])); } // construct the decay channels tPDVector extpart(4); tPDPtr pip(getParticleData(ParticleID::piplus )); tPDPtr pim(getParticleData(ParticleID::piminus)); tPDPtr pi0(getParticleData(ParticleID::pi0 )); tPDPtr rho0(getParticleData(113)); DecayPhaseSpaceModePtr mode; DecayPhaseSpaceChannelPtr newchannel; vector dummyweights(1,1.); for(unsigned int ix=0;ixaddIntermediate(extpart[0],0, 0.0,1,-1); newchannel->addIntermediate(rho0,1,0.0, 2,3); mode->addChannel(newchannel); // reset the resonance parameters mode->resetIntermediate(rho0,2*extpart[0]->mass(),2*extpart[0]->mass()); // add the mode addMode(mode,_maxweight[2*ix+iy],dummyweights); } } } void OniumToOniumPiPiDecayer::persistentOutput(PersistentOStream & os) const { os << _incoming << _outgoing << _maxweight << _initsize << ounit(_reA,1./GeV2) << ounit(_imA,1./GeV2) << ounit(_cA,1./GeV2) << ounit(_reB,1./GeV2) << ounit(_imB,1./GeV2) << ounit(_cB,1./GeV2) << ounit(_reC,1./GeV2) << ounit(_imC,1./GeV2) << ounit(_cC,1./GeV2); } void OniumToOniumPiPiDecayer::persistentInput(PersistentIStream & is, int) { is >> _incoming >> _outgoing >> _maxweight >> _initsize >> iunit(_reA,1./GeV2) >> iunit(_imA,1./GeV2) >> iunit(_cA,1./GeV2) >> iunit(_reB,1./GeV2) >> iunit(_imB,1./GeV2) >> iunit(_cB,1./GeV2) >> iunit(_reC,1./GeV2) >> iunit(_imC,1./GeV2) >> iunit(_cC,1./GeV2); } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigOniumToOniumPiPiDecayer("Herwig::OniumToOniumPiPiDecayer", "HwVMDecay.so"); void OniumToOniumPiPiDecayer::Init() { static ClassDocumentation documentation ("The OniumToOniumPiPiDecayer class uses the matrix element of " "Brown and Cahn, PRL35, 1 (1975), for" " the decay of onium resonaces to lighter states and pion pairs." " The results of hep-ex/9909038 are used for psi'->psi and " " arXiv:0706.2317 for Upsilon(3S) and Upsilon(2S) decays." " The remaining parameters are choosen to approximately reproduce" " the distributions from hep-ex/0604031 and hep-ex/0508023.", "The decays of onium resonances to lighter states and pion pairs were modelled" " using the matrix element of \\cite{Brown:1975dz}. The results of " "\\cite{Bai:1999mj} are used for $\\psi'\\to\\psi$ and " "\\cite{Cronin-Hennessy:2007sj} for $\\Upsilon(3S)$ and $\\Upsilon(2S)$ decays." " The remaining parameters are choosen to approximately reproduce" " the distributions from \\cite{Aubert:2006bm} and \\cite{Adam:2005mr}.", "\\bibitem{Brown:1975dz} L.~S.~Brown and R.~N.~Cahn," "Phys.\\ Rev.\\ Lett.\\ {\\bf 35} (1975) 1." "%%CITATION = PRLTA,35,1;%%\n" "\\bibitem{Bai:1999mj} J.~Z.~Bai {\\it et al.} [BES Collaboration]," "Phys.\\ Rev.\\ D {\\bf 62} (2000) 032002 [arXiv:hep-ex/9909038]." "%%CITATION = PHRVA,D62,032002;%%\n" "\\bibitem{Cronin-Hennessy:2007sj} D.~Cronin-Hennessy{\\it et al.} " "[CLEO Collaboration], arXiv:0706.2317 [hep-ex]." "%%CITATION = ARXIV:0706.2317;%%\n" "\\bibitem{Aubert:2006bm} B.~Aubert {\\it et al.} [BABAR Collaboration]," "Phys.\\ Rev.\\ Lett.\\ {\\bf 96} (2006) 232001 [arXiv:hep-ex/0604031]." "%%CITATION = PRLTA,96,232001;%%\n" "\\bibitem{Adam:2005mr} N.~E.~Adam {\\it et al.} [CLEO Collaboration]," "Phys.\\ Rev.\\ Lett.\\ {\\bf 96} (2006) 082004 [arXiv:hep-ex/0508023]." "%%CITATION = PRLTA,96,082004;%%"); static ParVector interfaceIncoming ("Incoming", "The PDG code for the incoming onium state", &OniumToOniumPiPiDecayer::_incoming, -1, long(0), -10000000, 10000000, false, false, Interface::limited); static ParVector interfaceOutgoing ("Outgoing", "The PDG code for the outgoing onium state", &OniumToOniumPiPiDecayer::_outgoing, -1, long(0), -10000000, 10000000, false, false, Interface::limited); static ParVector interfaceMaxWeight ("MaxWeight", "The maximum weight for the decay mode, there should be two " "for each mode as we have pi+ pi- and pi0 pi0", &OniumToOniumPiPiDecayer::_maxweight, -1, 1.0, 0.0, 10000.0, false, false, Interface::limited); static ParVector interfaceCoupling ("Coupling", "The overall coupling for the decay", &OniumToOniumPiPiDecayer::_coupling, -1, 1.0, 0.0, 10.0, false, false, Interface::limited); static ParVector interfaceReA ("ReA", "The real part of the A coupling", &OniumToOniumPiPiDecayer::_reA, 1./MeV2, -1, 1.0/MeV2, -1000.0/MeV2, 1000.0/MeV2, false, false, Interface::limited); static ParVector interfaceImA ("ImA", "The imaginary part of the A coupling", &OniumToOniumPiPiDecayer::_imA, 1./MeV2, -1, 1.0/MeV2, -1000.0/MeV2, 1000.0/MeV2, false, false, Interface::limited); static ParVector interfaceReB ("ReB", "The real part of the B coupling", &OniumToOniumPiPiDecayer::_reB, 1./MeV2, -1, 1.0/MeV2, -1000.0/MeV2, 1000.0/MeV2, false, false, Interface::limited); static ParVector interfaceImB ("ImB", "The imaginary part of the B coupling", &OniumToOniumPiPiDecayer::_imB, 1./MeV2, -1, 1.0/MeV2, -1000.0/MeV2, 1000.0/MeV2, false, false, Interface::limited); static ParVector interfaceReC ("ReC", "The real part of the C coupling", &OniumToOniumPiPiDecayer::_reC, 1./MeV2, -1, 1.0/MeV2, -1000.0/MeV2, 1000.0/MeV2, false, false, Interface::limited); static ParVector interfaceImC ("ImC", "The imaginary part of the C coupling", &OniumToOniumPiPiDecayer::_imC, 1./MeV2, -1, 1.0/MeV2, -1000.0/MeV2, 1000.0/MeV2, false, false, Interface::limited); } int OniumToOniumPiPiDecayer::modeNumber(bool & cc,tcPDPtr parent, const tPDVector & children) const { cc=false; int imode(-1); long idin(parent->id()); if(children.size()!=3) return -1; unsigned int npip(0),npim(0),npi0(0); long idother(0),id; for(tPDVector::const_iterator pit=children.begin(); pit!=children.end();++pit) { id=(**pit).id(); if(id==ParticleID::piplus) ++npip; else if(id==ParticleID::piminus) ++npim; else if(id==ParticleID::pi0) ++npi0; else idother=id; } // check pi+ pi- or pi0 pi0 and outgoing state if(!((npip==1&&npim==1)||npi0==2)||idother==0) return -1; unsigned int ix=0; do { if(idin==_incoming[ix]&&idother==_outgoing[ix]) imode=ix; ++ix; } while(ix<_incoming.size()&&imode<0); return npi0==2 ? 2*imode+1 : 2*imode; } double OniumToOniumPiPiDecayer::me2(const int, const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1,PDT::Spin0,PDT::Spin0))); useMe(); if(meopt==Initialize) { VectorWaveFunction::calculateWaveFunctions(_vectors[0],_rho, const_ptr_cast(&inpart), incoming,false); } if(meopt==Terminate) { VectorWaveFunction::constructSpinInfo(_vectors[0],const_ptr_cast(&inpart), incoming,true,false); VectorWaveFunction::constructSpinInfo(_vectors[1],decay[0], outgoing,true,false); for(unsigned int ix=1;ix<3;++ix) ScalarWaveFunction::constructSpinInfo(decay[ix],outgoing,true); return 0.; } VectorWaveFunction::calculateWaveFunctions(_vectors[1],decay[0],outgoing,false); // compute the matrix element complex A(_cA[imode()/2]),B(_cB[imode()/2]),C(_cC[imode()/2]); Energy2 q2 =(decay[1]->momentum()+decay[2]->momentum()).m2(); Energy2 mpi2=sqr(decay[1]->mass()); for(unsigned int ix=0;ix<3;++ix) { for(unsigned int iy=0;iy<3;++iy) { Complex dota = _vectors[0][ix].dot(_vectors[1][iy]); complex dotb = (_vectors[0][ix]*decay[1]->momentum())*(_vectors[1][iy]*decay[2]->momentum())+ (_vectors[0][ix]*decay[2]->momentum())*(_vectors[1][iy]*decay[1]->momentum()); (*ME())(ix,iy,0,0)= _coupling[imode()/2]* - (A*dota*(q2-2.*mpi2)+B*dota*decay[1]->momentum().e()*decay[2]->momentum().e() + Complex(A*dota*(q2-2.*mpi2)+B*dota*decay[1]->momentum().e()*decay[2]->momentum().e() +C*dotb); } } // matrix element double output=ME()->contract(_rho).real(); if(imode()%2==1) output*=0.5; // test of the matrix element // Energy2 s1=(decay[1]->momentum()+decay[2]->momentum()).m2(); // Energy2 s2=(decay[0]->momentum()+decay[2]->momentum()).m2(); // Energy2 s3=(decay[1]->momentum()+decay[0]->momentum()).m2(); // double test=threeBodyMatrixElement(imode(),sqr(inpart.mass()), // s3,s2,s1,decay[0]->mass(), // decay[1]->mass(),decay[2]->mass()); // return the answer return output; } // output the setup information for the particle database void OniumToOniumPiPiDecayer::dataBaseOutput(ofstream & output, bool header) const { if(header) output << "update decayers set parameters=\""; // parameters for the DecayIntegrator base class DecayIntegrator::dataBaseOutput(output,false); // the rest of the parameters for(unsigned int ix=0;ix<_incoming.size();++ix) { if(ix<_initsize) { output << "newdef " << name() << ":Incoming " << ix << " " << _incoming[ix] << "\n"; output << "newdef " << name() << ":Outgoing " << ix << " " << _outgoing[ix] << "\n"; output << "newdef " << name() << ":Coupling " << ix << " " << _coupling[ix] << "\n"; output << "newdef " << name() << ":ReA " << ix << " " << _reA[ix]*MeV2 << "\n"; output << "newdef " << name() << ":ImA " << ix << " " << _imA[ix]*MeV2 << "\n"; output << "newdef " << name() << ":ReB " << ix << " " << _reB[ix]*MeV2 << "\n"; output << "newdef " << name() << ":ImB " << ix << " " << _imB[ix]*MeV2 << "\n"; output << "newdef " << name() << ":ReC " << ix << " " << _reC[ix]*MeV2 << "\n"; output << "newdef " << name() << ":ImC " << ix << " " << _imC[ix]*MeV2 << "\n"; } else { output << "insert " << name() << ":Incoming " << ix << " " << _incoming[ix] << "\n"; output << "insert " << name() << ":Outgoing " << ix << " " << _outgoing[ix] << "\n"; output << "insert " << name() << ":Coupling " << ix << " " << _coupling[ix] << "\n"; output << "insert " << name() << ":ReA " << ix << " " << _reA[ix]*MeV2 << "\n"; output << "insert " << name() << ":ImA " << ix << " " << _imA[ix]*MeV2 << "\n"; output << "insert " << name() << ":ReB " << ix << " " << _reB[ix]*MeV2 << "\n"; output << "insert " << name() << ":ImB " << ix << " " << _imB[ix]*MeV2 << "\n"; output << "insert " << name() << ":ReC " << ix << " " << _reC[ix]*MeV2 << "\n"; output << "insert " << name() << ":ImC " << ix << " " << _imC[ix]*MeV2 << "\n"; } } for(unsigned int ix=0;ix<_maxweight.size();++ix) { if(ix<2*_initsize) { output << "newdef " << name() << ":MaxWeight " << ix << " " << _maxweight[ix] << "\n"; } else { output << "insert " << name() << ":MaxWeight " << ix << " " << _maxweight[ix] << "\n"; } } if(header) output << "\n\" where BINARY ThePEGName=\"" << fullName() << "\";" << endl; } WidthCalculatorBasePtr OniumToOniumPiPiDecayer:: threeBodyMEIntegrator(const DecayMode & dm) const { int imode(-1); long idin(dm.parent()->id()); unsigned int npip(0),npim(0),npi0(0); long idother(0),id; for(ParticleMSet::const_iterator pit=dm.products().begin(); pit!=dm.products().end();++pit) { id=(**pit).id(); if(id==ParticleID::piplus) ++npip; else if(id==ParticleID::piminus) ++npim; else if(id==ParticleID::pi0) ++npi0; else idother=id; } unsigned int ix=0; do { if(idin==_incoming[ix]&&idother==_outgoing[ix]) imode=ix; ++ix; } while(ix<_incoming.size()&&imode<0); imode = npi0==2 ? 2*imode+1 : 2*imode; // construct the integrator vector inweights(1,1.); Energy scale=getParticleData(_incoming[ix-1])->mass(); Energy m1=getParticleData(_outgoing[ix-1])->mass(); Energy mpi = npi0==2 ? getParticleData(ParticleID::pi0)->mass() : getParticleData(ParticleID::piplus)->mass(); vector intype(1,3); vector inmass (1,scale); vector inwidth(1,scale); vector inpow(1,0.0); return new_ptr(ThreeBodyAllOnCalculator (inweights,intype,inmass,inwidth,inpow, *this,imode,m1,mpi,mpi)); } double OniumToOniumPiPiDecayer:: threeBodyMatrixElement(const int imode, const Energy2 q2, const Energy2 s3, const Energy2 s2, const Energy2 s1, const Energy m1, const Energy m2, const Energy m3) const { Energy q=sqrt(q2); Energy e2 = 0.5*(q2+sqr(m2)-s2)/q; Energy e3 = 0.5*(q2+sqr(m3)-s3)/q; Complex amp = _cA[imode/2]*(s1-sqr(m2)-sqr(m3))+_cB[imode/2]*e2*e3; Energy2 dot = 0.5*(q2+sqr(m1)-s1); double output=(2.+sqr(dot/q/m1))*real(amp*conj(amp))*sqr(_coupling[imode/2])/3.; if(imode%2==1) output*=0.5; return output; } diff --git a/MatrixElement/General/GeneralQQHiggs.cc b/MatrixElement/General/GeneralQQHiggs.cc --- a/MatrixElement/General/GeneralQQHiggs.cc +++ b/MatrixElement/General/GeneralQQHiggs.cc @@ -1,644 +1,644 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the MEPP2QQH class. // #include "GeneralQQHiggs.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/Switch.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 "Herwig/Models/StandardModel/StandardModel.h" #include "ThePEG/Utilities/SimplePhaseSpace.h" #include "Herwig/Utilities/Kinematics.h" #include "ThePEG/Cuts/Cuts.h" #include "Herwig/MatrixElement/HardVertex.h" using namespace Herwig; GeneralQQHiggs::GeneralQQHiggs() : quarkFlavour_(6), process_(0), shapeOpt_(2), mh_(), wh_(), alpha_(1.1) {} // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigGeneralQQHiggs("Herwig::GeneralQQHiggs", "Herwig.so"); void GeneralQQHiggs::Init() { static ClassDocumentation documentation ("The GeneralQQHiggs class implements the matrix elements for the " "production of the Higgs boson in association with a heavy quark-antiquark pair"); static Switch interfaceQuarkType ("QuarkType", "The type of quark", &GeneralQQHiggs::quarkFlavour_, 6, false, false); static SwitchOption interfaceQuarkTypeBottom (interfaceQuarkType, "Bottom", "Produce bottom-antibottom", 5); static SwitchOption interfaceQuarkTypeTop (interfaceQuarkType, "Top", "Produce top-antitop", 6); static Switch interfaceProcess ("Process", "Which subprocesses to include", &GeneralQQHiggs::process_, 0, false, false); static SwitchOption interfaceProcessAll (interfaceProcess, "All", "Include all subprocesses", 0); static SwitchOption interfaceProcess1 (interfaceProcess, "gg", "Include only gg -> QQbarH processes", 1); static SwitchOption interfaceProcessqbarqbarqbarqbar (interfaceProcess, "qqbar", "Include only qbar qbar -> QQbarH processes", 2); static Switch interfaceShapeOption ("ShapeScheme", "Option for the treatment of the Higgs resonance shape", &GeneralQQHiggs::shapeOpt_, 2, false, false); static SwitchOption interfaceStandardShapeFixed (interfaceShapeOption, "FixedBreitWigner", "Breit-Wigner s-channel resonance", 1); static SwitchOption interfaceStandardShapeRunning (interfaceShapeOption, "MassGenerator", "Use the mass generator to give the shape", 2); static SwitchOption interfaceStandardShapeOnShell (interfaceShapeOption, "OnShell", "Produce an on-shell Higgs boson", 0); static Parameter interfaceAlpha ("Alpha", "Power for the generation of the tranverse mass in the pT mapping", &GeneralQQHiggs::alpha_, 1.1, 0.0, 10.0, false, false, Interface::limited); } Energy2 GeneralQQHiggs::scale() const { return sHat(); } int GeneralQQHiggs::nDim() const { return 4 + int(shapeOpt_>0); } unsigned int GeneralQQHiggs::orderInAlphaS() const { return 2; } unsigned int GeneralQQHiggs::orderInAlphaEW() const { return 1; } IBPtr GeneralQQHiggs::clone() const { return new_ptr(*this); } IBPtr GeneralQQHiggs::fullclone() const { return new_ptr(*this); } void GeneralQQHiggs::setKinematics() { HwMEBase::setKinematics(); } void GeneralQQHiggs::persistentOutput(PersistentOStream & os) const { os << quarkFlavour_ << process_ << shapeOpt_ << ounit(mh_,GeV) << ounit(wh_,GeV) << hmass_ << GGGVertex_ << QQGVertex_ << QQHVertex_ << gluon_ << higgs_ << quark_ << antiquark_ << alpha_; } void GeneralQQHiggs::persistentInput(PersistentIStream & is, int) { is >> quarkFlavour_ >> process_ >> shapeOpt_ >> iunit(mh_,GeV) >> iunit(wh_,GeV) >> hmass_ >> GGGVertex_ >> QQGVertex_ >> QQHVertex_ >> gluon_ >> higgs_ >> quark_ >> antiquark_ >> alpha_; } void GeneralQQHiggs::doinit() { HwMEBase::doinit(); // stuff for the higgs mass mh_ = higgs_->mass(); wh_ = higgs_->width(); if(higgs_->massGenerator()) { hmass_=dynamic_ptr_cast(higgs_->massGenerator()); } if(shapeOpt_==2&&!hmass_) throw InitException() << "If using the mass generator for the line shape in GeneralQQHiggs::doinit()" << "the mass generator must be an instance of the GenericMassGenerator class" << Exception::runerror; // get the vertex pointers from the SM object tcHwSMPtr hwsm= dynamic_ptr_cast(standardModel()); // do the initialisation if(!hwsm) throw InitException() << "Wrong type of StandardModel object in " << "GeneralQQHiggs::doinit() the Herwig" << " version must be used" << Exception::runerror; GGGVertex_ = hwsm->vertexGGG(); QQGVertex_ = hwsm->vertexFFG(); // get the particle data objects gluon_=getParticleData(ParticleID::g); for(int ix=1;ix<=6;++ix) { quark_.push_back( getParticleData( ix)); antiquark_.push_back(getParticleData(-ix)); } } bool GeneralQQHiggs::generateKinematics(const double * r) { jacobian(1.); // CMS energy Energy rs = sqrt(sHat()); // quark mass Energy mq(quark_[quarkFlavour_-1]->mass()); // generate the higgs mass Energy mh(mh_); if(shapeOpt_!=0) { Energy mhmax = min(rs-2.*mq,higgs_->massMax()); Energy mhmin = max(ZERO ,higgs_->massMin()); if(mhmax<=mhmin) return false; double rhomin = atan2((sqr(mhmin)-sqr(mh_)), mh_*wh_); double rhomax = atan2((sqr(mhmax)-sqr(mh_)), mh_*wh_); mh = sqrt(mh_*wh_*tan(rhomin+r[4]*(rhomax-rhomin))+sqr(mh_)); jacobian(jacobian()*(rhomax-rhomin)); } if(rs ZERO ) { double ctm = 1.0 - sqr(ptmin/p1); if ( ctm <= 0.0 ) return false; ctmin = max(ctmin, -sqrt(ctm)); ctmax = min(ctmax, sqrt(ctm)); } double cos1 = getCosTheta(ctmin,ctmax,r[0]); double sin1(sqrt(1.-sqr(cos1))); double phi1 = Constants::twopi*UseRandom::rnd(); Lorentz5Momentum p13(sin1*p1*cos(phi1),sin1*p1*sin(phi1),cos1*p1, sqrt(sqr(p1)+m132),m13); meMomenta()[3].setVect(Momentum3(-sin1*p1*cos(phi1),-sin1*p1*sin(phi1),-cos1*p1)); meMomenta()[3].setMass(mq); meMomenta()[3].rescaleEnergy(); bool test=Kinematics::twoBodyDecay(p13,mq,mh,-1.+2*r[2],r[3]*Constants::twopi, meMomenta()[2],meMomenta()[4]); if(!test) return false; m232 = (meMomenta()[3]+meMomenta()[4]).m2(); double D = 2./(pow(sqr(mq)/(m132-sqr(mq)),alpha_)+ pow(sqr(mq)/(m232-sqr(mq)),alpha_)); jacobian(0.5*jacobian()*rs/m13*sqr(mq)*D*(rhomax-rhomin)/sHat()); } // second branch else { double rtemp = 2.*(r[1]-0.5); double rho = rhomin+rtemp*(rhomax-rhomin); if(alpha_==0) m232 = sqr(mq)*rho; else if(alpha_==1) m232 = sqr(mq)*(exp(rho)+1.); else m232 = sqr(mq)*(pow(rho,1./(1.-alpha_))+1.); Energy m23 = sqrt(m232); try { p1 = SimplePhaseSpace::getMagnitude(sHat(), m23, mq); p2 = SimplePhaseSpace::getMagnitude(m232,mq,mh); - } catch ( ImpossibleKinematics ) { + } catch ( ImpossibleKinematics & e ) { return false; } Energy ptmin = lastCuts().minKT(mePartonData()[2]); double ctmin = -1.0, ctmax = 1.0; if ( ptmin > ZERO ) { double ctm = 1.0 - sqr(ptmin/p1); if ( ctm <= 0.0 ) return false; ctmin = max(ctmin, -sqrt(ctm)); ctmax = min(ctmax, sqrt(ctm)); } double cos1 = getCosTheta(ctmin,ctmax,r[0]); double sin1(sqrt(1.-sqr(cos1))); double phi1 = Constants::twopi*UseRandom::rnd(); Lorentz5Momentum p23(-sin1*p1*cos(phi1),-sin1*p1*sin(phi1),-cos1*p1, sqrt(sqr(p1)+m232),m23); meMomenta()[2].setVect(Momentum3(sin1*p1*cos(phi1),sin1*p1*sin(phi1),cos1*p1)); meMomenta()[2].setMass(mq); meMomenta()[2].rescaleEnergy(); bool test=Kinematics::twoBodyDecay(p23,mq,mh,-1.+2*r[2],r[3]*Constants::twopi, meMomenta()[3],meMomenta()[4]); if(!test) return false; m132 = (meMomenta()[2]+meMomenta()[4]).m2(); double D = 2./(pow(sqr(mq)/(m132-sqr(mq)),alpha_)+ pow(sqr(mq)/(m232-sqr(mq)),alpha_)); jacobian(0.5*jacobian()*rs/m23*sqr(mq)*D*(rhomax-rhomin)/sHat()); } // calculate jacobian jacobian(0.125*jacobian()*p1*p2/sHat()); // check cuts vector out; tcPDVector tout; for(unsigned int ix=2;ix<5;++ix) { out .push_back(meMomenta()[ix]); tout.push_back(mePartonData()[ix]); } return lastCuts().passCuts(tout, out, mePartonData()[0], mePartonData()[1]); } CrossSection GeneralQQHiggs::dSigHatDR() const { using Constants::pi; // jacobian factor for the higgs InvEnergy2 bwfact(ZERO); Energy moff = meMomenta()[4].mass(); if(shapeOpt_==1) { bwfact = mePartonData()[4]->generateWidth(moff)*moff/pi/ (sqr(sqr(moff)-sqr(mh_))+sqr(mh_*wh_)); } else if(shapeOpt_==2) { bwfact = hmass_->BreitWignerWeight(moff); } double jac1 = shapeOpt_==0 ? 1. : double(bwfact*(sqr(sqr(moff)-sqr(mh_))+sqr(mh_*wh_))/(mh_*wh_)); return sqr(hbarc)*me2()*jacobian()*jac1/sHat()/pow(Constants::twopi,3); } void GeneralQQHiggs::getDiagrams() const { tPDPtr Q = quark_[quarkFlavour_-1]; tPDPtr QB = antiquark_[quarkFlavour_-1]; // gg -> q qbar h0 subprocesses if(process_==0||process_==1) { // first t-channel add(new_ptr((Tree2toNDiagram(3), gluon_, QB, gluon_, 1, Q, 4, Q , 2, QB, 4, higgs_, -1))); add(new_ptr((Tree2toNDiagram(4), gluon_, QB, QB, gluon_, 1, Q, 3, QB, 2, higgs_, -2))); add(new_ptr((Tree2toNDiagram(3),gluon_,QB,gluon_, 1, Q, 2, QB, 5, QB, 5, higgs_, -3))); // interchange add(new_ptr((Tree2toNDiagram(3),gluon_,Q,gluon_, 2, Q, 4, Q , 1, QB, 4, higgs_, -4))); add(new_ptr((Tree2toNDiagram(4),gluon_,Q,Q,gluon_, 3, Q, 1, QB, 2, higgs_, -5))); add(new_ptr((Tree2toNDiagram(3),gluon_,Q,gluon_, 2, Q, 1, QB, 5, QB, 5, higgs_, -6))); // s-channel add(new_ptr((Tree2toNDiagram(2),gluon_,gluon_, 1, gluon_, 3, Q, 4, Q, 3, QB, 4, higgs_, -7))); add(new_ptr((Tree2toNDiagram(2),gluon_,gluon_, 1, gluon_, 3,Q, 3, QB, 5, QB, 5, higgs_, -8))); } // q qbar -> q qbar if(process_==0||process_==2) { for(unsigned int ix=1;ix<5;++ix) { // gluon s-channel add(new_ptr((Tree2toNDiagram(2),quark_[ix-1], antiquark_[ix-1], 1, gluon_, 3, Q, 4, Q , 3, QB, 4, higgs_, -9))); add(new_ptr((Tree2toNDiagram(2),quark_[ix-1], antiquark_[ix-1], 1, gluon_, 3, Q, 3, QB, 5, QB, 5, higgs_, -10))); } } } double GeneralQQHiggs::me2() const { // total matrix element double me(0.); // gg initiated processes if(mePartonData()[0]->id()==ParticleID::g) { VectorWaveFunction g1w(meMomenta()[0],mePartonData()[0],incoming); VectorWaveFunction g2w(meMomenta()[1],mePartonData()[1],incoming); SpinorBarWaveFunction qw(meMomenta()[2],mePartonData()[2],outgoing); SpinorWaveFunction qbarw(meMomenta()[3],mePartonData()[3],outgoing); ScalarWaveFunction higgs(meMomenta()[4],mePartonData()[4],1.,outgoing); vector g1,g2; vector q; vector qbar; for(unsigned int ix=0;ix<2;++ix) { g1w.reset(2*ix);g1.push_back(g1w); g2w.reset(2*ix);g2.push_back(g2w); qw.reset(ix);q.push_back(qw); qbarw.reset(ix);qbar.push_back(qbarw); } // calculate the matrix element me=ggME(g1,g2,q,qbar,higgs,0); } // q qbar initiated else { SpinorWaveFunction q1w(meMomenta()[0],mePartonData()[0],incoming); SpinorBarWaveFunction q2w(meMomenta()[1],mePartonData()[1],incoming); SpinorBarWaveFunction q3w(meMomenta()[2],mePartonData()[2],outgoing); SpinorWaveFunction q4w(meMomenta()[3],mePartonData()[3],outgoing); ScalarWaveFunction higgs(meMomenta()[4],mePartonData()[4],1.,outgoing); vector q1,q4; vector q2,q3; for(unsigned int ix=0;ix<2;++ix) { q1w.reset(ix);q1.push_back(q1w); q2w.reset(ix);q2.push_back(q2w); q3w.reset(ix);q3.push_back(q3w); q4w.reset(ix);q4.push_back(q4w); } // calculate the matrix element me = qqME(q1,q2,q3,q4,higgs,0); } return me*sHat()*UnitRemoval::InvE2; } double GeneralQQHiggs::ggME(vector &g1, vector &g2, vector & q, vector & qbar, ScalarWaveFunction & hwave, unsigned int iflow) const { // scale Energy2 mt(scale()); Energy mass = q[0].mass(); // matrix element to be stored if(iflow!=0) me_.reset(ProductionMatrixElement(PDT::Spin1,PDT::Spin1, PDT::Spin1Half,PDT::Spin1Half, PDT::Spin0)); // calculate the matrix element double output(0.),sumflow[2]={0.,0.}; double sumdiag[8]={0.,0.,0.,0.,0.,0.,0.,0.}; Complex diag[8],flow[2]; VectorWaveFunction interv; SpinorWaveFunction inters,QBoff; SpinorBarWaveFunction intersb,Qoff; for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { interv = GGGVertex_->evaluate(mt,5,gluon_,g1[ihel1],g2[ihel2]); for(unsigned int ohel1=0;ohel1<2;++ohel1) { Qoff = QQHVertex_->evaluate(mt,3,q[ohel1].particle(), q[ohel1],hwave,mass); for(unsigned int ohel2=0;ohel2<2;++ohel2) { QBoff = QQHVertex_->evaluate(mt,3,qbar[ohel2].particle(), qbar[ohel2],hwave,mass); // 1st diagram inters = QQGVertex_->evaluate(mt,1,qbar[ohel2].particle(), qbar[ohel2],g2[ihel2],mass); diag[0] = QQGVertex_->evaluate(mt,inters,Qoff,g1[ihel1]); // 2nd diagram intersb = QQGVertex_->evaluate(mt,1,q[ohel1].particle(), q[ohel1],g1[ihel1],mass); diag[1] = QQHVertex_->evaluate(mt,inters,intersb,hwave); // 3rd diagram diag[2] = QQGVertex_->evaluate(mt,QBoff,intersb,g2[ihel2]); // 4th diagram inters = QQGVertex_->evaluate(mt,1,qbar[ohel2].particle(), qbar[ohel2],g1[ihel1],mass); diag[3] = QQGVertex_->evaluate(mt,inters,Qoff,g2[ihel2]); // 5th diagram intersb = QQGVertex_->evaluate(mt,1,q[ohel1].particle(), q[ohel1],g2[ihel2],mass); diag[4] = QQHVertex_->evaluate(mt,inters,intersb,hwave); // 6th diagram diag[5] = QQGVertex_->evaluate(mt,QBoff,intersb,g1[ihel1]); // 7th diagram diag[6] = QQGVertex_->evaluate(mt,qbar[ohel2],Qoff ,interv); // 8th diagram diag[7] = QQGVertex_->evaluate(mt,QBoff ,q[ohel1],interv); // colour flows flow[0]=diag[0]+diag[1]+diag[2]+(diag[6]+diag[7]); flow[1]=diag[3]+diag[4]+diag[5]-(diag[6]+diag[7]); // sums for(unsigned int ix=0;ix<8;++ix) sumdiag[ix] += norm(diag[ix]); for(unsigned int ix=0;ix<2;++ix) sumflow[ix] += norm(flow[ix]); // total output +=real(flow[0]*conj(flow[0])+flow[1]*conj(flow[1]) -0.25*flow[0]*conj(flow[1])); // store the me if needed if(iflow!=0) me_(2*ihel1,2*ihel2,ohel1,ohel2,0)=flow[iflow-1]; } } } } // select a colour flow flow_ = 1 + UseRandom::rnd2(sumflow[0],sumflow[1]); if(flow_==1) sumdiag[0]=sumdiag[1]=sumdiag[2]=0.; else sumdiag[3]=sumdiag[4]=sumdiag[5]=0.; // select a diagram from that flow double prob = UseRandom::rnd(); for(unsigned int ix=0;ix<8;++ix) { if(prob<=sumdiag[ix]) { diagram_=1+ix; break; } prob -= sumdiag[ix]; } // final part of colour and spin factors return output/48.; } double GeneralQQHiggs::qqME(vector & q1, vector & q2, vector & q3, vector & q4, ScalarWaveFunction & hwave, unsigned int iflow) const { // scale Energy2 mt(scale()); Energy mass = q3[0].mass(); // matrix element to be stored if(iflow!=0) me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half, PDT::Spin0)); // calculate the matrix element double output(0.),sumdiag[2]={0.,0.}; Complex diag[2]; VectorWaveFunction interv; SpinorWaveFunction QBoff; SpinorBarWaveFunction Qoff; for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { interv = QQGVertex_->evaluate(mt,5,gluon_,q1[ihel1],q2[ihel2]); for(unsigned int ohel1=0;ohel1<2;++ohel1) { Qoff = QQHVertex_->evaluate(mt,3,q3[ohel1].particle(), q3[ohel1],hwave,mass); for(unsigned int ohel2=0;ohel2<2;++ohel2) { QBoff = QQHVertex_->evaluate(mt,3,q4[ohel2].particle(), q4[ohel2],hwave,mass); // 1st diagram diag[0] = QQGVertex_->evaluate(mt,q4[ohel2],Qoff,interv); // 2nd diagram diag[1] = QQGVertex_->evaluate(mt,QBoff,q3[ohel1],interv); // sum of diagrams for(unsigned int ix=0;ix<2;++ix) sumdiag[ix] += norm(diag[ix]); diag[0] += diag[1]; output += norm(diag[0]); if(iflow!=0) me_(ihel1,ihel2,ohel1,ohel2,0) = diag[0]; } } } } // only 1 colour flow flow_=1; // select a diagram diagram_ = 9+UseRandom::rnd2(sumdiag[0],sumdiag[1]); // final part of colour and spin factors return output/18.; } Selector GeneralQQHiggs::colourGeometries(tcDiagPtr diag) const { // colour lines for gg -> Q Qbar H static const ColourLines cgg[10]= {ColourLines("1 4 5, -1 -2 3 , -3 -6 "), ColourLines("1 5 , -1 -2 -3 4, -4 -6 "), ColourLines("1 4 , -1 -2 3 , -3 -5 -6"), ColourLines("3 4 5, 1 2 -3 , -1 -6 "), ColourLines("4 5 , 1 2 3 -4, -1 -6"), ColourLines("3 4 , 1 2 -3 , -1 -5 -6"), ColourLines("1 3 4 5, -1 2, -2 -3 -6"), ColourLines("2 3 4 5, 1 -2, -1 -3 -6"), ColourLines("1 3 4, -1 2, -2 -3 -5 -6"), ColourLines("2 3 4, 1 -2, -1 -3 -5 -6")}; // colour lines for q qbar -> Q Qbar H static const ColourLines cqq[2]= {ColourLines("1 3 4 5, -2 -3 -6"), ColourLines("1 3 4 , -2 -3 -5 -6")}; // select the colour flow (as all ready picked just insert answer) Selector sel; switch(abs(diag->id())) { // gg -> q qbar subprocess case 1: case 2: case 3: case 4: case 5: case 6: sel.insert(1.0, &cgg[abs(diag->id())-1]); break; case 7: sel.insert(1.0, &cgg[5 + flow_]); break; case 8: sel.insert(1.0, &cgg[7 + flow_]); break; // q qbar -> q qbar subprocess case 9: case 10: sel.insert(1.0, &cqq[abs(diag->id())-9]); break; } return sel; } Selector GeneralQQHiggs::diagrams(const DiagramVector & diags) const { // select the diagram, this is easy for us as we have already done it Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ) { if(diags[i]->id()==-int(diagram_)) sel.insert(1.0, i); else sel.insert(0., i); } return sel; } void GeneralQQHiggs::constructVertex(tSubProPtr sub) { // extract the particles in the hard process ParticleVector hard; hard.push_back(sub->incoming().first); hard.push_back(sub->incoming().second); for(unsigned int ix=0;ix<3;++ix) hard.push_back(sub->outgoing()[ix]); // identify the process and calculate the matrix element if(hard[0]->id()<0) swap(hard[0],hard[1]); if(hard[2]->id()==higgs_->id()) swap(hard[2],hard[4]); if(hard[3]->id()==higgs_->id()) swap(hard[3],hard[4]); if(hard[2]->id()<0) swap(hard[2],hard[3]); if(hard[2]->id()<0) swap(hard[2],hard[3]); if(hard[0]->id()==ParticleID::g) { vector g1,g2; vector q; vector qbar; // off-shell wavefunctions for the spin correlations VectorWaveFunction( g1,hard[0],incoming,false,true,true); VectorWaveFunction( g2,hard[1],incoming,false,true,true); SpinorBarWaveFunction(q ,hard[2],outgoing,true ,true); SpinorWaveFunction( qbar,hard[3],outgoing,true ,true); ScalarWaveFunction hwave( hard[4],outgoing,true); g1[1]=g1[2];g2[1]=g2[2]; ggME(g1,g2,q,qbar,hwave,flow_); } // q qbar -> Q Qbar Higgs else { vector q1,q4; vector q2,q3; // off-shell for spin correlations SpinorWaveFunction( q1,hard[0],incoming,false,true); SpinorBarWaveFunction(q2,hard[1],incoming,false,true); SpinorBarWaveFunction(q3,hard[2],outgoing,true ,true); SpinorWaveFunction( q4,hard[3],outgoing,true ,true); ScalarWaveFunction hwave( hard[4],outgoing,true); qqME(q1,q2,q3,q4,hwave,flow_); } // 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 ix=0;ix<5;++ix) hard[ix]->spinInfo()->productionVertex(hardvertex); } void GeneralQQHiggs::setProcessInfo(unsigned int quark, PDPtr hin, AbstractFFSVertexPtr vertex, unsigned int shapeOpt, unsigned int proc) { quarkFlavour_ = quark; higgs_ = hin; QQHVertex_ = vertex; process_ = proc; shapeOpt_ = shapeOpt; } diff --git a/MatrixElement/General/GeneralfftoVH.cc b/MatrixElement/General/GeneralfftoVH.cc --- a/MatrixElement/General/GeneralfftoVH.cc +++ b/MatrixElement/General/GeneralfftoVH.cc @@ -1,181 +1,185 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the GeneralfftoVH class. // #include "GeneralfftoVH.h" #include "ThePEG/Utilities/DescribeClass.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/Utilities/EnumIO.h" #include "ThePEG/PDT/DecayMode.h" using namespace Herwig; GeneralfftoVH::GeneralfftoVH() {} void GeneralfftoVH::getDiagrams() const { if(process_==Lepton) { for(long ix=11;ix<=13;ix+=2) { tcPDPtr eplus = getParticleData( ix); tcPDPtr eminus = getParticleData(-ix); // find possible Z decays typedef Selector DecaySelector; DecaySelector Zdec = Z0()->decaySelector(); vector Zdecays; for(DecaySelector::const_iterator cit=Zdec.begin();cit!=Zdec.end();++cit) { if(cit->second->orderedProducts().size()!=2) continue; if(cit->second->orderedProducts()[0]->id()>0) Zdecays.push_back(make_pair(cit->second->orderedProducts()[0], cit->second->orderedProducts()[1])); else Zdecays.push_back(make_pair(cit->second->orderedProducts()[1], cit->second->orderedProducts()[0])); } // create the diagrams for(unsigned int ix=0;ix DecaySelector; DecaySelector Zdec = Z0()->decaySelector(); vector Zdecays; for(DecaySelector::const_iterator cit=Zdec.begin();cit!=Zdec.end();++cit) { if(cit->second->orderedProducts().size()!=2) continue; if(cit->second->orderedProducts()[0]->id()>0) Zdecays.push_back(make_pair(cit->second->orderedProducts()[0], cit->second->orderedProducts()[1])); else Zdecays.push_back(make_pair(cit->second->orderedProducts()[1], cit->second->orderedProducts()[0])); } // create the diagrams for ( int ix=1; ix<=int(maxFlavour()); ++ix ) { tcPDPtr q = getParticleData(ix); tcPDPtr qbar = q->CC(); for(unsigned int iz=0;iz parentpair; parentpair.reserve(6); // don't even think of putting 'break' in here! switch(maxFlavour()) { case 5: parentpair.push_back(make_pair(getParticleData(ParticleID::b), getParticleData(ParticleID::cbar))); parentpair.push_back(make_pair(getParticleData(ParticleID::b), getParticleData(ParticleID::ubar))); + [[fallthrough]]; case 4: parentpair.push_back(make_pair(getParticleData(ParticleID::s), getParticleData(ParticleID::cbar))); parentpair.push_back(make_pair(getParticleData(ParticleID::d), getParticleData(ParticleID::cbar))); + [[fallthrough]]; case 3: parentpair.push_back(make_pair(getParticleData(ParticleID::s), getParticleData(ParticleID::ubar))); + [[fallthrough]]; case 2: parentpair.push_back(make_pair(getParticleData(ParticleID::d), getParticleData(ParticleID::ubar))); + [[fallthrough]]; default: ; } // possible children typedef Selector DecaySelector; // for W+ DecaySelector wpdec = getParticleData(ParticleID::Wplus)->decaySelector(); vector wpdecays; for(DecaySelector::const_iterator cit=wpdec.begin();cit!=wpdec.end();++cit) { if(cit->second->orderedProducts().size()!=2) continue; if(cit->second->orderedProducts()[0]->id()>0) wpdecays.push_back(make_pair(cit->second->orderedProducts()[0], cit->second->orderedProducts()[1])); else wpdecays.push_back(make_pair(cit->second->orderedProducts()[1], cit->second->orderedProducts()[0])); } // for W- DecaySelector wmdec = getParticleData(ParticleID::Wminus)->decaySelector(); vector wmdecays; for(DecaySelector::const_iterator cit=wmdec.begin();cit!=wmdec.end();++cit) { if(cit->second->orderedProducts().size()!=2) continue; if(cit->second->orderedProducts()[0]->id()>0) wmdecays.push_back(make_pair(cit->second->orderedProducts()[0], cit->second->orderedProducts()[1])); else wmdecays.push_back(make_pair(cit->second->orderedProducts()[1], cit->second->orderedProducts()[0])); } vector::const_iterator parent = parentpair.begin(); for (; parent != parentpair.end(); ++parent) { // W- modes if(process_==HadronWminus) { for(unsigned int ix=0;ixfirst, parent->second, 1, WMinus(), 3, higgs(), 3, WMinus(), 5, wmdecays[ix].first,5, wmdecays[ix].second,-1))); } } else { // W+ modes for(unsigned int ix=0;ixsecond->CC(), parent->first->CC(), 1, WPlus(), 3, higgs(), 3, WPlus(), 5, wpdecays[ix].first, 5, wpdecays[ix].second, -1))); } } } } else assert(false); } IBPtr GeneralfftoVH::clone() const { return new_ptr(*this); } IBPtr GeneralfftoVH::fullclone() const { return new_ptr(*this); } void GeneralfftoVH::persistentOutput(PersistentOStream & os) const { os << oenum(process_); } void GeneralfftoVH::persistentInput(PersistentIStream & is, int) { is >> ienum(process_); } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigGeneralfftoVH("Herwig::GeneralfftoVH", "Herwig.so"); void GeneralfftoVH::Init() { static ClassDocumentation documentation ("The GeneralfftoVH class provides"); } void GeneralfftoVH::setProcessInfo(Process proc, PDPtr hin, AbstractVVSVertexPtr vertex, unsigned int shapeOpt) { higgs(hin); process_ = proc; setWWHVertex(vertex); lineShape(shapeOpt); } diff --git a/MatrixElement/Hadron/MEMinBias.cc b/MatrixElement/Hadron/MEMinBias.cc --- a/MatrixElement/Hadron/MEMinBias.cc +++ b/MatrixElement/Hadron/MEMinBias.cc @@ -1,167 +1,167 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the MEMinBias class. // #include "MEMinBias.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Utilities/SimplePhaseSpace.h" //#include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Handlers/StandardXComb.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" using namespace Herwig; #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/MatrixElement/Tree2toNDiagram.h" void MEMinBias::getDiagrams() const { int maxflav(2); // Pomeron data tcPDPtr pom = getParticleData(990); for ( int i = 1; i <= maxflav; ++i ) { for( int j=1; j <= i; ++j){ tcPDPtr q1 = getParticleData(i); tcPDPtr q1b = q1->CC(); tcPDPtr q2 = getParticleData(j); tcPDPtr q2b = q2->CC(); // For each flavour we add: //qq -> qq add(new_ptr((Tree2toNDiagram(3), q1, pom, q2, 1, q1, 2, q2, -1))); //qqb -> qqb add(new_ptr((Tree2toNDiagram(3), q1, pom, q2b, 1, q1, 2, q2b, -2))); //qbqb -> qbqb add(new_ptr((Tree2toNDiagram(3), q1b, pom, q2b, 1, q1b, 2, q2b, -3))); } } } Energy2 MEMinBias::scale() const { return sqr(10*GeV); } int MEMinBias::nDim() const { return 0; } void MEMinBias::setKinematics() { HwMEBase::setKinematics(); // Always call the base class method first. } bool MEMinBias::generateKinematics(const double *) { // generate the masses of the particles for ( int i = 2, N = meMomenta().size(); i < N; ++i ) { meMomenta()[i] = Lorentz5Momentum(mePartonData()[i]->generateMass()); } Energy q = ZERO; try { q = SimplePhaseSpace:: getMagnitude(sHat(), meMomenta()[2].mass(), meMomenta()[3].mass()); - } catch ( ImpossibleKinematics ) { + } catch ( ImpossibleKinematics & e ) { return false; } Energy pt = ZERO; meMomenta()[2].setVect(Momentum3( pt, pt, q)); meMomenta()[3].setVect(Momentum3(-pt, -pt, -q)); meMomenta()[2].rescaleEnergy(); meMomenta()[3].rescaleEnergy(); jacobian(1.0); return true; } double MEMinBias::me2() const { //tuned so it gives the correct normalization for xmin = 0.11 return csNorm_*(sqr(generator()->maximumCMEnergy())/GeV2); } CrossSection MEMinBias::dSigHatDR() const { return me2()*jacobian()/sHat()*sqr(hbarc); } unsigned int MEMinBias::orderInAlphaS() const { return 2; } unsigned int MEMinBias::orderInAlphaEW() const { return 0; } Selector MEMinBias::diagrams(const DiagramVector & diags) const { Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ) sel.insert(1.0, i); return sel; } Selector MEMinBias::colourGeometries(tcDiagPtr diag) const { static ColourLines qq("1 4, 3 5"); static ColourLines qqb("1 4, -3 -5"); static ColourLines qbqb("-1 -4, -3 -5"); Selector sel; switch(diag->id()){ case -1: sel.insert(1.0, &qq); break; case -2: sel.insert(1.0, &qqb); break; case -3: sel.insert(1.0, &qbqb); break; } return sel; } IBPtr MEMinBias::clone() const { return new_ptr(*this); } IBPtr MEMinBias::fullclone() const { return new_ptr(*this); } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigMEMinBias("Herwig::MEMinBias", "HwMEHadron.so"); void MEMinBias::persistentOutput(PersistentOStream & os) const { os << csNorm_; } void MEMinBias::persistentInput(PersistentIStream & is, int) { is >> csNorm_; } void MEMinBias::Init() { static ClassDocumentation documentation ("There is no documentation for the MEMinBias class"); static Parameter interfacecsNorm ("csNorm", "Normalization of the min-bias cross section.", &MEMinBias::csNorm_, 1.0, 0.0, 100.0, false, false, Interface::limited); } diff --git a/MatrixElement/Hadron/MEPP2Higgs.cc b/MatrixElement/Hadron/MEPP2Higgs.cc --- a/MatrixElement/Hadron/MEPP2Higgs.cc +++ b/MatrixElement/Hadron/MEPP2Higgs.cc @@ -1,1441 +1,1441 @@ // -*- C++ -*- // // MEPP2Higgs.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 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/Utilities/DescribeClass.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/RealEmissionProcess.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) {} // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigMEPP2Higgs("Herwig::MEPP2Higgs", "HwMEHadron.so"); 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.; } RealEmissionProcessPtr MEPP2Higgs::applyHardMatrixElementCorrection(RealEmissionProcessPtr born) { useMe(); assert(born->bornOutgoing().size()==1); if(born->bornIncoming()[0]->id()!=ParticleID::g) return RealEmissionProcessPtr(); // get gluons and Higgs // get the gluons ParticleVector incoming; vector beams; for(unsigned int ix=0;ixbornIncoming().size();++ix) { incoming.push_back(born->bornIncoming()[ix]); beams.push_back(dynamic_ptr_cast(born->hadrons()[ix]->dataPtr())); } pair xnew=born->x(); if(incoming[0]->momentum().z()bornOutgoing()[0]; // calculate the momenta unsigned int iemit,itype; vector pnew; // if not accepted return tPDPtr out; if(!applyHard(incoming,beams,higgs,iemit,itype,pnew,xnew,out)) return RealEmissionProcessPtr(); // fix the momentum of the higgs Boost boostv=born->bornOutgoing()[0]->momentum().findBoostToCM(); LorentzRotation trans(pnew[3].boostVector()); trans *=LorentzRotation(boostv); born->transformation(trans); born->outgoing().push_back(born->bornOutgoing()[0]->dataPtr()->produceParticle(pnew[3])); born->emitted(3); // 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 RealEmissionProcessPtr(); // create the new gluon PPtr newg= getParticleData(ParticleID::g)->produceParticle(pnew[2]); PPtr newg1 = incoming[0]->dataPtr()->produceParticle(pnew[0]); PPtr newg2 = incoming[1]->dataPtr()->produceParticle(pnew[1]); // set emitter and spectator if(born->bornIncoming()[0]->momentum().z()>ZERO) { born->incoming().push_back(newg1); born->incoming().push_back(newg2); if(iemit==0) { born->emitter(0); born->spectator(1); } else { born->emitter(1); born->spectator(0); } } else { born->incoming().push_back(newg2); born->incoming().push_back(newg1); if(iemit==0) { born->emitter(1); born->spectator(0); } else { born->emitter(0); born->spectator(1); } } bool colour = UseRandom::rndbool(); newg ->incomingColour(newg1,!colour); newg ->incomingColour(newg2, colour); newg1->colourConnect(newg2,!colour); born->outgoing().push_back(newg); } 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 RealEmissionProcessPtr(); // create the new particles PPtr newqout = out->produceParticle(pnew[2]); PPtr newqin,newg; if(iemit==0) { newqin = out ->produceParticle(pnew[0]); newg = incoming[1]->dataPtr()->produceParticle(pnew[1]); } else { newg = incoming[0]->dataPtr()->produceParticle(pnew[0]); newqin = out ->produceParticle(pnew[1]); } newqout->incomingColour(newg); newg->colourConnect(newqin); if((born->bornIncoming()[0]->momentum().z()>ZERO && iemit==0) || (born->bornIncoming()[0]->momentum().z()incoming().push_back(newqin); born->incoming().push_back(newg ); born->emitter(0); born->spectator(1); } else { born->incoming().push_back(newg ); born->incoming().push_back(newqin); born->emitter(1); born->spectator(0); } born->outgoing().push_back(newqout); } 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 RealEmissionProcessPtr(); // create the new particles PPtr newqout = out->produceParticle(pnew[2]); PPtr newqin,newg; if(iemit==0) { newqin = out ->produceParticle(pnew[0]); newg = incoming[1]->dataPtr()->produceParticle(pnew[1]); } else { newg = incoming[0]->dataPtr()->produceParticle(pnew[0]); newqin = out ->produceParticle(pnew[1]); } newqout->incomingAntiColour(newg); newg->colourConnect(newqin,true); if((born->bornIncoming()[0]->momentum().z()>ZERO && iemit==0) || (born->bornIncoming()[0]->momentum().z()incoming().push_back(newqin); born->incoming().push_back(newg ); born->emitter(0); born->spectator(1); } else { born->incoming().push_back(newg ); born->incoming().push_back(newqin); born->emitter(1); born->spectator(0); } born->outgoing().push_back(newqout); } if(born->bornIncoming()[0]->momentum().z()x(xnew); born->interaction(ShowerInteraction::QCD); return born; } bool MEPP2Higgs::softMatrixElementVeto(PPtr parent, PPtr progenitor, const bool & fs, const Energy & highestpT, const vector & ids, const double & z, const Energy & scale, const Energy & pT) { if(fs) return false; // check if me correction should be applied long id[2]={progenitor->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(ids[1]->id()!=ParticleID::g) return false; // check if hardest so far if(pTid()==ParticleID::g&&ids[2]->id()==ParticleID::g) { double split = 6.*(z/(1.-z)+(1.-z)/z+z*(1.-z)); me = ggME(shat,that,uhat)/split; } // q g else if(ids[0]->id() >= 1 && ids[0]->id() <= 5 && ids[2]->id()==ids[0]->id()) { double split = 4./3./z*(1.+sqr(1.-z)); me = qgME(shat,uhat,that)/split; } // qbar g else if(ids[0]->id() <= -1 && ids[0]->id() >= -5 && ids[2]->id()==ids[0]->id()) { 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 " << ids[0]->id() << " " << ids[1]->id() << " " << ids[2]->id() << "\n"; // return whether or not vetoed return !UseRandom::rndbool(wgt); } RealEmissionProcessPtr MEPP2Higgs::generateHardest(RealEmissionProcessPtr born, ShowerInteraction inter) { if(inter==ShowerInteraction::QED) return RealEmissionProcessPtr(); useMe(); // get the particles to be showered beams_.clear(); partons_.clear(); // find the incoming particles ParticleVector incoming; ParticleVector particlesToShower; for(unsigned int ix=0;ixbornIncoming().size();++ix) { incoming.push_back( born->bornIncoming()[ix] ); beams_.push_back( dynamic_ptr_cast(born->hadrons()[ix]->dataPtr())); partons_.push_back( born->bornIncoming()[ix]->dataPtr() ); particlesToShower.push_back( born->bornIncoming()[ix] ); } // find the higgs boson assert(born->bornOutgoing().size()==1); PPtr higgs = born->bornOutgoing()[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)) { born->pT()[ShowerInteraction::QCD] = minpT_; return born; } // construct the HardTree object needed to perform the showers ParticleVector newparticles(4); // create the partons int iemit=-1; // create the jet newparticles[3] = out_->produceParticle(pnew[3]); // g g -> h g if(emission_type==0) { newparticles[0] = partons_[0]->produceParticle(pnew[0]); newparticles[1] = partons_[1]->produceParticle(pnew[1]); iemit = pnew[0].z()/pnew[3].z()>0. ? 0 : 1; bool colour = UseRandom::rndbool(); newparticles[3]->incomingColour(newparticles[0],!colour); newparticles[3]->incomingColour(newparticles[1], colour); newparticles[0]-> colourConnect(newparticles[1],!colour); } // g q -> H q else if(emission_type==1) { newparticles[0] = partons_[0]->produceParticle(pnew[0]); newparticles[1] = out_ ->produceParticle(pnew[1]); iemit = 1; newparticles[3]->incomingColour(newparticles[0]); newparticles[0]->colourConnect (newparticles[1]); } // q g -> H q else if(emission_type==2) { newparticles[0] = out_ ->produceParticle(pnew[0]); newparticles[1] = partons_[1]->produceParticle(pnew[1]); iemit = 0; newparticles[3]->incomingColour(newparticles[1]); newparticles[1]->colourConnect (newparticles[0]); } // g qbar -> H qbar else if(emission_type==3) { newparticles[0] = partons_[0]->produceParticle(pnew[0]); newparticles[1] = out_ ->produceParticle(pnew[1]); iemit = 1; newparticles[3]->incomingAntiColour(newparticles[0]); newparticles[0]->colourConnect(newparticles[1],true); } // qbar g -> H qbar else if(emission_type==4) { newparticles[0] = out_ ->produceParticle(pnew[0]); newparticles[1] = partons_[1]->produceParticle(pnew[1]); iemit = 0; newparticles[3]->incomingAntiColour(newparticles[1]); newparticles[1]->colourConnect(newparticles[0],true); } unsigned int ispect = iemit==0 ? 1 : 0; // create the boson newparticles[2] = higgs->dataPtr()->produceParticle(pnew[2]); born->emitter (iemit); born->spectator(ispect); born->emitted(3); born->pT()[ShowerInteraction::QCD] = pt_; pair xnew; for(unsigned int ix=0;ix<2;++ix) { born->incoming().push_back(newparticles[ix]); if(ix==0) xnew.first = newparticles[ix]->momentum().rho()/born->hadrons()[ix]->momentum().rho(); else xnew.second = newparticles[ix]->momentum().rho()/born->hadrons()[ix]->momentum().rho(); } born->x(xnew); for(unsigned int ix=0;ix<2;++ix) born->outgoing().push_back(newparticles[ix+2]); // return the answer born->interaction(ShowerInteraction::QCD); return born; } bool MEPP2Higgs::applyHard(ParticleVector 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(smaxpdf(); 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)); + -2.*Complex(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(RealEmissionProcessPtr born, double & initial, double & final) { final = 1.; initial = born->bornIncoming()[0]->id()==ParticleID::g ? enhance_ : 1.; } diff --git a/MatrixElement/Hadron/MEPP2HiggsJet.cc b/MatrixElement/Hadron/MEPP2HiggsJet.cc --- a/MatrixElement/Hadron/MEPP2HiggsJet.cc +++ b/MatrixElement/Hadron/MEPP2HiggsJet.cc @@ -1,878 +1,878 @@ // -*- C++ -*- // // MEPP2HiggsJet.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 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 MEPP2HiggsJet class. // #include "MEPP2HiggsJet.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/StandardModel/StandardModelBase.h" #include "ThePEG/Utilities/SimplePhaseSpace.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Handlers/StandardXComb.h" #include "ThePEG/Cuts/Cuts.h" #include "ThePEG/MatrixElement/Tree2toNDiagram.h" #include "Herwig/MatrixElement/HardVertex.h" #include "Herwig/Utilities/HiggsLoopFunctions.h" using namespace Herwig; using namespace Herwig::HiggsLoopFunctions; IBPtr MEPP2HiggsJet::clone() const { return new_ptr(*this); } IBPtr MEPP2HiggsJet::fullclone() const { return new_ptr(*this); } unsigned int MEPP2HiggsJet::orderInAlphaS() const { return 3; } unsigned int MEPP2HiggsJet::orderInAlphaEW() const { return 1; } void MEPP2HiggsJet::persistentOutput(PersistentOStream & os) const { os << _shapeopt << _maxflavour << _process << _minloop << _maxloop << _massopt << ounit(_mh,GeV) << ounit(_wh,GeV) << _hmass; } void MEPP2HiggsJet::persistentInput(PersistentIStream & is, int) { is >> _shapeopt >> _maxflavour >> _process >> _minloop >> _maxloop >> _massopt >> iunit(_mh,GeV) >> iunit(_wh,GeV) >> _hmass; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigMEPP2HiggsJet("Herwig::MEPP2HiggsJet", "HwMEHadron.so"); void MEPP2HiggsJet::Init() { static ClassDocumentation documentation ("The MEPP2HiggsJet class implements the matrix elements for" " Higgs+Jet production in hadron-hadron collisions.", "The theoretical calculations of \\cite{Baur:1989cm} and \\cite{Ellis:1987xu}" " were used for the Higgs+jet matrix element in hadron-hadron collisions.", "\\bibitem{Baur:1989cm} U.~Baur and E.~W.~N.~Glover," "Nucl.\\ Phys.\\ B {\\bf 339} (1990) 38.\n" "\\bibitem{Ellis:1987xu} R.~K.~Ellis, I.~Hinchliffe, M.~Soldate and " "J.~J.~van der Bij, Nucl.\\ Phys.\\ B {\\bf 297} (1988) 221."); static Parameter interfaceMaximumFlavour ("MaximumFlavour", "The maximum flavour of the quarks in the process", &MEPP2HiggsJet::_maxflavour, 5, 1, 5, false, false, Interface::limited); static Switch interfaceShapeOption ("ShapeScheme", "Option for the treatment of the Higgs resonance shape", &MEPP2HiggsJet::_shapeopt, 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", &MEPP2HiggsJet::_process, 0, false, false); static SwitchOption interfaceProcessAll (interfaceProcess, "All", "Include all subprocesses", 0); static SwitchOption interfaceProcess1 (interfaceProcess, "qqbar", "Only include the incoming q qbar subprocess", 1); static SwitchOption interfaceProcessqg (interfaceProcess, "qg", "Only include the incoming qg subprocess", 2); static SwitchOption interfaceProcessqbarg (interfaceProcess, "qbarg", "Only include the incoming qbar g subprocess", 3); static SwitchOption interfaceProcessgg (interfaceProcess, "gg", "Only include the incoming gg subprocess", 4); static Parameter interfaceMinimumInLoop ("MinimumInLoop", "The minimum flavour of the quarks to include in the loops", &MEPP2HiggsJet::_minloop, 6, 4, 6, false, false, Interface::limited); static Parameter interfaceMaximumInLoop ("MaximumInLoop", "The maximum flavour of the quarks to include in the loops", &MEPP2HiggsJet::_maxloop, 6, 4, 6, false, false, Interface::limited); static Switch interfaceMassOption ("MassOption", "Option for the treatment of the masses in the loop diagrams", &MEPP2HiggsJet::_massopt, 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); } bool MEPP2HiggsJet::generateKinematics(const double * r) { Energy ptmin = max(lastCuts().minKT(mePartonData()[2]), lastCuts().minKT(mePartonData()[3])); Energy e = sqrt(sHat())/2.0; // generate the mass of the higgs boson Energy2 mhmax2 = sHat()-4.*ptmin*e; Energy2 mhmin2 =ZERO; if(mhmax2<=mhmin2) return false; double rhomin = atan2((mhmin2-sqr(_mh)), _mh*_wh); double rhomax = atan2((mhmax2-sqr(_mh)), _mh*_wh); Energy mh = sqrt(_mh*_wh*tan(rhomin+r[1]*(rhomax-rhomin))+sqr(_mh)); // assign masses if(mePartonData()[2]->id()!=ParticleID::h0) { meMomenta()[2].setMass(ZERO); meMomenta()[3].setMass(mh); } else { meMomenta()[3].setMass(ZERO); meMomenta()[2].setMass(mh); } Energy q = ZERO; try { q = SimplePhaseSpace:: getMagnitude(sHat(), meMomenta()[2].mass(), meMomenta()[3].mass()); } - catch ( ImpossibleKinematics ) { + catch ( ImpossibleKinematics & e ) { return false; } 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; double ctmin = -1.0,ctmax = 1.0; 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); 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)); } if ( ctmin >= ctmax ) return false; double cth = getCosTheta(ctmin, ctmax, r); Energy pt = q*sqrt(1.0-sqr(cth)); phi(rnd(2.0*Constants::pi)); meMomenta()[2].setX(pt*sin(phi())); meMomenta()[2].setY(pt*cos(phi())); meMomenta()[2].setZ(q*cth); meMomenta()[3].setX(-pt*sin(phi())); meMomenta()[3].setY(-pt*cos(phi())); meMomenta()[3].setZ(-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()); // main piece jacobian((pq/sHat())*Constants::pi*jacobian()); // mass piece jacobian((rhomax-rhomin)*jacobian()); return true; } void MEPP2HiggsJet::getDiagrams() const { tcPDPtr h0=getParticleData(ParticleID::h0); tcPDPtr g =getParticleData(ParticleID::g); tcPDPtr q[6],qb[6]; for(int ix=0;ix H g if(_process==0||_process==1) {for(unsigned int ix=0;ix<_maxflavour;++ix) {add(new_ptr((Tree2toNDiagram(2), q[ix], qb[ix], 1, g , 3, h0, 3, g, -1)));}} // q g -> H g if(_process==0||_process==2) {for(unsigned int ix=0;ix<_maxflavour;++ix) {add(new_ptr((Tree2toNDiagram(3), q[ix], g, g, 2, h0, 1, q[ix], -2)));}} // qbar g -> H qbar if(_process==0||_process==3) {for(unsigned int ix=0;ix<_maxflavour;++ix) {add(new_ptr((Tree2toNDiagram(3), qb[ix], g, g, 2, h0, 1, qb[ix], -3)));}} // g g -> H g if(_process==0||_process==4) { // t channel add(new_ptr((Tree2toNDiagram(3), g, g, g, 1, h0, 2, g, -4))); // u channel add(new_ptr((Tree2toNDiagram(3), g, g, g, 2, h0, 1, g, -5))); // s channel add(new_ptr((Tree2toNDiagram(2), g, g, 1, g , 3, h0, 3, g, -6))); } } Energy2 MEPP2HiggsJet::scale() const { return meMomenta()[2].perp2()+ meMomenta()[2].m2(); } double MEPP2HiggsJet::me2() const { useMe(); double output(0.); // g g to H g if(mePartonData()[0]->id()==ParticleID::g&&mePartonData()[1]->id()==ParticleID::g) { // order of the particles unsigned int ih(2),ig(3); if(mePartonData()[3]->id()==ParticleID::h0){ig=2;ih=3;} VectorWaveFunction glin1(meMomenta()[ 0],mePartonData()[ 0],incoming); VectorWaveFunction glin2(meMomenta()[ 1],mePartonData()[ 1],incoming); ScalarWaveFunction hout(meMomenta()[ih],mePartonData()[ih],outgoing); VectorWaveFunction glout(meMomenta()[ig],mePartonData()[ig],outgoing); vector g1,g2,g4; for(unsigned int ix=0;ix<2;++ix) { glin1.reset(2*ix);g1.push_back(glin1); glin2.reset(2*ix);g2.push_back(glin2); glout.reset(2*ix);g4.push_back(glout); } // calculate the matrix element output = ggME(g1,g2,hout,g4,false); } // qg -> H q else if(mePartonData()[0]->id()>0&&mePartonData()[1]->id()==ParticleID::g) { // order of the particles unsigned int iq(0),iqb(3),ih(2),ig(1); if(mePartonData()[0]->id()==ParticleID::g){iq=1;ig=0;} if(mePartonData()[3]->id()==ParticleID::h0){iqb=2;ih=3;} // calculate the spinors and polarization vectors vector fin; vector fout; vector gin; SpinorWaveFunction qin (meMomenta()[iq ],mePartonData()[iq ],incoming); VectorWaveFunction glin(meMomenta()[ig ],mePartonData()[ig ],incoming); ScalarWaveFunction hout(meMomenta()[ih ],mePartonData()[ih ],outgoing); SpinorBarWaveFunction qout(meMomenta()[iqb],mePartonData()[iqb],outgoing); 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); } // calculate the matrix element output = qgME(fin,gin,hout,fout,false); } // qbar g -> H q else if(mePartonData()[0]->id()<0&&mePartonData()[1]->id()==ParticleID::g) { // order of the particles unsigned int iq(0),iqb(3),ih(2),ig(1); if(mePartonData()[0]->id()==ParticleID::g){iq=1;ig=0;} if(mePartonData()[3]->id()==ParticleID::h0){iqb=2;ih=3;} // calculate the spinors and polarization vectors vector fin; vector fout; vector gin; SpinorBarWaveFunction qin (meMomenta()[iq ],mePartonData()[iq ],incoming); VectorWaveFunction glin(meMomenta()[ig ],mePartonData()[ig ],incoming); ScalarWaveFunction hout(meMomenta()[ih ],mePartonData()[ih ],outgoing); SpinorWaveFunction qout(meMomenta()[iqb],mePartonData()[iqb],outgoing); 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); } // calculate the matrix element output = qbargME(fin,gin,hout,fout,false); } // q qbar to H g else if(mePartonData()[0]->id()==-mePartonData()[1]->id()) { // order of the particles unsigned int iq(0),iqb(1),ih(2),ig(3); if(mePartonData()[0]->id()<0){iq=1;iqb=0;} if(mePartonData()[2]->id()==ParticleID::g){ig=2;ih=3;} // calculate the spinors and polarization vectors vector fin; vector ain; vector gout; SpinorWaveFunction qin (meMomenta()[iq ],mePartonData()[iq ],incoming); SpinorBarWaveFunction qbin(meMomenta()[iqb],mePartonData()[iqb],incoming); ScalarWaveFunction hout(meMomenta()[ih ],mePartonData()[ih ],outgoing); VectorWaveFunction glout(meMomenta()[ig ],mePartonData()[ig ],outgoing); 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); } // calculate the matrix element output = qqbarME(fin,ain,hout,gout,false); } else throw Exception() << "Unknown subprocess in MEPP2HiggsJet::me2()" << Exception::runerror; // return the answer return output; } double MEPP2HiggsJet::qqbarME(vector & fin, vector & ain, ScalarWaveFunction & hout, vector & gout, bool calc) 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 higgs // 1 outgoing gluon // me to be returned ProductionMatrixElement newme(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin0,PDT::Spin1); // get the kinematic invariants Energy2 s(sHat()),u(uHat()),t(tHat()),mh2(hout.m2()),et(scale()); // calculate the loop function complex A5 = Energy2(); for ( int ix=_minloop; ix<=_maxloop; ++ix ) { // full mass dependance if(_massopt==0) { Energy2 mf2=sqr(getParticleData(ix)->mass()); A5+= mf2*(4.+4.*double(s/(u+t))*(W1(s,mf2)-W1(mh2,mf2)) +(1.-4.*double(mf2/(u+t)))*(W2(s,mf2)-W2(mh2,mf2))); } // infinite mass limit else { A5+=2.*(s-mh2)/3.; } } // multiply by the rest of the form factors using Constants::pi; double g(sqrt(4.*pi*SM().alphaEM(mh2)/SM().sin2ThetaW())); double gs(sqrt(4.*pi*SM().alphaS(et))); Energy mw(getParticleData(ParticleID::Wplus)->mass()); complex A5c = A5 * Complex(0.,1.)*g*sqr(gs)*gs/(32.*s*sqr(pi)*mw); // compute the matrix element LorentzPolarizationVectorE fcurrent; complex fdotp; complex epsdot[2]; Complex diag; Lorentz5Momentum ps(fin[0].momentum()+ain[0].momentum()); ps.rescaleMass(); for(unsigned int ix=0;ix<2;++ix){epsdot[ix]=gout[ix].wave().dot(ps);} Energy2 denom(-ps*gout[0].momentum()); LorentzSpinorBar atemp; double output(0.); for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { // compute the fermion current atemp=ain[ihel2].wave(); fcurrent=UnitRemoval::E*fin[ihel1].wave().vectorCurrent(atemp); fdotp = -(fcurrent.dot(gout[0].momentum())); for(unsigned int ghel=0;ghel<2;++ghel) { // calculate the matrix element diag=A5c*(fcurrent.dot(gout[ghel].wave()) -fdotp*epsdot[ghel]/denom); // calculate the matrix element output+=real(diag*conj(diag)); if(calc) newme(ihel1,ihel2,0,2*ghel)=diag; } } } // test with glover form // final colour/spin factors if(calc) _me.reset(newme); return output/9.; } double MEPP2HiggsJet::qgME(vector & fin, vector & gin, ScalarWaveFunction & hout, vector & fout,bool calc) const { // the particles should be in the order // for the incoming // 0 incoming fermion (u spinor) // 1 incoming gluon // for the outgoing // 0 outgoing higgs // 1 outgoing fermion (ubar spinor) // me to be returned ProductionMatrixElement newme(PDT::Spin1Half,PDT::Spin1, PDT::Spin0,PDT::Spin1Half); // get the kinematic invariants Energy2 s(sHat()),u(uHat()),t(tHat()),mh2(hout.m2()),et(scale()); // calculate the loop function complex A5 = Energy2(); for(int ix=_minloop;ix<=_maxloop;++ix) { if(_massopt==0) { Energy2 mf2=sqr(getParticleData(ix)->mass()); A5+= mf2*(4.+4.*double(u/(s+t))*(W1(u,mf2)-W1(mh2,mf2)) +(1.-4.*double(mf2/(s+t)))*(W2(u,mf2)-W2(mh2,mf2))); } else { A5+=2.*(u-mh2)/3.; } } // multiply by the rest of the form factors using Constants::pi; double g(sqrt(4.*pi*SM().alphaEM(mh2)/SM().sin2ThetaW())); double gs(sqrt(4.*pi*SM().alphaS(et))); Energy mw(getParticleData(ParticleID::Wplus)->mass()); complex A5c =A5*Complex(0.,1.)*g*sqr(gs)*gs/(32.*u*sqr(pi)*mw); // compute the matrix element LorentzPolarizationVectorE fcurrent; complex fdotp; complex epsdot[2]; Complex diag; Lorentz5Momentum pu(fin[0].momentum()+fout[0].momentum()); pu.rescaleMass(); for(unsigned int ix=0;ix<2;++ix){epsdot[ix]=gin[ix].wave().dot(pu);} Energy2 denom(pu*gin[0].momentum()); LorentzSpinorBar atemp; double output(0.); for(unsigned int ihel=0;ihel<2;++ihel) { for(unsigned int ohel=0;ohel<2;++ohel) { // compute the fermion current atemp=fout[ohel].wave(); fcurrent=UnitRemoval::E*fin[ihel].wave().vectorCurrent(atemp); fdotp=fcurrent.dot(gin[0].momentum()); for(unsigned int ghel=0;ghel<2;++ghel) { // calculate the matrix element diag=A5c*(fcurrent.dot(gin[ghel].wave())-fdotp*epsdot[ghel]/denom); // calculate the matrix element output+=real(diag*conj(diag)); if(calc) newme(ihel,2*ghel,0,ohel)=diag; } } } // final colour/spin factors if(calc) _me.reset(newme); return output/24.; } double MEPP2HiggsJet::qbargME(vector & fin, vector & gin, ScalarWaveFunction & hout, vector & fout,bool calc) const { // the particles should be in the order // for the incoming // 0 incoming antifermion (vbar spinor) // 1 incoming gluon // for the outgoing // 0 outgoing higgs // 1 outgoing antifermion (v spinor) // me to be returned ProductionMatrixElement newme(PDT::Spin1Half,PDT::Spin1, PDT::Spin0,PDT::Spin1Half); // get the kinematic invariants Energy2 s(sHat()),u(uHat()),t(tHat()),mh2(hout.m2()),et(scale()); // calculate the loop function complex A5 = Energy2(); for(int ix=_minloop;ix<=_maxloop;++ix) { if(_massopt==0) { Energy2 mf2=sqr(getParticleData(ix)->mass()); A5+= mf2*(4.+4.*double(u/(s+t))*(W1(u,mf2)-W1(mh2,mf2)) +(1.-4.*double(mf2/(s+t)))*(W2(u,mf2)-W2(mh2,mf2))); } else { A5+=2.*(u-mh2)/3.; } } // multiply by the rest of the form factors using Constants::pi; double g(sqrt(4.*pi*SM().alphaEM(mh2)/SM().sin2ThetaW())); double gs(sqrt(4.*pi*SM().alphaS(et))); Energy mw(getParticleData(ParticleID::Wplus)->mass()); complex A5c = A5*Complex(0.,1.)*g*sqr(gs)*gs/(32.*u*sqr(pi)*mw); // compute the matrix element LorentzPolarizationVectorE fcurrent; complex fdotp; complex epsdot[2]; Complex diag; Lorentz5Momentum pu(fin[0].momentum()+fout[0].momentum()); pu.rescaleMass(); for(unsigned int ix=0;ix<2;++ix){epsdot[ix]=gin[ix].wave().dot(pu);} Energy2 denom(pu*gin[0].momentum()); LorentzSpinorBar atemp; double output(0.); for(unsigned int ihel=0;ihel<2;++ihel) { for(unsigned int ohel=0;ohel<2;++ohel) { // compute the fermion current atemp=fin[ihel].wave(); fcurrent=UnitRemoval::E*fout[ohel].wave().vectorCurrent(atemp); fdotp=fcurrent.dot(gin[0].momentum()); for(unsigned int ghel=0;ghel<2;++ghel) { // calculate the matrix element diag=A5c*(fcurrent.dot(gin[ghel].wave())-fdotp*epsdot[ghel]/denom); // calculate the matrix element output+=real(diag*conj(diag)); if(calc) newme(ihel,2*ghel,0,ohel)=diag; } } } // final colour/spin factors if(calc) _me.reset(newme); return output/24.; } Selector MEPP2HiggsJet::diagrams(const DiagramVector & diags) const { Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ) { if(abs(diags[i]->id())<4) sel.insert(1.0, i); else sel.insert(_diagwgt[abs(diags[i]->id())-4], i); } return sel; } Selector MEPP2HiggsJet::colourGeometries(tcDiagPtr diag) const { // colour lines for q qbar -> h0 g static const ColourLines cqqbar("1 3 5,-2 -3 -5"); // colour lines for q g -> h0 q static const ColourLines cqg("1 2 -3, 3 -2 5"); // colour lines for qbar q -> h0 qbar static const ColourLines cqbarg("-1 -2 3, -3 2 -5"); // colour lines for g g -> h0 g static const ColourLines cgg[6]={ColourLines("1 2 5, -3 -5, 3 -2 -1"), ColourLines("-1 -2 -5, 3 5, -3 2 1"), ColourLines("1 5, -1 -2 3, -3 2 -5"), ColourLines("-1 -5, 1 2 -3, 3 -2 5"), ColourLines("1 3 5, -5 -3 -2, 2 -1"), ColourLines("-1 -3 -5, 5 3 2 ,-2 1")}; // select the colour flow Selector sel; if ( diag->id() == -1) sel.insert(1.0, &cqqbar); else if ( diag->id() == -2) sel.insert(1.0, &cqg); else if ( diag->id() == -3) sel.insert(1.0, &cqbarg); else { sel.insert(0.5, &cgg[2*(abs(diag->id())-4) ]); sel.insert(0.5, &cgg[2*(abs(diag->id())-4)+1]); } // return the answer return sel; } double MEPP2HiggsJet::ggME(vector g1, vector g2, ScalarWaveFunction & hout, vector g4, bool calc) const { // the particles should be in the order // for the incoming // 0 first incoming gluon // 1 second incoming gluon // for the outgoing // 0 outgoing higgs // 1 outgoing gluon // me to be returned ProductionMatrixElement newme(PDT::Spin1,PDT::Spin1, PDT::Spin0,PDT::Spin1); // get the kinematic invariants Energy2 s(sHat()),u(uHat()),t(tHat()),mh2(hout.m2()),et(scale()); // calculate the loop functions Complex A4stu(0.),A2stu(0.),A2tsu(0.),A2ust(0.); Complex A5s(0.),A5t(0.),A5u(0.); for(int ix=_minloop;ix<=_maxloop;++ix) { Energy2 mf2=sqr(getParticleData(ix)->mass()); // loop functions if(_massopt==0) { A4stu+=A4(s,t,u,mf2); A2stu+=A2(s,t,u,mf2); A2tsu+=A2(u,s,t,mf2); A2ust+=A2(t,s,u,mf2); A5s+= mf2/s*(4.+4.*double(s/(u+t))*(W1(s,mf2)-W1(mh2,mf2)) +(1.-4.*double(mf2/(u+t)))*(W2(s,mf2)-W2(mh2,mf2))); A5t+= mf2/t*(4.+4.*double(t/(s+u))*(W1(t,mf2)-W1(mh2,mf2)) +(1.-4.*double(mf2/(s+u)))*(W2(t,mf2)-W2(mh2,mf2))); A5u+= mf2/u*(4.+4.*double(u/(s+t))*(W1(u,mf2)-W1(mh2,mf2)) +(1.-4.*double(mf2/(s+t)))*(W2(u,mf2)-W2(mh2,mf2))); } else { A4stu=-1./3.; A2stu=-sqr(s/mh2)/3.; A2tsu=-sqr(t/mh2)/3.; A2ust=-sqr(u/mh2)/3.; A5s+=2.*(s-mh2)/3./s; A5t+=2.*(t-mh2)/3./t; A5u+=2.*(u-mh2)/3./u; } } Complex A3stu=0.5*(A2stu+A2ust+A2tsu-A4stu); // compute the dot products for the matrix element complex eps[3][4][2]; Energy2 pdot[4][4]; pdot[0][0]=ZERO; pdot[0][1]= g1[0].momentum()*g2[0].momentum(); pdot[0][2]=-1.*g1[0].momentum()*g4[0].momentum(); pdot[0][3]=-1.*g1[0].momentum()*hout.momentum(); pdot[1][0]= pdot[0][1]; pdot[1][1]= ZERO; pdot[1][2]=-1.*g2[0].momentum()*g4[0].momentum(); pdot[1][3]=-1.*g2[0].momentum()*hout.momentum(); pdot[2][0]= pdot[0][2]; pdot[2][1]= pdot[1][2]; pdot[2][2]= ZERO; pdot[2][3]= g4[0].momentum()*hout.momentum(); pdot[3][0]=pdot[0][3]; pdot[3][1]=pdot[1][3]; pdot[3][2]=pdot[2][3]; pdot[3][3]=mh2; for(unsigned int ix=0;ix<2;++ix) { eps[0][0][ix]=InvEnergy(); eps[0][1][ix]=g1[ix].wave().dot(g2[0].momentum())/pdot[0][1]; eps[0][2][ix]=-1.*g1[ix].wave().dot(g4[0].momentum())/pdot[0][2]; eps[0][3][ix]=-1.*g1[ix].wave().dot(hout.momentum())/ pdot[0][3]; eps[1][0][ix]=g2[ix].wave().dot(g1[0].momentum())/ pdot[1][0]; eps[1][1][ix]=InvEnergy(); eps[1][2][ix]=-1.*g2[ix].wave().dot(g4[0].momentum())/pdot[1][2]; eps[1][3][ix]=-1.*g2[ix].wave().dot(hout.momentum())/ pdot[1][3]; eps[2][0][ix]=g4[ix].wave().dot(g1[0].momentum())/ pdot[2][0]; eps[2][1][ix]=g4[ix].wave().dot(g2[0].momentum())/ pdot[2][1]; eps[2][2][ix]=InvEnergy(); eps[2][3][ix]=-1.*g4[ix].wave().dot(hout.momentum())/ pdot[2][3]; } // prefactors using Constants::pi; double g(sqrt(4.*pi*SM().alphaEM(mh2)/SM().sin2ThetaW())); double gs(sqrt(4.*pi*SM().alphaS(et))); Energy mw(getParticleData(ParticleID::Wplus)->mass()); Energy3 pre=g*sqr(mh2)*gs*sqr(gs)/(32.*sqr(pi)*mw); // compute the matrix element double output(0.); Complex diag[4],wdot[3][3]; _diagwgt[0]=0.; _diagwgt[1]=0.; _diagwgt[2]=0.; for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { for(unsigned int ohel=0;ohel<2;++ohel) { wdot[0][1]=g1[ihel1].wave().dot(g2[ihel2].wave()); wdot[0][2]=g1[ihel1].wave().dot(g4[ohel ].wave()); wdot[1][0]=wdot[0][1]; wdot[1][2]=g2[ihel2].wave().dot(g4[ohel ].wave()); wdot[2][0]=wdot[0][2]; wdot[2][1]=wdot[1][2]; // last piece diag[3]=pre*A3stu*(eps[0][2][ihel1]*eps[1][0][ihel2]*eps[2][1][ohel]- eps[0][1][ihel1]*eps[1][2][ihel2]*eps[2][0][ohel]+ (eps[2][0][ohel ]-eps[2][1][ohel ])*wdot[0][1]/pdot[0][1]+ (eps[1][2][ihel2]-eps[1][0][ihel2])*wdot[0][2]/pdot[0][2]+ (eps[0][1][ihel1]-eps[0][2][ihel1])*wdot[1][2]/pdot[1][2]); // first piece diag[3]+=pre*( +A2stu*(eps[0][1][ihel1]*eps[1][0][ihel2]-wdot[0][1]/pdot[0][1])* (eps[2][0][ohel ]-eps[2][1][ohel ]) +A2ust*(eps[0][2][ihel1]*eps[2][0][ohel ]-wdot[0][2]/pdot[0][2])* (eps[1][2][ihel2]-eps[1][0][ihel2]) +A2tsu*(eps[1][2][ihel2]*eps[2][1][ohel ]-wdot[1][2]/pdot[1][2])* (eps[0][1][ihel1]-eps[0][2][ihel1]) ); output+=real(diag[3]*conj(diag[3])); // matrix element if needed if(calc) newme(2*ihel1,2*ihel2,0,2*ohel)=diag[3]; // different diagrams diag[0] = A5t*UnitRemoval::InvE*(-eps[0][3][ihel1]* (-2.*eps[2][1][ohel ]*eps[1][0][ihel2]*pdot[2][1]*pdot[1][0] -2.*eps[1][2][ihel2]*eps[2][0][ohel ]*pdot[1][2]*pdot[2][0] +wdot[1][2]*(pdot[0][1]+pdot[0][2])) -2.*eps[2][1][ohel ]*pdot[2][1]*wdot[0][1] -2.*eps[1][2][ihel2]*pdot[1][2]*wdot[0][2] +wdot[1][2]*(eps[0][1][ihel1]*pdot[0][1]+ eps[0][2][ihel1]*pdot[0][2])); diag[1] = A5u*UnitRemoval::InvE*(-eps[1][3][ihel2]* (+2.*eps[0][1][ihel1]*eps[2][0][ohel ]*pdot[0][1]*pdot[2][0] +2.*eps[0][2][ihel1]*eps[2][1][ohel ]*pdot[0][2]*pdot[2][1] -wdot[0][2]*(pdot[1][0]+pdot[1][2])) +2.*eps[2][0][ohel ]*pdot[2][0]*wdot[0][1] +2.*eps[0][2][ihel1]*pdot[0][2]*wdot[2][1] -wdot[0][2]*(eps[1][0][ihel2]*pdot[1][0]+ eps[1][2][ihel2]*pdot[1][2])); diag[2] = A5s*UnitRemoval::InvE*(-eps[2][3][ohel ]* (+2.*eps[0][1][ihel1]*eps[1][2][ihel2]*pdot[0][1]*pdot[1][2] -2.*eps[1][0][ihel2]*eps[0][2][ihel1]*pdot[1][0]*pdot[1][3] +wdot[0][1]*(pdot[2][0]-pdot[2][1])) +2.*eps[0][1][ihel1]*pdot[0][1]*wdot[1][2] -2.*eps[1][0][ihel2]*pdot[1][0]*wdot[0][2] +wdot[0][1]*(eps[2][0][ohel]*pdot[2][0]- eps[2][1][ohel]*pdot[2][1])); _diagwgt[0]+=real(diag[0]*conj(diag[0])); _diagwgt[1]+=real(diag[1]*conj(diag[1])); _diagwgt[2]+=real(diag[2]*conj(diag[2])); } } } // final colour and spin factors if(calc){_me.reset(newme);} return 3.*output/32.; } void MEPP2HiggsJet::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]); // ensure correct order or particles if((hard[0]->id()==ParticleID::g&&hard[1]->id()!=ParticleID::g)|| (hard[0]->id()<0&&hard[1]->id()<6)) swap(hard[0],hard[1]); if(hard[2]->id()!=ParticleID::h0) swap(hard[2],hard[3]); // different processes // g g to H g if(hard[0]->id()==ParticleID::g) { vector g1,g2,g4; VectorWaveFunction(g1,hard[0],incoming,false,true,true); VectorWaveFunction(g2,hard[1],incoming,false,true,true); VectorWaveFunction(g4,hard[3],outgoing,true ,true,true); ScalarWaveFunction hout(hard[2],outgoing,true); g1[1]=g1[2];g2[1]=g2[2];g4[1]=g4[2]; ggME(g1,g2,hout,g4,true); } // qg -> H q else if(hard[0]->id()>0&&hard[1]->id()==ParticleID::g) { vector g2; vector qin; vector qout; SpinorWaveFunction( qin,hard[0],incoming,false,true); VectorWaveFunction( g2,hard[1],incoming,false,true,true); SpinorBarWaveFunction(qout,hard[3],outgoing,true ,true); ScalarWaveFunction hout(hard[2],outgoing,true); g2[1]=g2[2]; qgME(qin,g2,hout,qout,true); } // qbar g -> H q else if(hard[0]->id()<0&&hard[1]->id()==ParticleID::g) { vector g2; vector qin; vector qout; SpinorBarWaveFunction( qin,hard[0],incoming,false,true); VectorWaveFunction( g2,hard[1],incoming,false,true,true); SpinorWaveFunction( qout,hard[3],outgoing,true ,true); ScalarWaveFunction hout(hard[2],outgoing,true); g2[1]=g2[2]; qbargME(qin,g2,hout,qout,true); } // q qbar to H g else if(hard[0]->id()==-hard[1]->id()) { vector qbar; vector q; vector g4; SpinorWaveFunction( q ,hard[0],incoming,false,true); SpinorBarWaveFunction(qbar,hard[1],incoming,false,true); VectorWaveFunction( g4,hard[3],outgoing,true ,true,true); ScalarWaveFunction hout(hard[2],outgoing,true); g4[1]=g4[2]; qqbarME(q,qbar,hout,g4,true); } else throw Exception() << "Unknown subprocess in MEPP2HiggsJet::constructVertex()" << Exception::runerror; // 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 ix=0;ix<4;++ix) { (hard[ix]->spinInfo())-> productionVertex(hardvertex); } } int MEPP2HiggsJet::nDim() const { return 2; } void MEPP2HiggsJet::doinit() { ME2to2Base::doinit(); tcPDPtr h0=getParticleData(ParticleID::h0); _mh = h0->mass(); _wh = h0->generateWidth(_mh); if(h0->massGenerator()) { _hmass=dynamic_ptr_cast(h0->massGenerator()); } if(_shapeopt==2&&!_hmass) throw InitException() << "If using the mass generator for the line shape in MEPP2HiggsJet::doinit()" << "the mass generator must be an instance of the GenericMassGenerator class" << Exception::runerror; } CrossSection MEPP2HiggsJet::dSigHatDR() const { using Constants::pi; InvEnergy2 bwfact; Energy moff = mePartonData()[2]->id()==ParticleID::h0 ? meMomenta()[2].mass() : meMomenta()[3].mass(); if(_shapeopt==1) { tcPDPtr h0 = mePartonData()[2]->id()==ParticleID::h0 ? mePartonData()[2] : mePartonData()[3]; bwfact = h0->generateWidth(moff)*moff/pi/ (sqr(sqr(moff)-sqr(_mh))+sqr(_mh*_wh)); } else { bwfact = _hmass->BreitWignerWeight(moff); } return me2()*jacobian()/(16.0*sqr(Constants::pi)*sHat())*sqr(hbarc)* (sqr(sqr(moff)-sqr(_mh))+sqr(_mh*_wh))/(_mh*_wh)*bwfact; } diff --git a/MatrixElement/Hadron/MEPP2QQHiggs.cc b/MatrixElement/Hadron/MEPP2QQHiggs.cc --- a/MatrixElement/Hadron/MEPP2QQHiggs.cc +++ b/MatrixElement/Hadron/MEPP2QQHiggs.cc @@ -1,636 +1,636 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the MEPP2QQH class. // #include "MEPP2QQHiggs.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/Switch.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 "Herwig/Models/StandardModel/StandardModel.h" #include "ThePEG/Utilities/SimplePhaseSpace.h" #include "Herwig/Utilities/Kinematics.h" #include "ThePEG/Cuts/Cuts.h" #include "Herwig/MatrixElement/HardVertex.h" using namespace Herwig; MEPP2QQHiggs::MEPP2QQHiggs() : quarkFlavour_(6), process_(0), shapeOpt_(2), mh_(), wh_(), alpha_(1.1) {} // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigMEPP2QQHiggs("Herwig::MEPP2QQHiggs", "HwMEHadron.so"); void MEPP2QQHiggs::Init() { static ClassDocumentation documentation ("The MEPP2QQHiggs class implements the matrix elements for the " "production of the Higgs boson in association with a heavy quark-antiquark pair"); static Switch interfaceQuarkType ("QuarkType", "The type of quark", &MEPP2QQHiggs::quarkFlavour_, 6, false, false); static SwitchOption interfaceQuarkTypeBottom (interfaceQuarkType, "Bottom", "Produce bottom-antibottom", 5); static SwitchOption interfaceQuarkTypeTop (interfaceQuarkType, "Top", "Produce top-antitop", 6); static Switch interfaceProcess ("Process", "Which subprocesses to include", &MEPP2QQHiggs::process_, 0, false, false); static SwitchOption interfaceProcessAll (interfaceProcess, "All", "Include all subprocesses", 0); static SwitchOption interfaceProcess1 (interfaceProcess, "gg", "Include only gg -> QQbarH processes", 1); static SwitchOption interfaceProcessqbarqbarqbarqbar (interfaceProcess, "qqbar", "Include only qbar qbar -> QQbarH processes", 2); static Switch interfaceShapeOption ("ShapeScheme", "Option for the treatment of the Higgs resonance shape", &MEPP2QQHiggs::shapeOpt_, 2, false, false); static SwitchOption interfaceStandardShapeFixed (interfaceShapeOption, "FixedBreitWigner", "Breit-Wigner s-channel resonance", 1); static SwitchOption interfaceStandardShapeRunning (interfaceShapeOption, "MassGenerator", "Use the mass generator to give the shape", 2); static SwitchOption interfaceStandardShapeOnShell (interfaceShapeOption, "OnShell", "Produce an on-shell Higgs boson", 0); static Parameter interfaceAlpha ("Alpha", "Power for the generation of the tranverse mass in the pT mapping", &MEPP2QQHiggs::alpha_, 1.1, 0.0, 10.0, false, false, Interface::limited); } Energy2 MEPP2QQHiggs::scale() const { return sHat(); // return sqr(mePartonData()[2]->mass()+mePartonData()[3]->mass()+ // mePartonData()[4]->mass()); } int MEPP2QQHiggs::nDim() const { return 4 + int(shapeOpt_>0); } unsigned int MEPP2QQHiggs::orderInAlphaS() const { return 2; } unsigned int MEPP2QQHiggs::orderInAlphaEW() const { return 1; } IBPtr MEPP2QQHiggs::clone() const { return new_ptr(*this); } IBPtr MEPP2QQHiggs::fullclone() const { return new_ptr(*this); } void MEPP2QQHiggs::setKinematics() { HwMEBase::setKinematics(); } void MEPP2QQHiggs::persistentOutput(PersistentOStream & os) const { os << quarkFlavour_ << process_ << shapeOpt_ << ounit(mh_,GeV) << ounit(wh_,GeV) << hmass_ << GGGVertex_ << QQGVertex_ << QQHVertex_ << gluon_ << higgs_ << quark_ << antiquark_ << alpha_; } void MEPP2QQHiggs::persistentInput(PersistentIStream & is, int) { is >> quarkFlavour_ >> process_ >> shapeOpt_ >> iunit(mh_,GeV) >> iunit(wh_,GeV) >> hmass_ >> GGGVertex_ >> QQGVertex_ >> QQHVertex_ >> gluon_ >> higgs_ >> quark_ >> antiquark_ >> alpha_; } void MEPP2QQHiggs::doinit() { HwMEBase::doinit(); // stuff for the higgs mass higgs_=getParticleData(ParticleID::h0); mh_ = higgs_->mass(); wh_ = higgs_->width(); if(higgs_->massGenerator()) { hmass_=dynamic_ptr_cast(higgs_->massGenerator()); } if(shapeOpt_==2&&!hmass_) throw InitException() << "If using the mass generator for the line shape in MEPP2QQHiggs::doinit()" << "the mass generator must be an instance of the GenericMassGenerator class" << Exception::runerror; // get the vertex pointers from the SM object tcHwSMPtr hwsm= dynamic_ptr_cast(standardModel()); // do the initialisation if(!hwsm) throw InitException() << "Wrong type of StandardModel object in " << "MEPP2QQHiggs::doinit() the Herwig" << " version must be used" << Exception::runerror; GGGVertex_ = hwsm->vertexGGG(); QQGVertex_ = hwsm->vertexFFG(); QQHVertex_ = hwsm->vertexFFH(); // get the particle data objects gluon_=getParticleData(ParticleID::g); for(int ix=1;ix<=6;++ix) { quark_.push_back( getParticleData( ix)); antiquark_.push_back(getParticleData(-ix)); } } bool MEPP2QQHiggs::generateKinematics(const double * r) { jacobian(1.); // CMS energy Energy rs = sqrt(sHat()); // quark mass Energy mq(quark_[quarkFlavour_-1]->mass()); // generate the higgs mass Energy mh(mh_); if(shapeOpt_!=0) { Energy mhmax = min(rs-2.*mq,higgs_->massMax()); Energy mhmin = max(ZERO ,higgs_->massMin()); if(mhmax<=mhmin) return false; double rhomin = atan2((sqr(mhmin)-sqr(mh_)), mh_*wh_); double rhomax = atan2((sqr(mhmax)-sqr(mh_)), mh_*wh_); mh = sqrt(mh_*wh_*tan(rhomin+r[4]*(rhomax-rhomin))+sqr(mh_)); jacobian(jacobian()*(rhomax-rhomin)); } if(rs ZERO ) { double ctm = 1.0 - sqr(ptmin/p1); if ( ctm <= 0.0 ) return false; ctmin = max(ctmin, -sqrt(ctm)); ctmax = min(ctmax, sqrt(ctm)); } double cos1 = getCosTheta(ctmin,ctmax,r[0]); double sin1(sqrt(1.-sqr(cos1))); double phi1 = Constants::twopi*UseRandom::rnd(); Lorentz5Momentum p13(sin1*p1*cos(phi1),sin1*p1*sin(phi1),cos1*p1, sqrt(sqr(p1)+m132),m13); meMomenta()[3].setVect(Momentum3(-sin1*p1*cos(phi1),-sin1*p1*sin(phi1),-cos1*p1)); meMomenta()[3].setMass(mq); meMomenta()[3].rescaleEnergy(); bool test=Kinematics::twoBodyDecay(p13,mq,mh,-1.+2*r[2],r[3]*Constants::twopi, meMomenta()[2],meMomenta()[4]); if(!test) return false; m232 = (meMomenta()[3]+meMomenta()[4]).m2(); double D = 2./(pow(sqr(mq)/(m132-sqr(mq)),alpha_)+ pow(sqr(mq)/(m232-sqr(mq)),alpha_)); jacobian(0.5*jacobian()*rs/m13*sqr(mq)*D*(rhomax-rhomin)/sHat()); } // second branch else { double rtemp = 2.*(r[1]-0.5); double rho = rhomin+rtemp*(rhomax-rhomin); if(alpha_==0) m232 = sqr(mq)*rho; else if(alpha_==1) m232 = sqr(mq)*(exp(rho)+1.); else m232 = sqr(mq)*(pow(rho,1./(1.-alpha_))+1.); Energy m23 = sqrt(m232); try { p1 = SimplePhaseSpace::getMagnitude(sHat(), m23, mq); p2 = SimplePhaseSpace::getMagnitude(m232,mq,mh); - } catch ( ImpossibleKinematics ) { + } catch ( ImpossibleKinematics & e ) { return false; } Energy ptmin = lastCuts().minKT(mePartonData()[2]); double ctmin = -1.0, ctmax = 1.0; if ( ptmin > ZERO ) { double ctm = 1.0 - sqr(ptmin/p1); if ( ctm <= 0.0 ) return false; ctmin = max(ctmin, -sqrt(ctm)); ctmax = min(ctmax, sqrt(ctm)); } double cos1 = getCosTheta(ctmin,ctmax,r[0]); double sin1(sqrt(1.-sqr(cos1))); double phi1 = Constants::twopi*UseRandom::rnd(); Lorentz5Momentum p23(-sin1*p1*cos(phi1),-sin1*p1*sin(phi1),-cos1*p1, sqrt(sqr(p1)+m232),m23); meMomenta()[2].setVect(Momentum3(sin1*p1*cos(phi1),sin1*p1*sin(phi1),cos1*p1)); meMomenta()[2].setMass(mq); meMomenta()[2].rescaleEnergy(); bool test=Kinematics::twoBodyDecay(p23,mq,mh,-1.+2*r[2],r[3]*Constants::twopi, meMomenta()[3],meMomenta()[4]); if(!test) return false; m132 = (meMomenta()[2]+meMomenta()[4]).m2(); double D = 2./(pow(sqr(mq)/(m132-sqr(mq)),alpha_)+ pow(sqr(mq)/(m232-sqr(mq)),alpha_)); jacobian(0.5*jacobian()*rs/m23*sqr(mq)*D*(rhomax-rhomin)/sHat()); } // calculate jacobian jacobian(0.125*jacobian()*p1*p2/sHat()); // check cuts vector out; tcPDVector tout; for(unsigned int ix=2;ix<5;++ix) { out .push_back(meMomenta()[ix]); tout.push_back(mePartonData()[ix]); } return lastCuts().passCuts(tout, out, mePartonData()[0], mePartonData()[1]); } CrossSection MEPP2QQHiggs::dSigHatDR() const { using Constants::pi; // jacobian factor for the higgs InvEnergy2 bwfact; Energy moff = meMomenta()[4].mass(); if(shapeOpt_==1) { bwfact = mePartonData()[4]->generateWidth(moff)*moff/pi/ (sqr(sqr(moff)-sqr(mh_))+sqr(mh_*wh_)); } else if(shapeOpt_==2) { bwfact = hmass_->BreitWignerWeight(moff); } double jac1 = shapeOpt_==0 ? 1. : double(bwfact*(sqr(sqr(moff)-sqr(mh_))+sqr(mh_*wh_))/(mh_*wh_)); return sqr(hbarc)*me2()*jacobian()*jac1/sHat()/pow(Constants::twopi,3); } void MEPP2QQHiggs::getDiagrams() const { tPDPtr Q = quark_[quarkFlavour_-1]; tPDPtr QB = antiquark_[quarkFlavour_-1]; // gg -> q qbar h0 subprocesses if(process_==0||process_==1) { // first t-channel add(new_ptr((Tree2toNDiagram(3), gluon_, QB, gluon_, 1, Q, 4, Q , 2, QB, 4, higgs_, -1))); add(new_ptr((Tree2toNDiagram(4), gluon_, QB, QB, gluon_, 1, Q, 3, QB, 2, higgs_, -2))); add(new_ptr((Tree2toNDiagram(3),gluon_,QB,gluon_, 1, Q, 2, QB, 5, QB, 5, higgs_, -3))); // interchange add(new_ptr((Tree2toNDiagram(3),gluon_,Q,gluon_, 2, Q, 4, Q , 1, QB, 4, higgs_, -4))); add(new_ptr((Tree2toNDiagram(4),gluon_,Q,Q,gluon_, 3, Q, 1, QB, 2, higgs_, -5))); add(new_ptr((Tree2toNDiagram(3),gluon_,Q,gluon_, 2, Q, 1, QB, 5, QB, 5, higgs_, -6))); // s-channel add(new_ptr((Tree2toNDiagram(2),gluon_,gluon_, 1, gluon_, 3, Q, 4, Q, 3, QB, 4, higgs_, -7))); add(new_ptr((Tree2toNDiagram(2),gluon_,gluon_, 1, gluon_, 3,Q, 3, QB, 5, QB, 5, higgs_, -8))); } // q qbar -> q qbar if(process_==0||process_==2) { for(unsigned int ix=1;ix<5;++ix) { // gluon s-channel add(new_ptr((Tree2toNDiagram(2),quark_[ix-1], antiquark_[ix-1], 1, gluon_, 3, Q, 4, Q , 3, QB, 4, higgs_, -9))); add(new_ptr((Tree2toNDiagram(2),quark_[ix-1], antiquark_[ix-1], 1, gluon_, 3, Q, 3, QB, 5, QB, 5, higgs_, -10))); } } } double MEPP2QQHiggs::me2() const { // total matrix element double me(0.); // gg initiated processes if(mePartonData()[0]->id()==ParticleID::g) { VectorWaveFunction g1w(meMomenta()[0],mePartonData()[0],incoming); VectorWaveFunction g2w(meMomenta()[1],mePartonData()[1],incoming); SpinorBarWaveFunction qw(meMomenta()[2],mePartonData()[2],outgoing); SpinorWaveFunction qbarw(meMomenta()[3],mePartonData()[3],outgoing); ScalarWaveFunction higgs(meMomenta()[4],mePartonData()[4],1.,outgoing); vector g1,g2; vector q; vector qbar; for(unsigned int ix=0;ix<2;++ix) { g1w.reset(2*ix);g1.push_back(g1w); g2w.reset(2*ix);g2.push_back(g2w); qw.reset(ix);q.push_back(qw); qbarw.reset(ix);qbar.push_back(qbarw); } // calculate the matrix element me=ggME(g1,g2,q,qbar,higgs,0); } // q qbar initiated else { SpinorWaveFunction q1w(meMomenta()[0],mePartonData()[0],incoming); SpinorBarWaveFunction q2w(meMomenta()[1],mePartonData()[1],incoming); SpinorBarWaveFunction q3w(meMomenta()[2],mePartonData()[2],outgoing); SpinorWaveFunction q4w(meMomenta()[3],mePartonData()[3],outgoing); ScalarWaveFunction higgs(meMomenta()[4],mePartonData()[4],1.,outgoing); vector q1,q4; vector q2,q3; for(unsigned int ix=0;ix<2;++ix) { q1w.reset(ix);q1.push_back(q1w); q2w.reset(ix);q2.push_back(q2w); q3w.reset(ix);q3.push_back(q3w); q4w.reset(ix);q4.push_back(q4w); } // calculate the matrix element me = qqME(q1,q2,q3,q4,higgs,0); } return me*sHat()*UnitRemoval::InvE2; } double MEPP2QQHiggs::ggME(vector &g1, vector &g2, vector & q, vector & qbar, ScalarWaveFunction & hwave, unsigned int iflow) const { // scale Energy2 mt(scale()); Energy mass = q[0].mass(); // matrix element to be stored if(iflow!=0) me_.reset(ProductionMatrixElement(PDT::Spin1,PDT::Spin1, PDT::Spin1Half,PDT::Spin1Half, PDT::Spin0)); // calculate the matrix element double output(0.),sumflow[2]={0.,0.}; double sumdiag[8]={0.,0.,0.,0.,0.,0.,0.,0.}; Complex diag[8],flow[2]; VectorWaveFunction interv; SpinorWaveFunction inters,QBoff; SpinorBarWaveFunction intersb,Qoff; for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { interv = GGGVertex_->evaluate(mt,5,gluon_,g1[ihel1],g2[ihel2]); for(unsigned int ohel1=0;ohel1<2;++ohel1) { Qoff = QQHVertex_->evaluate(mt,3,q[ohel1].particle()->CC(), q[ohel1],hwave,mass); for(unsigned int ohel2=0;ohel2<2;++ohel2) { QBoff = QQHVertex_->evaluate(mt,3,qbar[ohel2].particle()->CC(), qbar[ohel2],hwave,mass); // 1st diagram inters = QQGVertex_->evaluate(mt,1,qbar[ohel2].particle()->CC(), qbar[ohel2],g2[ihel2],mass); diag[0] = QQGVertex_->evaluate(mt,inters,Qoff,g1[ihel1]); // 2nd diagram intersb = QQGVertex_->evaluate(mt,1,q[ohel1].particle()->CC(), q[ohel1],g1[ihel1],mass); diag[1] = QQHVertex_->evaluate(mt,inters,intersb,hwave); // 3rd diagram diag[2] = QQGVertex_->evaluate(mt,QBoff,intersb,g2[ihel2]); // 4th diagram inters = QQGVertex_->evaluate(mt,1,qbar[ohel2].particle()->CC(), qbar[ohel2],g1[ihel1],mass); diag[3] = QQGVertex_->evaluate(mt,inters,Qoff,g2[ihel2]); // 5th diagram intersb = QQGVertex_->evaluate(mt,1,q[ohel1].particle()->CC(), q[ohel1],g2[ihel2],mass); diag[4] = QQHVertex_->evaluate(mt,inters,intersb,hwave); // 6th diagram diag[5] = QQGVertex_->evaluate(mt,QBoff,intersb,g1[ihel1]); // 7th diagram diag[6] = QQGVertex_->evaluate(mt,qbar[ohel2],Qoff ,interv); // 8th diagram diag[7] = QQGVertex_->evaluate(mt,QBoff ,q[ohel1],interv); // colour flows flow[0]=diag[0]+diag[1]+diag[2]+(diag[6]+diag[7]); flow[1]=diag[3]+diag[4]+diag[5]-(diag[6]+diag[7]); // sums for(unsigned int ix=0;ix<8;++ix) sumdiag[ix] += norm(diag[ix]); for(unsigned int ix=0;ix<2;++ix) sumflow[ix] += norm(flow[ix]); // total output +=real(flow[0]*conj(flow[0])+flow[1]*conj(flow[1]) -0.25*flow[0]*conj(flow[1])); // store the me if needed if(iflow!=0) me_(2*ihel1,2*ihel2,ohel1,ohel2,0)=flow[iflow-1]; } } } } // select a colour flow flow_ = 1 + UseRandom::rnd2(sumflow[0],sumflow[1]); if(flow_==1) sumdiag[0]=sumdiag[1]=sumdiag[2]=0.; else sumdiag[3]=sumdiag[4]=sumdiag[5]=0.; // select a diagram from that flow double prob = UseRandom::rnd(); for(unsigned int ix=0;ix<8;++ix) { if(prob<=sumdiag[ix]) { diagram_=1+ix; break; } prob -= sumdiag[ix]; } // final part of colour and spin factors return output/48.; } double MEPP2QQHiggs::qqME(vector & q1, vector & q2, vector & q3, vector & q4, ScalarWaveFunction & hwave, unsigned int iflow) const { // scale Energy2 mt(scale()); Energy mass = q3[0].mass(); // matrix element to be stored if(iflow!=0) me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half, PDT::Spin0)); // calculate the matrix element double output(0.),sumdiag[2]={0.,0.}; Complex diag[2]; VectorWaveFunction interv; SpinorWaveFunction QBoff; SpinorBarWaveFunction Qoff; for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { interv = QQGVertex_->evaluate(mt,5,gluon_,q1[ihel1],q2[ihel2]); for(unsigned int ohel1=0;ohel1<2;++ohel1) { Qoff = QQHVertex_->evaluate(mt,3,q3[ohel1].particle()->CC(), q3[ohel1],hwave,mass); for(unsigned int ohel2=0;ohel2<2;++ohel2) { QBoff = QQHVertex_->evaluate(mt,3,q4[ohel2].particle()->CC(), q4[ohel2],hwave,mass); // 1st diagram diag[0] = QQGVertex_->evaluate(mt,q4[ohel2],Qoff,interv); // 2nd diagram diag[1] = QQGVertex_->evaluate(mt,QBoff,q3[ohel1],interv); // sum of diagrams for(unsigned int ix=0;ix<2;++ix) sumdiag[ix] += norm(diag[ix]); diag[0] += diag[1]; output += norm(diag[0]); if(iflow!=0) me_(ihel1,ihel2,ohel1,ohel2,0) = diag[0]; } } } } // only 1 colour flow flow_=1; // select a diagram diagram_ = 9+UseRandom::rnd2(sumdiag[0],sumdiag[1]); // final part of colour and spin factors return output/18.; } Selector MEPP2QQHiggs::colourGeometries(tcDiagPtr diag) const { // colour lines for gg -> Q Qbar H static const ColourLines cgg[10]= {ColourLines("1 4 5, -1 -2 3 , -3 -6 "), ColourLines("1 5 , -1 -2 -3 4, -4 -6 "), ColourLines("1 4 , -1 -2 3 , -3 -5 -6"), ColourLines("3 4 5, 1 2 -3 , -1 -6 "), ColourLines("4 5 , 1 2 3 -4, -1 -6"), ColourLines("3 4 , 1 2 -3 , -1 -5 -6"), ColourLines("1 3 4 5, -1 2, -2 -3 -6"), ColourLines("2 3 4 5, 1 -2, -1 -3 -6"), ColourLines("1 3 4, -1 2, -2 -3 -5 -6"), ColourLines("2 3 4, 1 -2, -1 -3 -5 -6")}; // colour lines for q qbar -> Q Qbar H static const ColourLines cqq[2]= {ColourLines("1 3 4 5, -2 -3 -6"), ColourLines("1 3 4 , -2 -3 -5 -6")}; // select the colour flow (as all ready picked just insert answer) Selector sel; switch(abs(diag->id())) { // gg -> q qbar subprocess case 1: case 2: case 3: case 4: case 5: case 6: sel.insert(1.0, &cgg[abs(diag->id())-1]); break; case 7: sel.insert(1.0, &cgg[5 + flow_]); break; case 8: sel.insert(1.0, &cgg[7 + flow_]); break; // q qbar -> q qbar subprocess case 9: case 10: sel.insert(1.0, &cqq[abs(diag->id())-9]); break; } return sel; } Selector MEPP2QQHiggs::diagrams(const DiagramVector & diags) const { // select the diagram, this is easy for us as we have already done it Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ) { if(diags[i]->id()==-int(diagram_)) sel.insert(1.0, i); else sel.insert(0., i); } return sel; } void MEPP2QQHiggs::constructVertex(tSubProPtr sub) { // extract the particles in the hard process ParticleVector hard; hard.push_back(sub->incoming().first); hard.push_back(sub->incoming().second); for(unsigned int ix=0;ix<3;++ix) hard.push_back(sub->outgoing()[ix]); // identify the process and calculate the matrix element if(hard[0]->id()<0) swap(hard[0],hard[1]); if(hard[2]->id()==ParticleID::h0) swap(hard[2],hard[4]); if(hard[3]->id()==ParticleID::h0) swap(hard[3],hard[4]); if(hard[2]->id()<0) swap(hard[2],hard[3]); if(hard[0]->id()==ParticleID::g) { vector g1,g2; vector q; vector qbar; // off-shell wavefunctions for the spin correlations VectorWaveFunction( g1,hard[0],incoming,false,true,true); VectorWaveFunction( g2,hard[1],incoming,false,true,true); SpinorBarWaveFunction(q ,hard[2],outgoing,true ,true); SpinorWaveFunction( qbar,hard[3],outgoing,true ,true); ScalarWaveFunction hwave( hard[4],outgoing,true); g1[1]=g1[2];g2[1]=g2[2]; ggME(g1,g2,q,qbar,hwave,flow_); } // q qbar -> Q Qbar Higgs else { vector q1,q4; vector q2,q3; // off-shell for spin correlations SpinorWaveFunction( q1,hard[0],incoming,false,true); SpinorBarWaveFunction(q2,hard[1],incoming,false,true); SpinorBarWaveFunction(q3,hard[2],outgoing,true ,true); SpinorWaveFunction( q4,hard[3],outgoing,true ,true); ScalarWaveFunction hwave( hard[4],outgoing,true); qqME(q1,q2,q3,q4,hwave,flow_); } // 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 ix=0;ix<5;++ix) hard[ix]->spinInfo()->productionVertex(hardvertex); } diff --git a/MatrixElement/Hadron/MEPP2WJet.cc b/MatrixElement/Hadron/MEPP2WJet.cc --- a/MatrixElement/Hadron/MEPP2WJet.cc +++ b/MatrixElement/Hadron/MEPP2WJet.cc @@ -1,842 +1,842 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the MEPP2WJet class. // #include "MEPP2WJet.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/MatrixElement/Tree2toNDiagram.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Handlers/StandardXComb.h" #include "ThePEG/Utilities/SimplePhaseSpace.h" #include "ThePEG/Cuts/Cuts.h" #include "Herwig/MatrixElement/HardVertex.h" using namespace Herwig; MEPP2WJet::MEPP2WJet() : _process(0), _maxflavour(5), _plusminus(0), _wdec(0), _widthopt(1) {} void MEPP2WJet::doinit() { HwMEBase::doinit(); _wplus = getParticleData(ThePEG::ParticleID::Wplus ); _wminus = getParticleData(ThePEG::ParticleID::Wminus); // cast the SM pointer to the Herwig SM pointer ThePEG::Ptr::transient_const_pointer hwsm=ThePEG::dynamic_ptr_cast< ThePEG::Ptr ::transient_const_pointer>(standardModel()); // do the initialisation if(!hwsm) throw InitException() << "Must be Herwig::StandardModel in MEPP2WJet::doinit()" << Exception::runerror; // set the vertex pointers _theFFWVertex = hwsm->vertexFFW(); _theQQGVertex = hwsm->vertexFFG(); } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigMEPP2WJet("Herwig::MEPP2WJet", "HwMEHadron.so"); void MEPP2WJet::Init() { static ClassDocumentation documentation ("The MEPP2WJet class implements the matrix element for W + jet production"); static Parameter interfaceMaxFlavour ( "MaxFlavour", "The heaviest incoming quark flavour this matrix element is allowed to handle " "(if applicable).", &MEPP2WJet::_maxflavour, 5, 0, 8, false, false, true); static Switch interfaceProcess ("Process", "Which subprocesses to include", &MEPP2WJet::_process, 0, false, false); static SwitchOption interfaceProcessAll (interfaceProcess, "All", "Include all subprocesses", 0); static SwitchOption interfaceProcessqqbar (interfaceProcess, "qqbar", "Only include q qbar -> W g process", 1); static SwitchOption interfaceProcessqg (interfaceProcess, "qg", "Only include the q g -> W q process", 2); static SwitchOption interfaceProcessqbarg (interfaceProcess, "qbarg", "Only include the qbar g -> W qbar process", 3); static Switch interfacePlusMinus ("Wcharge", "Which intermediate W bosons to include", &MEPP2WJet::_plusminus, 0, false, false); static SwitchOption interfacePlusMinusAll (interfacePlusMinus, "Both", "Include W+ and W-", 0); static SwitchOption interfacePlusMinusPlus (interfacePlusMinus, "Plus", "Only include W+", 1); static SwitchOption interfacePlusMinusMinus (interfacePlusMinus, "Minus", "Only include W-", 2); static Switch interfaceWDecay ("WDecay", "Which processes to include", &MEPP2WJet::_wdec, 0, false, false); static SwitchOption interfaceWDecayAll (interfaceWDecay, "All", "Include all SM fermions as outgoing particles", 0); static SwitchOption interfaceWDecayQuarks (interfaceWDecay, "Quarks", "Only include outgoing quarks", 1); static SwitchOption interfaceWDecayLeptons (interfaceWDecay, "Leptons", "All include outgoing leptons", 2); static SwitchOption interfaceWDecayElectron (interfaceWDecay, "Electron", "Only include outgoing e nu_e", 3); static SwitchOption interfaceWDecayMuon (interfaceWDecay, "Muon", "Only include outgoing mu nu_mu", 4); static SwitchOption interfaceWDecayTau (interfaceWDecay, "Tau", "Only include outgoing tauu nu_tau", 5); static SwitchOption interfaceWDecayUpDown (interfaceWDecay, "UpDown", "Only include outgoing u dbar/ d ubar", 6); static SwitchOption interfaceWDecayUpStrange (interfaceWDecay, "UpStrange", "Only include outgoing u sbar/ s ubar", 7); static SwitchOption interfaceWDecayUpBottom (interfaceWDecay, "UpBottom", "Only include outgoing u bbar/ b ubar", 8); static SwitchOption interfaceWDecayCharmDown (interfaceWDecay, "CharmDown", "Only include outgoing c dbar/ d cbar", 9); static SwitchOption interfaceWDecayCharmStrange (interfaceWDecay, "CharmStrange", "Only include outgoing c sbar/ s cbar", 10); static SwitchOption interfaceWDecayCharmBottom (interfaceWDecay, "CharmBottom", "Only include outgoing c bbar/ b cbar", 11); static Switch interfaceWidthOption ("WidthOption", "The option for handling the width of the off-shell W boson", &MEPP2WJet::_widthopt, 1, false, false); static SwitchOption interfaceWidthOptionFixedDenominator (interfaceWidthOption, "FixedDenominator", "Use a fixed with in the W propagator but the full matrix element" " in the numerator", 1); static SwitchOption interfaceWidthOptionAllRunning (interfaceWidthOption, "AllRunning", "Use a running width in the W propagator and the full matrix " "element in the numerator", 2); } void MEPP2WJet::getDiagrams() const { // which intgermediates to include bool wplus = _plusminus==0 || _plusminus==1; bool wminus = _plusminus==0 || _plusminus==2; // possible incoming and outgoing particles typedef std::vector > Pairvector; // possible parents Pairvector parentpair; parentpair.reserve(6); // don't even think of putting 'break' in here! switch(_maxflavour) { case 5: parentpair.push_back(make_pair(ParticleID::b, ParticleID::cbar)); parentpair.push_back(make_pair(ParticleID::b, ParticleID::ubar)); [[fallthrough]]; case 4: parentpair.push_back(make_pair(ParticleID::s, ParticleID::cbar)); parentpair.push_back(make_pair(ParticleID::d, ParticleID::cbar)); [[fallthrough]]; case 3: parentpair.push_back(make_pair(ParticleID::s, ParticleID::ubar)); [[fallthrough]]; case 2: parentpair.push_back(make_pair(ParticleID::d, ParticleID::ubar)); [[fallthrough]]; default: ; } // possible children Pairvector childpair; childpair.reserve(9); childpair.push_back(make_pair(ParticleID::eminus, ParticleID::nu_ebar)); childpair.push_back(make_pair(ParticleID::muminus, ParticleID::nu_mubar)); childpair.push_back(make_pair(ParticleID::tauminus, ParticleID::nu_taubar)); childpair.push_back(make_pair(ParticleID::d, ParticleID::ubar)); childpair.push_back(make_pair(ParticleID::s, ParticleID::ubar)); childpair.push_back(make_pair(ParticleID::b, ParticleID::ubar)); childpair.push_back(make_pair(ParticleID::d, ParticleID::cbar)); childpair.push_back(make_pair(ParticleID::s, ParticleID::cbar)); childpair.push_back(make_pair(ParticleID::b, ParticleID::cbar)); // gluon for diagrams tcPDPtr g = getParticleData(ParticleID::g); // loop over the children bool lepton,quark; Pairvector::const_iterator child = childpair.begin(); for (; child != childpair.end(); ++child) { // allowed leptonic decay lepton=child->first>10&& (_wdec==0||_wdec==2|| (abs(child->first)-5)/2==int(_wdec)); // allowed quark decay quark =abs(child->second)<10&& (_wdec==0||_wdec==1|| (abs(child->second)==2&&(abs(child->first)+11)/2==int(_wdec))|| (abs(child->second)==4&&(abs(child->first)+17)/2==int(_wdec))); // if decay not allowed skip if(!(quark||lepton)) continue; // decay products tcPDPtr lNeg1 = getParticleData(child->first); tcPDPtr lNeg2 = getParticleData(child->second); tcPDPtr lPos1 = lNeg2->CC(); tcPDPtr lPos2 = lNeg1->CC(); Pairvector::const_iterator parent = parentpair.begin(); for (; parent != parentpair.end(); ++parent) { // parents tcPDPtr qNeg1 = getParticleData(parent->first); tcPDPtr qNeg2 = getParticleData(parent->second); tcPDPtr qPos1 = qNeg2->CC(); tcPDPtr qPos2 = qNeg1->CC(); // diagrams // q qbar annhilation processes if(_process==0||_process==1) { // q qbar -> W- g if(wminus) { add(new_ptr((Tree2toNDiagram(3), qNeg1, qNeg2, qNeg2, 1, _wminus, 2, g, 4, lNeg1, 4, lNeg2, -1))); add(new_ptr((Tree2toNDiagram(3), qNeg1, qNeg1, qNeg2, 2, _wminus, 1, g, 4, lNeg1, 4, lNeg2, -2))); } // q qbar -> W+ g if(wplus) { add(new_ptr((Tree2toNDiagram(3), qPos1, qPos2, qPos2, 1, _wplus, 2, g, 4, lPos1, 4, lPos2, -3))); add(new_ptr((Tree2toNDiagram(3), qPos1, qPos1, qPos2, 2, _wplus, 1, g, 4, lPos1, 4, lPos2, -4))); } } // q g compton if(_process==0||_process==2) { if(wminus) { add(new_ptr((Tree2toNDiagram(3), qNeg1, qPos1, g , 1, _wminus, 2, qPos1, 4, lNeg1, 4, lNeg2, -5))); add(new_ptr((Tree2toNDiagram(2), qNeg1, g, 1, qNeg1, 3, _wminus, 3, qPos1, 4, lNeg1, 4, lNeg2, -6))); } if(wplus) { add(new_ptr((Tree2toNDiagram(3), qPos1, qNeg1, g, 1, _wplus, 2, qNeg1, 4, lPos1, 4, lPos2, -7))); add(new_ptr((Tree2toNDiagram(2), qPos1, g, 1, qNeg1, 3, _wplus, 3, qNeg1, 4, lPos1, 4, lPos2, -8))); } } // qbar g compton if(_process==0||_process==3) { if(wminus) { add(new_ptr((Tree2toNDiagram(3), qNeg2, qPos2, g, 1, _wminus, 2, qPos2, 4, lNeg1, 4, lNeg2, -9 ))); add(new_ptr((Tree2toNDiagram(2), qNeg2, g, 1, qNeg2, 3, _wminus, 3, qPos2, 4, lNeg1, 4, lNeg2, -10))); } if(wplus) { add(new_ptr((Tree2toNDiagram(3), qPos2, qNeg2, g, 1, _wplus, 2, qNeg2, 4, lPos1, 4, lPos2, -11))); add(new_ptr((Tree2toNDiagram(2), qPos2, g, 1, qPos2, 3, _wplus, 3, qNeg2, 4, lPos1, 4, lPos2, -12))); } } } } } unsigned int MEPP2WJet::orderInAlphaS() const { return 1; } unsigned int MEPP2WJet::orderInAlphaEW() const { return 2; } void MEPP2WJet::persistentOutput(PersistentOStream & os) const { os << _theFFWVertex << _theQQGVertex << _wplus << _widthopt << _wminus << _process << _maxflavour << _plusminus << _wdec; } void MEPP2WJet::persistentInput(PersistentIStream & is, int) { is >> _theFFWVertex >> _theQQGVertex >> _wplus >> _widthopt >> _wminus >> _process >> _maxflavour >> _plusminus >> _wdec; } int MEPP2WJet::nDim() const { return 5; } Selector MEPP2WJet::colourGeometries(tcDiagPtr diag) const { // colour lines for q qbar -> W g static const ColourLines cqqbar[4]={ColourLines("1 -2 5,-3 -5"), ColourLines("1 5, -5 2 -3"), ColourLines("1 -2 5,-3 -5,6 -7"), ColourLines("1 5, -5 2 -3,6 -7")}; // colour lines for q g -> W q static const ColourLines cqg [4]={ColourLines("1 2 -3,3 5"), ColourLines("1 -2,2 3 5"), ColourLines("1 2 -3,3 5,6 -7"), ColourLines("1 -2,2 3 5,6 -7")}; // colour lines for qbar q -> W qbar static const ColourLines cqbarg[4]={ColourLines("-1 -2 3,-3 -5"), ColourLines("-1 2,-2 -3 -5"), ColourLines("-1 -2 3,-3 -5,6 -7"), ColourLines("-1 2,-2 -3 -5,6 -7")}; // select the correct line unsigned int icol = mePartonData()[3]->coloured() ? 2 : 0; Selector sel; switch(abs(diag->id())) { case 1 : case 3: sel.insert(1.0, &cqqbar[icol]); break; case 2 : case 4: sel.insert(1.0, &cqqbar[icol+1]); break; case 5 : case 7: sel.insert(1.0, &cqg[icol]); break; case 6 : case 8: sel.insert(1.0, &cqg[icol+1]); break; case 9 : case 11: sel.insert(1.0, &cqbarg[icol]); break; case 10 : case 12: sel.insert(1.0, &cqbarg[icol+1]); break; } return sel; } Selector MEPP2WJet::diagrams(const DiagramVector & diags) const { Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ) { int id=abs(diags[i]->id()); if (id <= 2 ) sel.insert(meInfo()[id- 1],i); else if(id <= 4 ) sel.insert(meInfo()[id- 3],i); else if(id <= 6 ) sel.insert(meInfo()[id- 5],i); else if(id <= 8 ) sel.insert(meInfo()[id- 7],i); else if(id <= 10) sel.insert(meInfo()[id- 9],i); else if(id <= 12) sel.insert(meInfo()[id-11],i); } return sel; } Energy2 MEPP2WJet::scale() const { return _scale; } CrossSection MEPP2WJet::dSigHatDR() const { return me2()*jacobian()/(16.0*sqr(Constants::pi)*sHat())*sqr(hbarc); } bool MEPP2WJet::generateKinematics(const double * r) { // initialize jacobian jacobian(1.); // cms energy Energy ecm=sqrt(sHat()); // find the right W pointer tcPDPtr wdata = mePartonData()[3]->iCharge()+mePartonData()[4]->iCharge() > 0 ? _wplus :_wminus; // first generate the mass of the off-shell gauge boson // minimum mass of the tcPDVector ptemp; ptemp.push_back(mePartonData()[3]); ptemp.push_back(mePartonData()[4]); Energy2 minMass2 = max(lastCuts().minSij(mePartonData()[3],mePartonData()[4]), lastCuts().minS(ptemp)); // minimum pt of the jet Energy ptmin = max(lastCuts().minKT(mePartonData()[2]), lastCuts().minKT(wdata)); // maximum mass of the gauge boson so pt is possible Energy2 maxMass2 = min(ecm*(ecm-2.*ptmin),lastCuts().maxS(ptemp)); if(maxMass2<=ZERO||minMass2massMin())); maxMass2 = min(maxMass2,sqr(wdata->massMax())); // return if not kinematically possible if(minMass2>maxMass2) return false; // generation of the mass Energy M(wdata->mass()),Gamma(wdata->width()); Energy2 M2(sqr(M)),MG(M*Gamma); double rhomin = atan2((minMass2-M2),MG); double rhomax = atan2((maxMass2-M2),MG); _mw2=M2+MG*tan(rhomin+r[1]*(rhomax-rhomin)); Energy mw=sqrt(_mw2); // jacobian jacobian(jacobian()*(sqr(_mw2-M2)+sqr(MG))/MG*(rhomax-rhomin)/sHat()); // set the masses of the outgoing particles in the 2-2 scattering meMomenta()[2].setMass(ZERO); Lorentz5Momentum pw(mw); // generate the polar angle of the hard scattering double ctmin(-1.0), ctmax(1.0); Energy q(ZERO); try { q = SimplePhaseSpace::getMagnitude(sHat(), meMomenta()[2].mass(),mw); } - catch ( ImpossibleKinematics ) { + catch ( ImpossibleKinematics & e ) { return false; } Energy2 pq = sqrt(sHat())*q; 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)); } if ( ctmin >= ctmax ) return false; double cth = getCosTheta(ctmin, ctmax, r[0]); // momenta of particle in hard scattering Energy pt = q*sqrt(1.0-sqr(cth)); double phi=2.0*Constants::pi*r[2]; meMomenta()[2].setVect(Momentum3( pt*sin(phi), pt*cos(phi), q*cth)); pw.setVect( Momentum3(-pt*sin(phi),-pt*cos(phi),-q*cth)); meMomenta()[2].rescaleEnergy(); pw.rescaleEnergy(); // set the scale _scale = _mw2+sqr(pt); // generate the momenta of the W decay products meMomenta()[3].setMass(mePartonData()[3]->mass()); meMomenta()[4].setMass(mePartonData()[4]->mass()); Energy q2 = ZERO; try { q2 = SimplePhaseSpace::getMagnitude(_mw2, meMomenta()[3].mass(), meMomenta()[4].mass()); - } catch ( ImpossibleKinematics ) { + } catch ( ImpossibleKinematics & e ) { return false; } double cth2 =-1.+2.*r[3]; double phi2=Constants::twopi*r[4]; Energy pt2 =q2*sqrt(1.-sqr(cth2)); Lorentz5Momentum pl[2]={Lorentz5Momentum( pt2*cos(phi2), pt2*sin(phi2), q2*cth2,ZERO, meMomenta()[3].mass()), Lorentz5Momentum(-pt2*cos(phi2),-pt2*sin(phi2),-q2*cth2,ZERO, meMomenta()[4].mass())}; pl[0].rescaleEnergy(); pl[1].rescaleEnergy(); Boost boostv(pw.boostVector()); pl[0].boost(boostv); pl[1].boost(boostv); meMomenta()[3] = pl[0]; meMomenta()[4] = pl[1]; // check passes all the cuts vector out(3); out[0] = meMomenta()[2]; out[1] = meMomenta()[3]; out[2] = meMomenta()[4]; tcPDVector tout(3); tout[0] = mePartonData()[2]; tout[1] = mePartonData()[3]; tout[2] = mePartonData()[4]; if ( !lastCuts().passCuts(tout, out, mePartonData()[0], mePartonData()[1]) ) return false; // jacobian jacobian((pq/sHat())*Constants::pi*jacobian()/8./sqr(Constants::pi)*q2/mw); return true; } double MEPP2WJet::me2() const { InvEnergy2 output(ZERO); // construct spinors for the leptons (always the same) vector lm; vector lp; SpinorBarWaveFunction lmout(meMomenta()[3],mePartonData()[3],outgoing); SpinorWaveFunction lpout(meMomenta()[4],mePartonData()[4],outgoing); for(unsigned int ix=0;ix<2;++ix) { lmout.reset(ix);lm.push_back(lmout); lpout.reset(ix);lp.push_back(lpout); } // q g to q W if(mePartonData()[0]->id()<=6&&mePartonData()[0]->id()>0&& mePartonData()[1]->id()==ParticleID::g) { // polarization states for the particles vector fin; vector gin; vector fout; SpinorWaveFunction qin (meMomenta()[0],mePartonData()[0],incoming); VectorWaveFunction glin(meMomenta()[1],mePartonData()[1],incoming); SpinorBarWaveFunction qout(meMomenta()[2],mePartonData()[2],outgoing); for(unsigned int ix=0;ix<2;++ix) { qin.reset(ix) ; fin.push_back(qin); glin.reset(2*ix); gin.push_back(glin); qout.reset(ix);fout.push_back(qout); } output=qgME(fin,gin,fout,lm,lp); } // qbar g to qbar W else if(mePartonData()[0]->id()>=-6&&mePartonData()[0]->id()<0&& mePartonData()[1]->id()==ParticleID::g) { vector ain; vector gin; vector aout; SpinorBarWaveFunction qbin (meMomenta()[0],mePartonData()[0],incoming); VectorWaveFunction glin (meMomenta()[1],mePartonData()[1],incoming); SpinorWaveFunction qbout(meMomenta()[2],mePartonData()[2],outgoing); for(unsigned int ix=0;ix<2;++ix) { qbin.reset(ix) ; ain.push_back(qbin); glin.reset(2*ix) ; gin.push_back(glin); qbout.reset(ix);aout.push_back(qbout); } output=qbargME(ain,gin,aout,lm,lp); } // q qbar to g W else { vector fin; vector ain; vector gout; SpinorWaveFunction qin (meMomenta()[0],mePartonData()[0],incoming); SpinorBarWaveFunction qbin(meMomenta()[1],mePartonData()[1],incoming); VectorWaveFunction glout(meMomenta()[2],mePartonData()[2],outgoing); 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); } output=qqbarME(fin,ain,gout,lm,lp); } return output*sHat(); } InvEnergy2 MEPP2WJet::qqbarME(vector & fin, vector & ain, vector & gout, vector & lm, vector & lp, bool calc) const { // if calculation spin corrections construct the me if(calc) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1,PDT::Spin1Half, PDT::Spin1Half)); // some integers unsigned int ihel1,ihel2,ohel1,ohel2,ohel3; // find the right W pointer tcPDPtr wdata = mePartonData()[3]->iCharge()+mePartonData()[4]->iCharge() > 0 ? _wplus :_wminus; // compute the W current for speed VectorWaveFunction bcurr[2][2]; for(ohel2=0;ohel2<2;++ohel2) { for(ohel3=0;ohel3<2;++ohel3) { bcurr[ohel2][ohel3] = _theFFWVertex->evaluate(_mw2,_widthopt,wdata, lp[ohel3],lm[ohel2]); } } double me[3]={0.,0.,0.}; Complex diag[2]; SpinorWaveFunction inters; SpinorBarWaveFunction interb; for(ihel1=0;ihel1<2;++ihel1) { for(ihel2=0;ihel2<2;++ihel2) { for(ohel1=0;ohel1<2;++ohel1) { // intermediates for the diagrams inters=_theQQGVertex->evaluate(_scale,5,mePartonData()[0], fin[ihel1],gout[ohel1]); interb=_theQQGVertex->evaluate(_scale,5,mePartonData()[1], ain[ihel2],gout[ohel1]); for(ohel2=0;ohel2<2;++ohel2) { for(ohel3=0;ohel3<2;++ohel3) { diag[0] = _theFFWVertex->evaluate(_mw2,fin[ihel1],interb, bcurr[ohel2][ohel3]); diag[1] = _theFFWVertex->evaluate(_mw2,inters,ain[ihel2], bcurr[ohel2][ohel3]); // diagram contributions me[1] += norm(diag[0]); me[2] += norm(diag[1]); // total diag[0] += diag[1]; me[0] += norm(diag[0]); if(calc) _me(ihel1,ihel2,2*ohel1,ohel2,ohel3) = diag[0]; } } } } } // results // initial state spin and colour average double colspin=1./9./4.; // and C_F N_c from matrix element colspin *= 4.; // colour factor for the W decay if(mePartonData()[3]->coloured()) colspin*=3.; DVector save; for(unsigned int ix=0;ix<3;++ix) { me[ix]*=colspin; if(ix>0) save.push_back(me[ix]); } meInfo(save); return me[0] * UnitRemoval::InvE2; } InvEnergy2 MEPP2WJet::qgME(vector & fin, vector & gin, vector & fout, vector & lm, vector & lp, bool calc) const { // if calculation spin corrections construct the me if(calc) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1, PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half)); // find the right W pointer tcPDPtr wdata = mePartonData()[3]->iCharge()+mePartonData()[4]->iCharge() > 0 ? _wplus :_wminus; // some integers unsigned int ihel1,ihel2,ohel1,ohel2,ohel3; // compute the leptonic W current for speed VectorWaveFunction bcurr[2][2]; for(ohel2=0;ohel2<2;++ohel2) { for(ohel3=0;ohel3<2;++ohel3) { bcurr[ohel2][ohel3] = _theFFWVertex->evaluate(_mw2,_widthopt,wdata, lp[ohel3],lm[ohel2]); } } // compute the matrix elements double me[3]={0.,0.,0.}; Complex diag[2]; SpinorWaveFunction inters; SpinorBarWaveFunction interb; for(ihel1=0;ihel1<2;++ihel1) { for(ihel2=0;ihel2<2;++ihel2) { for(ohel1=0;ohel1<2;++ohel1) { // intermediates for the diagrams interb=_theQQGVertex->evaluate(_scale,5,mePartonData()[2]->CC(), fout[ohel1],gin[ihel2]); inters=_theQQGVertex->evaluate(_scale,5,mePartonData()[0], fin[ihel1],gin[ihel2]); for(ohel2=0;ohel2<2;++ohel2) { for(ohel3=0;ohel3<2;++ohel3) { diag[0]=_theFFWVertex->evaluate(_mw2,fin[ihel1],interb, bcurr[ohel2][ohel3]); diag[1]=_theFFWVertex->evaluate(_mw2,inters,fout[ohel1], bcurr[ohel2][ohel3]); // diagram contributions me[1] += norm(diag[0]); me[2] += norm(diag[1]); // total diag[0] += diag[1]; me[0] += norm(diag[0]); if(calc) _me(ihel1,2*ihel2,ohel1,ohel2,ohel3) = diag[0]; } } } } } // results // initial state spin and colour average double colspin=1./24./4.; // and C_F N_c from matrix element colspin *=4.; // colour factor for the W decay if(mePartonData()[3]->coloured()) colspin*=3.; DVector save; for(unsigned int ix=0;ix<3;++ix) { me[ix]*=colspin; if(ix>0) save.push_back(me[ix]); } meInfo(save); return me[0] * UnitRemoval::InvE2; } InvEnergy2 MEPP2WJet::qbargME(vector & fin, vector & gin, vector & fout, vector & lm, vector & lp, bool calc) const { // if calculation spin corrections construct the me if(calc) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1, PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half)); // find the right W pointer tcPDPtr wdata = mePartonData()[3]->iCharge()+mePartonData()[4]->iCharge() > 0 ? _wplus :_wminus; // some integers unsigned int ihel1,ihel2,ohel1,ohel2,ohel3; // compute the leptonic W current for speed VectorWaveFunction bcurr[2][2]; for(ohel2=0;ohel2<2;++ohel2) { for(ohel3=0;ohel3<2;++ohel3) { bcurr[ohel2][ohel3] = _theFFWVertex->evaluate(_mw2,_widthopt,wdata, lp[ohel3],lm[ohel2]); } } // compute the matrix elements double me[3]={0.,0.,0.}; Complex diag[2]; SpinorWaveFunction inters; SpinorBarWaveFunction interb; for(ihel1=0;ihel1<2;++ihel1) { for(ihel2=0;ihel2<2;++ihel2) { for(ohel1=0;ohel1<2;++ohel1) { // intermediates for the diagrams inters=_theQQGVertex->evaluate(_scale,5,mePartonData()[2]->CC(), fout[ohel1],gin[ihel2]); interb=_theQQGVertex->evaluate(_scale,5,mePartonData()[0], fin[ihel1],gin[ihel2]); for(ohel2=0;ohel2<2;++ohel2) { for(ohel3=0;ohel3<2;++ohel3) { diag[0]= _theFFWVertex->evaluate(_mw2,inters,fin[ihel1], bcurr[ohel2][ohel3]); diag[1]= _theFFWVertex->evaluate(_mw2,fout[ohel1],interb, bcurr[ohel2][ohel3]); // diagram contributions me[1] += norm(diag[0]); me[2] += norm(diag[1]); // total diag[0] += diag[1]; me[0] += norm(diag[0]); if(calc) _me(ihel1,2*ihel2,ohel1,ohel2,ohel3) = diag[0]; } } } } } // results // initial state spin and colour average double colspin=1./24./4.; // and C_F N_c from matrix element colspin *= 4.; // colour factor for the W decay if(mePartonData()[3]->coloured()) colspin*=3.; DVector save; for(unsigned int ix=0;ix<3;++ix) { me[ix]*=colspin; if(ix>0) save.push_back(me[ix]); } meInfo(save); return me[0] * UnitRemoval::InvE2; } void MEPP2WJet::constructVertex(tSubProPtr sub) { // extract the particles in the hard process ParticleVector hard(5); // incoming hard[0]=sub->incoming().first; hard[1]=sub->incoming().second; if((hard[0]->id()<0&&hard[1]->id()<=6)|| hard[0]->id()==ParticleID::g) swap(hard[0],hard[1]); // outgoing for(unsigned int ix=0;ix<3;++ix) { unsigned int iloc; PPtr mother=sub->outgoing()[ix]->parents()[0]; if(mother&&abs(mother->id())==ParticleID::Wplus) { if(sub->outgoing()[ix]->id()>0) iloc=3; else iloc=4; } else iloc=2; hard[iloc]=sub->outgoing()[ix]; } // wavefunctions for the W decay products vector lm; vector lp; SpinorBarWaveFunction(lm,hard[3],outgoing,true,true); SpinorWaveFunction (lp,hard[4],outgoing,true,true); // identify hard process and calculate matrix element // q g to q W if(hard[0]->id()<=6&&hard[0]->id()>0&&hard[1]->id()==ParticleID::g) { vector fin; vector gin; vector fout; SpinorWaveFunction (fin ,hard[0],incoming,false,true); VectorWaveFunction (gin ,hard[1],incoming,false,true,true); SpinorBarWaveFunction (fout,hard[2],outgoing,true ,true); gin[1]=gin[2]; qgME(fin,gin,fout,lm,lp,true); } // qbar g to qbar W else if(hard[0]->id()>=-6&&hard[0]->id()<0&&hard[1]->id()==ParticleID::g) { vector ain; vector gin; vector aout; SpinorBarWaveFunction(ain ,hard[0],incoming,false,true); VectorWaveFunction (gin ,hard[1],incoming,false,true,true); SpinorWaveFunction (aout,hard[2],outgoing,true ,true); gin[1]=gin[2]; qbargME(ain,gin,aout,lm,lp,true); } // q qbar to g W else { vector fin; vector ain; vector gout; SpinorWaveFunction (fin ,hard[0],incoming,false,true); SpinorBarWaveFunction(ain ,hard[1],incoming,false,true); VectorWaveFunction (gout,hard[2],outgoing,true ,true,true); gout[1]=gout[2]; qqbarME(fin,ain,gout,lm,lp,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 ix=0;ix<5;++ix) (hard[ix]->spinInfo())->productionVertex(hardvertex); } diff --git a/MatrixElement/Hadron/MEPP2ZJet.cc b/MatrixElement/Hadron/MEPP2ZJet.cc --- a/MatrixElement/Hadron/MEPP2ZJet.cc +++ b/MatrixElement/Hadron/MEPP2ZJet.cc @@ -1,861 +1,861 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the MEPP2ZJet class. // #include "MEPP2ZJet.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.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 "Herwig/Models/StandardModel/StandardModel.h" #include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Handlers/StandardXComb.h" #include "ThePEG/Utilities/SimplePhaseSpace.h" #include "ThePEG/Cuts/Cuts.h" #include "Herwig/MatrixElement/HardVertex.h" using namespace Herwig; MEPP2ZJet::MEPP2ZJet() : _process(0), _maxflavour(5), _zdec(0), _gammaZ(0), _widthopt(1), _pprob(0.5) {} void MEPP2ZJet::doinit() { HwMEBase::doinit(); _z0 = getParticleData(ThePEG::ParticleID::Z0 ); _gamma = getParticleData(ThePEG::ParticleID::gamma); // cast the SM pointer to the Herwig SM pointer ThePEG::Ptr::transient_const_pointer hwsm=ThePEG::dynamic_ptr_cast< ThePEG::Ptr ::transient_const_pointer>(standardModel()); // do the initialisation if(!hwsm) throw InitException() << "Must be Herwig::StandardModel in MEPP2ZJet::doinit()" << Exception::runerror; // set the vertex pointers _theFFZVertex = hwsm->vertexFFZ(); _theFFPVertex = hwsm->vertexFFP(); _theQQGVertex = hwsm->vertexFFG(); } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigMEPP2ZJet("Herwig::MEPP2ZJet", "HwMEHadron.so"); void MEPP2ZJet::Init() { static ClassDocumentation documentation ("The MEPP2ZJet class implements the matrix element for Z/gamma+ jet production"); static Parameter interfaceMaxFlavour ( "MaxFlavour", "The heaviest incoming quark flavour this matrix element is allowed to handle " "(if applicable).", &MEPP2ZJet::_maxflavour, 5, 0, 8, false, false, true); static Switch interfaceZDecay ("ZDecay", "Which process to included", &MEPP2ZJet::_zdec, 0, false, false); static SwitchOption interfaceZDecayAll (interfaceZDecay, "All", "Include all SM fermions as outgoing particles", 0); static SwitchOption interfaceZDecayQuarks (interfaceZDecay, "Quarks", "All include the quarks as outgoing particles", 1); static SwitchOption interfaceZDecayLeptons (interfaceZDecay, "Leptons", "Only include the leptons as outgoing particles", 2); static SwitchOption interfaceZDecayChargedLeptons (interfaceZDecay, "ChargedLeptons", "Only include the charged leptons as outgoing particles", 3); static SwitchOption interfaceZDecayNeutrinos (interfaceZDecay, "Neutrinos", "Only include the neutrinos as outgoing particles", 4); static SwitchOption interfaceZDecayElectron (interfaceZDecay, "Electron", "Only include e+e- as outgoing particles", 5); static SwitchOption interfaceZDecayMuon (interfaceZDecay, "Muon", "Only include mu+mu- as outgoing particles", 6); static SwitchOption interfaceZDecayTau (interfaceZDecay, "Tau", "Only include tau+tau- as outgoing particles", 7); static SwitchOption interfaceZDecayNu_e (interfaceZDecay, "Nu_e", "Only include nu_e ne_ebar as outgoing particles", 8); static SwitchOption interfaceZDecaynu_mu (interfaceZDecay, "Nu_mu", "Only include nu_mu nu_mubar as outgoing particles", 9); static SwitchOption interfaceZDecaynu_tau (interfaceZDecay, "Nu_tau", "Only include nu_tau nu_taubar as outgoing particles", 10); static SwitchOption interfaceZDecayDown (interfaceZDecay, "Down", "Only include d dbar as outgoing particles", 11); static SwitchOption interfaceZDecayUp (interfaceZDecay, "Up", "Only include u ubar as outgoing particles", 12); static SwitchOption interfaceZDecayStrange (interfaceZDecay, "Strange", "Only include s sbar as outgoing particles", 13); static SwitchOption interfaceZDecayCharm (interfaceZDecay, "Charm", "Only include c cbar as outgoing particles", 14); static SwitchOption interfaceZDecayBottom (interfaceZDecay, "Bottom", "Only include b bbar as outgoing particles", 15); static SwitchOption interfaceZDecayTop (interfaceZDecay, "Top", "Only include t tbar as outgoing particles", 16); static Switch interfaceProcess ("Process", "Which subprocesses to include", &MEPP2ZJet::_process, 0, false, false); static SwitchOption interfaceProcessAll (interfaceProcess, "All", "Include all subprocesses", 0); static SwitchOption interfaceProcessqqbar (interfaceProcess, "qqbar", "Only include q qbar -> Z/gamma g process", 1); static SwitchOption interfaceProcessqg (interfaceProcess, "qg", "Only include the q g -> Z/gamma q process", 2); static SwitchOption interfaceProcessqbarg (interfaceProcess, "qbarg", "Only include the qbar g -> Z/gamma qbar process", 3); static Parameter interfacePhotonProbablity ("PhotonProbablity", "Probability for using the \\f$1/s^2\\f$ piece for the" " generation of the gauge boson mass", &MEPP2ZJet::_pprob, 0.5, 0.0, 1.0, false, false, Interface::limited); static Switch interfaceGammaZ ("GammaZ", "Which terms to include", &MEPP2ZJet::_gammaZ, 0, false, false); static SwitchOption interfaceGammaZAll (interfaceGammaZ, "All", "Include both gamma and Z terms", 0); static SwitchOption interfaceGammaZGamma (interfaceGammaZ, "Gamma", "Only include the photon", 1); static SwitchOption interfaceGammaZZ (interfaceGammaZ, "Z", "Only include the Z", 2); static Switch interfaceWidthOption ("WidthOption", "The option for handling the width of the off-shell W boson", &MEPP2ZJet::_widthopt, 1, false, false); static SwitchOption interfaceWidthOptionFixedDenominator (interfaceWidthOption, "FixedDenominator", "Use a fxied with in the W propagator but the full matrix element" " in the numerator", 1); static SwitchOption interfaceWidthOptionAllRunning (interfaceWidthOption, "AllRunning", "Use a running width in the W propagator and the full matrix " "element in the numerator", 2); } void MEPP2ZJet::getDiagrams() const { // which intermediates to include bool gamma = _gammaZ==0 || _gammaZ==1; bool Z0 = _gammaZ==0 || _gammaZ==2; // pointer for gluon tcPDPtr g = getParticleData(ParticleID::g); bool quark,lepton; for ( int ix=1; ix<17; ++ix ) { // increment counter to switch between quarks and leptons if(ix==7) ix+=4; // is it a valid quark process quark=ix<=6&&(_zdec==0||_zdec==1||_zdec-10==ix); // is it a valid lepton process lepton=ix>=11&&ix<=16&& (_zdec==0||_zdec==2||(_zdec==3&&ix%2==1)|| (_zdec==4&&ix%2==0)||(ix%2==0&&(ix-10)/2==_zdec-7)|| (ix%2==1&&(ix-9)/2==_zdec-4)); // if not a validf process continue if(!(quark||lepton)) continue; // pointer for Z decay products tcPDPtr lm = getParticleData(ix); tcPDPtr lp = lm->CC(); for (int i = 1; i <= _maxflavour; ++i ) { tcPDPtr q = getParticleData(i); tcPDPtr qb = q->CC(); // q qbar -> Z g -> l+l- g if(_process==0||_process==1) { if(gamma) add(new_ptr((Tree2toNDiagram(3), q, q, qb, 1, _gamma, 2, g, 4, lm, 4, lp, -1))); if(Z0) add(new_ptr((Tree2toNDiagram(3), q, q, qb, 1, _z0, 2, g, 4, lm, 4, lp, -2))); if(gamma) add(new_ptr((Tree2toNDiagram(3), q, q, qb, 2, _gamma, 1, g, 4, lm, 4, lp, -3))); if(Z0) add(new_ptr((Tree2toNDiagram(3), q, q, qb, 2, _z0, 1, g, 4, lm, 4, lp, -4))); } // q g -> Z q -> l+l- qbar if(_process==0||_process==2) { if(gamma) add(new_ptr((Tree2toNDiagram(3), q, q, g, 1, _gamma, 2, q, 4, lm, 4, lp, -5))); if(Z0) add(new_ptr((Tree2toNDiagram(3), q, q, g, 1, _z0, 2, q, 4, lm, 4, lp, -6))); if(gamma) add(new_ptr((Tree2toNDiagram(2), q, g, 1, q, 3, _gamma, 3, q, 4, lm, 4, lp, -7))); if(Z0) add(new_ptr((Tree2toNDiagram(2), q, g, 1, q, 3, _z0, 3, q, 4, lm, 4, lp, -8))); } // qbar g -> Z qbar -> l+l- qbar if(_process==0||_process==3) { if(gamma) add(new_ptr((Tree2toNDiagram(3), qb, qb, g, 1, _gamma, 2, qb, 4, lm, 4, lp, -9 ))); if(Z0) add(new_ptr((Tree2toNDiagram(3), qb, qb, g, 1, _z0, 2, qb, 4, lm, 4, lp, -10))); if(gamma) add(new_ptr((Tree2toNDiagram(2), qb, g, 1, qb, 3, _gamma, 3, qb, 4, lm, 4, lp, -11))); if(Z0) add(new_ptr((Tree2toNDiagram(2), qb, g, 1, qb, 3, _z0, 3, qb, 4, lm, 4, lp, -12))); } } } } unsigned int MEPP2ZJet::orderInAlphaS() const { return 1; } unsigned int MEPP2ZJet::orderInAlphaEW() const { return 2; } void MEPP2ZJet::persistentOutput(PersistentOStream & os) const { os << _theFFZVertex << _theFFPVertex << _theQQGVertex << _z0 << _widthopt << _gamma << _process << _maxflavour << _zdec << _pprob << _gammaZ; } void MEPP2ZJet::persistentInput(PersistentIStream & is, int) { is >> _theFFZVertex >> _theFFPVertex >> _theQQGVertex >> _z0 >> _widthopt >> _gamma >> _process >> _maxflavour >> _zdec >> _pprob >> _gammaZ; } int MEPP2ZJet::nDim() const { return 5; } Selector MEPP2ZJet::colourGeometries(tcDiagPtr diag) const { // colour lines for q qbar -> Z g static const ColourLines cqqbar[4]={ColourLines("1 2 5,-3 -5"), ColourLines("1 5,-5 2 -3"), ColourLines("1 2 5,-3 -5, 6 -7"), ColourLines("1 5,-5 2 -3, 6 -7")}; // colour lines for q g -> Z q static const ColourLines cqg [4]={ColourLines("1 2 -3,3 5"), ColourLines("1 -2,2 3 5"), ColourLines("1 2 -3,3 5, 6 -7"), ColourLines("1 -2,2 3 5, 6 -7")}; // colour lines for qbar q -> Z qbar static const ColourLines cqbarg[4]={ColourLines("-1 -2 3,-3 -5"), ColourLines("-1 2,-2 -3 -5"), ColourLines("-1 -2 3,-3 -5, 6 -7"), ColourLines("-1 2,-2 -3 -5, 6 -7")}; // select the correct line unsigned int icol = mePartonData()[3]->coloured() ? 2 : 0; Selector sel; switch(abs(diag->id())) { case 1 : case 2: sel.insert(1.0, &cqqbar[icol]); break; case 3 : case 4: sel.insert(1.0, &cqqbar[icol+1]); break; case 5 : case 6: sel.insert(1.0, &cqg[icol]); break; case 7 : case 8: sel.insert(1.0, &cqg[icol+1]); break; case 9 : case 10: sel.insert(1.0, &cqbarg[icol]); break; case 11 : case 12: sel.insert(1.0, &cqbarg[icol+1]); break; } return sel; } Selector MEPP2ZJet::diagrams(const DiagramVector & diags) const { Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ) { int id=abs(diags[i]->id()); if (id <= 4 ) sel.insert(meInfo()[id-1],i); else if(id <= 8 ) sel.insert(meInfo()[id-5],i); else if(id <= 12) sel.insert(meInfo()[id-9],i); } return sel; } Energy2 MEPP2ZJet::scale() const { return _scale; } CrossSection MEPP2ZJet::dSigHatDR() const { return me2()*jacobian()/(16.0*sqr(Constants::pi)*sHat())*sqr(hbarc); } bool MEPP2ZJet::generateKinematics(const double * r) { // initialize jacobian jacobian(1.); // cms energy Energy ecm=sqrt(sHat()); // first generate the mass of the off-shell gauge boson // minimum mass of the tcPDVector ptemp; ptemp.push_back(mePartonData()[3]); ptemp.push_back(mePartonData()[4]); Energy2 minMass2 = max(lastCuts().minSij(mePartonData()[3],mePartonData()[4]), lastCuts().minS(ptemp)); // minimum pt of the jet Energy ptmin = max(lastCuts().minKT(mePartonData()[2]), lastCuts().minKT(_z0)); // maximum mass of the gauge boson so pt is possible Energy2 maxMass2 = min(ecm*(ecm-2.*ptmin),lastCuts().maxS(ptemp)); if(maxMass2<=ZERO||minMass2massMin())); maxMass2 = min(maxMass2,sqr(_z0->massMax())); // also impose the limits from the ParticleData object if(maxMass2mass()),Gamma(_z0->width()); Energy2 M2(sqr(M)),MG(M*Gamma); double rhomin = atan2((minMass2-M2),MG); double rhomax = atan2((maxMass2-M2),MG); if(r[1]<_pprob) { double rand=r[1]/_pprob; _mz2=minMass2*maxMass2/(minMass2+rand*(maxMass2-minMass2)); } else { double rand=(r[1]-_pprob)/(1.-_pprob); _mz2=M2+MG*tan(rhomin+rand*(rhomax-rhomin)); } Energy mz=sqrt(_mz2); InvEnergy2 emjac1 = _pprob*minMass2*maxMass2/(maxMass2-minMass2)/sqr(_mz2); InvEnergy2 emjac2 = (1.-_pprob)*MG/(rhomax-rhomin)/(sqr(_mz2-M2)+sqr(MG)); // jacobian jacobian(jacobian()/sHat()/(emjac1+emjac2)); // set the masses of the outgoing particles to 2-2 scattering meMomenta()[2].setMass(ZERO); Lorentz5Momentum pz(mz); // generate the polar angle of the hard scattering double ctmin(-1.0), ctmax(1.0); Energy q(ZERO); try { q = SimplePhaseSpace::getMagnitude(sHat(), meMomenta()[2].mass(),mz); } - catch ( ImpossibleKinematics ) { + catch ( ImpossibleKinematics & e ) { return false; } Energy2 pq = sqrt(sHat())*q; 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)); } if ( ctmin >= ctmax ) return false; double cth = getCosTheta(ctmin, ctmax, r[0]); Energy pt = q*sqrt(1.0-sqr(cth)); double phi = 2.0*Constants::pi*r[2]; meMomenta()[2].setVect(Momentum3( pt*sin(phi), pt*cos(phi), q*cth)); pz.setVect( Momentum3(-pt*sin(phi),-pt*cos(phi),-q*cth)); meMomenta()[2].rescaleEnergy(); pz.rescaleEnergy(); // set the scale _scale = _mz2+sqr(pt); // generate the momenta of the Z decay products meMomenta()[3].setMass(mePartonData()[3]->mass()); meMomenta()[4].setMass(mePartonData()[4]->mass()); Energy q2 = ZERO; try { q2 = SimplePhaseSpace::getMagnitude(_mz2, meMomenta()[3].mass(), meMomenta()[4].mass()); - } catch ( ImpossibleKinematics ) { + } catch ( ImpossibleKinematics & e ) { return false; } double cth2 =-1.+2.*r[3]; double phi2=Constants::twopi*r[4]; Energy pt2 =q2*sqrt(1.-sqr(cth2)); Lorentz5Momentum pl[2]={Lorentz5Momentum( pt2*cos(phi2), pt2*sin(phi2), q2*cth2,ZERO, meMomenta()[3].mass()), Lorentz5Momentum(-pt2*cos(phi2),-pt2*sin(phi2),-q2*cth2,ZERO, meMomenta()[4].mass())}; pl[0].rescaleEnergy(); pl[1].rescaleEnergy(); Boost boostv(pz.boostVector()); pl[0].boost(boostv); pl[1].boost(boostv); meMomenta()[3] = pl[0]; meMomenta()[4] = pl[1]; // check passes all the cuts vector out(3); tcPDVector tout(3); for(unsigned int ix=0;ix<3;++ix) { out[ ix] = meMomenta()[ix+2]; tout[ix] = mePartonData()[ix+2]; } if ( !lastCuts().passCuts(tout, out, mePartonData()[0], mePartonData()[1]) ) return false; // jacobian jacobian((pq/sHat())*Constants::pi*jacobian()/8./sqr(Constants::pi)*q2/mz); return true; } double MEPP2ZJet::me2() const { InvEnergy2 output(ZERO); // construct spinors for the leptons (always the same) vector lm; vector lp; SpinorBarWaveFunction lmout(meMomenta()[3],mePartonData()[3],outgoing); SpinorWaveFunction lpout(meMomenta()[4],mePartonData()[4],outgoing); for(unsigned int ix=0;ix<2;++ix) { lmout.reset(ix);lm.push_back(lmout); lpout.reset(ix);lp.push_back(lpout); } // q g to q Z if(mePartonData()[0]->id()<=6&&mePartonData()[0]->id()>0&& mePartonData()[1]->id()==ParticleID::g) { // polarization states for the particles vector fin; vector gin; vector fout; SpinorWaveFunction qin (meMomenta()[0],mePartonData()[0],incoming); VectorWaveFunction glin(meMomenta()[1],mePartonData()[1],incoming); SpinorBarWaveFunction qout(meMomenta()[2],mePartonData()[2],outgoing); for(unsigned int ix=0;ix<2;++ix) { qin.reset(ix) ; fin.push_back(qin); glin.reset(2*ix); gin.push_back(glin); qout.reset(ix);fout.push_back(qout); } output=qgME(fin,gin,fout,lm,lp); } // qbar g to qbar Z else if(mePartonData()[0]->id()>=-6&&mePartonData()[0]->id()<0&& mePartonData()[1]->id()==ParticleID::g) { vector ain; vector gin; vector aout; SpinorBarWaveFunction qbin (meMomenta()[0],mePartonData()[0],incoming); VectorWaveFunction glin (meMomenta()[1],mePartonData()[1],incoming); SpinorWaveFunction qbout(meMomenta()[2],mePartonData()[2],outgoing); for(unsigned int ix=0;ix<2;++ix) { qbin .reset(ix ); ain .push_back(qbin ); glin .reset(2*ix); gin .push_back(glin ); qbout.reset(ix ); aout.push_back(qbout); } output=qbargME(ain,gin,aout,lm,lp); } // q qbar to g Z else { vector fin; vector ain; vector gout; SpinorWaveFunction qin (meMomenta()[0],mePartonData()[0],incoming); SpinorBarWaveFunction qbin(meMomenta()[1],mePartonData()[1],incoming); VectorWaveFunction glout(meMomenta()[2],mePartonData()[2],outgoing); 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); } output=qqbarME(fin,ain,gout,lm,lp); } return output*sHat(); } InvEnergy2 MEPP2ZJet::qqbarME(vector & fin, vector & ain, vector & gout, vector & lm, vector & lp, bool calc) const { // if calculation spin corrections construct the me if(calc) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1,PDT::Spin1Half, PDT::Spin1Half)); // diagrams to include bool gamma = _gammaZ==0 || _gammaZ==1; bool Z0 = _gammaZ==0 || _gammaZ==2; // some integers unsigned int ihel1,ihel2,ohel1,ohel2,ohel3; // compute the leptonic photon and Z currents for speed VectorWaveFunction bcurr[2][2][2]; for(ohel2=0;ohel2<2;++ohel2) { for(ohel3=0;ohel3<2;++ohel3) { // photon current if(gamma) bcurr[0][ohel2][ohel3]= _theFFPVertex->evaluate(_mz2,1,_gamma,lp[ohel3],lm[ohel2]); // Z current if(Z0) bcurr[1][ohel2][ohel3]= _theFFZVertex->evaluate(_mz2,_widthopt,_z0,lp[ohel3],lm[ohel2]); } } // compute the matrix elements double me[5]={0.,0.,0.,0.,0.}; Complex diag[4]; SpinorWaveFunction inters; SpinorBarWaveFunction interb; for(ihel1=0;ihel1<2;++ihel1) { for(ihel2=0;ihel2<2;++ihel2) { for(ohel1=0;ohel1<2;++ohel1) { // intermediates for the diagrams inters=_theQQGVertex->evaluate(_scale,5,mePartonData()[0], fin[ihel1],gout[ohel1]); interb=_theQQGVertex->evaluate(_scale,5,mePartonData()[1], ain[ihel2],gout[ohel1]); for(ohel2=0;ohel2<2;++ohel2) { for(ohel3=0;ohel3<2;++ohel3) { diag[0] = gamma ? _theFFPVertex->evaluate(_mz2,fin[ihel1],interb, bcurr[0][ohel2][ohel3]) : 0.; diag[1]= Z0 ? _theFFZVertex->evaluate(_mz2,fin[ihel1],interb, bcurr[1][ohel2][ohel3]) : 0.; diag[2]= gamma ? _theFFPVertex->evaluate(_mz2,inters,ain[ihel2], bcurr[0][ohel2][ohel3]) : 0.; diag[3]= Z0 ? _theFFZVertex->evaluate(_mz2,inters,ain[ihel2], bcurr[1][ohel2][ohel3]) : 0.; // diagram contributions me[1] += norm(diag[0]); me[2] += norm(diag[1]); me[3] += norm(diag[2]); me[4] += norm(diag[3]); // total diag[0] += diag[1] + diag[2] + diag[3]; me[0] += norm(diag[0]); if(calc) _me(ihel1,ihel2,2*ohel1,ohel2,ohel3) = diag[0]; } } } } } // results // initial state spin and colour average double colspin = 1./9./4.; // and C_F N_c from matrix element colspin *= 4.; // and for Z decay products if(mePartonData()[3]->coloured()) colspin *= 3.; DVector save; for(unsigned int ix=0;ix<5;++ix) { me[ix] *= colspin; if(ix>0) save.push_back(me[ix]); } meInfo(save); return me[0]*UnitRemoval::InvE2; } InvEnergy2 MEPP2ZJet::qgME(vector & fin, vector & gin, vector & fout, vector & lm, vector & lp, bool calc) const { // diagrams to include bool gamma = _gammaZ==0 || _gammaZ==1; bool Z0 = _gammaZ==0 || _gammaZ==2; // if calculation spin corrections construct the me if(calc) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1, PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half)); // some integers unsigned int ihel1,ihel2,ohel1,ohel2,ohel3; // compute the leptonic photon and Z currents for speed VectorWaveFunction bcurr[2][2][2]; for(ohel2=0;ohel2<2;++ohel2) { for(ohel3=0;ohel3<2;++ohel3) { // photon current if(gamma) bcurr[0][ohel2][ohel3]= _theFFPVertex->evaluate(_mz2,1,_gamma,lp[ohel3],lm[ohel2]); // Z current if(Z0) bcurr[1][ohel2][ohel3]= _theFFZVertex->evaluate(_mz2,_widthopt,_z0,lp[ohel3],lm[ohel2]); } } // compute the matrix elements double me[5]={0.,0.,0.,0.,0.}; Complex diag[4]; SpinorWaveFunction inters; SpinorBarWaveFunction interb; Energy2 _scale=scale(); for(ihel1=0;ihel1<2;++ihel1) { for(ihel2=0;ihel2<2;++ihel2) { for(ohel1=0;ohel1<2;++ohel1) { // intermediates for the diagrams interb=_theQQGVertex->evaluate(_scale,5,mePartonData()[2]->CC(), fout[ohel1],gin[ihel2]); inters=_theQQGVertex->evaluate(_scale,5,mePartonData()[0], fin[ihel1],gin[ihel2]); for(ohel2=0;ohel2<2;++ohel2) { for(ohel3=0;ohel3<2;++ohel3) { diag[0]=gamma ? _theFFPVertex->evaluate(_mz2,fin[ihel1],interb, bcurr[0][ohel2][ohel3]) : 0.; diag[1]=Z0 ? _theFFZVertex->evaluate(_mz2,fin[ihel1],interb, bcurr[1][ohel2][ohel3]) : 0.; diag[2]=gamma ? _theFFPVertex->evaluate(_mz2,inters,fout[ohel1], bcurr[0][ohel2][ohel3]) : 0.; diag[3]=Z0 ? _theFFZVertex->evaluate(_mz2,inters,fout[ohel1], bcurr[1][ohel2][ohel3]) : 0.; // diagram contributions me[1] += norm(diag[0]); me[2] += norm(diag[1]); me[3] += norm(diag[2]); me[4] += norm(diag[3]); // total diag[0] += diag[1] + diag[2] + diag[3]; me[0] += norm(diag[0]); if(calc) _me(ihel1,2*ihel2,ohel1,ohel2,ohel3) = diag[0]; } } } } } // results // initial state spin and colour average double colspin = 1./24./4.; // and C_F N_c from matrix element colspin *= 4.; // and for Z decay products if(mePartonData()[3]->coloured()) colspin *= 3.; DVector save; for(unsigned int ix=0;ix<5;++ix) { me[ix] *= colspin; if(ix>0) save.push_back(me[ix]); } meInfo(save); return me[0]*UnitRemoval::InvE2; } InvEnergy2 MEPP2ZJet::qbargME(vector & fin, vector & gin, vector & fout, vector & lm, vector & lp, bool calc) const { // diagrams to include bool gamma = _gammaZ==0 || _gammaZ==1; bool Z0 = _gammaZ==0 || _gammaZ==2; // if calculation spin corrections construct the me if(calc) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1, PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half)); // some integers unsigned int ihel1,ihel2,ohel1,ohel2,ohel3; // compute the leptonic photon and Z currents for speed VectorWaveFunction bcurr[2][2][2]; for(ohel2=0;ohel2<2;++ohel2) { for(ohel3=0;ohel3<2;++ohel3) { // photon current if(gamma) bcurr[0][ohel2][ohel3]= _theFFPVertex->evaluate(_mz2,1,_gamma,lp[ohel3],lm[ohel2]); // Z current if(Z0) bcurr[1][ohel2][ohel3]= _theFFZVertex->evaluate(_mz2,_widthopt,_z0,lp[ohel3],lm[ohel2]); } } // compute the matrix elements double me[5]={0.,0.,0.,0.,0.}; Complex diag[4]; SpinorWaveFunction inters; SpinorBarWaveFunction interb; Energy2 _scale=scale(); for(ihel1=0;ihel1<2;++ihel1) { for(ihel2=0;ihel2<2;++ihel2) { for(ohel1=0;ohel1<2;++ohel1) { // intermediates for the diagrams inters=_theQQGVertex->evaluate(_scale,5,mePartonData()[2]->CC(), fout[ohel1],gin[ihel2]); interb=_theQQGVertex->evaluate(_scale,5,mePartonData()[0], fin[ihel1],gin[ihel2]); for(ohel2=0;ohel2<2;++ohel2) { for(ohel3=0;ohel3<2;++ohel3) { diag[0]= gamma ? _theFFPVertex->evaluate(_mz2,inters,fin[ihel1], bcurr[0][ohel2][ohel3]) : 0.; diag[1]= Z0 ? _theFFZVertex->evaluate(_mz2,inters,fin[ihel1], bcurr[1][ohel2][ohel3]) : 0.; diag[2]= gamma ? _theFFPVertex->evaluate(_mz2,fout[ohel1],interb, bcurr[0][ohel2][ohel3]) : 0.; diag[3]= Z0 ? _theFFZVertex->evaluate(_mz2,fout[ohel1],interb, bcurr[1][ohel2][ohel3]) : 0.; // diagram contributions me[1] += norm(diag[0]); me[2] += norm(diag[1]); me[3] += norm(diag[2]); me[4] += norm(diag[3]); // total diag[0] += diag[1] + diag[2] + diag[3]; me[0] += norm(diag[0]); if(calc) _me(ihel1,2*ihel2,ohel1,ohel2,ohel3) = diag[0]; } } } } } // results // initial state spin and colour average double colspin = 1./24./4.; // and C_F N_c from matrix element colspin *= 4.; // and for Z decay products if(mePartonData()[3]->coloured()) colspin*=3.; DVector save; for(unsigned int ix=0;ix<5;++ix) { me[ix] *= colspin; if(ix>0) save.push_back(me[ix]); } meInfo(save); return me[0]*UnitRemoval::InvE2; } void MEPP2ZJet::constructVertex(tSubProPtr sub) { // extract the particles in the hard process ParticleVector hard(5); // incoming hard[0]=sub->incoming().first; hard[1]=sub->incoming().second; if((hard[0]->id()<0&&hard[1]->id()<=6)|| hard[0]->id()==ParticleID::g) swap(hard[0],hard[1]); // outgoing for(unsigned int ix=0;ix<3;++ix) { unsigned int iloc; PPtr mother=sub->outgoing()[ix]->parents()[0]; if(mother&&(mother->id()==ParticleID::gamma||mother->id()==ParticleID::Z0)) { if(sub->outgoing()[ix]->id()>0) iloc=3; else iloc=4; } else iloc=2; hard[iloc]=sub->outgoing()[ix]; } // wavefunctions for the Z decay products vector lm; vector lp; SpinorBarWaveFunction(lm,hard[3],outgoing,true,true); SpinorWaveFunction (lp,hard[4],outgoing,true,true); // identify hard process and calculate matrix element // q g to q Z if(hard[0]->id()<=6&&hard[0]->id()>0&&hard[1]->id()==ParticleID::g) { vector fin; vector gin; vector fout; SpinorWaveFunction (fin ,hard[0],incoming,false,true); VectorWaveFunction (gin ,hard[1],incoming,false,true,true); SpinorBarWaveFunction (fout,hard[2],outgoing,true ,true); gin[1]=gin[2]; qgME(fin,gin,fout,lm,lp,true); } // qbar g to qbar Z else if(hard[0]->id()>=-6&&hard[0]->id()<0&&hard[1]->id()==ParticleID::g) { vector ain; vector gin; vector aout; SpinorBarWaveFunction(ain ,hard[0],incoming,false,true); VectorWaveFunction (gin ,hard[1],incoming,false,true,true); SpinorWaveFunction (aout,hard[2],outgoing,true ,true); gin[1]=gin[2]; qbargME(ain,gin,aout,lm,lp,true); } // q qbar to g Z else { vector fin; vector ain; vector gout; SpinorWaveFunction (fin ,hard[0],incoming,false,true); SpinorBarWaveFunction(ain ,hard[1],incoming,false,true); VectorWaveFunction (gout,hard[2],outgoing,true ,true,true); gout[1]=gout[2]; qqbarME(fin,ain,gout,lm,lp,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 ix=0;ix<5;++ix) (hard[ix]->spinInfo())->productionVertex(hardvertex); } diff --git a/MatrixElement/HwMEBase.cc b/MatrixElement/HwMEBase.cc --- a/MatrixElement/HwMEBase.cc +++ b/MatrixElement/HwMEBase.cc @@ -1,308 +1,308 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the HwMEBase class. // #include "HwMEBase.h" #include "ThePEG/Utilities/DescribeClass.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/RealEmissionProcess.h" using namespace Herwig; void HwMEBase::persistentOutput(PersistentOStream & os) const { os << massOption_ << rescaleOption_; } void HwMEBase::persistentInput(PersistentIStream & is, int) { is >> massOption_ >> rescaleOption_; } // The following static variable is needed for the type // description system in ThePEG. DescribeAbstractClass describeHerwigHwMEBase("Herwig::HwMEBase", "Herwig.so"); 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 ) { + catch ( ImpossibleKinematics & e) { 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(PPtr, PPtr, const bool &, const Energy & , const vector & , const double & , const Energy & , const Energy & ) { assert(false); return false; } RealEmissionProcessPtr HwMEBase::generateHardest(RealEmissionProcessPtr,ShowerInteraction) { assert(false); return RealEmissionProcessPtr(); } RealEmissionProcessPtr HwMEBase::applyHardMatrixElementCorrection(RealEmissionProcessPtr) { assert(false); return RealEmissionProcessPtr(); } void HwMEBase::initializeMECorrection(RealEmissionProcessPtr , double & , double & ) { assert(false); } diff --git a/MatrixElement/MEfftoVH.cc b/MatrixElement/MEfftoVH.cc --- a/MatrixElement/MEfftoVH.cc +++ b/MatrixElement/MEfftoVH.cc @@ -1,424 +1,424 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the MEfftoVH class. // #include "MEfftoVH.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/MatrixElement/Tree2toNDiagram.h" #include "ThePEG/Utilities/SimplePhaseSpace.h" #include "ThePEG/Handlers/StandardXComb.h" #include "ThePEG/Cuts/Cuts.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "Herwig/MatrixElement/HardVertex.h" #include "Herwig/Utilities/Kinematics.h" #include "ThePEG/PDF/PolarizedBeamParticleData.h" using namespace Herwig; void MEfftoVH::persistentOutput(PersistentOStream & os) const { os << _shapeopt << _wplus << _wminus << _z0 << _higgs << _vertexFFW << _vertexFFZ << _vertexWWH << _maxflavour << ounit(_mh,GeV) << ounit(_wh,GeV) << _hmass; } void MEfftoVH::persistentInput(PersistentIStream & is, int) { is >> _shapeopt >> _wplus >> _wminus >> _z0 >> _higgs >> _vertexFFW >> _vertexFFZ >> _vertexWWH >> _maxflavour >> iunit(_mh,GeV) >> iunit(_wh,GeV) >> _hmass; } // The following static variable is needed for the type // description system in ThePEG. DescribeAbstractClass describeHerwigMEfftoVH("Herwig::MEfftoVH", "Herwig.so"); void MEfftoVH::Init() { static ClassDocumentation documentation ("The MEfftoVH class is the base class for the Bjirken process f fbar -> V H"); static Switch interfaceShapeOption ("ShapeScheme", "Option for the treatment of the Higgs resonance shape", &MEfftoVH::_shapeopt, 2, 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 SwitchOption interfaceStandardShapeOnShell (interfaceShapeOption, "OnShell", "Produce an on-shell Higgs boson", 0); static Parameter interfaceMaxFlavour ( "MaxFlavour", "The heaviest incoming quark flavour this matrix element is allowed to handle " "(if applicable).", &MEfftoVH::_maxflavour, 5, 1, 5, false, false, true); } unsigned int MEfftoVH::orderInAlphaS() const { return 0; } unsigned int MEfftoVH::orderInAlphaEW() const { return 3; } Energy2 MEfftoVH::scale() const { return sHat(); } int MEfftoVH::nDim() const { return 4 + int(_shapeopt>0); } void MEfftoVH::setKinematics() { DrellYanBase::setKinematics(); } Selector MEfftoVH::diagrams(const DiagramVector & diags) const { Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ) sel.insert(1.0, i); return sel; } Selector MEfftoVH::colourGeometries(tcDiagPtr ) const { static ColourLines c1(""); static ColourLines c2("6 -7"); static ColourLines c3("1 -2"); static ColourLines c4("1 -2, 6 -7"); Selector sel; if(mePartonData()[0]->coloured()) { if(mePartonData()[4]->coloured()) sel.insert(1.0, &c4); else sel.insert(1.0, &c3); } else { if(mePartonData()[4]->coloured()) sel.insert(1.0, &c2); else sel.insert(1.0, &c1); } return sel; } void MEfftoVH::doinit() { DrellYanBase::doinit(); // get the vedrtex pointers from the SM object tcHwSMPtr hwsm= dynamic_ptr_cast(standardModel()); // do the initialisation if(hwsm) { _vertexFFW = hwsm->vertexFFW(); _vertexFFZ = hwsm->vertexFFZ(); } else throw InitException() << "Wrong type of StandardModel object in " << "MEfftoVH::doinit() the Herwig" << " version must be used" << Exception::runerror; // get the particle data objects for the intermediates _wplus = getParticleData(ParticleID::Wplus ); _wminus = getParticleData(ParticleID::Wminus); _z0 = getParticleData(ParticleID::Z0); // higgs stuff _mh = _higgs->mass(); _wh = _higgs->width(); if(_higgs->massGenerator()) { _hmass=dynamic_ptr_cast(_higgs->massGenerator()); } if(_shapeopt==2&&!_hmass) throw InitException() << "If using the mass generator for the line shape in MEfftoVH::doinit()" << "the mass generator must be an instance of the GenericMassGenerator class" << Exception::runerror; } double MEfftoVH::me2() const { vector fin,aout; vector ain,fout; SpinorWaveFunction q(meMomenta()[0],mePartonData()[0],incoming); SpinorBarWaveFunction qbar(meMomenta()[1],mePartonData()[1],incoming); SpinorBarWaveFunction f(meMomenta()[3],mePartonData()[3],outgoing); SpinorWaveFunction fbar(meMomenta()[4],mePartonData()[4],outgoing); for(unsigned int ix=0;ix<2;++ix) { q.reset(ix) ; fin.push_back(q); qbar.reset(ix); ain.push_back(qbar); f.reset(ix) ;fout.push_back(f); fbar.reset(ix);aout.push_back(fbar); } return helicityME(fin,ain,fout,aout,false)*sHat()*UnitRemoval::InvE2; } double MEfftoVH::helicityME(vector & fin , vector & ain , vector & fout, vector & aout, bool calc) const { // scale Energy2 mb2(scale()); // matrix element to be stored ProductionMatrixElement menew(PDT::Spin1Half,PDT::Spin1Half,PDT::Spin0, PDT::Spin1Half,PDT::Spin1Half); // work out the id of the vector boson int incharge = mePartonData()[0]->iCharge()+mePartonData()[1]->iCharge(); tcPDPtr vec; if(incharge==0) vec = _z0; else if(incharge>0) vec = _wplus; else vec = _wminus; // vertex for vector boson AbstractFFVVertexPtr vertex = vec==_z0 ? _vertexFFZ : _vertexFFW; // wavefunction for the scalar ScalarWaveFunction higgs(meMomenta()[2],mePartonData()[2],1.,outgoing); // calculate the matrix element VectorWaveFunction inter[2]; unsigned int ihel1,ihel2,ohel1,ohel2; Complex diag; double me(0.); for(ihel1=0;ihel1<2;++ihel1) { for(ihel2=0;ihel2<2;++ihel2) { // wavefunction for the intermediate 1st vector inter[0] = vertex->evaluate(mb2,1,vec,fin[ihel1],ain[ihel2]); // boson decay piece for(ohel1=0;ohel1<2;++ohel1) { for(ohel2=0;ohel2<2;++ohel2) { inter[1] = vertex->evaluate(sqr(vec->mass()),1,vec, aout[ohel2],fout[ohel1]); diag = _vertexWWH->evaluate(mb2,inter[1],inter[0],higgs); me += norm(diag); menew(ihel1,ihel2,0,ohel1,ohel2) = diag; } } } } // spin factor me *=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())}; me = menew.average(rho[0],rho[1]); } // incoming colour factor if(mePartonData()[0]->coloured()) me /= 3.; // outgoing colour factor if(mePartonData()[3]->coloured()) me *= 3.; if(calc) _me.reset(menew); return me; } void MEfftoVH::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]); hard.push_back(sub->outgoing()[2]); // ensure right order if(hard[0]->id()<0) swap(hard[0],hard[1]); if(hard[3]->dataPtr()->iSpin()==PDT::Spin0) swap(hard[2],hard[3]); if(hard[4]->dataPtr()->iSpin()==PDT::Spin0) swap(hard[2],hard[4]); if(hard[3]->id()<0) swap(hard[3],hard[4]); vector fin,aout; vector ain,fout; SpinorWaveFunction( fin ,hard[0],incoming,false,true); SpinorBarWaveFunction(ain ,hard[1],incoming,false,true); ScalarWaveFunction( hard[2],outgoing,true); SpinorBarWaveFunction(fout,hard[3],outgoing,true ,true); SpinorWaveFunction( aout,hard[4],outgoing,true ,true); helicityME(fin,ain,fout,aout,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 ix=0;ix<5;++ix) { tcSpinPtr spin = hard[ix]->spinInfo(); if(ix<2) { tcPolarizedBeamPDPtr beam = dynamic_ptr_cast(hard[ix]->dataPtr()); if(beam) spin->rhoMatrix() = beam->rhoMatrix(); } spin->productionVertex(hardvertex); } } bool MEfftoVH::generateKinematics(const double * r) { using Constants::pi; // workout the ID of the vector boson tcPDPtr vec = mePartonData()[0]->iCharge()+mePartonData()[1]->iCharge()!=0 ? _wplus : _z0; // order determined randomly Energy e = sqrt(sHat())/2.0; Energy mh(_mh),mv; double jac(1.); if(UseRandom::rndbool()) { double rhomax,rhomin; // generate the mass of the Higgs if(_shapeopt!=0) { Energy mhmax = min(2.*e-vec->massMin(),mePartonData()[2]->massMax()); Energy mhmin = max(ZERO ,mePartonData()[2]->massMin()); if(mhmax<=mhmin) return false; rhomin = atan2((sqr(mhmin)-sqr(_mh)), _mh*_wh); rhomax = atan2((sqr(mhmax)-sqr(_mh)), _mh*_wh); mh = sqrt(_mh*_wh*tan(rhomin+r[3]*(rhomax-rhomin))+sqr(_mh)); jac *= rhomax-rhomin; } // generate the mass of the vector boson Energy2 mvmax2 = sqr(min(2.*e-mh,vec->massMax())); Energy2 mvmin2 = sqr(vec->massMin()); if(mvmax2<=mvmin2) return false; rhomin = atan2((mvmin2-sqr(vec->mass())), vec->mass()*vec->width()); rhomax = atan2((mvmax2-sqr(vec->mass())), vec->mass()*vec->width()); mv = sqrt(vec->mass()*vec->width()*tan(rhomin+r[1]*(rhomax-rhomin)) +sqr(vec->mass())); jac *= rhomax-rhomin; } else { // generate the mass of the vector boson Energy2 mvmax2 = sqr(min(2.*e,vec->massMax())); Energy2 mvmin2 = sqr(vec->massMin()); if(mvmax2<=mvmin2) return false; double rhomin = atan2((mvmin2-sqr(vec->mass())), vec->mass()*vec->width()); double rhomax = atan2((mvmax2-sqr(vec->mass())), vec->mass()*vec->width()); mv = sqrt(vec->mass()*vec->width()*tan(rhomin+r[1]*(rhomax-rhomin)) +sqr(vec->mass())); jac *= rhomax-rhomin; // generate the mass of the Higgs if(_shapeopt!=0) { Energy mhmax = min(2.*e-mv,mePartonData()[2]->massMax()); Energy mhmin = max(ZERO ,mePartonData()[2]->massMin()); if(mhmax<=mhmin) return false; rhomin = atan2((sqr(mhmin)-sqr(_mh)), _mh*_wh); rhomax = atan2((sqr(mhmax)-sqr(_mh)), _mh*_wh); mh = sqrt(_mh*_wh*tan(rhomin+r[3]*(rhomax-rhomin))+sqr(_mh)); jac *= rhomax-rhomin; } } if(mh+mv>2.*e) return false; // assign masses meMomenta()[2].setMass(mh); for(unsigned int ix=3;ix<5;++ix) meMomenta()[ix] = Lorentz5Momentum(mePartonData()[ix]->generateMass()); Energy q = ZERO; Lorentz5Momentum pvec(mv); try { q = SimplePhaseSpace:: getMagnitude(sHat(), meMomenta()[2].mass(), mv); } - catch ( ImpossibleKinematics ) { + catch ( ImpossibleKinematics & e) { return false; } Energy ptmin = max(lastCuts().minKT(mePartonData()[2]), lastCuts().minKT(vec)); Energy2 m22 = meMomenta()[2].mass2(); Energy2 m32 = pvec .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; double ctmin = -1.0,ctmax = 1.0; 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); 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)); } if ( ctmin >= ctmax ) return false; jacobian(1.); double cth = getCosTheta(ctmin, ctmax, r[0]); Energy pt = q*sqrt(1.0-sqr(cth)); double phi = UseRandom::rnd()*2.0*pi; meMomenta()[2].setX(pt*sin(phi)); meMomenta()[2].setY(pt*cos(phi)); meMomenta()[2].setZ(q*cth); pvec .setX(-pt*sin(phi)); pvec .setY(-pt*cos(phi)); pvec .setZ(-q*cth); meMomenta()[2].rescaleEnergy(); pvec .rescaleEnergy(); // decay of the vector boson bool test=Kinematics::twoBodyDecay(pvec,meMomenta()[3].mass(), meMomenta()[4].mass(), -1.+2*r[2],r[3]*2.*pi, meMomenta()[3],meMomenta()[4]); if(!test) return false; // check cuts vector out; tcPDVector tout; for(unsigned int ix=2;ix<5;++ix) { out .push_back(meMomenta()[ix]); tout.push_back(mePartonData()[ix]); } if ( !lastCuts().passCuts(tout, out, mePartonData()[0], mePartonData()[1]) ) return false; // jacobian factors // main piece jacobian((pq/sHat())*pi*jacobian()); // mass piece jacobian(jac*jacobian()); // decay piece Energy p2 = Kinematics::pstarTwoBodyDecay(mv,meMomenta()[3].mass(), meMomenta()[4].mass()); jacobian(p2/mv/8./sqr(pi)*jacobian()); // jacobian factor for the gauge boson jacobian((sqr(sqr(mv)-sqr(vec->mass()))+sqr(vec->mass()*vec->width()))/ (vec->mass()*vec->width())*jacobian()/sHat()); return true; } CrossSection MEfftoVH::dSigHatDR() const { using Constants::pi; // jacobian factor for the higgs InvEnergy2 bwfact(ZERO); Energy moff =meMomenta()[2].mass(); if(_shapeopt==1) { tcPDPtr h0 = mePartonData()[2]->iSpin()==PDT::Spin0 ? mePartonData()[2] : mePartonData()[3]; bwfact = h0->generateWidth(moff)*moff/pi/ (sqr(sqr(moff)-sqr(_mh))+sqr(_mh*_wh)); } else if(_shapeopt==2) { bwfact = _hmass->BreitWignerWeight(moff); } double jac1 = _shapeopt!=0 ? double(bwfact*(sqr(sqr(moff)-sqr(_mh))+sqr(_mh*_wh))/(_mh*_wh)) : 1.; // answer return jac1*me2()*jacobian()/(16.0*sqr(pi)*sHat())*sqr(hbarc); } diff --git a/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxCurrents.cc b/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxCurrents.cc --- a/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxCurrents.cc +++ b/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxCurrents.cc @@ -1,2861 +1,2832 @@ // - * - C++ - * - // // MatchboxCurrents.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #include "MatchboxCurrents.h" #include "Herwig/Utilities/Maths.h" using namespace Herwig; using namespace Herwig::Math; using Constants::pi; namespace { - const static LorentzVector czero(0.,0.,0.,0.); + static const LorentzVector czero(0.,0.,0.,0.); inline Complex csqr(const Complex & a) { return a * a; } inline double theta(const double x) { if ( x >= 0. ) return 1.; return 0.; } inline double sign(const double x) { if ( x >= 0. ) return 1.; return -1.; } - // quick'n'dirty fix to template troubles - - Complex operator * (const Complex& a, const double b) { - return Complex(a.real() * b,a.imag() * b); - } - - Complex operator * (const double b, const Complex& a) { - return Complex(a.real() * b,a.imag() * b); - } - - Complex operator+(const Complex& a, const double b) { - return Complex(a.real()+b,a.imag()); - } - - Complex operator+(const double b, const Complex& a) { - return Complex(a.real()+b,a.imag()); - } - - Complex operator-(const Complex& a, const double b) { - return Complex(a.real()-b,a.imag()); - } - - Complex operator-(const double b, const Complex& a) { - return Complex(b-a.real(),-a.imag()); - } - - - // end fix, needs to be looked at in ThePEG/Config/ - } void MatchboxCurrents::setupLeptons(const int l, const Lorentz5Momentum& pl, const int lbar, const Lorentz5Momentum& plbar) { const Energy4 Delta = (sqr(pl*plbar) - (pl*pl)*(plbar*plbar)); const Energy2 prod = pl*plbar; // Variable to contain the sign of pl*plbar double sgn; if (prod < ZERO ) {sgn = -1;} else if (prod > ZERO) {sgn = 1;} else {sgn = 0;} InvEnergy2 fact = 0.5/(sgn*sqrt(Delta)); Lorentz5Momentum lmassless = ( double(fact*(sgn*sqrt(Delta) + prod))*pl - double(fact*( pl*pl))*plbar ); Lorentz5Momentum lbarmassless = ( double(fact*(sgn*sqrt(Delta) + prod))*plbar - double(fact*(plbar*plbar))*pl ); lmassless.setMass(ZERO); lmassless.rescaleEnergy(); lbarmassless.setMass(ZERO); lbarmassless.rescaleEnergy(); if ( pl.t() < ZERO ) lmassless.setT(-lmassless.t()); if ( plbar.t() < ZERO ) lbarmassless.setT(-lbarmassless.t()); momentum(l,lmassless,true,pl.mass()); momentum(lbar,lbarmassless,true,plbar.mass()); } void MatchboxCurrents::setupQuarks(const int q, const Lorentz5Momentum& pq, const int qbar, const Lorentz5Momentum& pqbar) { const Energy4 Delta = (sqr(pq*pqbar) - (pq*pq)*(pqbar*pqbar)); const Energy2 prod = pq*pqbar; // Variable to contain the sign of pq*pqbar double sgn; if (prod < ZERO) {sgn = -1;} else if (prod > ZERO) {sgn = 1;} else {sgn = 0;} InvEnergy2 fact = 0.5/(sgn*sqrt(Delta)); Lorentz5Momentum qmassless = ( double(fact*(sgn*sqrt(Delta) + prod))*pq - double(fact*(pq*pq))*pqbar ); Lorentz5Momentum qbarmassless = ( double(fact*(sgn*sqrt(Delta) + prod))*pqbar - double(fact*(pqbar*pqbar))*pq ); qmassless.setMass(ZERO); qmassless.rescaleEnergy(); qbarmassless.setMass(ZERO); qbarmassless.rescaleEnergy(); if ( pq.t() < ZERO ) qmassless.setT(-qmassless.t()); if ( pqbar.t() < ZERO ) qbarmassless.setT(-qbarmassless.t()); momentum(q,qmassless,true,pq.mass()); momentum(qbar,qbarmassless,true,pqbar.mass()); } const LorentzVector& MatchboxCurrents::llbarLeftCurrent(const int l, const int lHel, const int lbar, const int lbarHel) { if ( getCurrent(hash<0>(1,1,l,lHel,lbar,lbarHel)) ) { if ( lHel == 1 && lbarHel == 1 ) cacheCurrent(Complex(0.,1.) * minusCurrent(l,lbar)); if ( lHel == 1 && lbarHel == -1 ) cacheCurrent((Complex(0.,2.) * mass(lbar)/plusProduct(l,lbar)) * momentum(l)); if ( lHel == -1 && lbarHel == 1 ) cacheCurrent((Complex(0.,-2.) * mass(l)/minusProduct(l,lbar)) * momentum(lbar)); if ( lHel == -1 && lbarHel == -1 ) cacheCurrent((Complex(0.,1.) * mass(l) * mass(lbar)/invariant(l,lbar)) * minusCurrent(lbar,l)); } return cachedCurrent(); } const LorentzVector& MatchboxCurrents::llbarRightCurrent(const int l, const int lHel, const int lbar, const int lbarHel) { if ( getCurrent(hash<0>(2,1,l,lHel,lbar,lbarHel)) ) { if ( lHel == 1 && lbarHel == 1 ) cacheCurrent((Complex(0.,1.) * mass(l) * mass(lbar)/invariant(l,lbar)) * minusCurrent(l,lbar)); if ( lHel == 1 && lbarHel == -1 ) cacheCurrent((Complex(0.,-2.) * mass(l)/plusProduct(l,lbar)) * momentum(lbar)); if ( lHel == -1 && lbarHel == 1 ) cacheCurrent((Complex(0.,2.) * mass(lbar)/minusProduct(l,lbar)) * momentum(l)); if ( lHel == -1 && lbarHel == -1 ) cacheCurrent(Complex(0.,1.) * minusCurrent(lbar,l)); } return cachedCurrent(); } const LorentzVector& MatchboxCurrents::qqbarLeftCurrent(const int q, const int qHel, const int qbar, const int qbarHel) { if ( getCurrent(hash<1>(1,1,q,qHel,qbar,qbarHel)) ) { if ( qHel == 1 && qbarHel == 1 ) cacheCurrent(Complex(0.,1.) * minusCurrent(q,qbar)); if ( qHel == 1 && qbarHel == -1 ) cacheCurrent((Complex(0.,2.) * mass(qbar)/plusProduct(q,qbar)) * momentum(q)); if ( qHel == -1 && qbarHel == 1 ) cacheCurrent((Complex(0.,-2.) * mass(q)/minusProduct(q,qbar)) * momentum(qbar)); if ( qHel == -1 && qbarHel == -1 ) cacheCurrent((Complex(0.,1.) * mass(q) * mass(qbar)/invariant(q,qbar)) * minusCurrent(qbar,q)); } #ifdef CHECK_MatchboxCurrents checkCurrent("qqbarLeftCurrent",cachedCurrent(),momentum(q)+momentum(qbar)); #endif return cachedCurrent(); } const LorentzVector& MatchboxCurrents::qqbarRightCurrent(const int q, const int qHel, const int qbar, const int qbarHel) { if ( getCurrent(hash<1>(2,1,q,qHel,qbar,qbarHel)) ) { if ( qHel == 1 && qbarHel == 1 ) cacheCurrent((Complex(0.,1.) * mass(q) * mass(qbar)/invariant(q,qbar)) * minusCurrent(q,qbar)); if ( qHel == 1 && qbarHel == -1 ) cacheCurrent((Complex(0.,-2.) * mass(q)/plusProduct(q,qbar)) * momentum(qbar)); if ( qHel == -1 && qbarHel == 1 ) cacheCurrent((Complex(0.,2.) * mass(qbar)/minusProduct(q,qbar)) * momentum(q)); if ( qHel == -1 && qbarHel == -1 ) cacheCurrent(Complex(0.,1.) * minusCurrent(qbar,q)); } #ifdef CHECK_MatchboxCurrents checkCurrent("qqbarRightCurrent",cachedCurrent(),momentum(q)+momentum(qbar)); #endif return cachedCurrent(); } const LorentzVector& MatchboxCurrents::qqbargLeftCurrent(const int q, const int qHel, const int qbar, const int qbarHel, const int g, const int gHel) { if ( gHel == 1 ) { if ( getCurrent(hash<2>(1,1,q,qHel,qbar,qbarHel,g,gHel)) ) { // Invariant products from propagator denominators const Complex den_i = invariant(q,g) + (sqr(mass(q))/invariant(q,qbar))*invariant(qbar,g); const Complex den_j = invariant(qbar,g) + (sqr(mass(qbar))/invariant(q,qbar))*invariant(q,g); // 2*factor from the spinor definition of the negative helicity gluon // Note that the gluon is outgoing so the polarisation vector of the hel=+1 gluon is conjugated to give the hel=-1 vector const Complex cminus = sqrt(2.0) / minusProduct(g,q); if ( qHel == 1 && qbarHel == 1 ) cacheCurrent( Complex(0.,1.)*cminus*( ((sqr(mass(q))*plusProduct(qbar,g)/(plusProduct(qbar,q)*den_i)) - (minusProduct(qbar,q)*plusProduct(g,qbar)/den_j))*minusCurrent(q, qbar) - (minusProduct(g,q)*plusProduct(g,qbar)/den_j)*minusCurrent(q,g) ) ); if ( qHel == 1 && qbarHel == -1 ) - cacheCurrent( Complex(0.,1.)*cminus*(-mass(qbar)/plusProduct(qbar,q)) * ( ((sqr(mass(q))*plusProduct(qbar,g)/(plusProduct(qbar,q)*den_i)) - (plusProduct(qbar,g)*minusProduct(q,qbar)/den_j))*2*momentum(q) + (invariant(q,g)/den_j)*minusCurrent(q,g) ) ); + cacheCurrent( Complex(0.,1.)*cminus*(-mass(qbar)/plusProduct(qbar,q)) * ( ((sqr(mass(q))*plusProduct(qbar,g)/(plusProduct(qbar,q)*den_i)) - (plusProduct(qbar,g)*minusProduct(q,qbar)/den_j))*2.*momentum(q) + (invariant(q,g)/den_j)*minusCurrent(q,g) ) ); if ( qHel == -1 && qbarHel == 1 ) - cacheCurrent( Complex(0.,1.)*cminus*(mass(q)/minusProduct(qbar,q)) * ( ((sqr(mass(q))*plusProduct(g,qbar)/(plusProduct(q,qbar)*den_i)) - (plusProduct(g,qbar)*minusProduct(qbar,q)/den_j))*2*momentum(qbar) - (minusProduct(g,q)*plusProduct(g,qbar)/den_j)*minusCurrent(qbar,g) ) ); + cacheCurrent( Complex(0.,1.)*cminus*(mass(q)/minusProduct(qbar,q)) * ( ((sqr(mass(q))*plusProduct(g,qbar)/(plusProduct(q,qbar)*den_i)) - (plusProduct(g,qbar)*minusProduct(qbar,q)/den_j))*2.*momentum(qbar) - (minusProduct(g,q)*plusProduct(g,qbar)/den_j)*minusCurrent(qbar,g) ) ); if ( qHel == -1 && qbarHel == -1 ) cacheCurrent( Complex(0.,1.)*cminus*(mass(qbar)*mass(q)/(invariant(q,qbar))) * ( ((sqr(mass(q))*plusProduct(g,qbar)/(plusProduct(q,qbar)*den_i)) - (minusProduct(q,qbar)*plusProduct(qbar,g)/den_j))*minusCurrent(qbar,q) + (invariant(q,g)/den_j)*minusCurrent(qbar,g) ) ); } #ifdef CHECK_MatchboxCurrents checkCurrent("qqbargLeftCurrent",cachedCurrent(),momentum(q)+momentum(qbar)+momentum(g)); #endif return cachedCurrent(); } if ( gHel == -1 ) { if ( getCurrent(hash<2>(1,1,q,qHel,qbar,qbarHel,g,gHel)) ) { // Invariant products from propagator denominators const Complex den_i = invariant(q,g) + (sqr(mass(q))/invariant(q,qbar))*invariant(qbar,g); const Complex den_j = invariant(qbar,g) + (sqr(mass(qbar))/invariant(q,qbar))*invariant(q,g); // 2*factor from the spinor definition of the positive helicity gluon const Complex cplus = sqrt(2.0) / plusProduct(q,g); if ( qHel == 1 && qbarHel == 1 ) cacheCurrent( Complex(0.,1.)*cplus*( ((sqr(mass(q))*minusProduct(g,qbar)/(minusProduct(q,qbar)*den_i)) - (minusProduct(qbar,g)*plusProduct(q,qbar)/den_j))*minusCurrent(q, qbar) - (invariant(q,g)/den_i)*minusCurrent(g,qbar) ) ); if ( qHel == 1 && qbarHel == -1 ) - cacheCurrent( Complex(0.,1.)*cplus*(-mass(qbar)/plusProduct(qbar,q)) * ( ((sqr(mass(q))*minusProduct(g,qbar)/(minusProduct(q,qbar)*den_i)) - (plusProduct(qbar,q)*minusProduct(g,qbar)/den_j))*2*momentum(q) - (invariant(q,g)/den_i)*minusCurrent(g,q) ) ); + cacheCurrent( Complex(0.,1.)*cplus*(-mass(qbar)/plusProduct(qbar,q)) * ( ((sqr(mass(q))*minusProduct(g,qbar)/(minusProduct(q,qbar)*den_i)) - (plusProduct(qbar,q)*minusProduct(g,qbar)/den_j))*2.*momentum(q) - (invariant(q,g)/den_i)*minusCurrent(g,q) ) ); if ( qHel == -1 && qbarHel == 1 ) - cacheCurrent( Complex(0.,1.)*cplus*(mass(q)/minusProduct(qbar,q)) * ( ((sqr(mass(q))*minusProduct(qbar,g)/(minusProduct(qbar,q)*den_i)) - (minusProduct(qbar,g)*plusProduct(q,qbar)/den_j))*2*momentum(qbar) + (minusProduct(qbar,g)*plusProduct(q,g)/den_i)*minusCurrent(g,qbar) ) ); + cacheCurrent( Complex(0.,1.)*cplus*(mass(q)/minusProduct(qbar,q)) * ( ((sqr(mass(q))*minusProduct(qbar,g)/(minusProduct(qbar,q)*den_i)) - (minusProduct(qbar,g)*plusProduct(q,qbar)/den_j))*2.*momentum(qbar) + (minusProduct(qbar,g)*plusProduct(q,g)/den_i)*minusCurrent(g,qbar) ) ); if ( qHel == -1 && qbarHel == -1 ) cacheCurrent( Complex(0.,1.)*cplus*(mass(qbar)*mass(q)/(invariant(q,qbar))) * ( ((sqr(mass(q))*minusProduct(qbar,g)/(minusProduct(qbar,q)*den_i)) - (plusProduct(qbar,q)*minusProduct(g,qbar)/den_j))*minusCurrent(qbar, q) + (minusProduct(qbar,g)*plusProduct(q,g)/den_i)*minusCurrent(g,q) ) ); } #ifdef CHECK_MatchboxCurrents checkCurrent("qqbargLeftCurrent",cachedCurrent(),momentum(q)+momentum(qbar)+momentum(g)); #endif return cachedCurrent(); } return czero; } const LorentzVector& MatchboxCurrents::qqbargRightCurrent(const int q, const int qHel, const int qbar, const int qbarHel, const int g, const int gHel) { if ( gHel == 1 ) { if ( getCurrent(hash<2>(2,1,q,qHel,qbar,qbarHel,g,gHel)) ) { // Invariant products from propagator denominators const Complex den_i = invariant(q,g) + (sqr(mass(q))/invariant(q,qbar))*invariant(qbar,g); const Complex den_j = invariant(qbar,g) + (sqr(mass(qbar))/invariant(q,qbar))*invariant(q,g); // 2*factor from the spinor definition of the positive helicity gluon const Complex cminus = sqrt(2.0) / minusProduct(g,q); if ( qHel == 1 && qbarHel == 1 ) cacheCurrent( Complex(0.,1.)*cminus*(mass(qbar)*mass(q)/(invariant(q,qbar))) * ( ((sqr(mass(q))*plusProduct(qbar,g)/(plusProduct(qbar,q)*den_i)) - (minusProduct(qbar,q)*plusProduct(g,qbar)/den_j))*plusCurrent(qbar, q) + (plusProduct(qbar,g)*minusProduct(q,g)/den_i)*plusCurrent(g,q) ) ); if ( qHel == 1 && qbarHel == -1 ) - cacheCurrent( Complex(0.,1.)*cminus*(mass(q)/plusProduct(qbar,q)) * ( ((sqr(mass(q))*plusProduct(qbar,g)/(plusProduct(qbar,q)*den_i)) - (plusProduct(qbar,g)*minusProduct(q,qbar)/den_j))*2*momentum(qbar) + (plusProduct(qbar,g)*minusProduct(q,g)/den_i)*plusCurrent(g,qbar) ) ); + cacheCurrent( Complex(0.,1.)*cminus*(mass(q)/plusProduct(qbar,q)) * ( ((sqr(mass(q))*plusProduct(qbar,g)/(plusProduct(qbar,q)*den_i)) - (plusProduct(qbar,g)*minusProduct(q,qbar)/den_j))*2.*momentum(qbar) + (plusProduct(qbar,g)*minusProduct(q,g)/den_i)*plusCurrent(g,qbar) ) ); if ( qHel == -1 && qbarHel == 1 ) - cacheCurrent( Complex(0.,1.)*cminus*(-mass(qbar)/minusProduct(qbar,q)) * ( ((sqr(mass(q))*plusProduct(g,qbar)/(plusProduct(q,qbar)*den_i)) - (minusProduct(qbar,q)*plusProduct(g,qbar)/den_j))*2*momentum(q) - (invariant(q,g)/den_i)*plusCurrent(g,q) ) ); + cacheCurrent( Complex(0.,1.)*cminus*(-mass(qbar)/minusProduct(qbar,q)) * ( ((sqr(mass(q))*plusProduct(g,qbar)/(plusProduct(q,qbar)*den_i)) - (minusProduct(qbar,q)*plusProduct(g,qbar)/den_j))*2.*momentum(q) - (invariant(q,g)/den_i)*plusCurrent(g,q) ) ); if ( qHel == -1 && qbarHel == -1 ) cacheCurrent( Complex(0.,1.)*cminus*( ((sqr(mass(q))*plusProduct(g,qbar)/(plusProduct(q,qbar)*den_i)) - (plusProduct(qbar,g)*minusProduct(q,qbar)/den_j))*plusCurrent(q, qbar) - (invariant(q,g)/den_i)*plusCurrent(g,qbar) ) ); } #ifdef CHECK_MatchboxCurrents checkCurrent("qqbargRightCurrent",cachedCurrent(),momentum(q)+momentum(qbar)+momentum(g)); #endif return cachedCurrent(); } if ( gHel == -1 ) { if ( getCurrent(hash<2>(2,1,q,qHel,qbar,qbarHel,g,gHel)) ) { // Invariant products from propagator denominators const Complex den_i = invariant(q,g) + (sqr(mass(q))/invariant(q,qbar))*invariant(qbar,g); const Complex den_j = invariant(qbar,g) + (sqr(mass(qbar))/invariant(q,qbar))*invariant(q,g); // 2*factor from the spinor definition of the positive helicity gluon const Complex cplus = sqrt(2.0) / plusProduct(q,g); if ( qHel == 1 && qbarHel == 1 ) cacheCurrent( Complex(0.,1.)*cplus*(mass(qbar)*mass(q)/(invariant(q,qbar))) * ( ((sqr(mass(q))*minusProduct(g,qbar)/(minusProduct(q,qbar)*den_i)) - (plusProduct(q,qbar)*minusProduct(qbar,g)/den_j))*plusCurrent(qbar, q) + (invariant(q,g)/den_j)*plusCurrent(qbar,g) ) ); if ( qHel == 1 && qbarHel == -1 ) - cacheCurrent( Complex(0.,1.)*cplus*(mass(q)/plusProduct(qbar,q)) * ( ((sqr(mass(q))*minusProduct(g,qbar)/(minusProduct(q,qbar)*den_i)) - (minusProduct(g,qbar)*plusProduct(qbar,q)/den_j))*2*momentum(qbar) - (plusProduct(g,q)*minusProduct(g,qbar)/den_j)*plusCurrent(qbar,g) ) ); + cacheCurrent( Complex(0.,1.)*cplus*(mass(q)/plusProduct(qbar,q)) * ( ((sqr(mass(q))*minusProduct(g,qbar)/(minusProduct(q,qbar)*den_i)) - (minusProduct(g,qbar)*plusProduct(qbar,q)/den_j))*2.*momentum(qbar) - (plusProduct(g,q)*minusProduct(g,qbar)/den_j)*plusCurrent(qbar,g) ) ); if ( qHel == -1 && qbarHel == 1 ) - cacheCurrent( Complex(0.,1.)*cplus*(-mass(qbar)/minusProduct(qbar,q)) * ( ((sqr(mass(q))*minusProduct(qbar,g)/(minusProduct(qbar,q)*den_i)) - (minusProduct(qbar,g)*plusProduct(q,qbar)/den_j))*2*momentum(q) + (invariant(q,g)/den_j)*plusCurrent(q,g) ) ); + cacheCurrent( Complex(0.,1.)*cplus*(-mass(qbar)/minusProduct(qbar,q)) * ( ((sqr(mass(q))*minusProduct(qbar,g)/(minusProduct(qbar,q)*den_i)) - (minusProduct(qbar,g)*plusProduct(q,qbar)/den_j))*2.*momentum(q) + (invariant(q,g)/den_j)*plusCurrent(q,g) ) ); if ( qHel == -1 && qbarHel == -1 ) cacheCurrent( Complex(0.,1.)*cplus*( ((sqr(mass(q))*minusProduct(qbar,g)/(minusProduct(qbar,q)*den_i)) - (plusProduct(qbar,q)*minusProduct(g,qbar)/den_j))*plusCurrent(q, qbar) - (plusProduct(g,q)*minusProduct(g,qbar)/den_j)*plusCurrent(q,g) ) ); } #ifdef CHECK_MatchboxCurrents checkCurrent("qqbargRightCurrent",cachedCurrent(),momentum(q)+momentum(qbar)+momentum(g)); #endif return cachedCurrent(); } return czero; } LorentzVector MatchboxCurrents::qqbarggGeneralLeftCurrent(const int i, const int, const int j, const int, const int k, const int g1Hel, const int l, const int g2Hel, const int n) { const double ik = invariant(i,k); const double il = invariant(i,l); const double jk = invariant(j,k); const double jl = invariant(j,l); const double kl = invariant(k,l); const Complex plusP_ik = plusProduct(i,k); const Complex plusP_il = plusProduct(i,l); const Complex plusP_in = plusProduct(i,n); const Complex plusP_jk = plusProduct(j,k); const Complex plusP_jl = plusProduct(j,l); const Complex plusP_jn = plusProduct(j,n); const Complex plusP_kl = plusProduct(k,l); const Complex plusP_kn = plusProduct(k,n); const Complex plusP_ln = plusProduct(l,n); const Complex minusP_ik = minusProduct(i,k); const Complex minusP_il = minusProduct(i,l); const Complex minusP_in = minusProduct(i,n); const Complex minusP_jk = minusProduct(j,k); const Complex minusP_jl = minusProduct(j,l); const Complex minusP_jn = minusProduct(j,n); const Complex minusP_kl = minusProduct(k,l); const Complex minusP_kn = minusProduct(k,n); const Complex minusP_ln = minusProduct(l,n); const LorentzVector & minusC_ij = minusCurrent(i,j); const LorentzVector & minusC_ik = minusCurrent(i,k); const LorentzVector & minusC_il = minusCurrent(i,l); const LorentzVector & minusC_kj = minusCurrent(k,j); const LorentzVector & minusC_kl = minusCurrent(k,l); const LorentzVector & minusC_lj = minusCurrent(l,j); if ( g1Hel == 1 && g2Hel == 1 ) { return (Complex(0,-2) * plusP_jl * plusP_kl * minusC_ik)/ (jl * (jk + jl + kl)) - (Complex(0,2) * plusP_jl * plusP_kl * minusC_ik)/ (kl * (jk + jl + kl)) - (Complex(0,2) * plusP_jk * plusP_kl * minusC_il)/ (kl * (jk + jl + kl)) + (Complex(0,2) * plusP_il * plusP_kl * minusC_ij * minusP_in)/ (kl * (ik + il + kl) * minusP_kn) - (Complex(0,2) * plusP_ik * plusP_jl * minusC_il * minusP_in)/ (ik * jl * minusP_kn) + (Complex(0,2) * sqr(plusP_kl) * minusC_kj * minusP_in)/ (kl * (ik + il + kl) * minusP_kn) - (Complex(0,2) * plusP_jl * plusP_kl * minusC_ij * minusP_jn)/ (jl * (jk + jl + kl) * minusP_kn) - (Complex(0,2) * plusP_jl * plusP_kl * minusC_ij * minusP_jn)/ (kl * (jk + jl + kl) * minusP_kn) + (Complex(0,2) * plusP_jk * plusP_jl * minusC_il * minusP_jn)/ (jl * (jk + jl + kl) * minusP_kn) + (Complex(0,2) * plusP_ik * plusP_kl * minusC_ij * minusP_in)/ (kl * (ik + il + kl) * minusP_ln) - (Complex(0,2) * sqr(plusP_kl) * minusC_lj * minusP_in)/ (kl * (ik + il + kl) * minusP_ln) - (Complex(0,2) * plusP_jk * plusP_kl * minusC_ij * minusP_jn)/ (kl * (jk + jl + kl) * minusP_ln) + (Complex(0,2) * plusP_jk * plusP_jl * minusC_ik * minusP_jn)/ (jl * (jk + jl + kl) * minusP_ln) + (Complex(0,2) * plusP_ik * plusP_il * minusC_ij * sqr(minusP_in))/ (ik * (ik + il + kl) * minusP_kn * minusP_ln) + (Complex(0,2) * plusP_ik * plusP_kl * minusC_kj * sqr(minusP_in))/ (ik * (ik + il + kl) * minusP_kn * minusP_ln) - (Complex(0,2) * plusP_ik * plusP_jl * minusC_ij * minusP_in * minusP_jn)/ (ik * jl * minusP_kn * minusP_ln) + (Complex(0,2) * plusP_jk * plusP_jl * minusC_ij * sqr(minusP_jn))/ (jl * (jk + jl + kl) * minusP_kn * minusP_ln) - (Complex(0,2) * plusP_jk * plusP_kl * minusC_ik * minusP_kn)/ (kl * (jk + jl + kl) * minusP_ln) - (Complex(0,2) * plusP_jl * plusP_kl * minusC_il * minusP_ln)/ (jl * (jk + jl + kl) * minusP_kn) - (Complex(0,2) * plusP_jl * plusP_kl * minusC_il * minusP_ln)/ (kl * (jk + jl + kl) * minusP_kn); } if ( g1Hel == 1 && g2Hel == -1 ) { return (Complex(0,-2) * plusP_jk * plusP_jn * minusC_ik * minusP_jl)/ (jl * (jk + jl + kl) * plusP_ln) + (Complex(0,2) * plusP_jk * plusP_kn * minusC_ik * minusP_kl)/ (kl * (jk + jl + kl) * plusP_ln) - (Complex(0,2) * plusP_ik * plusP_in * minusC_ij * minusP_il * minusP_in)/ (ik * (ik + il + kl) * plusP_ln * minusP_kn) - (Complex(0,2) * plusP_ik * plusP_kn * minusC_kj * minusP_il * minusP_in)/ (ik * (ik + il + kl) * plusP_ln * minusP_kn) - (Complex(0,2) * plusP_ik * minusC_lj * minusP_il * minusP_in)/ (ik * (ik + il + kl) * minusP_kn) + (Complex(0,2) * plusP_ik * plusP_jn * minusC_ij * minusP_in * minusP_jl)/ (ik * jl * plusP_ln * minusP_kn) - (Complex(0,2) * plusP_jk * plusP_jn * minusC_ij * minusP_jl * minusP_jn)/ (jl * (jk + jl + kl) * plusP_ln * minusP_kn) - (Complex(0,2) * plusP_ik * plusP_kn * minusC_ij * minusP_in * minusP_kl)/ (kl * (ik + il + kl) * plusP_ln * minusP_kn) + (Complex(0,2) * plusP_kl * plusP_kn * minusC_lj * minusP_in * minusP_kl)/ (kl * (ik + il + kl) * plusP_ln * minusP_kn) + (Complex(0,2) * plusP_jk * plusP_kn * minusC_ij * minusP_jn * minusP_kl)/ (kl * (jk + jl + kl) * plusP_ln * minusP_kn) - (Complex(0,1) * plusP_ik * plusP_kn * minusC_ij * minusP_ik * minusP_ln)/ (kl * (ik + il + kl) * plusP_ln * minusP_kn) + (Complex(0,1) * plusP_kl * plusP_kn * minusC_lj * minusP_ik * minusP_ln)/ (kl * (ik + il + kl) * plusP_ln * minusP_kn) - (Complex(0,2) * plusP_in * plusP_kl * minusC_ij * minusP_il * minusP_ln)/ (kl * (ik + il + kl) * plusP_ln * minusP_kn) + (Complex(0,1) * plusP_il * plusP_kn * minusC_ij * minusP_il * minusP_ln)/ (kl * (ik + il + kl) * plusP_ln * minusP_kn) - (Complex(0,1) * plusP_kl * plusP_kn * minusC_kj * minusP_il * minusP_ln)/ (kl * (ik + il + kl) * plusP_ln * minusP_kn) - (Complex(0,2) * plusP_kl * minusC_lj * minusP_il * minusP_ln)/ (kl * (ik + il + kl) * minusP_kn) + (Complex(0,1) * plusP_jk * plusP_kn * minusC_ij * minusP_jk * minusP_ln)/ (kl * (jk + jl + kl) * plusP_ln * minusP_kn) + (Complex(0,2) * plusP_jn * plusP_kl * minusC_ij * minusP_jl * minusP_ln)/ (kl * (jk + jl + kl) * plusP_ln * minusP_kn) - (Complex(0,1) * plusP_jl * plusP_kn * minusC_ij * minusP_jl * minusP_ln)/ (kl * (jk + jl + kl) * plusP_ln * minusP_kn) - (Complex(0,2) * plusP_jk * plusP_jn * minusC_il * minusP_jl * minusP_ln)/ (jl * (jk + jl + kl) * plusP_ln * minusP_kn) + (Complex(0,2) * plusP_jn * plusP_kl * minusC_ik * minusP_kl * minusP_ln)/ (kl * (jk + jl + kl) * plusP_ln * minusP_kn) - (Complex(0,1) * plusP_jl * plusP_kn * minusC_ik * minusP_kl * minusP_ln)/ (kl * (jk + jl + kl) * plusP_ln * minusP_kn) + (Complex(0,1) * plusP_jk * plusP_kn * minusC_il * minusP_kl * minusP_ln)/ (kl * (jk + jl + kl) * plusP_ln * minusP_kn); } if ( g1Hel == -1 && g2Hel == 1 ) { return (Complex(0,2) * plusP_in * plusP_jl * minusC_il * minusP_ik)/ (ik * jl * plusP_kn) + (Complex(0,2) * plusP_jl * minusC_kl * minusP_ik)/(ik * jl) - (Complex(0,2) * plusP_jl * plusP_ln * minusC_ij * minusP_jk)/ (jl * (jk + jl + kl) * plusP_kn) + (Complex(0,2) * plusP_jl * plusP_ln * minusC_il * minusP_kl)/ (jl * (jk + jl + kl) * plusP_kn) + (Complex(0,2) * plusP_jl * plusP_ln * minusC_il * minusP_kl)/ (kl * (jk + jl + kl) * plusP_kn) - (Complex(0,2) * plusP_il * plusP_in * minusC_ij * minusP_ik * minusP_in)/ (ik * (ik + il + kl) * plusP_kn * minusP_ln) - (Complex(0,2) * plusP_in * plusP_kl * minusC_kj * minusP_ik * minusP_in)/ (ik * (ik + il + kl) * plusP_kn * minusP_ln) + (Complex(0,2) * plusP_in * plusP_jl * minusC_ij * minusP_ik * minusP_jn)/ (ik * jl * plusP_kn * minusP_ln) + (Complex(0,2) * plusP_jl * minusC_kj * minusP_ik * minusP_jn)/ (ik * jl * minusP_ln) - (Complex(0,2) * plusP_jl * plusP_jn * minusC_ij * minusP_jk * minusP_jn)/ (jl * (jk + jl + kl) * plusP_kn * minusP_ln) - (Complex(0,2) * plusP_il * plusP_ln * minusC_ij * minusP_in * minusP_kl)/ (kl * (ik + il + kl) * plusP_kn * minusP_ln) - (Complex(0,2) * plusP_kl * plusP_ln * minusC_kj * minusP_in * minusP_kl)/ (kl * (ik + il + kl) * plusP_kn * minusP_ln) + (Complex(0,2) * plusP_jl * plusP_ln * minusC_ij * minusP_jn * minusP_kl)/ (kl * (jk + jl + kl) * plusP_kn * minusP_ln) + (Complex(0,2) * plusP_jl * plusP_jn * minusC_il * minusP_jn * minusP_kl)/ (jl * (jk + jl + kl) * plusP_kn * minusP_ln) - (Complex(0,2) * plusP_il * minusC_ij * minusP_ik * minusP_kn)/ (ik * (ik + il + kl) * minusP_ln) - (Complex(0,2) * plusP_in * plusP_kl * minusC_ij * minusP_ik * minusP_kn)/ (kl * (ik + il + kl) * plusP_kn * minusP_ln) - (Complex(0,1) * plusP_ik * plusP_ln * minusC_ij * minusP_ik * minusP_kn)/ (kl * (ik + il + kl) * plusP_kn * minusP_ln) - (Complex(0,2) * plusP_kl * minusC_kj * minusP_ik * minusP_kn)/ (ik * (ik + il + kl) * minusP_ln) - (Complex(0,2) * plusP_kl * minusC_kj * minusP_ik * minusP_kn)/ (kl * (ik + il + kl) * minusP_ln) - (Complex(0,1) * plusP_kl * plusP_ln * minusC_lj * minusP_ik * minusP_kn)/ (kl * (ik + il + kl) * plusP_kn * minusP_ln) + (Complex(0,1) * plusP_il * plusP_ln * minusC_ij * minusP_il * minusP_kn)/ (kl * (ik + il + kl) * plusP_kn * minusP_ln) + (Complex(0,1) * plusP_kl * plusP_ln * minusC_kj * minusP_il * minusP_kn)/ (kl * (ik + il + kl) * plusP_kn * minusP_ln) + (Complex(0,2) * plusP_jn * plusP_kl * minusC_ij * minusP_jk * minusP_kn)/ (kl * (jk + jl + kl) * plusP_kn * minusP_ln) + (Complex(0,1) * plusP_jk * plusP_ln * minusC_ij * minusP_jk * minusP_kn)/ (kl * (jk + jl + kl) * plusP_kn * minusP_ln) - (Complex(0,1) * plusP_jl * plusP_ln * minusC_ij * minusP_jl * minusP_kn)/ (kl * (jk + jl + kl) * plusP_kn * minusP_ln) + (Complex(0,1) * plusP_jl * plusP_ln * minusC_ik * minusP_kl * minusP_kn)/ (kl * (jk + jl + kl) * plusP_kn * minusP_ln) - (Complex(0,2) * plusP_jn * plusP_kl * minusC_il * minusP_kl * minusP_kn)/ (kl * (jk + jl + kl) * plusP_kn * minusP_ln) - (Complex(0,1) * plusP_jk * plusP_ln * minusC_il * minusP_kl * minusP_kn)/ (kl * (jk + jl + kl) * plusP_kn * minusP_ln); } if ( g1Hel == -1 && g2Hel == -1 ) { return (Complex(0,2) * sqr(plusP_in) * minusC_ij * minusP_ik * minusP_il)/ (ik * (ik + il + kl) * plusP_kn * plusP_ln) + (Complex(0,2) * plusP_in * minusC_kj * minusP_ik * minusP_il)/ (ik * (ik + il + kl) * plusP_ln) + (Complex(0,2) * plusP_in * minusC_lj * minusP_ik * minusP_il)/ (ik * (ik + il + kl) * plusP_kn) - (Complex(0,2) * plusP_in * plusP_jn * minusC_ij * minusP_ik * minusP_jl)/ (ik * jl * plusP_kn * plusP_ln) - (Complex(0,2) * plusP_jn * minusC_kj * minusP_ik * minusP_jl)/ (ik * jl * plusP_ln) + (Complex(0,2) * sqr(plusP_jn) * minusC_ij * minusP_jk * minusP_jl)/ (jl * (jk + jl + kl) * plusP_kn * plusP_ln) + (Complex(0,2) * plusP_in * minusC_ij * minusP_ik * minusP_kl)/ (ik * (ik + il + kl) * plusP_ln) + (Complex(0,2) * plusP_in * minusC_ij * minusP_ik * minusP_kl)/ (kl * (ik + il + kl) * plusP_ln) + (Complex(0,2) * plusP_kn * minusC_kj * minusP_ik * minusP_kl)/ (ik * (ik + il + kl) * plusP_ln) + (Complex(0,2) * plusP_kn * minusC_kj * minusP_ik * minusP_kl)/ (kl * (ik + il + kl) * plusP_ln) + (Complex(0,2) * minusC_lj * minusP_ik * minusP_kl)/ (ik * (ik + il + kl)) + (Complex(0,2) * minusC_lj * minusP_ik * minusP_kl)/ (kl * (ik + il + kl)) + (Complex(0,2) * plusP_in * minusC_ij * minusP_il * minusP_kl)/ (kl * (ik + il + kl) * plusP_kn) + (Complex(0,2) * minusC_kj * minusP_il * minusP_kl)/ (kl * (ik + il + kl)) + (Complex(0,2) * plusP_ln * minusC_lj * minusP_il * minusP_kl)/ (kl * (ik + il + kl) * plusP_kn) - (Complex(0,2) * plusP_jn * minusC_ij * minusP_jk * minusP_kl)/ (kl * (jk + jl + kl) * plusP_ln) - (Complex(0,2) * plusP_jn * minusC_ij * minusP_jl * minusP_kl)/ (kl * (jk + jl + kl) * plusP_kn) - (Complex(0,2) * sqr(plusP_jn) * minusC_il * minusP_jl * minusP_kl)/ (jl * (jk + jl + kl) * plusP_kn * plusP_ln) - (Complex(0,2) * plusP_jn * minusC_ik * sqr(minusP_kl))/ (kl * (jk + jl + kl) * plusP_kn) + (Complex(0,2) * plusP_jn * minusC_il * sqr(minusP_kl))/ (kl * (jk + jl + kl) * plusP_ln); } return czero; } LorentzVector MatchboxCurrents::qqbarggFixedLeftCurrent(const int i, const int, const int j, const int, const int k, const int g1Hel, const int l, const int g2Hel) { const double ik = invariant(i,k); const double il = invariant(i,l); const double jk = invariant(j,k); const double jl = invariant(j,l); const double kl = invariant(k,l); const Complex plusP_ij = plusProduct(i,j); const Complex plusP_ik = plusProduct(i,k); const Complex plusP_il = plusProduct(i,l); const Complex plusP_jk = plusProduct(j,k); const Complex plusP_jl = plusProduct(j,l); const Complex plusP_kl = plusProduct(k,l); const Complex minusP_ij = minusProduct(i,j); const Complex minusP_ik = minusProduct(i,k); const Complex minusP_il = minusProduct(i,l); const Complex minusP_jk = minusProduct(j,k); const Complex minusP_jl = minusProduct(j,l); const Complex minusP_kl = minusProduct(k,l); const LorentzVector & minusC_ij = minusCurrent(i,j); const LorentzVector & minusC_ik = minusCurrent(i,k); const LorentzVector & minusC_il = minusCurrent(i,l); const LorentzVector & minusC_kj = minusCurrent(k,j); const LorentzVector & minusC_kl = minusCurrent(k,l); const LorentzVector & minusC_lj = minusCurrent(l,j); if ( g1Hel == 1 && g2Hel == 1 ) { return (Complex(0,-2) * plusP_jl * plusP_kl * minusC_ik)/ (jl * (jk + jl + kl)) - (Complex(0,2) * plusP_jl * plusP_kl * minusC_ik)/ (kl * (jk + jl + kl)) - (Complex(0,2) * plusP_jk * plusP_kl * minusC_il)/ (kl * (jk + jl + kl)) - (Complex(0,2) * plusP_jl * plusP_kl * minusC_ij * minusP_ij)/ (jl * (jk + jl + kl) * minusP_ik) - (Complex(0,2) * plusP_jl * plusP_kl * minusC_ij * minusP_ij)/ (kl * (jk + jl + kl) * minusP_ik) + (Complex(0,2) * plusP_jk * plusP_jl * minusC_il * minusP_ij)/ (jl * (jk + jl + kl) * minusP_ik) - (Complex(0,2) * plusP_jk * plusP_kl * minusC_ij * minusP_ij)/ (kl * (jk + jl + kl) * minusP_il) + (Complex(0,2) * plusP_jk * plusP_jl * minusC_ik * minusP_ij)/ (jl * (jk + jl + kl) * minusP_il) + (Complex(0,2) * plusP_jk * plusP_jl * minusC_ij * sqr(minusP_ij))/ (jl * (jk + jl + kl) * minusP_ik * minusP_il) - (Complex(0,2) * plusP_jk * plusP_kl * minusC_ik * minusP_ik)/ (kl * (jk + jl + kl) * minusP_il) - (Complex(0,2) * plusP_jl * plusP_kl * minusC_il * minusP_il)/ (jl * (jk + jl + kl) * minusP_ik) - (Complex(0,2) * plusP_jl * plusP_kl * minusC_il * minusP_il)/ (kl * (jk + jl + kl) * minusP_ik); } if ( g1Hel == 1 && g2Hel == -1 ) { return (Complex(0,-1) * sqr(plusP_ik) * minusC_ij * minusP_il)/ (kl * (ik + il + kl) * plusP_il) + (Complex(0,1) * plusP_ik * plusP_kl * minusC_lj * minusP_il)/ (kl * (ik + il + kl) * plusP_il) + (Complex(0,1) * plusP_ik * minusC_ij * sqr(minusP_il))/ (kl * (ik + il + kl) * minusP_ik) - (Complex(0,1) * plusP_ik * plusP_kl * minusC_kj * sqr(minusP_il))/ (kl * (ik + il + kl) * plusP_il * minusP_ik) - (Complex(0,2) * plusP_kl * minusC_lj * sqr(minusP_il))/ (kl * (ik + il + kl) * minusP_ik) + (Complex(0,1) * plusP_ik * plusP_jk * minusC_ij * minusP_il * minusP_jk)/ (kl * (jk + jl + kl) * plusP_il * minusP_ik) - (Complex(0,2) * plusP_ij * plusP_jk * minusC_ik * minusP_jl)/ (jl * (jk + jl + kl) * plusP_il) - (Complex(0,2) * plusP_ij * plusP_jk * minusC_ij * minusP_ij * minusP_jl)/ (jl * (jk + jl + kl) * plusP_il * minusP_ik) - (Complex(0,1) * plusP_ik * plusP_jl * minusC_ij * minusP_il * minusP_jl)/ (kl * (jk + jl + kl) * plusP_il * minusP_ik) + (Complex(0,2) * plusP_ij * plusP_kl * minusC_ij * minusP_il * minusP_jl)/ (kl * (jk + jl + kl) * plusP_il * minusP_ik) - (Complex(0,2) * plusP_ij * plusP_jk * minusC_il * minusP_il * minusP_jl)/ (jl * (jk + jl + kl) * plusP_il * minusP_ik) + (Complex(0,2) * plusP_ik * plusP_jk * minusC_ik * minusP_kl)/ (kl * (jk + jl + kl) * plusP_il) + (Complex(0,2) * plusP_ik * plusP_jk * minusC_ij * minusP_ij * minusP_kl)/ (kl * (jk + jl + kl) * plusP_il * minusP_ik) - (Complex(0,1) * plusP_ik * plusP_jl * minusC_ik * minusP_il * minusP_kl)/ (kl * (jk + jl + kl) * plusP_il * minusP_ik) + (Complex(0,2) * plusP_ij * plusP_kl * minusC_ik * minusP_il * minusP_kl)/ (kl * (jk + jl + kl) * plusP_il * minusP_ik) + (Complex(0,1) * plusP_ik * plusP_jk * minusC_il * minusP_il * minusP_kl)/ (kl * (jk + jl + kl) * plusP_il * minusP_ik); } if ( g1Hel == -1 && g2Hel == 1 ) { return (Complex(0,1) * sqr(plusP_il) * minusC_ij * minusP_ik)/ (kl * (ik + il + kl) * plusP_ik) + (Complex(0,1) * plusP_il * plusP_kl * minusC_kj * minusP_ik)/ (kl * (ik + il + kl) * plusP_ik) + (Complex(0,2) * plusP_jl * minusC_kl * minusP_ik)/(ik * jl) + (Complex(0,2) * plusP_jl * minusC_kj * minusP_ij * minusP_ik)/ (ik * jl * minusP_il) - (Complex(0,2) * plusP_il * minusC_ij * sqr(minusP_ik))/ (ik * (ik + il + kl) * minusP_il) - (Complex(0,1) * plusP_il * minusC_ij * sqr(minusP_ik))/ (kl * (ik + il + kl) * minusP_il) - (Complex(0,2) * plusP_kl * minusC_kj * sqr(minusP_ik))/ (ik * (ik + il + kl) * minusP_il) - (Complex(0,2) * plusP_kl * minusC_kj * sqr(minusP_ik))/ (kl * (ik + il + kl) * minusP_il) - (Complex(0,1) * plusP_il * plusP_kl * minusC_lj * sqr(minusP_ik))/ (kl * (ik + il + kl) * plusP_ik * minusP_il) - (Complex(0,2) * plusP_il * plusP_jl * minusC_ij * minusP_jk)/ (jl * (jk + jl + kl) * plusP_ik) - (Complex(0,2) * plusP_ij * plusP_jl * minusC_ij * minusP_ij * minusP_jk)/ (jl * (jk + jl + kl) * plusP_ik * minusP_il) + (Complex(0,1) * plusP_il * plusP_jk * minusC_ij * minusP_ik * minusP_jk)/ (kl * (jk + jl + kl) * plusP_ik * minusP_il) + (Complex(0,2) * plusP_ij * plusP_kl * minusC_ij * minusP_ik * minusP_jk)/ (kl * (jk + jl + kl) * plusP_ik * minusP_il) - (Complex(0,1) * plusP_il * plusP_jl * minusC_ij * minusP_ik * minusP_jl)/ (kl * (jk + jl + kl) * plusP_ik * minusP_il) + (Complex(0,2) * plusP_il * plusP_jl * minusC_il * minusP_kl)/ (jl * (jk + jl + kl) * plusP_ik) + (Complex(0,2) * plusP_il * plusP_jl * minusC_il * minusP_kl)/ (kl * (jk + jl + kl) * plusP_ik) + (Complex(0,2) * plusP_il * plusP_jl * minusC_ij * minusP_ij * minusP_kl)/ (kl * (jk + jl + kl) * plusP_ik * minusP_il) + (Complex(0,2) * plusP_ij * plusP_jl * minusC_il * minusP_ij * minusP_kl)/ (jl * (jk + jl + kl) * plusP_ik * minusP_il) + (Complex(0,1) * plusP_il * plusP_jl * minusC_ik * minusP_ik * minusP_kl)/ (kl * (jk + jl + kl) * plusP_ik * minusP_il) - (Complex(0,1) * plusP_il * plusP_jk * minusC_il * minusP_ik * minusP_kl)/ (kl * (jk + jl + kl) * plusP_ik * minusP_il) - (Complex(0,2) * plusP_ij * plusP_kl * minusC_il * minusP_ik * minusP_kl)/ (kl * (jk + jl + kl) * plusP_ik * minusP_il); } if ( g1Hel == -1 && g2Hel == -1 ) { return (Complex(0,-2) * plusP_ij * minusC_kj * minusP_ik * minusP_jl)/ (ik * jl * plusP_il) + (Complex(0,2) * sqr(plusP_ij) * minusC_ij * minusP_jk * minusP_jl)/ (jl * (jk + jl + kl) * plusP_ik * plusP_il) + (Complex(0,2) * plusP_ik * minusC_kj * minusP_ik * minusP_kl)/ (ik * (ik + il + kl) * plusP_il) + (Complex(0,2) * plusP_ik * minusC_kj * minusP_ik * minusP_kl)/ (kl * (ik + il + kl) * plusP_il) + (Complex(0,2) * minusC_lj * minusP_ik * minusP_kl)/ (ik * (ik + il + kl)) + (Complex(0,2) * minusC_lj * minusP_ik * minusP_kl)/ (kl * (ik + il + kl)) + (Complex(0,2) * minusC_kj * minusP_il * minusP_kl)/ (kl * (ik + il + kl)) + (Complex(0,2) * plusP_il * minusC_lj * minusP_il * minusP_kl)/ (kl * (ik + il + kl) * plusP_ik) - (Complex(0,2) * plusP_ij * minusC_ij * minusP_jk * minusP_kl)/ (kl * (jk + jl + kl) * plusP_il) - (Complex(0,2) * plusP_ij * minusC_ij * minusP_jl * minusP_kl)/ (kl * (jk + jl + kl) * plusP_ik) - (Complex(0,2) * sqr(plusP_ij) * minusC_il * minusP_jl * minusP_kl)/ (jl * (jk + jl + kl) * plusP_ik * plusP_il) - (Complex(0,2) * plusP_ij * minusC_ik * sqr(minusP_kl))/ (kl * (jk + jl + kl) * plusP_ik) + (Complex(0,2) * plusP_ij * minusC_il * sqr(minusP_kl))/ (kl * (jk + jl + kl) * plusP_il); } return czero; } LorentzVector MatchboxCurrents::qqbarggGeneralRightCurrent(const int i, const int, const int j, const int, const int k, const int g1Hel, const int l, const int g2Hel, const int n) { const double ik = invariant(i,k); const double il = invariant(i,l); const double jk = invariant(j,k); const double jl = invariant(j,l); const double kl = invariant(k,l); const Complex plusP_ik = plusProduct(i,k); const Complex plusP_il = plusProduct(i,l); const Complex plusP_in = plusProduct(i,n); const Complex plusP_jk = plusProduct(j,k); const Complex plusP_jl = plusProduct(j,l); const Complex plusP_jn = plusProduct(j,n); const Complex plusP_kl = plusProduct(k,l); const Complex plusP_kn = plusProduct(k,n); const Complex plusP_ln = plusProduct(l,n); const Complex minusP_ik = minusProduct(i,k); const Complex minusP_il = minusProduct(i,l); const Complex minusP_in = minusProduct(i,n); const Complex minusP_jk = minusProduct(j,k); const Complex minusP_jl = minusProduct(j,l); const Complex minusP_jn = minusProduct(j,n); const Complex minusP_kl = minusProduct(k,l); const Complex minusP_kn = minusProduct(k,n); const Complex minusP_ln = minusProduct(l,n); const LorentzVector & minusC_ji = minusCurrent(j,i); const LorentzVector & minusC_jk = minusCurrent(j,k); const LorentzVector & minusC_jl = minusCurrent(j,l); const LorentzVector & minusC_ki = minusCurrent(k,i); const LorentzVector & minusC_li = minusCurrent(l,i); const LorentzVector & minusC_lk = minusCurrent(l,k); if ( g1Hel == 1 && g2Hel == 1 ) { return (Complex(0,2) * plusP_il * plusP_kl * minusC_jk)/ (kl * (ik + il + kl)) + (Complex(0,2) * plusP_ik * plusP_kl * minusC_jl)/ (ik * (ik + il + kl)) + (Complex(0,2) * plusP_ik * plusP_kl * minusC_jl)/ (kl * (ik + il + kl)) + (Complex(0,2) * plusP_il * plusP_kl * minusC_ji * minusP_in)/ (kl * (ik + il + kl) * minusP_kn) + (Complex(0,2) * plusP_ik * plusP_il * minusC_jl * minusP_in)/ (ik * (ik + il + kl) * minusP_kn) - (Complex(0,2) * plusP_jl * plusP_kl * minusC_ji * minusP_jn)/ (kl * (jk + jl + kl) * minusP_kn) - (Complex(0,2) * sqr(plusP_kl) * minusC_ki * minusP_jn)/ (kl * (jk + jl + kl) * minusP_kn) + (Complex(0,2) * plusP_ik * plusP_kl * minusC_ji * minusP_in)/ (ik * (ik + il + kl) * minusP_ln) + (Complex(0,2) * plusP_ik * plusP_kl * minusC_ji * minusP_in)/ (kl * (ik + il + kl) * minusP_ln) + (Complex(0,2) * plusP_ik * plusP_il * minusC_jk * minusP_in)/ (ik * (ik + il + kl) * minusP_ln) - (Complex(0,2) * plusP_jk * plusP_kl * minusC_ji * minusP_jn)/ (kl * (jk + jl + kl) * minusP_ln) - (Complex(0,2) * plusP_ik * plusP_jl * minusC_jk * minusP_jn)/ (ik * jl * minusP_ln) + (Complex(0,2) * sqr(plusP_kl) * minusC_li * minusP_jn)/ (kl * (jk + jl + kl) * minusP_ln) + (Complex(0,2) * plusP_ik * plusP_il * minusC_ji * sqr(minusP_in))/ (ik * (ik + il + kl) * minusP_kn * minusP_ln) - (Complex(0,2) * plusP_ik * plusP_jl * minusC_ji * minusP_in * minusP_jn)/ (ik * jl * minusP_kn * minusP_ln) + (Complex(0,2) * plusP_jk * plusP_jl * minusC_ji * sqr(minusP_jn))/ (jl * (jk + jl + kl) * minusP_kn * minusP_ln) - (Complex(0,2) * plusP_jl * plusP_kl * minusC_li * sqr(minusP_jn))/ (jl * (jk + jl + kl) * minusP_kn * minusP_ln) + (Complex(0,2) * plusP_ik * plusP_kl * minusC_jk * minusP_kn)/ (ik * (ik + il + kl) * minusP_ln) + (Complex(0,2) * plusP_ik * plusP_kl * minusC_jk * minusP_kn)/ (kl * (ik + il + kl) * minusP_ln) + (Complex(0,2) * plusP_il * plusP_kl * minusC_jl * minusP_ln)/ (kl * (ik + il + kl) * minusP_kn); } if ( g1Hel == 1 && g2Hel == -1 ) { return (Complex(0,-2) * plusP_ik * plusP_kn * minusC_ji * minusP_il)/ (ik * (ik + il + kl) * plusP_ln) + (Complex(0,2) * plusP_ik * plusP_jn * minusC_jk * minusP_jl)/ (ik * jl * plusP_ln) + (Complex(0,2) * plusP_ik * minusC_lk * minusP_jl)/(ik * jl) - (Complex(0,2) * plusP_ik * plusP_kn * minusC_jk * minusP_kl)/ (ik * (ik + il + kl) * plusP_ln) - (Complex(0,2) * plusP_ik * plusP_kn * minusC_jk * minusP_kl)/ (kl * (ik + il + kl) * plusP_ln) - (Complex(0,2) * plusP_ik * plusP_in * minusC_ji * minusP_il * minusP_in)/ (ik * (ik + il + kl) * plusP_ln * minusP_kn) + (Complex(0,2) * plusP_ik * plusP_jn * minusC_ji * minusP_in * minusP_jl)/ (ik * jl * plusP_ln * minusP_kn) + (Complex(0,2) * plusP_ik * minusC_li * minusP_in * minusP_jl)/ (ik * jl * minusP_kn) - (Complex(0,2) * plusP_jk * plusP_jn * minusC_ji * minusP_jl * minusP_jn)/ (jl * (jk + jl + kl) * plusP_ln * minusP_kn) + (Complex(0,2) * plusP_jn * plusP_kl * minusC_li * minusP_jl * minusP_jn)/ (jl * (jk + jl + kl) * plusP_ln * minusP_kn) - (Complex(0,2) * plusP_ik * plusP_kn * minusC_ji * minusP_in * minusP_kl)/ (kl * (ik + il + kl) * plusP_ln * minusP_kn) - (Complex(0,2) * plusP_ik * plusP_in * minusC_jk * minusP_in * minusP_kl)/ (ik * (ik + il + kl) * plusP_ln * minusP_kn) + (Complex(0,2) * plusP_jk * plusP_kn * minusC_ji * minusP_jn * minusP_kl)/ (kl * (jk + jl + kl) * plusP_ln * minusP_kn) - (Complex(0,2) * plusP_kl * plusP_kn * minusC_li * minusP_jn * minusP_kl)/ (kl * (jk + jl + kl) * plusP_ln * minusP_kn) - (Complex(0,1) * plusP_ik * plusP_kn * minusC_ji * minusP_ik * minusP_ln)/ (kl * (ik + il + kl) * plusP_ln * minusP_kn) - (Complex(0,2) * plusP_in * plusP_kl * minusC_ji * minusP_il * minusP_ln)/ (kl * (ik + il + kl) * plusP_ln * minusP_kn) + (Complex(0,1) * plusP_il * plusP_kn * minusC_ji * minusP_il * minusP_ln)/ (kl * (ik + il + kl) * plusP_ln * minusP_kn) + (Complex(0,1) * plusP_jk * plusP_kn * minusC_ji * minusP_jk * minusP_ln)/ (kl * (jk + jl + kl) * plusP_ln * minusP_kn) - (Complex(0,1) * plusP_kl * plusP_kn * minusC_li * minusP_jk * minusP_ln)/ (kl * (jk + jl + kl) * plusP_ln * minusP_kn) - (Complex(0,2) * plusP_jk * minusC_ji * minusP_jl * minusP_ln)/ (jl * (jk + jl + kl) * minusP_kn) + (Complex(0,2) * plusP_jn * plusP_kl * minusC_ji * minusP_jl * minusP_ln)/ (kl * (jk + jl + kl) * plusP_ln * minusP_kn) - (Complex(0,1) * plusP_jl * plusP_kn * minusC_ji * minusP_jl * minusP_ln)/ (kl * (jk + jl + kl) * plusP_ln * minusP_kn) + (Complex(0,1) * plusP_kl * plusP_kn * minusC_ki * minusP_jl * minusP_ln)/ (kl * (jk + jl + kl) * plusP_ln * minusP_kn) + (Complex(0,2) * plusP_kl * minusC_li * minusP_jl * minusP_ln)/ (jl * (jk + jl + kl) * minusP_kn) + (Complex(0,2) * plusP_kl * minusC_li * minusP_jl * minusP_ln)/ (kl * (jk + jl + kl) * minusP_kn) - (Complex(0,2) * plusP_in * plusP_kl * minusC_jk * minusP_kl * minusP_ln)/ (kl * (ik + il + kl) * plusP_ln * minusP_kn) + (Complex(0,1) * plusP_il * plusP_kn * minusC_jk * minusP_kl * minusP_ln)/ (kl * (ik + il + kl) * plusP_ln * minusP_kn) - (Complex(0,1) * plusP_ik * plusP_kn * minusC_jl * minusP_kl * minusP_ln)/ (kl * (ik + il + kl) * plusP_ln * minusP_kn); } if ( g1Hel == -1 && g2Hel == 1 ) { return (Complex(0,-2) * plusP_il * plusP_in * minusC_jl * minusP_ik)/ (ik * (ik + il + kl) * plusP_kn) - (Complex(0,2) * plusP_il * plusP_ln * minusC_jl * minusP_kl)/ (kl * (ik + il + kl) * plusP_kn) - (Complex(0,2) * plusP_il * plusP_in * minusC_ji * minusP_ik * minusP_in)/ (ik * (ik + il + kl) * plusP_kn * minusP_ln) + (Complex(0,2) * plusP_in * plusP_jl * minusC_ji * minusP_ik * minusP_jn)/ (ik * jl * plusP_kn * minusP_ln) - (Complex(0,2) * plusP_jl * plusP_jn * minusC_ji * minusP_jk * minusP_jn)/ (jl * (jk + jl + kl) * plusP_kn * minusP_ln) - (Complex(0,2) * plusP_jl * minusC_ki * minusP_jk * minusP_jn)/ (jl * (jk + jl + kl) * minusP_ln) - (Complex(0,2) * plusP_jl * plusP_ln * minusC_li * minusP_jk * minusP_jn)/ (jl * (jk + jl + kl) * plusP_kn * minusP_ln) - (Complex(0,2) * plusP_il * plusP_ln * minusC_ji * minusP_in * minusP_kl)/ (kl * (ik + il + kl) * plusP_kn * minusP_ln) + (Complex(0,2) * plusP_jl * plusP_ln * minusC_ji * minusP_jn * minusP_kl)/ (kl * (jk + jl + kl) * plusP_kn * minusP_ln) + (Complex(0,2) * plusP_kl * plusP_ln * minusC_ki * minusP_jn * minusP_kl)/ (kl * (jk + jl + kl) * plusP_kn * minusP_ln) - (Complex(0,2) * plusP_in * plusP_kl * minusC_ji * minusP_ik * minusP_kn)/ (kl * (ik + il + kl) * plusP_kn * minusP_ln) - (Complex(0,1) * plusP_ik * plusP_ln * minusC_ji * minusP_ik * minusP_kn)/ (kl * (ik + il + kl) * plusP_kn * minusP_ln) - (Complex(0,2) * plusP_il * plusP_in * minusC_jk * minusP_ik * minusP_kn)/ (ik * (ik + il + kl) * plusP_kn * minusP_ln) + (Complex(0,1) * plusP_il * plusP_ln * minusC_ji * minusP_il * minusP_kn)/ (kl * (ik + il + kl) * plusP_kn * minusP_ln) + (Complex(0,2) * plusP_jn * plusP_kl * minusC_ji * minusP_jk * minusP_kn)/ (kl * (jk + jl + kl) * plusP_kn * minusP_ln) + (Complex(0,1) * plusP_jk * plusP_ln * minusC_ji * minusP_jk * minusP_kn)/ (kl * (jk + jl + kl) * plusP_kn * minusP_ln) + (Complex(0,2) * plusP_kl * minusC_ki * minusP_jk * minusP_kn)/ (kl * (jk + jl + kl) * minusP_ln) + (Complex(0,1) * plusP_kl * plusP_ln * minusC_li * minusP_jk * minusP_kn)/ (kl * (jk + jl + kl) * plusP_kn * minusP_ln) - (Complex(0,1) * plusP_jl * plusP_ln * minusC_ji * minusP_jl * minusP_kn)/ (kl * (jk + jl + kl) * plusP_kn * minusP_ln) - (Complex(0,1) * plusP_kl * plusP_ln * minusC_ki * minusP_jl * minusP_kn)/ (kl * (jk + jl + kl) * plusP_kn * minusP_ln) - (Complex(0,1) * plusP_il * plusP_ln * minusC_jk * minusP_kl * minusP_kn)/ (kl * (ik + il + kl) * plusP_kn * minusP_ln) + (Complex(0,2) * plusP_in * plusP_kl * minusC_jl * minusP_kl * minusP_kn)/ (kl * (ik + il + kl) * plusP_kn * minusP_ln) + (Complex(0,1) * plusP_ik * plusP_ln * minusC_jl * minusP_kl * minusP_kn)/ (kl * (ik + il + kl) * plusP_kn * minusP_ln); } if ( g1Hel == -1 && g2Hel == -1 ) { return (Complex(0,2) * sqr(plusP_in) * minusC_ji * minusP_ik * minusP_il)/ (ik * (ik + il + kl) * plusP_kn * plusP_ln) - (Complex(0,2) * plusP_in * plusP_jn * minusC_ji * minusP_ik * minusP_jl)/ (ik * jl * plusP_kn * plusP_ln) - (Complex(0,2) * plusP_in * minusC_li * minusP_ik * minusP_jl)/ (ik * jl * plusP_kn) + (Complex(0,2) * sqr(plusP_jn) * minusC_ji * minusP_jk * minusP_jl)/ (jl * (jk + jl + kl) * plusP_kn * plusP_ln) + (Complex(0,2) * plusP_jn * minusC_ki * minusP_jk * minusP_jl)/ (jl * (jk + jl + kl) * plusP_ln) + (Complex(0,2) * plusP_jn * minusC_li * minusP_jk * minusP_jl)/ (jl * (jk + jl + kl) * plusP_kn) + (Complex(0,2) * plusP_in * minusC_ji * minusP_ik * minusP_kl)/ (kl * (ik + il + kl) * plusP_ln) + (Complex(0,2) * sqr(plusP_in) * minusC_jk * minusP_ik * minusP_kl)/ (ik * (ik + il + kl) * plusP_kn * plusP_ln) + (Complex(0,2) * plusP_in * minusC_ji * minusP_il * minusP_kl)/ (kl * (ik + il + kl) * plusP_kn) - (Complex(0,2) * plusP_jn * minusC_ji * minusP_jk * minusP_kl)/ (kl * (jk + jl + kl) * plusP_ln) - (Complex(0,2) * plusP_kn * minusC_ki * minusP_jk * minusP_kl)/ (kl * (jk + jl + kl) * plusP_ln) - (Complex(0,2) * minusC_li * minusP_jk * minusP_kl)/ (kl * (jk + jl + kl)) - (Complex(0,2) * plusP_jn * minusC_ji * minusP_jl * minusP_kl)/ (jl * (jk + jl + kl) * plusP_kn) - (Complex(0,2) * plusP_jn * minusC_ji * minusP_jl * minusP_kl)/ (kl * (jk + jl + kl) * plusP_kn) - (Complex(0,2) * minusC_ki * minusP_jl * minusP_kl)/ (jl * (jk + jl + kl)) - (Complex(0,2) * minusC_ki * minusP_jl * minusP_kl)/ (kl * (jk + jl + kl)) - (Complex(0,2) * plusP_ln * minusC_li * minusP_jl * minusP_kl)/ (jl * (jk + jl + kl) * plusP_kn) - (Complex(0,2) * plusP_ln * minusC_li * minusP_jl * minusP_kl)/ (kl * (jk + jl + kl) * plusP_kn) + (Complex(0,2) * plusP_in * minusC_jk * sqr(minusP_kl))/ (kl * (ik + il + kl) * plusP_kn) - (Complex(0,2) * plusP_in * minusC_jl * sqr(minusP_kl))/ (kl * (ik + il + kl) * plusP_ln); } return czero; } LorentzVector MatchboxCurrents::qqbarggFixedRightCurrent(const int i, const int, const int j, const int, const int k, const int g1Hel, const int l, const int g2Hel) { const double ik = invariant(i,k); const double il = invariant(i,l); const double jk = invariant(j,k); const double jl = invariant(j,l); const double kl = invariant(k,l); const Complex plusP_ij = plusProduct(i,j); const Complex plusP_ik = plusProduct(i,k); const Complex plusP_il = plusProduct(i,l); const Complex plusP_jk = plusProduct(j,k); const Complex plusP_jl = plusProduct(j,l); const Complex plusP_kl = plusProduct(k,l); const Complex minusP_ij = minusProduct(i,j); const Complex minusP_ik = minusProduct(i,k); const Complex minusP_il = minusProduct(i,l); const Complex minusP_jk = minusProduct(j,k); const Complex minusP_jl = minusProduct(j,l); const Complex minusP_kl = minusProduct(k,l); const LorentzVector & minusC_ji = minusCurrent(j,i); const LorentzVector & minusC_jk = minusCurrent(j,k); const LorentzVector & minusC_jl = minusCurrent(j,l); const LorentzVector & minusC_ki = minusCurrent(k,i); const LorentzVector & minusC_li = minusCurrent(l,i); const LorentzVector & minusC_lk = minusCurrent(l,k); if ( g1Hel == 1 && g2Hel == 1 ) { return (Complex(0,2) * plusP_il * plusP_kl * minusC_jk)/ (kl * (ik + il + kl)) + (Complex(0,2) * plusP_ik * plusP_kl * minusC_jl)/ (ik * (ik + il + kl)) + (Complex(0,2) * plusP_ik * plusP_kl * minusC_jl)/ (kl * (ik + il + kl)) - (Complex(0,2) * plusP_jl * plusP_kl * minusC_ji * minusP_ij)/ (kl * (jk + jl + kl) * minusP_ik) - (Complex(0,2) * sqr(plusP_kl) * minusC_ki * minusP_ij)/ (kl * (jk + jl + kl) * minusP_ik) - (Complex(0,2) * plusP_jk * plusP_kl * minusC_ji * minusP_ij)/ (kl * (jk + jl + kl) * minusP_il) - (Complex(0,2) * plusP_ik * plusP_jl * minusC_jk * minusP_ij)/ (ik * jl * minusP_il) + (Complex(0,2) * sqr(plusP_kl) * minusC_li * minusP_ij)/ (kl * (jk + jl + kl) * minusP_il) + (Complex(0,2) * plusP_jk * plusP_jl * minusC_ji * sqr(minusP_ij))/ (jl * (jk + jl + kl) * minusP_ik * minusP_il) - (Complex(0,2) * plusP_jl * plusP_kl * minusC_li * sqr(minusP_ij))/ (jl * (jk + jl + kl) * minusP_ik * minusP_il) + (Complex(0,2) * plusP_ik * plusP_kl * minusC_jk * minusP_ik)/ (ik * (ik + il + kl) * minusP_il) + (Complex(0,2) * plusP_ik * plusP_kl * minusC_jk * minusP_ik)/ (kl * (ik + il + kl) * minusP_il) + (Complex(0,2) * plusP_il * plusP_kl * minusC_jl * minusP_il)/ (kl * (ik + il + kl) * minusP_ik); } if ( g1Hel == 1 && g2Hel == -1 ) { return (Complex(0,-2) * sqr(plusP_ik) * minusC_ji * minusP_il)/ (ik * (ik + il + kl) * plusP_il) - (Complex(0,1) * sqr(plusP_ik) * minusC_ji * minusP_il)/ (kl * (ik + il + kl) * plusP_il) + (Complex(0,1) * plusP_ik * minusC_ji * sqr(minusP_il))/ (kl * (ik + il + kl) * minusP_ik) + (Complex(0,1) * plusP_ik * plusP_jk * minusC_ji * minusP_il * minusP_jk)/ (kl * (jk + jl + kl) * plusP_il * minusP_ik) - (Complex(0,1) * plusP_ik * plusP_kl * minusC_li * minusP_il * minusP_jk)/ (kl * (jk + jl + kl) * plusP_il * minusP_ik) + (Complex(0,2) * plusP_ij * plusP_ik * minusC_jk * minusP_jl)/ (ik * jl * plusP_il) + (Complex(0,2) * plusP_ik * minusC_lk * minusP_jl)/(ik * jl) - (Complex(0,2) * plusP_ij * plusP_jk * minusC_ji * minusP_ij * minusP_jl)/ (jl * (jk + jl + kl) * plusP_il * minusP_ik) + (Complex(0,2) * plusP_ij * plusP_kl * minusC_li * minusP_ij * minusP_jl)/ (jl * (jk + jl + kl) * plusP_il * minusP_ik) - (Complex(0,2) * plusP_jk * minusC_ji * minusP_il * minusP_jl)/ (jl * (jk + jl + kl) * minusP_ik) - (Complex(0,1) * plusP_ik * plusP_jl * minusC_ji * minusP_il * minusP_jl)/ (kl * (jk + jl + kl) * plusP_il * minusP_ik) + (Complex(0,2) * plusP_ij * plusP_kl * minusC_ji * minusP_il * minusP_jl)/ (kl * (jk + jl + kl) * plusP_il * minusP_ik) + (Complex(0,1) * plusP_ik * plusP_kl * minusC_ki * minusP_il * minusP_jl)/ (kl * (jk + jl + kl) * plusP_il * minusP_ik) + (Complex(0,2) * plusP_kl * minusC_li * minusP_il * minusP_jl)/ (jl * (jk + jl + kl) * minusP_ik) + (Complex(0,2) * plusP_kl * minusC_li * minusP_il * minusP_jl)/ (kl * (jk + jl + kl) * minusP_ik) - (Complex(0,2) * sqr(plusP_ik) * minusC_jk * minusP_kl)/ (ik * (ik + il + kl) * plusP_il) - (Complex(0,2) * sqr(plusP_ik) * minusC_jk * minusP_kl)/ (kl * (ik + il + kl) * plusP_il) + (Complex(0,2) * plusP_ik * plusP_jk * minusC_ji * minusP_ij * minusP_kl)/ (kl * (jk + jl + kl) * plusP_il * minusP_ik) - (Complex(0,2) * plusP_ik * plusP_kl * minusC_li * minusP_ij * minusP_kl)/ (kl * (jk + jl + kl) * plusP_il * minusP_ik) + (Complex(0,1) * plusP_ik * minusC_jk * minusP_il * minusP_kl)/ (kl * (ik + il + kl) * minusP_ik) - (Complex(0,1) * sqr(plusP_ik) * minusC_jl * minusP_il * minusP_kl)/ (kl * (ik + il + kl) * plusP_il * minusP_ik); } if ( g1Hel == -1 && g2Hel == 1 ) { return (Complex(0,1) * sqr(plusP_il) * minusC_ji * minusP_ik)/ (kl * (ik + il + kl) * plusP_ik) - (Complex(0,1) * plusP_il * minusC_ji * sqr(minusP_ik))/ (kl * (ik + il + kl) * minusP_il) - (Complex(0,2) * plusP_ij * plusP_jl * minusC_ji * minusP_ij * minusP_jk)/ (jl * (jk + jl + kl) * plusP_ik * minusP_il) - (Complex(0,2) * plusP_jl * minusC_ki * minusP_ij * minusP_jk)/ (jl * (jk + jl + kl) * minusP_il) - (Complex(0,2) * plusP_il * plusP_jl * minusC_li * minusP_ij * minusP_jk)/ (jl * (jk + jl + kl) * plusP_ik * minusP_il) + (Complex(0,1) * plusP_il * plusP_jk * minusC_ji * minusP_ik * minusP_jk)/ (kl * (jk + jl + kl) * plusP_ik * minusP_il) + (Complex(0,2) * plusP_ij * plusP_kl * minusC_ji * minusP_ik * minusP_jk)/ (kl * (jk + jl + kl) * plusP_ik * minusP_il) + (Complex(0,2) * plusP_kl * minusC_ki * minusP_ik * minusP_jk)/ (kl * (jk + jl + kl) * minusP_il) + (Complex(0,1) * plusP_il * plusP_kl * minusC_li * minusP_ik * minusP_jk)/ (kl * (jk + jl + kl) * plusP_ik * minusP_il) - (Complex(0,1) * plusP_il * plusP_jl * minusC_ji * minusP_ik * minusP_jl)/ (kl * (jk + jl + kl) * plusP_ik * minusP_il) - (Complex(0,1) * plusP_il * plusP_kl * minusC_ki * minusP_ik * minusP_jl)/ (kl * (jk + jl + kl) * plusP_ik * minusP_il) - (Complex(0,2) * sqr(plusP_il) * minusC_jl * minusP_kl)/ (kl * (ik + il + kl) * plusP_ik) + (Complex(0,2) * plusP_il * plusP_jl * minusC_ji * minusP_ij * minusP_kl)/ (kl * (jk + jl + kl) * plusP_ik * minusP_il) + (Complex(0,2) * plusP_il * plusP_kl * minusC_ki * minusP_ij * minusP_kl)/ (kl * (jk + jl + kl) * plusP_ik * minusP_il) - (Complex(0,1) * sqr(plusP_il) * minusC_jk * minusP_ik * minusP_kl)/ (kl * (ik + il + kl) * plusP_ik * minusP_il) + (Complex(0,1) * plusP_il * minusC_jl * minusP_ik * minusP_kl)/ (kl * (ik + il + kl) * minusP_il); } if ( g1Hel == -1 && g2Hel == -1 ) { return (Complex(0,2) * sqr(plusP_ij) * minusC_ji * minusP_jk * minusP_jl)/ (jl * (jk + jl + kl) * plusP_ik * plusP_il) + (Complex(0,2) * plusP_ij * minusC_ki * minusP_jk * minusP_jl)/ (jl * (jk + jl + kl) * plusP_il) + (Complex(0,2) * plusP_ij * minusC_li * minusP_jk * minusP_jl)/ (jl * (jk + jl + kl) * plusP_ik) - (Complex(0,2) * plusP_ij * minusC_ji * minusP_jk * minusP_kl)/ (kl * (jk + jl + kl) * plusP_il) - (Complex(0,2) * plusP_ik * minusC_ki * minusP_jk * minusP_kl)/ (kl * (jk + jl + kl) * plusP_il) - (Complex(0,2) * minusC_li * minusP_jk * minusP_kl)/ (kl * (jk + jl + kl)) - (Complex(0,2) * plusP_ij * minusC_ji * minusP_jl * minusP_kl)/ (jl * (jk + jl + kl) * plusP_ik) - (Complex(0,2) * plusP_ij * minusC_ji * minusP_jl * minusP_kl)/ (kl * (jk + jl + kl) * plusP_ik) - (Complex(0,2) * minusC_ki * minusP_jl * minusP_kl)/ (jl * (jk + jl + kl)) - (Complex(0,2) * minusC_ki * minusP_jl * minusP_kl)/ (kl * (jk + jl + kl)) - (Complex(0,2) * plusP_il * minusC_li * minusP_jl * minusP_kl)/ (jl * (jk + jl + kl) * plusP_ik) - (Complex(0,2) * plusP_il * minusC_li * minusP_jl * minusP_kl)/ (kl * (jk + jl + kl) * plusP_ik); } return czero; } const LorentzVector& MatchboxCurrents::qqbarggLeftCurrent(const int q, const int qHel, const int qbar, const int qbarHel, const int g1, const int g1Hel, const int g2, const int g2Hel) { if ( qHel != 1 || qbarHel != 1 ) return czero; if ( getCurrent(hash<3>(1,1,q,qHel,qbar,qbarHel,g1,g1Hel,g2,g2Hel)) ) { #ifdef CHECK_MatchboxCurrents LorentzVector ni = qqbarggGeneralLeftCurrent(q,qHel,qbar,qbarHel,g1,g1Hel,g2,g2Hel,q); LorentzVector nj = qqbarggGeneralLeftCurrent(q,qHel,qbar,qbarHel,g1,g1Hel,g2,g2Hel,qbar); LorentzVector nl = qqbarggGeneralLeftCurrent(q,qHel,qbar,qbarHel,g1,g1Hel,g2,g2Hel,0); LorentzVector nlbar = qqbarggGeneralLeftCurrent(q,qHel,qbar,qbarHel,g1,g1Hel,g2,g2Hel,1); LorentzVector fixed = qqbarggFixedLeftCurrent(q,qHel,qbar,qbarHel,g1,g1Hel,g2,g2Hel); LorentzVector x1 = fixed - ni; LorentzVector x2 = fixed - nj; LorentzVector x3 = fixed - nl; LorentzVector x4 = fixed - nlbar; double c1 = real(x1.t() * conj(x1.t())) + real(x1.x() * conj(x1.x())) + real(x1.y() * conj(x1.y())) + real(x1.z() * conj(x1.z())); double c2 = real(x2.t() * conj(x2.t())) + real(x2.x() * conj(x2.x())) + real(x2.y() * conj(x2.y())) + real(x2.z() * conj(x2.z())); double c3 = real(x3.t() * conj(x3.t())) + real(x3.x() * conj(x3.x())) + real(x3.y() * conj(x3.y())) + real(x3.z() * conj(x3.z())); double c4 = real(x4.t() * conj(x4.t())) + real(x4.x() * conj(x4.x())) + real(x4.y() * conj(x4.y())) + real(x4.z() * conj(x4.z())); ostream& ncheck = checkStream("qqbarggLeftCurrentNChoice"); ncheck << (c1 != 0. ? log10(abs(c1)) : 0.) << " " << (c2 != 0. ? log10(abs(c2)) : 0.) << " " << (c3 != 0. ? log10(abs(c3)) : 0.) << " " << (c4 != 0. ? log10(abs(c4)) : 0.) << " " << "\n" << flush; #endif cacheCurrent(qqbarggFixedLeftCurrent(q,qHel,qbar,qbarHel,g1,g1Hel,g2,g2Hel)); } #ifdef CHECK_MatchboxCurrents checkCurrent("qqbarggLeftCurrent",cachedCurrent(),momentum(q)+momentum(qbar)+momentum(g1)+momentum(g2)); #endif return cachedCurrent(); } const LorentzVector& MatchboxCurrents::qqbarggRightCurrent(const int q, const int qHel, const int qbar, const int qbarHel, const int g1, const int g1Hel, const int g2, const int g2Hel) { if ( qHel != -1 || qbarHel != -1 ) return czero; if ( getCurrent(hash<3>(2,1,q,qHel,qbar,qbarHel,g1,g1Hel,g2,g2Hel)) ) { #ifdef CHECK_MatchboxCurrents LorentzVector ni = qqbarggGeneralRightCurrent(q,qHel,qbar,qbarHel,g1,g1Hel,g2,g2Hel,q); LorentzVector nj = qqbarggGeneralRightCurrent(q,qHel,qbar,qbarHel,g1,g1Hel,g2,g2Hel,qbar); LorentzVector nl = qqbarggGeneralRightCurrent(q,qHel,qbar,qbarHel,g1,g1Hel,g2,g2Hel,0); LorentzVector nlbar = qqbarggGeneralRightCurrent(q,qHel,qbar,qbarHel,g1,g1Hel,g2,g2Hel,1); LorentzVector fixed = qqbarggFixedRightCurrent(q,qHel,qbar,qbarHel,g1,g1Hel,g2,g2Hel); LorentzVector x1 = fixed - ni; LorentzVector x2 = fixed - nj; LorentzVector x3 = fixed - nl; LorentzVector x4 = fixed - nlbar; double c1 = real(x1.t() * conj(x1.t())) + real(x1.x() * conj(x1.x())) + real(x1.y() * conj(x1.y())) + real(x1.z() * conj(x1.z())); double c2 = real(x2.t() * conj(x2.t())) + real(x2.x() * conj(x2.x())) + real(x2.y() * conj(x2.y())) + real(x2.z() * conj(x2.z())); double c3 = real(x3.t() * conj(x3.t())) + real(x3.x() * conj(x3.x())) + real(x3.y() * conj(x3.y())) + real(x3.z() * conj(x3.z())); double c4 = real(x4.t() * conj(x4.t())) + real(x4.x() * conj(x4.x())) + real(x4.y() * conj(x4.y())) + real(x4.z() * conj(x4.z())); ostream& ncheck = checkStream("qqbarggRightCurrentNChoice"); ncheck << (c1 != 0. ? log10(abs(c1)) : 0.) << " " << (c2 != 0. ? log10(abs(c2)) : 0.) << " " << (c3 != 0. ? log10(abs(c3)) : 0.) << " " << (c4 != 0. ? log10(abs(c4)) : 0.) << " " << "\n" << flush; #endif cacheCurrent(qqbarggFixedRightCurrent(q,qHel,qbar,qbarHel,g1,g1Hel,g2,g2Hel)); } #ifdef CHECK_MatchboxCurrents checkCurrent("qqbarggRightCurrent",cachedCurrent(),momentum(q)+momentum(qbar)+momentum(g1)+momentum(g2)); #endif return cachedCurrent(); } const LorentzVector& MatchboxCurrents::qqbarqqbarLeftCurrent(const int q, const int qHel, const int qbar, const int qbarHel, const int k, const int kHel, const int kbar, const int kbarHel) { if ( qHel != 1 || qbarHel != 1 || abs(kHel+kbarHel) != 2 ) return czero; const int i = q; const int j = qbar; const int l = kbar; const double ik = invariant(i,k); const double il = invariant(i,l); const double jk = invariant(j,k); const double jl = invariant(j,l); const double kl = invariant(k,l); const Complex plusP_ik = plusProduct(i,k); const Complex plusP_il = plusProduct(i,l); const Complex plusP_kj = plusProduct(k,j); const Complex plusP_kl = plusProduct(k,l); const Complex plusP_lj = plusProduct(l,j); const Complex plusP_lk = plusProduct(l,k); const Complex minusP_ik = minusProduct(i,k); const Complex minusP_il = minusProduct(i,l); const Complex minusP_jk = minusProduct(j,k); const Complex minusP_jl = minusProduct(j,l); const Complex minusP_ki = minusProduct(k,i); const Complex minusP_kl = minusProduct(k,l); const Complex minusP_li = minusProduct(l,i); const Complex minusP_lk = minusProduct(l,k); const LorentzVector & minusC_ij = minusCurrent(i,j); const LorentzVector & minusC_ik = minusCurrent(i,k); const LorentzVector & minusC_il = minusCurrent(i,l); const LorentzVector & minusC_kj = minusCurrent(k,j); const LorentzVector & minusC_lj = minusCurrent(l,j); if ( kHel == 1 && kbarHel == 1 ) { if ( getCurrent(hash<4>(1,1,q,qHel,qbar,qbarHel,k,kHel,kbar,kbarHel)) ) { cacheCurrent((Complex(0.,-2.)/kl)* ((minusP_ki * plusP_il * minusC_ij+ minusP_ik * plusP_lk * minusC_kj)/ (kl+il+ik)- (minusP_jk * plusP_lj * minusC_ij+ minusP_lk * plusP_lj * minusC_il)/ (kl+jl+jk))); } #ifdef CHECK_MatchboxCurrents checkCurrent("qqbarqqbarLeftCurrent",cachedCurrent(),momentum(q)+momentum(qbar)+momentum(k)+momentum(kbar)); #endif return cachedCurrent(); } if ( kHel == -1 && kbarHel == -1 ) { if ( getCurrent(hash<4>(1,1,q,qHel,qbar,qbarHel,k,kHel,kbar,kbarHel)) ) { cacheCurrent((Complex(0.,-2.)/kl)* ((minusP_li * plusP_ik * minusC_ij+ minusP_il * plusP_kl * minusC_lj)/ (kl+il+ik)- (minusP_jl * plusP_kj * minusC_ij+ minusP_kl * plusP_kj * minusC_ik)/ (kl+jl+jk))); } #ifdef CHECK_MatchboxCurrents checkCurrent("qqbarqqbarLeftCurrent",cachedCurrent(),momentum(q)+momentum(qbar)+momentum(k)+momentum(kbar)); #endif return cachedCurrent(); } return czero; } const LorentzVector& MatchboxCurrents::qqbarqqbarRightCurrent(const int q, const int qHel, const int qbar, const int qbarHel, const int k, const int kHel, const int kbar, const int kbarHel) { if ( qHel != -1 || qbarHel != -1 || abs(kHel+kbarHel) != 2 ) return czero; const int i = q; const int j = qbar; const int l = kbar; const double ik = invariant(i,k); const double il = invariant(i,l); const double jk = invariant(j,k); const double jl = invariant(j,l); const double kl = invariant(k,l); const Complex plusP_ik = plusProduct(i,k); const Complex plusP_il = plusProduct(i,l); const Complex plusP_ki = plusProduct(k,i); const Complex plusP_kj = plusProduct(k,j); const Complex plusP_kl = plusProduct(k,l); const Complex plusP_li = plusProduct(l,i); const Complex plusP_lj = plusProduct(l,j); const Complex plusP_lk = plusProduct(l,k); const Complex minusP_jk = minusProduct(j,k); const Complex minusP_jl = minusProduct(j,l); const Complex minusP_ki = minusProduct(k,i); const Complex minusP_kl = minusProduct(k,l); const Complex minusP_li = minusProduct(l,i); const Complex minusP_lk = minusProduct(l,k); const LorentzVector & minusC_ji = minusCurrent(j,i); const LorentzVector & minusC_jk = minusCurrent(j,k); const LorentzVector & minusC_jl = minusCurrent(j,l); const LorentzVector & minusC_ki = minusCurrent(k,i); const LorentzVector & minusC_li = minusCurrent(l,i); if ( kHel == 1 && kbarHel == 1 ) { if ( getCurrent(hash<4>(2,1,q,qHel,qbar,qbarHel,k,kHel,kbar,kbarHel)) ) { cacheCurrent((Complex(0.,-2.)/kl)* ((minusP_ki * plusP_il * minusC_ji+ minusP_lk * plusP_li * minusC_jl)/ (kl+il+ik)- (minusP_jk * plusP_lj * minusC_ji+ minusP_jk * plusP_lk * minusC_ki)/ (kl+jl+jk))); } #ifdef CHECK_MatchboxCurrents checkCurrent("qqbarqqbarRightCurrent",cachedCurrent(),momentum(q)+momentum(qbar)+momentum(k)+momentum(kbar)); #endif return cachedCurrent(); } if ( kHel == -1 && kbarHel == -1 ) { if ( getCurrent(hash<4>(2,1,q,qHel,qbar,qbarHel,k,kHel,kbar,kbarHel)) ) { cacheCurrent((Complex(0.,-2.)/kl)* ((minusP_li * plusP_ik * minusC_ji+ minusP_kl * plusP_ki * minusC_jk)/ (kl+il+ik)- (minusP_jl * plusP_kj * minusC_ji+ minusP_jl * plusP_kl * minusC_li)/ (kl+jl+jk))); } #ifdef CHECK_MatchboxCurrents checkCurrent("qqbarqqbarRightCurrent",cachedCurrent(),momentum(q)+momentum(qbar)+momentum(k)+momentum(kbar)); #endif return cachedCurrent(); } return czero; } // Definition of sqrt to enable calculation of the sqrt of a negative double inline Complex sqrt1 (double a) { if (a > 0.) { return Complex(sqrt(a), 0.) ;} else if (a < 0.) { return Complex(0., sqrt(abs(a))) ;} else { return Complex(0., 0.); } } // Definition of sqrt to enable calculation of the sqrt of Complex arguments inline Complex sqrt1 (Complex a) { const double real_part = sqrt(abs(a))*cos(0.5*arg(a)); const double imag_part = sqrt(abs(a))*sin(0.5*arg(a)); return Complex(real_part, imag_part) ; } // Definition of log to enable continuation of the log of a negative double inline Complex log1 (double a) { if (a < 0.) { return Complex(log(abs(a)), Constants::pi) ;} else { return Complex(log(a), 0.) ;} } // Definition of log to enable continuation of the log of a Complex argument with a negative real part inline Complex log1 (Complex a) { return Complex(log(abs(a)), arg(a)) ; } const LorentzVector& MatchboxCurrents::qqbarLeftOneLoopCurrent(const int q, const int qHel, const int qbar, const int qbarHel) { // Note this cannot currently handle the case of one massive quark and one massless quark assert( (mass(q) == 0 && mass(qbar) == 0) || (mass(q) != 0 && mass(qbar) != 0) ); // Massless quarks if ( mass(q) == 0 && mass(qbar) == 0 ) { if ( qHel != 1 || qbarHel != 1 ) return czero; const LorentzVector& tree = qqbarLeftCurrent(q,qHel,qbar,qbarHel); if ( getCurrent(hash<1>(1,2,q,qHel,qbar,qbarHel)) ) { cacheCurrent( 0.5*CF*( -8. - 3.*log1(-1./invariant(q,qbar)) - sqr(log1(-1./invariant(q,qbar))) ) * tree ); } #ifdef CHECK_MatchboxCurrents checkCurrent("qqbarLeftOneLoopCurrent",cachedCurrent(),momentum(q)+momentum(qbar)); #endif return cachedCurrent(); } // Massive quarks else { const LorentzVector& momQ = momentum(q) + (sqr(mass(q))/invariant(q,qbar))*momentum(qbar); const LorentzVector& momQbar = momentum(qbar) + (sqr(mass(qbar))/invariant(q,qbar))*momentum(q); const Complex s = (momQ+momQbar).dot(momQ+momQbar); const Complex inv12 = s - sqr(mass(q)) - sqr(mass(qbar)); // Coefficient of the left-handed born-level current - const Complex coeffLeftTree = -1.0*log1(1./sqr(mass(q)))-1.0*log1(1./sqr(mass(qbar)))-4.0 + 0.5*((2.*log1(sqr(mass(q))/sqr(mass(qbar)))*(0.5*inv12+sqr(mass(q))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))-(2.*inv12*Li2(0.5-(0.25*inv12)/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))-(0.5*sqr(mass(qbar)))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(2.*inv12*Li2((0.5*(0.5*inv12+sqr(mass(q))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))-(1.*inv12*log1(-((0.5*inv12+sqr(mass(q))-1.*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))))*log1(-((1.*inv12+sqr(mass(q))+sqr(mass(qbar)))/(0.5*inv12+sqr(mass(q))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(2.*inv12*log1((2*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar))))*log1((-0.5*inv12-1.*sqr(mass(qbar))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(0.5*inv12+sqr(mass(q))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(1.*inv12*log1((1.*inv12+sqr(mass(q))+sqr(mass(qbar)))/(0.5*inv12+sqr(mass(qbar))-1.*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))*log1((0.5*inv12+sqr(mass(qbar))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(0.5*inv12*sqr(log1(-((0.5*inv12+sqr(mass(q))-1.*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(0.5*inv12*sqr(log1((1.*inv12+sqr(mass(q))+sqr(mass(qbar)))/(0.5*inv12+sqr(mass(qbar))-1.*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))-(0.5*inv12*sqr(log1(-((1.*inv12+sqr(mass(q))+sqr(mass(qbar)))/(0.5*inv12+sqr(mass(q))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))-(0.5*inv12*sqr(log1((0.5*inv12+sqr(mass(qbar))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(4*log1((-1.*mass(q)*mass(qbar))/(0.5*inv12+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))*(-0.25*(3+2*log1(1./(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))))*sqr(inv12)+sqr(mass(q))*sqr(mass(qbar))-0.5*inv12*(1.+log1(1./(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))))*(sqr(mass(q))+sqr(mass(qbar)))))/((1.*inv12+sqr(mass(q))+sqr(mass(qbar)))*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))); + const Complex coeffLeftTree = -1.0*log1(1./sqr(mass(q)))-1.0*log1(1./sqr(mass(qbar)))-4.0 + 0.5*((2.*log1(sqr(mass(q))/sqr(mass(qbar)))*(0.5*inv12+sqr(mass(q))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))-(2.*inv12*Li2(0.5-(0.25*inv12)/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))-(0.5*sqr(mass(qbar)))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(2.*inv12*Li2((0.5*(0.5*inv12+sqr(mass(q))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))-(1.*inv12*log1(-((0.5*inv12+sqr(mass(q))-1.*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))))*log1(-((1.*inv12+sqr(mass(q))+sqr(mass(qbar)))/(0.5*inv12+sqr(mass(q))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(2.*inv12*log1((2.*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar))))*log1((-0.5*inv12-1.*sqr(mass(qbar))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(0.5*inv12+sqr(mass(q))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(1.*inv12*log1((1.*inv12+sqr(mass(q))+sqr(mass(qbar)))/(0.5*inv12+sqr(mass(qbar))-1.*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))*log1((0.5*inv12+sqr(mass(qbar))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(0.5*inv12*sqr(log1(-((0.5*inv12+sqr(mass(q))-1.*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(0.5*inv12*sqr(log1((1.*inv12+sqr(mass(q))+sqr(mass(qbar)))/(0.5*inv12+sqr(mass(qbar))-1.*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))-(0.5*inv12*sqr(log1(-((1.*inv12+sqr(mass(q))+sqr(mass(qbar)))/(0.5*inv12+sqr(mass(q))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))-(0.5*inv12*sqr(log1((0.5*inv12+sqr(mass(qbar))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(4.*log1((-1.*mass(q)*mass(qbar))/(0.5*inv12+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))*(-0.25*(3.+2.*log1(1./(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))))*sqr(inv12)+sqr(mass(q))*sqr(mass(qbar))-0.5*inv12*(1.+log1(1./(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))))*(sqr(mass(q))+sqr(mass(qbar)))))/((1.*inv12+sqr(mass(q))+sqr(mass(qbar)))*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))); // Coefficient of the right-handed born-level current - const Complex coeffRightTree = (2*log1((-1.*mass(q)*mass(qbar))/(0.5*inv12+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))*mass(q)*mass(qbar))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))); + const Complex coeffRightTree = (2.*log1((-1.*mass(q)*mass(qbar))/(0.5*inv12+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))*mass(q)*mass(qbar))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))); const LorentzVector& leftTree = qqbarLeftCurrent(q,qHel,qbar,qbarHel); const LorentzVector& rightTree = qqbarRightCurrent(q,qHel,qbar,qbarHel); if ( getCurrent(hash<1>(1,2,q,qHel,qbar,qbarHel)) ) { if ( qHel == 1 && qbarHel == 1 ) { cacheCurrent( 0.5*CF*( coeffLeftTree*leftTree + coeffRightTree*rightTree) ); } if ( qHel == 1 && qbarHel == -1 ) { // Coefficients of the left and right handed products of massive spinors const LorentzVector& coeffLeftProd = ( (mass(qbar)*(-2.*(momQ+momQbar)*(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))+log1(sqr(mass(q))/sqr(mass(qbar)))*(1.*inv12*(2.*momQ+momQbar)+(3.*momQ+2.*momQbar)*sqr(mass(q))+momQ*sqr(mass(qbar)))-(2.*log1((-1.*mass(q)*mass(qbar))/(0.5*inv12+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))*(0.5*(2.*momQ+momQbar)*sqr(inv12)-momQbar*sqr(mass(q))*sqr(mass(qbar))+0.5*inv12*((5.*momQ+2.*momQbar)*sqr(mass(q))+momQ*sqr(mass(qbar)))+(2.*momQ+momQbar)*sqr(sqr(mass(q)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))/sqr(1.*inv12+sqr(mass(q))+sqr(mass(qbar))) ); const LorentzVector& coeffRightProd = ( (mass(q)*(2.*(momQ+momQbar)*(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))+log1(sqr(mass(q))/sqr(mass(qbar)))*(1.*inv12*(momQ+2.*momQbar)+momQbar*sqr(mass(q))+(2.*momQ+3.*momQbar)*sqr(mass(qbar)))+(2.*log1((-1.*mass(q)*mass(qbar))/(0.5*inv12+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))*(0.5*(momQ+2.*momQbar)*sqr(inv12)-momQ*sqr(mass(q))*sqr(mass(qbar))+0.5*inv12*(momQbar*sqr(mass(q))+(2.*momQ+5.*momQbar)*sqr(mass(qbar)))+(momQ+2.*momQbar)*sqr(sqr(mass(qbar)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))/sqr(1.*inv12+sqr(mass(q))+sqr(mass(qbar))) ); const Complex leftProd = Complex(0.,1.) * minusProduct(q,qbar); const Complex rightProd = Complex(0.,1.) * mass(q)*mass(qbar)/plusProduct(q,qbar); cacheCurrent( 0.5*CF*( coeffLeftTree*leftTree + coeffRightTree*rightTree + coeffLeftProd*leftProd + coeffRightProd*rightProd ) ); } if ( qHel == -1 && qbarHel == 1 ){ // Coefficients of the left and right handed products of massive spinors const LorentzVector& coeffLeftProd = ( (mass(qbar)*(-2.*(momQ+momQbar)*(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))+log1(sqr(mass(q))/sqr(mass(qbar)))*(1.*inv12*(2.*momQ+momQbar)+(3.*momQ+2.*momQbar)*sqr(mass(q))+momQ*sqr(mass(qbar)))-(2.*log1((-1.*mass(q)*mass(qbar))/(0.5*inv12+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))*(0.5*(2.*momQ+momQbar)*sqr(inv12)-momQbar*sqr(mass(q))*sqr(mass(qbar))+0.5*inv12*((5.*momQ+2.*momQbar)*sqr(mass(q))+momQ*sqr(mass(qbar)))+(2.*momQ+momQbar)*sqr(sqr(mass(q)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))/sqr(1.*inv12+sqr(mass(q))+sqr(mass(qbar))) ); const LorentzVector& coeffRightProd = ( (mass(q)*(2.*(momQ+momQbar)*(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))+log1(sqr(mass(q))/sqr(mass(qbar)))*(1.*inv12*(momQ+2.*momQbar)+momQbar*sqr(mass(q))+(2.*momQ+3.*momQbar)*sqr(mass(qbar)))+(2.*log1((-1.*mass(q)*mass(qbar))/(0.5*inv12+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))*(0.5*(momQ+2.*momQbar)*sqr(inv12)-momQ*sqr(mass(q))*sqr(mass(qbar))+0.5*inv12*(momQbar*sqr(mass(q))+(2.*momQ+5.*momQbar)*sqr(mass(qbar)))+(momQ+2.*momQbar)*sqr(sqr(mass(qbar)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))/sqr(1.*inv12+sqr(mass(q))+sqr(mass(qbar))) ); const Complex leftProd = Complex(0.,1.) * mass(q)*mass(qbar)/minusProduct(q,qbar); const Complex rightProd = Complex(0.,1.) * plusProduct(q,qbar); cacheCurrent( 0.5*CF*( coeffLeftTree*leftTree + coeffRightTree*rightTree + coeffLeftProd*leftProd + coeffRightProd*rightProd ) ); } if ( qHel == -1 && qbarHel == -1 ){ cacheCurrent( 0.5*CF*( coeffLeftTree*leftTree + coeffRightTree*rightTree ) ); } } #ifdef CHECK_MatchboxCurrents checkCurrent("qqbarLeftOneLoopCurrent",cachedCurrent(),momentum(q)+momentum(qbar)); #endif return cachedCurrent(); } } const LorentzVector& MatchboxCurrents::qqbarRightOneLoopCurrent(const int q, const int qHel, const int qbar, const int qbarHel) { // Note this cannot currently handle the case of one massive quark and one massless quark assert( (mass(q) == 0 && mass(qbar) == 0) || (mass(q) != 0 && mass(qbar) != 0) ); // Massless quarks if ( mass(q) == 0 && mass(qbar) ==0 ) { if ( qHel != -1 || qbarHel != -1 ) return czero; const LorentzVector& tree = qqbarRightCurrent(q,qHel,qbar,qbarHel); if ( getCurrent(hash<1>(2,2,q,qHel,qbar,qbarHel)) ) { cacheCurrent( 0.5*CF*( -8. - 3.*log1(-1./invariant(q,qbar)) - sqr(log1(-1./invariant(q,qbar))) ) * tree ); } #ifdef CHECK_MatchboxCurrents checkCurrent("qqbarRightOneLoopCurrent",cachedCurrent(),momentum(q)+momentum(qbar)); #endif return cachedCurrent(); } // Massive quarks else { const LorentzVector& momQ = momentum(q) + (sqr(mass(q))/invariant(q,qbar))*momentum(qbar); const LorentzVector& momQbar = momentum(qbar) + (sqr(mass(qbar))/invariant(q,qbar))*momentum(q); const Complex s = (momQ+momQbar).dot(momQ+momQbar); const Complex inv12 = s - sqr(mass(q)) - sqr(mass(qbar)); // Coefficient of the right-handed born-level current - const Complex coeffRightTree = -1.0*log1(1./sqr(mass(q)))-1.0*log1(1./sqr(mass(qbar)))-4.0 + 0.5*((2.*log1(sqr(mass(q))/sqr(mass(qbar)))*(0.5*inv12+sqr(mass(q))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))-(2.*inv12*Li2(0.5-(0.25*inv12)/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))-(0.5*sqr(mass(qbar)))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(2.*inv12*Li2((0.5*(0.5*inv12+sqr(mass(q))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))-(1.*inv12*log1(-((0.5*inv12+sqr(mass(q))-1.*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))))*log1(-((1.*inv12+sqr(mass(q))+sqr(mass(qbar)))/(0.5*inv12+sqr(mass(q))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(2.*inv12*log1((2*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar))))*log1((-0.5*inv12-1.*sqr(mass(qbar))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(0.5*inv12+sqr(mass(q))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(1.*inv12*log1((1.*inv12+sqr(mass(q))+sqr(mass(qbar)))/(0.5*inv12+sqr(mass(qbar))-1.*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))*log1((0.5*inv12+sqr(mass(qbar))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(0.5*inv12*sqr(log1(-((0.5*inv12+sqr(mass(q))-1.*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(0.5*inv12*sqr(log1((1.*inv12+sqr(mass(q))+sqr(mass(qbar)))/(0.5*inv12+sqr(mass(qbar))-1.*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))-(0.5*inv12*sqr(log1(-((1.*inv12+sqr(mass(q))+sqr(mass(qbar)))/(0.5*inv12+sqr(mass(q))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))-(0.5*inv12*sqr(log1((0.5*inv12+sqr(mass(qbar))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(4*log1((-1.*mass(q)*mass(qbar))/(0.5*inv12+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))*(-0.25*(3+2*log1(1./(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))))*sqr(inv12)+sqr(mass(q))*sqr(mass(qbar))-0.5*inv12*(1.+log1(1./(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))))*(sqr(mass(q))+sqr(mass(qbar)))))/((1.*inv12+sqr(mass(q))+sqr(mass(qbar)))*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))); + const Complex coeffRightTree = -1.0*log1(1./sqr(mass(q)))-1.0*log1(1./sqr(mass(qbar)))-4.0 + 0.5*((2.*log1(sqr(mass(q))/sqr(mass(qbar)))*(0.5*inv12+sqr(mass(q))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))-(2.*inv12*Li2(0.5-(0.25*inv12)/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))-(0.5*sqr(mass(qbar)))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(2.*inv12*Li2((0.5*(0.5*inv12+sqr(mass(q))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))-(1.*inv12*log1(-((0.5*inv12+sqr(mass(q))-1.*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))))*log1(-((1.*inv12+sqr(mass(q))+sqr(mass(qbar)))/(0.5*inv12+sqr(mass(q))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(2.*inv12*log1((2.*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar))))*log1((-0.5*inv12-1.*sqr(mass(qbar))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(0.5*inv12+sqr(mass(q))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(1.*inv12*log1((1.*inv12+sqr(mass(q))+sqr(mass(qbar)))/(0.5*inv12+sqr(mass(qbar))-1.*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))*log1((0.5*inv12+sqr(mass(qbar))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(0.5*inv12*sqr(log1(-((0.5*inv12+sqr(mass(q))-1.*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(0.5*inv12*sqr(log1((1.*inv12+sqr(mass(q))+sqr(mass(qbar)))/(0.5*inv12+sqr(mass(qbar))-1.*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))-(0.5*inv12*sqr(log1(-((1.*inv12+sqr(mass(q))+sqr(mass(qbar)))/(0.5*inv12+sqr(mass(q))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))-(0.5*inv12*sqr(log1((0.5*inv12+sqr(mass(qbar))+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))/(1.*inv12+sqr(mass(q))+sqr(mass(qbar))))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))+(4.*log1((-1.*mass(q)*mass(qbar))/(0.5*inv12+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))*(-0.25*(3.+2.*log1(1./(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))))*sqr(inv12)+sqr(mass(q))*sqr(mass(qbar))-0.5*inv12*(1.+log1(1./(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))))*(sqr(mass(q))+sqr(mass(qbar)))))/((1.*inv12+sqr(mass(q))+sqr(mass(qbar)))*sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))))); // Coefficient of the left-handed born-level current - const Complex coeffLeftTree = (2*log1((-1.*mass(q)*mass(qbar))/(0.5*inv12+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))*mass(q)*mass(qbar))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))); + const Complex coeffLeftTree = (2.*log1((-1.*mass(q)*mass(qbar))/(0.5*inv12+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))*mass(q)*mass(qbar))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar))); const LorentzVector& leftTree = qqbarLeftCurrent(q,qHel,qbar,qbarHel); const LorentzVector& rightTree = qqbarRightCurrent(q,qHel,qbar,qbarHel); if ( getCurrent(hash<1>(2,2,q,qHel,qbar,qbarHel)) ) { if ( qHel == 1 && qbarHel == 1 ) { cacheCurrent( 0.5*CF*( coeffLeftTree*leftTree + coeffRightTree*rightTree ) ); } if ( qHel == 1 && qbarHel == -1 ) { // Coefficients of the right and left handed products of massive spinors const LorentzVector& coeffRightProd = ( (mass(qbar)*(-2.*(momQ+momQbar)*(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))+log1(sqr(mass(q))/sqr(mass(qbar)))*(1.*inv12*(2.*momQ+momQbar)+(3.*momQ+2.*momQbar)*sqr(mass(q))+momQ*sqr(mass(qbar)))-(2.*log1((-1.*mass(q)*mass(qbar))/(0.5*inv12+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))*(0.5*(2.*momQ+momQbar)*sqr(inv12)-momQbar*sqr(mass(q))*sqr(mass(qbar))+0.5*inv12*((5.*momQ+2.*momQbar)*sqr(mass(q))+momQ*sqr(mass(qbar)))+(2.*momQ+momQbar)*sqr(sqr(mass(q)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))/sqr(1.*inv12+sqr(mass(q))+sqr(mass(qbar))) ); const LorentzVector& coeffLeftProd = ( (mass(q)*(2.*(momQ+momQbar)*(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))+log1(sqr(mass(q))/sqr(mass(qbar)))*(1.*inv12*(momQ+2.*momQbar)+momQbar*sqr(mass(q))+(2.*momQ+3.*momQbar)*sqr(mass(qbar)))+(2.*log1((-1.*mass(q)*mass(qbar))/(0.5*inv12+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))*(0.5*(momQ+2.*momQbar)*sqr(inv12)-momQ*sqr(mass(q))*sqr(mass(qbar))+0.5*inv12*(momQbar*sqr(mass(q))+(2.*momQ+5.*momQbar)*sqr(mass(qbar)))+(momQ+2.*momQbar)*sqr(sqr(mass(qbar)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))/sqr(1.*inv12+sqr(mass(q))+sqr(mass(qbar))) ); const Complex leftProd = Complex(0.,1.) * minusProduct(q,qbar); const Complex rightProd = Complex(0.,1.) * mass(q)*mass(qbar)/plusProduct(q,qbar); cacheCurrent( 0.5*CF*( coeffLeftTree*leftTree + coeffRightTree*rightTree + coeffLeftProd*leftProd + coeffRightProd*rightProd ) ); } if ( qHel == -1 && qbarHel == 1 ){ // Coefficients of the right and left handed products of massive spinors const LorentzVector& coeffRightProd = ( (mass(qbar)*(-2.*(momQ+momQbar)*(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))+log1(sqr(mass(q))/sqr(mass(qbar)))*(1.*inv12*(2.*momQ+momQbar)+(3.*momQ+2.*momQbar)*sqr(mass(q))+momQ*sqr(mass(qbar)))-(2.*log1((-1.*mass(q)*mass(qbar))/(0.5*inv12+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))*(0.5*(2.*momQ+momQbar)*sqr(inv12)-momQbar*sqr(mass(q))*sqr(mass(qbar))+0.5*inv12*((5.*momQ+2.*momQbar)*sqr(mass(q))+momQ*sqr(mass(qbar)))+(2.*momQ+momQbar)*sqr(sqr(mass(q)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))/sqr(1.*inv12+sqr(mass(q))+sqr(mass(qbar))) ); const LorentzVector& coeffLeftProd = ( (mass(q)*(2.*(momQ+momQbar)*(1.*inv12+sqr(mass(q))+sqr(mass(qbar)))+log1(sqr(mass(q))/sqr(mass(qbar)))*(1.*inv12*(momQ+2.*momQbar)+momQbar*sqr(mass(q))+(2.*momQ+3.*momQbar)*sqr(mass(qbar)))+(2.*log1((-1.*mass(q)*mass(qbar))/(0.5*inv12+sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))*(0.5*(momQ+2.*momQbar)*sqr(inv12)-momQ*sqr(mass(q))*sqr(mass(qbar))+0.5*inv12*(momQbar*sqr(mass(q))+(2.*momQ+5.*momQbar)*sqr(mass(qbar)))+(momQ+2.*momQbar)*sqr(sqr(mass(qbar)))))/sqrt1(0.25*sqr(inv12)-sqr(mass(q))*sqr(mass(qbar)))))/sqr(1.*inv12+sqr(mass(q))+sqr(mass(qbar))) ); const Complex leftProd = Complex(0.,1.) * mass(q)*mass(qbar)/minusProduct(q,qbar); const Complex rightProd = Complex(0.,1.) * plusProduct(q,qbar); cacheCurrent( 0.5*CF*( coeffLeftTree*leftTree + coeffRightTree*rightTree + coeffLeftProd*leftProd + coeffRightProd*rightProd ) ); } if ( qHel == -1 && qbarHel == -1 ){ cacheCurrent( 0.5*CF*( coeffLeftTree*leftTree + coeffRightTree*rightTree ) ); } } #ifdef CHECK_MatchboxCurrents checkCurrent("qqbarRightOneLoopCurrent",cachedCurrent(),momentum(q)+momentum(qbar)); #endif return cachedCurrent(); } } // ln(s(a+i0)) inline Complex log(double s, double a) { return s < 0. ? Complex(log(abs(a)),-pi * theta(a)) : Complex(log(abs(a)),pi * theta(-a)); } // ln(s(a+i0)/(b+i0)) inline Complex log(double s, double a, double b) { return s < 0. ? Complex(log(abs(a/b)),-pi * theta(a/b) * sign(b-a)) : Complex(log(abs(a/b)),pi * theta(-a/b) * sign(b-a)); } // Li2(-(a+i0)/(b+i0)) inline Complex Li2(double a, double b) { if ( -a/b < 1. ) return Complex(Herwig::Math::ReLi2(-a/b),0.0); return Complex(Herwig::Math::ReLi2(-a/b),-pi * log(-a/b) * sign(b-a)); } Complex MatchboxCurrents::box6(const int i, const int j, const int k) { const double sij = invariant(i,j); const double sik = invariant(i,k); const double sjk = invariant(j,k); return -( Li2(sik+sjk,sij) + Li2(sik+sij,sjk) + 0.5 * csqr(log(1.,sij,sjk)) + sqr(pi)/6. )/8.; } void MatchboxCurrents::qqbargLoopCoefficients(const int i, const int j, const int k) { // use a dummy cache entry to check if we need to get some work done static Complex dummy; if ( getAmplitude(hash<5>(1,2,i,0,j,0,k,0)) ) { dummy = 0.; cacheAmplitude(dummy); cachedAmplitude(); } else { cachedAmplitude(); return; } qqbargLoops.resize(13); // get the transcendentals const double ij = invariant(i,j); const double ij2 = sqr(ij); const double ij3 = ij2 * ij; const double ik = invariant(i,k); const double ik2 = sqr(ik); //const double ik3 = ik2 * ik; const double jk = invariant(j,k); const double jk2 = sqr(jk); const double jk3 = jk2 * jk; const double ij_ik = ij + ik; const double ij_ik_2 = sqr(ij_ik); const double ij_jk = ij + jk; const double ij_jk_2 = sqr(ij_jk); const double ik_jk = ik + jk; const double ik_jk_2 = sqr(ik_jk); const double Q2 = ij + ik + jk; // checked for LEP that virtuals + I operator are mu2 independent //double xmu2 = 10 * GeV2/sqr(amplitudeScale()); const double xmu2 = 1.; const Complex Lijk = log(1.,-xmu2/Q2); const Complex Lij = log(1.,Q2,ij); const Complex Lik = log(1.,Q2,ik); const Complex Ljk = log(1.,Q2,jk); const Complex Box6ijk = box6(i,j,k); const Complex Box6ikj = box6(i,k,j); const Complex Box6jik = box6(j,i,k); // get the coefficients qqbargLoops[0] = ( (2 * CF * ij2) - (32 * CA * Box6ijk * ij2) + (64 * CF * Box6ijk * ij2) - (8 * CA * Box6jik * ij2) + (16 * CF * Box6jik * ij2) + (2 * CA * Lij * ij2) - (4 * CF * Lij * ij2) - (CA * Lik * ij2) - (2 * CF * Lik * ij2) - (4 * CF * Ljk * ij2) - (16 * CA * Box6ijk * ij3) / ik + (32 * CF * Box6ijk * ij3) / ik + (CA * Lij * ij3) / ik - (2 * CF * Lij * ij3) / ik + (2 * CF * ij * ik) - (16 * CA * Box6ijk * ij * ik) + (32 * CF * Box6ijk * ij * ik) - (16 * CA * Box6jik * ij * ik) + (32 * CF * Box6jik * ij * ik) + (CA * Lij * ij * ik) - (2 * CF * Lij * ij * ik) - (2 * CA * Lik * ij * ik) - (4 * CF * Lik * ij * ik) - (4 * CF * Ljk * ij * ik) - (8 * CA * Box6jik * ik2) + (16 * CF * Box6jik * ik2) - (CA * Lik * ik2) - (2 * CF * Lik * ik2) - (8 * CA * Box6jik * ij3) / jk + (16 * CF * Box6jik * ij3) / jk - (16 * CA * Box6jik * ij2 * ik) / jk + (32 * CF * Box6jik * ij2 * ik) / jk - (8 * CA * Box6jik * ij * ik2) / jk + (16 * CF * Box6jik * ij * ik2) / jk + (2 * CF * ij * jk) - (40 * CA * Box6ijk * ij * jk) + (80 * CF * Box6ijk * ij * jk) + (24 * CA * Box6ikj * ij * jk) + (2 * CA * Lij * ij * jk) - (4 * CF * Lij * ij * jk) - (CA * Lik * ij * jk) - (4 * CF * Lik * ij * jk) - (12 * CF * Ljk * ij * jk) - (8 * CA * Box6ijk * ij3 * jk) / ik2 + (16 * CF * Box6ijk * ij3 * jk) / ik2 - (32 * CA * Box6ijk * ij2 * jk) / ik + (64 * CF * Box6ijk * ij2 * jk) / ik + (CA * Lij * ij2 * jk) / ik - (2 * CF * Lij * ij2 * jk) / ik + (CA * Ljk * ij2 * jk) / ik - (2 * CF * Ljk * ij2 * jk) / ik + (2 * CF * ik * jk) - (16 * CA * Box6ijk * ik * jk) + (32 * CF * Box6ijk * ik * jk) + (48 * CA * Box6ikj * ik * jk) + (CA * Lij * ik * jk) - (2 * CF * Lij * ik * jk) - (2 * CA * Lik * ik * jk) - (8 * CF * Lik * ik * jk) - (CA * Ljk * ik * jk) - (8 * CF * Ljk * ik * jk) + (24 * CA * Box6ikj * ik2 * jk) / ij - (CA * Lik * ik2 * jk) / ij - (4 * CF * Lik * ik2 * jk) / ij - (8 * CA * Box6ijk * jk2) + (16 * CF * Box6ijk * jk2) + (24 * CA * Box6ikj * jk2) - (8 * CF * Ljk * jk2) - (8 * CA * Box6ijk * ij2 * jk2) / ik2 + (16 * CF * Box6ijk * ij2 * jk2) / ik2 - (16 * CA * Box6ijk * ij * jk2) / ik + (32 * CF * Box6ijk * ij * jk2) / ik + (CA * Ljk * ij * jk2) / ik - (2 * CF * Ljk * ij * jk2) / ik + (48 * CA * Box6ikj * ik * jk2) / ij - (CA * Ljk * ik * jk2) / ij - (4 * CF * Ljk * ik * jk2) / ij + (24 * CA * Box6ikj * ik2 * jk2) / ij2 ) / (ij_ik_2 * ij_jk); qqbargLoops[1] = ( (-2 * CF * ij2) + (8 * CA * Box6ijk * ij2) - (16 * CF * Box6ijk * ij2) + (32 * CA * Box6jik * ij2) - (64 * CF * Box6jik * ij2) - (2 * CA * Lij * ij2) + (4 * CF * Lij * ij2) + (4 * CF * Lik * ij2) + (CA * Ljk * ij2) + (2 * CF * Ljk * ij2) + (8 * CA * Box6ijk * ij3) / ik - (16 * CF * Box6ijk * ij3) / ik - (2 * CF * ij * ik) - (24 * CA * Box6ikj * ij * ik) + (40 * CA * Box6jik * ij * ik) - (80 * CF * Box6jik * ij * ik) - (2 * CA * Lij * ij * ik) + (4 * CF * Lij * ij * ik) + (12 * CF * Lik * ij * ik) + (CA * Ljk * ij * ik) + (4 * CF * Ljk * ij * ik) - (24 * CA * Box6ikj * ik2) + (8 * CA * Box6jik * ik2) - (16 * CF * Box6jik * ik2) + (8 * CF * Lik * ik2) + (8 * CA * Box6jik * ij3 * ik) / jk2 - (16 * CF * Box6jik * ij3 * ik) / jk2 + (8 * CA * Box6jik * ij2 * ik2) / jk2 - (16 * CF * Box6jik * ij2 * ik2) / jk2 + (16 * CA * Box6jik * ij3) / jk - (32 * CF * Box6jik * ij3) / jk - (CA * Lij * ij3) / jk + (2 * CF * Lij * ij3) / jk + (32 * CA * Box6jik * ij2 * ik) / jk - (64 * CF * Box6jik * ij2 * ik) / jk - (CA * Lij * ij2 * ik) / jk + (2 * CF * Lij * ij2 * ik) / jk - (CA * Lik * ij2 * ik) / jk + (2 * CF * Lik * ij2 * ik) / jk + (16 * CA * Box6jik * ij * ik2) / jk - (32 * CF * Box6jik * ij * ik2) / jk - (CA * Lik * ij * ik2) / jk + (2 * CF * Lik * ij * ik2) / jk - (2 * CF * ij * jk) + (16 * CA * Box6ijk * ij * jk) - (32 * CF * Box6ijk * ij * jk) + (16 * CA * Box6jik * ij * jk) - (32 * CF * Box6jik * ij * jk) - (CA * Lij * ij * jk) + (2 * CF * Lij * ij * jk) + (4 * CF * Lik * ij * jk) + (2 * CA * Ljk * ij * jk) + (4 * CF * Ljk * ij * jk) + (16 * CA * Box6ijk * ij2 * jk) / ik - (32 * CF * Box6ijk * ij2 * jk) / ik - (2 * CF * ik * jk) - (48 * CA * Box6ikj * ik * jk) + (16 * CA * Box6jik * ik * jk) - (32 * CF * Box6jik * ik * jk) - (CA * Lij * ik * jk) + (2 * CF * Lij * ik * jk) + (CA * Lik * ik * jk) + (8 * CF * Lik * ik * jk) + (2 * CA * Ljk * ik * jk) + (8 * CF * Ljk * ik * jk) - (48 * CA * Box6ikj * ik2 * jk) / ij + (CA * Lik * ik2 * jk) / ij + (4 * CF * Lik * ik2 * jk) / ij + (8 * CA * Box6ijk * jk2) - (16 * CF * Box6ijk * jk2) + (CA * Ljk * jk2) + (2 * CF * Ljk * jk2) + (8 * CA * Box6ijk * ij * jk2) / ik - (16 * CF * Box6ijk * ij * jk2) / ik - (24 * CA * Box6ikj * ik * jk2) / ij + (CA * Ljk * ik * jk2) / ij + (4 * CF * Ljk * ik * jk2) / ij - (24 * CA * Box6ikj * ik2 * jk2) / ij2 ) / (ij_ik * ij_jk_2); qqbargLoops[2] = -3 * CF * Lijk + ( (-4 * CA * Box6jik * ij3) + (8 * CF * Box6jik * ij3) + (CA * Lij * ij3) / 2. - (CF * Lij * ij3) + (CA * ij2 * ik) - (9 * CF * ij2 * ik) + (8 * CA * Box6ijk * ij2 * ik) - (16 * CF * Box6ijk * ij2 * ik) - (8 * CA * Box6ikj * ij2 * ik) - (8 * CA * Box6jik * ij2 * ik) + (16 * CF * Box6jik * ij2 * ik) + (CA * Lij * ij2 * ik) / 2. - (CF * Lij * ij2 * ik) + (CA * Lik * ij2 * ik) / 2. - (CF * Lik * ij2 * ik) + (CA * ij * ik2) - (9 * CF * ij * ik2) + (8 * CA * Box6ijk * ij * ik2) - (16 * CF * Box6ijk * ij * ik2) - (8 * CA * Box6ikj * ij * ik2) - (4 * CA * Box6jik * ij * ik2) + (8 * CF * Box6jik * ij * ik2) + (CA * Lik * ij * ik2) / 2. - (CF * Lik * ij * ik2) - (4 * CA * Box6jik * ij3 * ik) / jk + (8 * CF * Box6jik * ij3 * ik) / jk - (4 * CA * Box6jik * ij2 * ik2) / jk + (8 * CF * Box6jik * ij2 * ik2) / jk + (CA * ij2 * jk) - (9 * CF * ij2 * jk) + (12 * CA * Box6ijk * ij2 * jk) - (24 * CF * Box6ijk * ij2 * jk) - (8 * CA * Box6ikj * ij2 * jk) - (4 * CA * Box6jik * ij2 * jk) + (8 * CF * Box6jik * ij2 * jk) + (CA * Lik * ij2 * jk) / 2. - (CF * Lik * ij2 * jk) - (CA * Ljk * ij2 * jk) / 2. + (CF * Ljk * ij2 * jk) + (4 * CA * Box6ijk * ij3 * jk) / ik - (8 * CF * Box6ijk * ij3 * jk) / ik - (CA * Lij * ij3 * jk) / (2. * ik) + (CF * Lij * ij3 * jk) / ik + (2 * CA * ij * ik * jk) - (18 * CF * ij * ik * jk) + (16 * CA * Box6ijk * ij * ik * jk) - (32 * CF * Box6ijk * ij * ik * jk) - (28 * CA * Box6ikj * ij * ik * jk) - (4 * CA * Box6jik * ij * ik * jk) + (8 * CF * Box6jik * ij * ik * jk) + (CA * Lij * ij * ik * jk) / 2. - (CF * Lij * ij * ik * jk) + (CA * Lik * ij * ik * jk) - (CF * Lik * ij * ik * jk) - (CA * Ljk * ij * ik * jk) / 2. + (3 * CF * Ljk * ij * ik * jk) + (CA * ik2 * jk) - (9 * CF * ik2 * jk) + (8 * CA * Box6ijk * ik2 * jk) - (16 * CF * Box6ijk * ik2 * jk) - (20 * CA * Box6ikj * ik2 * jk) + (CA * Lik * ik2 * jk) / 2. + (CA * ij * jk2) - (9 * CF * ij * jk2) + (12 * CA * Box6ijk * ij * jk2) - (24 * CF * Box6ijk * ij * jk2) - (20 * CA * Box6ikj * ij * jk2) - (CA * Lij * ij * jk2) / 2. + (CF * Lij * ij * jk2) + (CA * Lik * ij * jk2) / 2. - (CA * Ljk * ij * jk2) + (4 * CF * Ljk * ij * jk2) + (4 * CA * Box6ijk * ij3 * jk2) / ik2 - (8 * CF * Box6ijk * ij3 * jk2) / ik2 + (8 * CA * Box6ijk * ij2 * jk2) / ik - (16 * CF * Box6ijk * ij2 * jk2) / ik - (CA * Lij * ij2 * jk2) / (2. * ik) + (CF * Lij * ij2 * jk2) / ik - (CA * Ljk * ij2 * jk2) / (2. * ik) + (CF * Ljk * ij2 * jk2) / ik + (CA * ik * jk2) - (9 * CF * ik * jk2) + (8 * CA * Box6ijk * ik * jk2) - (16 * CF * Box6ijk * ik * jk2) - (32 * CA * Box6ikj * ik * jk2) + (CA * Lik * ik * jk2) / 2. - (CA * Ljk * ik * jk2) / 2. + (3 * CF * Ljk * ik * jk2) - (12 * CA * Box6ikj * ik2 * jk2) / ij - (12 * CA * Box6ikj * jk3) - (CA * Ljk * jk3) / 2. + (3 * CF * Ljk * jk3) + (4 * CA * Box6ijk * ij2 * jk3) / ik2 - (8 * CF * Box6ijk * ij2 * jk3) / ik2 + (4 * CA * Box6ijk * ij * jk3) / ik - (8 * CF * Box6ijk * ij * jk3) / ik - (CA * Ljk * ij * jk3) / (2. * ik) + (CF * Ljk * ij * jk3) / ik - (12 * CA * Box6ikj * ik * jk3) / ij ) / (ij_ik * ij_jk * ik_jk); qqbargLoops[3] = 3 * CF * Lijk + ( (8 * CF * ij2) - (8 * CA * Box6ijk * ij2) + (16 * CF * Box6ijk * ij2) + (8 * CA * Box6ikj * ij2) - (8 * CA * Box6jik * ij2) + (16 * CF * Box6jik * ij2) + (CA * Lij * ij2) / 2. - (CF * Lij * ij2) + (8 * CF * ij * ik) - (8 * CA * Box6ijk * ij * ik) + (16 * CF * Box6ijk * ij * ik) + (8 * CA * Box6ikj * ij * ik) - (12 * CA * Box6jik * ij * ik) + (24 * CF * Box6jik * ij * ik) + (CA * Lij * ij * ik) / 2. - (CF * Lij * ij * ik) + (CA * Lik * ij * ik) / 2. - (CF * Lik * ij * ik) - (4 * CA * Box6jik * ik2) + (8 * CF * Box6jik * ik2) + (CA * Lik * ik2) / 2. - (CF * Lik * ik2) - (4 * CA * Box6jik * ij2 * ik) / jk + (8 * CF * Box6jik * ij2 * ik) / jk - (4 * CA * Box6jik * ij * ik2) / jk + (8 * CF * Box6jik * ij * ik2) / jk + (8 * CF * ij * jk) - (12 * CA * Box6ijk * ij * jk) + (24 * CF * Box6ijk * ij * jk) + (8 * CA * Box6ikj * ij * jk) - (8 * CA * Box6jik * ij * jk) + (16 * CF * Box6jik * ij * jk) + (CA * Lij * ij * jk) / 2. - (CF * Lij * ij * jk) + (CA * Ljk * ij * jk) / 2. - (CF * Ljk * ij * jk) - (4 * CA * Box6ijk * ij2 * jk) / ik + (8 * CF * Box6ijk * ij2 * jk) / ik + (8 * CF * ik * jk) - (8 * CA * Box6ijk * ik * jk) + (16 * CF * Box6ijk * ik * jk) - (4 * CA * Box6ikj * ik * jk) - (8 * CA * Box6jik * ik * jk) + (16 * CF * Box6jik * ik * jk) + (CA * Lij * ik * jk) / 2. - (CF * Lij * ik * jk) + (CA * Lik * ik * jk) / 2. + (2 * CF * Lik * ik * jk) + (CA * Ljk * ik * jk) / 2. + (2 * CF * Ljk * ik * jk) - (12 * CA * Box6ikj * ik2 * jk) / ij + (CA * Lik * ik2 * jk) / (2. * ij) + (2 * CF * Lik * ik2 * jk) / ij - (4 * CA * Box6ijk * jk2) + (8 * CF * Box6ijk * jk2) + (CA * Ljk * jk2) / 2. - (CF * Ljk * jk2) - (4 * CA * Box6ijk * ij * jk2) / ik + (8 * CF * Box6ijk * ij * jk2) / ik - (12 * CA * Box6ikj * ik * jk2) / ij + (CA * Ljk * ik * jk2) / (2. * ij) + (2 * CF * Ljk * ik * jk2) / ij - (12 * CA * Box6ikj * ik2 * jk2) / ij2 ) / (ij_ik * ij_jk); qqbargLoops[4] = -3 * CF * Lijk + ( (-8 * CF * ij2) + (8 * CA * Box6ijk * ij2) - (16 * CF * Box6ijk * ij2) - (8 * CA * Box6ikj * ij2) + (8 * CA * Box6jik * ij2) - (16 * CF * Box6jik * ij2) - (CA * Lij * ij2) / 2. + (CF * Lij * ij2) - (8 * CF * ij * ik) + (8 * CA * Box6ijk * ij * ik) - (16 * CF * Box6ijk * ij * ik) - (8 * CA * Box6ikj * ij * ik) + (12 * CA * Box6jik * ij * ik) - (24 * CF * Box6jik * ij * ik) - (CA * Lij * ij * ik) / 2. + (CF * Lij * ij * ik) - (CA * Lik * ij * ik) / 2. + (CF * Lik * ij * ik) + (4 * CA * Box6jik * ik2) - (8 * CF * Box6jik * ik2) - (CA * Lik * ik2) / 2. + (CF * Lik * ik2) + (4 * CA * Box6jik * ij2 * ik) / jk - (8 * CF * Box6jik * ij2 * ik) / jk + (4 * CA * Box6jik * ij * ik2) / jk - (8 * CF * Box6jik * ij * ik2) / jk - (8 * CF * ij * jk) + (12 * CA * Box6ijk * ij * jk) - (24 * CF * Box6ijk * ij * jk) - (8 * CA * Box6ikj * ij * jk) + (8 * CA * Box6jik * ij * jk) - (16 * CF * Box6jik * ij * jk) - (CA * Lij * ij * jk) / 2. + (CF * Lij * ij * jk) - (CA * Ljk * ij * jk) / 2. + (CF * Ljk * ij * jk) + (4 * CA * Box6ijk * ij2 * jk) / ik - (8 * CF * Box6ijk * ij2 * jk) / ik - (8 * CF * ik * jk) + (8 * CA * Box6ijk * ik * jk) - (16 * CF * Box6ijk * ik * jk) + (4 * CA * Box6ikj * ik * jk) + (8 * CA * Box6jik * ik * jk) - (16 * CF * Box6jik * ik * jk) - (CA * Lij * ik * jk) / 2. + (CF * Lij * ik * jk) - (CA * Lik * ik * jk) / 2. - (2 * CF * Lik * ik * jk) - (CA * Ljk * ik * jk) / 2. - (2 * CF * Ljk * ik * jk) + (12 * CA * Box6ikj * ik2 * jk) / ij - (CA * Lik * ik2 * jk) / (2. * ij) - (2 * CF * Lik * ik2 * jk) / ij + (4 * CA * Box6ijk * jk2) - (8 * CF * Box6ijk * jk2) - (CA * Ljk * jk2) / 2. + (CF * Ljk * jk2) + (4 * CA * Box6ijk * ij * jk2) / ik - (8 * CF * Box6ijk * ij * jk2) / ik + (12 * CA * Box6ikj * ik * jk2) / ij - (CA * Ljk * ik * jk2) / (2. * ij) - (2 * CF * Ljk * ik * jk2) / ij + (12 * CA * Box6ikj * ik2 * jk2) / ij2 ) / (ij_ik * ij_jk); qqbargLoops[5] = 3 * CF * Lijk + ( (-4 * CA * Box6jik * ij2) + (8 * CF * Box6jik * ij2) + (CA * Lij * ij2) / 2. - (CF * Lij * ij2) - (CA * ij * ik) + (9 * CF * ij * ik) - (8 * CA * Box6ijk * ij * ik) + (16 * CF * Box6ijk * ij * ik) + (8 * CA * Box6ikj * ij * ik) - (4 * CA * Box6jik * ij * ik) + (8 * CF * Box6jik * ij * ik) + (CA * Lij * ij * ik) / 2. - (CF * Lij * ij * ik) + (CA * Lik * ij * ik) / 2. - (CF * Lik * ij * ik) - (CA * ik2) + (9 * CF * ik2) - (8 * CA * Box6ijk * ik2) + (16 * CF * Box6ijk * ik2) + (8 * CA * Box6ikj * ik2) + (CA * Lik * ik2) / 2. - (CF * Lik * ik2) - (4 * CA * Box6jik * ij2 * ik) / jk + (8 * CF * Box6jik * ij2 * ik) / jk - (4 * CA * Box6jik * ij * ik2) / jk + (8 * CF * Box6jik * ij * ik2) / jk - (CA * ij * jk) + (9 * CF * ij * jk) - (4 * CA * Box6ijk * ij * jk) + (8 * CF * Box6ijk * ij * jk) + (8 * CA * Box6ikj * ij * jk) - (CA * Lij * ij * jk) / 2. + (CF * Lij * ij * jk) + (CA * Lik * ij * jk) / 2. - (CF * Lik * ij * jk) - (CA * Ljk * ij * jk) / 2. + (CF * Ljk * ij * jk) + (4 * CA * Box6ijk * ij2 * jk) / ik - (8 * CF * Box6ijk * ij2 * jk) / ik - (CA * Lij * ij2 * jk) / (2. * ik) + (CF * Lij * ij2 * jk) / ik - (CA * ik * jk) + (9 * CF * ik * jk) - (8 * CA * Box6ijk * ik * jk) + (16 * CF * Box6ijk * ik * jk) + (20 * CA * Box6ikj * ik * jk) + (CA * Lik * ik * jk) / 2. - (CF * Lik * ik * jk) - (CA * Ljk * ik * jk) / 2. - (2 * CF * Ljk * ik * jk) + (12 * CA * Box6ikj * ik2 * jk) / ij + (12 * CA * Box6ikj * jk2) - (CA * Ljk * jk2) / 2. - (2 * CF * Ljk * jk2) + (4 * CA * Box6ijk * ij2 * jk2) / ik2 - (8 * CF * Box6ijk * ij2 * jk2) / ik2 + (4 * CA * Box6ijk * ij * jk2) / ik - (8 * CF * Box6ijk * ij * jk2) / ik - (CA * Ljk * ij * jk2) / (2. * ik) + (CF * Ljk * ij * jk2) / ik + (12 * CA * Box6ikj * ik * jk2) / ij ) / (ij_ik * ik_jk); qqbargLoops[6] = ( (-2 * CF * ij) + (32 * CA * Box6ijk * ij) - (64 * CF * Box6ijk * ij) - (4 * CA * Lij * ij) + (8 * CF * Lij * ij) + (4 * CF * Ljk * ij) + (16 * CA * Box6ijk * ij2) / ik - (32 * CF * Box6ijk * ij2) / ik - (2 * CA * Lij * ij2) / ik + (4 * CF * Lij * ij2) / ik - (2 * CF * ik) + (16 * CA * Box6ijk * ik) - (32 * CF * Box6ijk * ik) - (2 * CA * Lij * ik) + (4 * CF * Lij * ik) + (4 * CF * Ljk * ik) + (16 * CA * Box6ijk * jk) - (32 * CF * Box6ijk * jk) - (2 * CA * Ljk * jk) + (6 * CF * Ljk * jk) + (16 * CA * Box6ijk * ij2 * jk) / ik2 - (32 * CF * Box6ijk * ij2 * jk) / ik2 + (32 * CA * Box6ijk * ij * jk) / ik - (64 * CF * Box6ijk * ij * jk) / ik - (2 * CA * Ljk * ij * jk) / ik + (4 * CF * Ljk * ij * jk) / ik ) / ij_ik_2; qqbargLoops[7] = ( (8 * CA * Box6jik * ij) - (16 * CF * Box6jik * ij) + (CA * Lij * ij) - (2 * CF * Lij * ij) + (CA * Lik * ij) + (2 * CF * Lik * ij) + (CA * Lij * ij2) / ik - (2 * CF * Lij * ij2) / ik + (8 * CA * Box6jik * ik) - (16 * CF * Box6jik * ik) + (CA * Lik * ik) + (2 * CF * Lik * ik) + (8 * CA * Box6jik * ij2) / jk - (16 * CF * Box6jik * ij2) / jk + (8 * CA * Box6jik * ij * ik) / jk - (16 * CF * Box6jik * ij * ik) / jk - (24 * CA * Box6ikj * jk) + (CA * Lij * jk) - (2 * CF * Lij * jk) + (CA * Lik * jk) + (4 * CF * Lik * jk) + (CA * Ljk * jk) + (4 * CF * Ljk * jk) - (8 * CA * Box6ijk * ij2 * jk) / ik2 + (16 * CF * Box6ijk * ij2 * jk) / ik2 - (8 * CA * Box6ijk * ij * jk) / ik + (16 * CF * Box6ijk * ij * jk) / ik + (CA * Lij * ij * jk) / ik - (2 * CF * Lij * ij * jk) / ik + (CA * Ljk * ij * jk) / ik - (2 * CF * Ljk * ij * jk) / ik - (24 * CA * Box6ikj * ik * jk) / ij + (CA * Lik * ik * jk) / ij + (4 * CF * Lik * ik * jk) / ij - (24 * CA * Box6ikj * jk2) / ij + (CA * Ljk * jk2) / ij + (4 * CF * Ljk * jk2) / ij - (8 * CA * Box6ijk * ij * jk2) / ik2 + (16 * CF * Box6ijk * ij * jk2) / ik2 - (8 * CA * Box6ijk * jk2) / ik + (16 * CF * Box6ijk * jk2) / ik + (CA * Ljk * jk2) / ik - (2 * CF * Ljk * jk2) / ik - (24 * CA * Box6ikj * ik * jk2) / ij2 ) / (ij_ik * ij_jk); qqbargLoops[8] = ( (-8 * CA * Box6ijk * ij) + (16 * CF * Box6ijk * ij) - (CA * Lij * ij) + (2 * CF * Lij * ij) - (CA * Ljk * ij) - (2 * CF * Ljk * ij) - (8 * CA * Box6ijk * ij2) / ik + (16 * CF * Box6ijk * ij2) / ik + (24 * CA * Box6ikj * ik) - (CA * Lij * ik) + (2 * CF * Lij * ik) - (CA * Lik * ik) - (4 * CF * Lik * ik) - (CA * Ljk * ik) - (4 * CF * Ljk * ik) + (24 * CA * Box6ikj * ik2) / ij - (CA * Lik * ik2) / ij - (4 * CF * Lik * ik2) / ij + (8 * CA * Box6jik * ij2 * ik) / jk2 - (16 * CF * Box6jik * ij2 * ik) / jk2 + (8 * CA * Box6jik * ij * ik2) / jk2 - (16 * CF * Box6jik * ij * ik2) / jk2 - (CA * Lij * ij2) / jk + (2 * CF * Lij * ij2) / jk + (8 * CA * Box6jik * ij * ik) / jk - (16 * CF * Box6jik * ij * ik) / jk - (CA * Lij * ij * ik) / jk + (2 * CF * Lij * ij * ik) / jk - (CA * Lik * ij * ik) / jk + (2 * CF * Lik * ij * ik) / jk + (8 * CA * Box6jik * ik2) / jk - (16 * CF * Box6jik * ik2) / jk - (CA * Lik * ik2) / jk + (2 * CF * Lik * ik2) / jk - (8 * CA * Box6ijk * jk) + (16 * CF * Box6ijk * jk) - (CA * Ljk * jk) - (2 * CF * Ljk * jk) - (8 * CA * Box6ijk * ij * jk) / ik + (16 * CF * Box6ijk * ij * jk) / ik + (24 * CA * Box6ikj * ik * jk) / ij - (CA * Ljk * ik * jk) / ij - (4 * CF * Ljk * ik * jk) / ij + (24 * CA * Box6ikj * ik2 * jk) / ij2 ) / (ij_ik * ij_jk); qqbargLoops[9] = ( (2 * CF * ij) - (32 * CA * Box6jik * ij) + (64 * CF * Box6jik * ij) + (4 * CA * Lij * ij) - (8 * CF * Lij * ij) - (4 * CF * Lik * ij) - (16 * CA * Box6jik * ik) + (32 * CF * Box6jik * ik) + (2 * CA * Lik * ik) - (6 * CF * Lik * ik) - (16 * CA * Box6jik * ij2 * ik) / jk2 + (32 * CF * Box6jik * ij2 * ik) / jk2 - (16 * CA * Box6jik * ij2) / jk + (32 * CF * Box6jik * ij2) / jk + (2 * CA * Lij * ij2) / jk - (4 * CF * Lij * ij2) / jk - (32 * CA * Box6jik * ij * ik) / jk + (64 * CF * Box6jik * ij * ik) / jk + (2 * CA * Lik * ij * ik) / jk - (4 * CF * Lik * ij * ik) / jk + (2 * CF * jk) - (16 * CA * Box6jik * jk) + (32 * CF * Box6jik * jk) + (2 * CA * Lij * jk) - (4 * CF * Lij * jk) - (4 * CF * Lik * jk) ) / ij_jk_2; qqbargLoops[10] = ( (-8 * CA * Box6ijk * ij2 * jk) + (16 * CF * Box6ijk * ij2 * jk) + (2 * CA * Lij * ij2 * jk) - (4 * CF * Lij * ij2 * jk) - (CA * ij * ik * jk) + (2 * CF * ij * ik * jk) - (8 * CA * Box6ijk * ij * ik * jk) + (16 * CF * Box6ijk * ij * ik * jk) + (3 * CA * Lij * ij * ik * jk) - (6 * CF * Lij * ij * ik * jk) + (CA * Ljk * ij * ik * jk) - (2 * CF * Ljk * ij * ik * jk) - (CA * ik2 * jk) + (2 * CF * ik2 * jk) + (CA * Lij * ik2 * jk) - (2 * CF * Lij * ik2 * jk) + (CA * Ljk * ik2 * jk) - (CF * Ljk * ik2 * jk) - (CA * ij * jk2) + (2 * CF * ij * jk2) - (16 * CA * Box6ijk * ij * jk2) + (32 * CF * Box6ijk * ij * jk2) + (2 * CA * Lij * ij * jk2) - (4 * CF * Lij * ij * jk2) + (2 * CA * Ljk * ij * jk2) - (4 * CF * Ljk * ij * jk2) - (16 * CA * Box6ijk * ij2 * jk2) / ik + (32 * CF * Box6ijk * ij2 * jk2) / ik + (CA * Lij * ij2 * jk2) / ik - (2 * CF * Lij * ij2 * jk2) / ik - (CA * ik * jk2) + (2 * CF * ik * jk2) + (CA * Lij * ik * jk2) - (2 * CF * Lij * ik * jk2) + (2 * CA * Ljk * ik * jk2) - (2 * CF * Ljk * ik * jk2) + (CA * Ljk * jk3) - (CF * Ljk * jk3) - (8 * CA * Box6ijk * ij2 * jk3) / ik2 + (16 * CF * Box6ijk * ij2 * jk3) / ik2 - (8 * CA * Box6ijk * ij * jk3) / ik + (16 * CF * Box6ijk * ij * jk3) / ik + (CA * Ljk * ij * jk3) / ik - (2 * CF * Ljk * ij * jk3) / ik ) / (ij_ik * ik_jk_2); qqbargLoops[11] = ( (16 * CA * Box6jik * ij2 * ik) - (32 * CF * Box6jik * ij2 * ik) - (CA * Lij * ij2 * ik) + (2 * CF * Lij * ij2 * ik) + (8 * CA * Box6jik * ij * ik2) - (16 * CF * Box6jik * ij * ik2) - (CA * Lik * ij * ik2) + (2 * CF * Lik * ij * ik2) + (8 * CA * Box6jik * ij2 * ik2) / jk - (16 * CF * Box6jik * ij2 * ik2) / jk + (8 * CA * Box6jik * ij2 * jk) - (16 * CF * Box6jik * ij2 * jk) - (2 * CA * Lij * ij2 * jk) + (4 * CF * Lij * ij2 * jk) + (CA * ij * ik * jk) - (2 * CF * ij * ik * jk) + (16 * CA * Box6jik * ij * ik * jk) - (32 * CF * Box6jik * ij * ik * jk) - (2 * CA * Lij * ij * ik * jk) + (4 * CF * Lij * ij * ik * jk) - (2 * CA * Lik * ij * ik * jk) + (4 * CF * Lik * ij * ik * jk) - (CA * Lik * ik2 * jk) + (CF * Lik * ik2 * jk) + (CA * ij * jk2) - (2 * CF * ij * jk2) + (8 * CA * Box6jik * ij * jk2) - (16 * CF * Box6jik * ij * jk2) - (3 * CA * Lij * ij * jk2) + (6 * CF * Lij * ij * jk2) - (CA * Lik * ij * jk2) + (2 * CF * Lik * ij * jk2) + (CA * ik * jk2) - (2 * CF * ik * jk2) - (CA * Lij * ik * jk2) + (2 * CF * Lij * ik * jk2) - (2 * CA * Lik * ik * jk2) + (2 * CF * Lik * ik * jk2) + (CA * jk3) - (2 * CF * jk3) - (CA * Lij * jk3) + (2 * CF * Lij * jk3) - (CA * Lik * jk3) + (CF * Lik * jk3) ) / (ij_jk * ik_jk_2); qqbargLoops[12] = -3 * CF * Lijk + ( (CA * ij2 * ik) - (9 * CF * ij2 * ik) + (8 * CA * Box6ijk * ij2 * ik) - (16 * CF * Box6ijk * ij2 * ik) - (8 * CA * Box6ikj * ij2 * ik) + (CA * ij * ik2) - (9 * CF * ij * ik2) + (8 * CA * Box6ijk * ij * ik2) - (16 * CF * Box6ijk * ij * ik2) - (8 * CA * Box6ikj * ij * ik2) + (CA * ij2 * jk) - (9 * CF * ij2 * jk) - (8 * CA * Box6ikj * ij2 * jk) + (8 * CA * Box6jik * ij2 * jk) - (16 * CF * Box6jik * ij2 * jk) + (2 * CA * ij * ik * jk) - (18 * CF * ij * ik * jk) + (8 * CA * Box6ijk * ij * ik * jk) - (16 * CF * Box6ijk * ij * ik * jk) - (40 * CA * Box6ikj * ij * ik * jk) + (8 * CA * Box6jik * ij * ik * jk) - (16 * CF * Box6jik * ij * ik * jk) + (3 * CF * Lik * ij * ik * jk) + (3 * CF * Ljk * ij * ik * jk) + (CA * ik2 * jk) - (9 * CF * ik2 * jk) + (8 * CA * Box6ijk * ik2 * jk) - (16 * CF * Box6ijk * ik2 * jk) - (32 * CA * Box6ikj * ik2 * jk) + (3 * CF * Lik * ik2 * jk) + (CA * ij * jk2) - (9 * CF * ij * jk2) - (8 * CA * Box6ikj * ij * jk2) + (8 * CA * Box6jik * ij * jk2) - (16 * CF * Box6jik * ij * jk2) + (CA * ik * jk2) - (9 * CF * ik * jk2) - (32 * CA * Box6ikj * ik * jk2) + (8 * CA * Box6jik * ik * jk2) - (16 * CF * Box6jik * ik * jk2) + (3 * CF * Ljk * ik * jk2) - (24 * CA * Box6ikj * ik2 * jk2) / ij ) / (ij_ik * ij_jk * ik_jk); /* // idendities implied by gauge invariance and current conservation; checked analytically and numerically Complex c1 = qqbargLoops[0] + qqbargLoops[6] + qqbargLoops[7]; Complex c2 = qqbargLoops[1] + qqbargLoops[8] + qqbargLoops[9]; Complex c3 = qqbargLoops[3] + qqbargLoops[4]; Complex c4 = qqbargLoops[2] + qqbargLoops[5] + qqbargLoops[10] + qqbargLoops[11]; Complex c5 = 2. * qqbargLoops[3]/ik + 2. * qqbargLoops[5]/jk + qqbargLoops[6] * (1.+ij/ik) + qqbargLoops[8] * (jk+ij)/ik + 2. * qqbargLoops[10] * (1./ik+1./jk) + 2. * qqbargLoops[12] * (1./ik+1./jk); Complex c6 = 2. * qqbargLoops[4]/jk + 2. * qqbargLoops[5]/jk + qqbargLoops[7] * (ik+ij)/jk + qqbargLoops[9] * (1.+ij/jk) + 2. * qqbargLoops[11] * (ik/jk2+1./jk); Complex c7 = 0.5 * qqbargLoops[0] * (ij+ik) + 0.5 * qqbargLoops[1] * (ij+jk) + qqbargLoops[2] * (1.+ik/jk) - qqbargLoops[12] * (1.+ik/jk); double x1 = c1 != 0. ? log(abs(real(c1 * conj(c1)))) : 0.; double x2 = c2 != 0. ? log(abs(real(c2 * conj(c2)))) : 0.; double x3 = c3 != 0. ? log(abs(real(c3 * conj(c3)))) : 0.; double x4 = c4 != 0. ? log(abs(real(c4 * conj(c4)))) : 0.; double x5 = c5 != 0. ? log(abs(real(c5 * conj(c5)))) : 0.; double x6 = c6 != 0. ? log(abs(real(c6 * conj(c6)))) : 0.; double x7 = c7 != 0. ? log(abs(real(c7 * conj(c7)))) : 0.; cerr << x1 << " " << x2 << " " << x3 << " " << x4 << " " << x5 << " " << x6 << " " << x7 << "\n"; */ } LorentzVector MatchboxCurrents::qqbargGeneralLeftLoopCurrent(const int i, const int, const int j, const int, const int k, const int gHel, const int n) { qqbargLoopCoefficients(i,j,k); const double ik = invariant(i,k); const double jk = invariant(j,k); const Complex plusP_ik = plusProduct(i,k); const Complex plusP_in = plusProduct(i,n); const Complex plusP_jk = plusProduct(j,k); const Complex plusP_jn = plusProduct(j,n); const Complex plusP_kn = plusProduct(k,n); const Complex minusP_ik = minusProduct(i,k); const Complex minusP_in = minusProduct(i,n); const Complex minusP_jk = minusProduct(j,k); const Complex minusP_jn = minusProduct(j,n); const Complex minusP_kn = minusProduct(k,n); const LorentzVector & minusC_ij = minusCurrent(i,j); const LorentzVector & minusC_nk = minusCurrent(n,k); const LorentzVector & minusC_kj = minusCurrent(k,j); const LorentzVector & minusC_kn = minusCurrent(k,n); Complex c1 = qqbargLoops[0]; Complex c2 = qqbargLoops[1]; Complex c3 = qqbargLoops[2]; Complex c4 = qqbargLoops[3]; Complex c5 = qqbargLoops[4]; Complex c6 = qqbargLoops[5]; Complex c7 = qqbargLoops[6]; Complex c8 = qqbargLoops[7]; Complex c9 = qqbargLoops[8]; Complex c10 = qqbargLoops[9]; Complex c11 = qqbargLoops[10]; Complex c12 = qqbargLoops[11]; Complex c13 = qqbargLoops[12]; if ( gHel == 1 ) { return (sqrt(2) * c6 * plusP_jk * minusC_nk * minusP_ik)/(jk * minusP_kn) + (sqrt(2) * c1 * plusP_jk * momentum(i) * minusP_in)/minusP_kn + (sqrt(2) * c2 * plusP_jk * momentum(j) * minusP_in)/minusP_kn + (2 * sqrt(2) * c3 * plusP_jk * momentum(k) * minusP_in)/(jk * minusP_kn) + (sqrt(2) * c4 * plusP_ik * minusC_ij * minusP_in)/(ik * minusP_kn) - (sqrt(2) * c7 * plusP_ik * plusP_jk * momentum(i) * minusP_ik * minusP_in)/(ik * minusP_kn) - (sqrt(2) * c9 * plusP_ik * plusP_jk * momentum(j) * minusP_ik * minusP_in)/(ik * minusP_kn) - (2 * sqrt(2) * c11 * plusP_ik * plusP_jk * momentum(k) * minusP_ik * minusP_in)/(ik * jk * minusP_kn) + (sqrt(2) * c5 * plusP_jk * minusC_ij * minusP_jn)/(jk * minusP_kn) - (sqrt(2) * c8 * sqr(plusP_jk) * momentum(i) * minusP_ik * minusP_jn)/(jk * minusP_kn) - (sqrt(2) * c10 * sqr(plusP_jk) * momentum(j) * minusP_ik * minusP_jn)/(jk * minusP_kn) - (2 * sqrt(2) * c12 * sqr(plusP_jk) * momentum(k) * minusP_ik * minusP_jn)/(sqr(jk) * minusP_kn); } if ( gHel == -1 ) { return -((sqrt(2) * c1 * plusP_jn * momentum(i) * minusP_ik)/plusP_kn) - (sqrt(2) * c2 * plusP_jn * momentum(j) * minusP_ik)/plusP_kn - (2 * sqrt(2) * c3 * plusP_jn * momentum(k) * minusP_ik)/(jk * plusP_kn) - (sqrt(2) * c4 * plusP_in * minusC_ij * minusP_ik)/(ik * plusP_kn) + (sqrt(2) * c13 * minusC_kj * minusP_ik)/ik + (sqrt(2) * c13 * minusC_kj * minusP_ik)/jk - (sqrt(2) * c6 * plusP_jk * minusC_kn * minusP_ik)/(jk * plusP_kn) + (sqrt(2) * c7 * plusP_in * plusP_jk * momentum(i) * sqr(minusP_ik))/(ik * plusP_kn) + (sqrt(2) * c9 * plusP_in * plusP_jk * momentum(j) * sqr(minusP_ik))/(ik * plusP_kn) + (2 * sqrt(2) * c11 * plusP_in * plusP_jk * momentum(k) * sqr(minusP_ik))/(ik * jk * plusP_kn) - (sqrt(2) * c5 * plusP_jn * minusC_ij * minusP_jk)/(jk * plusP_kn) + (sqrt(2) * c8 * plusP_jk * plusP_jn * momentum(i) * minusP_ik * minusP_jk)/(jk * plusP_kn) + (sqrt(2) * c10 * plusP_jk * plusP_jn * momentum(j) * minusP_ik * minusP_jk)/(jk * plusP_kn) + (2 * sqrt(2) * c12 * plusP_jk * plusP_jn * momentum(k) * minusP_ik * minusP_jk)/(sqr(jk) * plusP_kn); } return czero; } LorentzVector MatchboxCurrents::qqbargFixedLeftLoopCurrent(const int i, const int, const int j, const int, const int k, const int gHel) { qqbargLoopCoefficients(i,j,k); const double ik = invariant(i,k); const double jk = invariant(j,k); const Complex plusP_ij = plusProduct(i,j); const Complex plusP_jk = plusProduct(j,k); const Complex minusP_ij = minusProduct(i,j); const Complex minusP_ik = minusProduct(i,k); const LorentzVector & minusC_ij = minusCurrent(i,j); const LorentzVector & minusC_ik = minusCurrent(i,k); const LorentzVector & minusC_kj = minusCurrent(k,j); //Complex c1 = qqbargLoops[0]; Complex c2 = qqbargLoops[1]; Complex c3 = qqbargLoops[2]; Complex c4 = qqbargLoops[3]; Complex c5 = qqbargLoops[4]; Complex c6 = qqbargLoops[5]; Complex c7 = qqbargLoops[6]; Complex c8 = qqbargLoops[7]; Complex c9 = qqbargLoops[8]; Complex c10 = qqbargLoops[9]; Complex c11 = qqbargLoops[10]; Complex c12 = qqbargLoops[11]; Complex c13 = qqbargLoops[12]; if ( gHel == 1 ) { return -((sqrt(2) * c6 * plusP_jk * minusC_ik)/jk) - (sqrt(2) * c8 * sqr(plusP_jk) * momentum(i) * minusP_ij)/jk - (sqrt(2) * c10 * sqr(plusP_jk) * momentum(j) * minusP_ij)/jk - (2 * sqrt(2) * c12 * sqr(plusP_jk) * momentum(k) * minusP_ij)/sqr(jk) + (sqrt(2) * c5 * plusP_jk * minusC_ij * minusP_ij)/(jk * minusP_ik); } if ( gHel == -1 ) { return (sqrt(2) * c4 * plusP_ij * minusC_ij * minusP_ik)/(ik * plusP_jk) + (sqrt(2) * c13 * minusC_kj * minusP_ik)/ik + (sqrt(2) * c13 * minusC_kj * minusP_ik)/jk + (sqrt(2) * c6 * minusC_kj * minusP_ik)/jk - (sqrt(2) * c7 * plusP_ij * momentum(i)* sqr(minusP_ik))/ik - (sqrt(2) * c9 * plusP_ij * momentum(j) * sqr(minusP_ik))/ik - (2 * sqrt(2) * c11 * plusP_ij * momentum(k) * sqr(minusP_ik))/(ik * jk); } return czero; } LorentzVector MatchboxCurrents::qqbargGeneralRightLoopCurrent(const int i, const int, const int j, const int, const int k, const int gHel, const int n) { qqbargLoopCoefficients(i,j,k); const double ik = invariant(i,k); const double jk = invariant(j,k); const Complex plusP_ik = plusProduct(i,k); const Complex plusP_in = plusProduct(i,n); const Complex plusP_jk = plusProduct(j,k); const Complex plusP_jn = plusProduct(j,n); const Complex plusP_kn = plusProduct(k,n); const Complex minusP_ik = minusProduct(i,k); const Complex minusP_in = minusProduct(i,n); const Complex minusP_jk = minusProduct(j,k); const Complex minusP_jn = minusProduct(j,n); const Complex minusP_kn = minusProduct(k,n); const LorentzVector & minusC_ji = minusCurrent(j,i); const LorentzVector & minusC_jk = minusCurrent(j,k); const LorentzVector & minusC_nk = minusCurrent(n,k); const LorentzVector & minusC_kn = minusCurrent(k,n); Complex c1 = qqbargLoops[0]; Complex c2 = qqbargLoops[1]; Complex c3 = qqbargLoops[2]; Complex c4 = qqbargLoops[3]; Complex c5 = qqbargLoops[4]; Complex c6 = qqbargLoops[5]; Complex c7 = qqbargLoops[6]; Complex c8 = qqbargLoops[7]; Complex c9 = qqbargLoops[8]; Complex c10 = qqbargLoops[9]; Complex c11 = qqbargLoops[10]; Complex c12 = qqbargLoops[11]; Complex c13 = qqbargLoops[12]; if ( gHel == 1 ) { return -((sqrt(2) * c13 * plusP_ik * minusC_jk)/ik) - (sqrt(2) * c13 * plusP_ik * minusC_jk)/jk + (sqrt(2) * c4 * plusP_ik * minusC_ji * minusP_in)/(ik * minusP_kn) + (sqrt(2) * c6 * plusP_ik * minusC_nk * minusP_jk)/(jk * minusP_kn) - (sqrt(2) * c7 * sqr(plusP_ik) * momentum(i) * minusP_in * minusP_jk)/(ik * minusP_kn) - (sqrt(2) * c9 * sqr(plusP_ik) * momentum(j) * minusP_in * minusP_jk)/(ik * minusP_kn) - (2 * sqrt(2) * c11 * sqr(plusP_ik) * momentum(k) * minusP_in * minusP_jk)/(ik * jk * minusP_kn) + (sqrt(2) * c1 * plusP_ik * momentum(i) * minusP_jn)/minusP_kn + (sqrt(2) * c2 * plusP_ik * momentum(j) * minusP_jn)/minusP_kn + (2 * sqrt(2) * c3 * plusP_ik * momentum(k) * minusP_jn)/(jk * minusP_kn) + (sqrt(2) * c5 * plusP_jk * minusC_ji * minusP_jn)/(jk * minusP_kn) - (sqrt(2) * c8 * plusP_ik * plusP_jk * momentum(i) * minusP_jk * minusP_jn)/(jk * minusP_kn) - (sqrt(2) * c10 * plusP_ik * plusP_jk * momentum(j) * minusP_jk * minusP_jn)/(jk * minusP_kn) - (2 * sqrt(2) * c12 * plusP_ik * plusP_jk * momentum(k) * minusP_jk * minusP_jn)/(sqr(jk) * minusP_kn); } if ( gHel == -1 ) { return -((sqrt(2) * c4 * plusP_in * minusC_ji * minusP_ik)/(ik * plusP_kn)) - (sqrt(2) * c1 * plusP_in * momentum(i) * minusP_jk)/plusP_kn - (sqrt(2) * c2 * plusP_in * momentum(j) * minusP_jk)/plusP_kn - (2 * sqrt(2) * c3 * plusP_in * momentum(k) * minusP_jk)/(jk * plusP_kn) - (sqrt(2) * c5 * plusP_jn * minusC_ji * minusP_jk)/(jk * plusP_kn) - (sqrt(2) * c6 * plusP_ik * minusC_kn * minusP_jk)/(jk * plusP_kn) + (sqrt(2) * c7 * plusP_ik * plusP_in * momentum(i) * minusP_ik * minusP_jk)/(ik * plusP_kn) + (sqrt(2) * c9 * plusP_ik * plusP_in * momentum(j) * minusP_ik * minusP_jk)/(ik * plusP_kn) + (2 * sqrt(2) * c11 * plusP_ik * plusP_in * momentum(k) * minusP_ik * minusP_jk)/ (ik * jk * plusP_kn) + (sqrt(2) * c8 * plusP_ik * plusP_jn * momentum(i) * sqr(minusP_jk))/(jk * plusP_kn) + (sqrt(2) * c10 * plusP_ik * plusP_jn * momentum(j) * sqr(minusP_jk))/(jk * plusP_kn) + (2 * sqrt(2) * c12 * plusP_ik * plusP_jn * momentum(k) * sqr(minusP_jk))/(sqr(jk) * plusP_kn); } return czero; } LorentzVector MatchboxCurrents::qqbargFixedRightLoopCurrent(const int i, const int, const int j, const int, const int k, const int gHel) { qqbargLoopCoefficients(i,j,k); const double ik = invariant(i,k); const double jk = invariant(j,k); const Complex plusP_ij = plusProduct(i,j); const Complex plusP_ik = plusProduct(i,k); const Complex minusP_ij = minusProduct(i,j); const Complex minusP_jk = minusProduct(j,k); const LorentzVector & minusC_ji = minusCurrent(j,i); const LorentzVector & minusC_jk = minusCurrent(j,k); const LorentzVector & minusC_ki = minusCurrent(k,i); //Complex c1 = qqbargLoops[0]; Complex c2 = qqbargLoops[1]; Complex c3 = qqbargLoops[2]; Complex c4 = qqbargLoops[3]; Complex c5 = qqbargLoops[4]; Complex c6 = qqbargLoops[5]; Complex c7 = qqbargLoops[6]; Complex c8 = qqbargLoops[7]; Complex c9 = qqbargLoops[8]; Complex c10 = qqbargLoops[9]; Complex c11 = qqbargLoops[10]; Complex c12 = qqbargLoops[11]; Complex c13 = qqbargLoops[12]; if ( gHel == 1 ) { return -((sqrt(2) * c13 * plusP_ik * minusC_jk)/ik) - (sqrt(2) * c13 * plusP_ik * minusC_jk)/jk - (sqrt(2) * c6 * plusP_ik * minusC_jk)/jk + (sqrt(2) * c7 * sqr(plusP_ik) * momentum(i) * minusP_ij)/ik + (sqrt(2) * c9 * sqr(plusP_ik) * momentum(j) * minusP_ij)/ik + (2 * sqrt(2) * c11 * sqr(plusP_ik) * momentum(k) * minusP_ij)/(ik * jk) - (sqrt(2) * c4 * plusP_ik * minusC_ji * minusP_ij)/(ik * minusP_jk); } if ( gHel == -1 ) { return -((sqrt(2) * c5 * plusP_ij * minusC_ji * minusP_jk)/(jk * plusP_ik)) + (sqrt(2) * c6 * minusC_ki * minusP_jk)/jk + (sqrt(2) * c8 * plusP_ij * momentum(i) * sqr(minusP_jk))/jk + (sqrt(2) * c10 * plusP_ij * momentum(j) * sqr(minusP_jk))/jk + (2 * sqrt(2) * c12 * plusP_ij * momentum(k) * sqr(minusP_jk))/sqr(jk); } return czero; } const LorentzVector& MatchboxCurrents::qqbargLeftOneLoopCurrent(const int q, const int qHel, const int qbar, const int qbarHel, const int g1, const int g1Hel) { if ( qHel != 1 || qbarHel != 1 ) return czero; if ( getCurrent(hash<2>(1,2,q,qHel,qbar,qbarHel,g1,g1Hel)) ) { #ifdef CHECK_MatchboxCurrents LorentzVector ni = Complex(0.,0.5) * qqbargGeneralLeftLoopCurrent(q,qHel,qbar,qbarHel,g1,g1Hel,q); LorentzVector nj = Complex(0.,0.5) * qqbargGeneralLeftLoopCurrent(q,qHel,qbar,qbarHel,g1,g1Hel,qbar); LorentzVector nl = Complex(0.,0.5) * qqbargGeneralLeftLoopCurrent(q,qHel,qbar,qbarHel,g1,g1Hel,0); LorentzVector nlbar = Complex(0.,0.5) * qqbargGeneralLeftLoopCurrent(q,qHel,qbar,qbarHel,g1,g1Hel,1); LorentzVector fixed = Complex(0.,0.5) * qqbargFixedLeftLoopCurrent(q,qHel,qbar,qbarHel,g1,g1Hel); LorentzVector x1 = fixed - ni; LorentzVector x2 = fixed - nj; LorentzVector x3 = fixed - nl; LorentzVector x4 = fixed - nlbar; double c1 = real(x1.t() * conj(x1.t())) + real(x1.x() * conj(x1.x())) + real(x1.y() * conj(x1.y())) + real(x1.z() * conj(x1.z())); double c2 = real(x2.t() * conj(x2.t())) + real(x2.x() * conj(x2.x())) + real(x2.y() * conj(x2.y())) + real(x2.z() * conj(x2.z())); double c3 = real(x3.t() * conj(x3.t())) + real(x3.x() * conj(x3.x())) + real(x3.y() * conj(x3.y())) + real(x3.z() * conj(x3.z())); double c4 = real(x4.t() * conj(x4.t())) + real(x4.x() * conj(x4.x())) + real(x4.y() * conj(x4.y())) + real(x4.z() * conj(x4.z())); ostream& ncheck = checkStream("qqbargLeftLoopCurrentNChoice"); ncheck << (c1 != 0. ? log10(abs(c1)) : 0.) << " " << (c2 != 0. ? log10(abs(c2)) : 0.) << " " << (c3 != 0. ? log10(abs(c3)) : 0.) << " " << (c4 != 0. ? log10(abs(c4)) : 0.) << " " << "\n" << flush; #endif cacheCurrent(Complex(0.,0.5) * qqbargFixedLeftLoopCurrent(q,qHel,qbar,qbarHel,g1,g1Hel)); } #ifdef CHECK_MatchboxCurrents checkCurrent("qqbargLeftLoopCurrent",cachedCurrent(),momentum(q)+momentum(qbar)+momentum(g1)); #endif return cachedCurrent(); } const LorentzVector& MatchboxCurrents::qqbargRightOneLoopCurrent(const int q, const int qHel, const int qbar, const int qbarHel, const int g1, const int g1Hel) { if ( qHel != -1 || qbarHel != -1 ) return czero; if ( getCurrent(hash<2>(2,2,q,qHel,qbar,qbarHel,g1,g1Hel)) ) { #ifdef CHECK_MatchboxCurrents LorentzVector ni = Complex(0.,0.5) * qqbargGeneralRightLoopCurrent(q,qHel,qbar,qbarHel,g1,g1Hel,q); LorentzVector nj = Complex(0.,0.5) * qqbargGeneralRightLoopCurrent(q,qHel,qbar,qbarHel,g1,g1Hel,qbar); LorentzVector nl = Complex(0.,0.5) * qqbargGeneralRightLoopCurrent(q,qHel,qbar,qbarHel,g1,g1Hel,0); LorentzVector nlbar = Complex(0.,0.5) * qqbargGeneralRightLoopCurrent(q,qHel,qbar,qbarHel,g1,g1Hel,1); LorentzVector fixed = Complex(0.,0.5) * qqbargFixedRightLoopCurrent(q,qHel,qbar,qbarHel,g1,g1Hel); LorentzVector x1 = fixed - ni; LorentzVector x2 = fixed - nj; LorentzVector x3 = fixed - nl; LorentzVector x4 = fixed - nlbar; double c1 = real(x1.t() * conj(x1.t())) + real(x1.x() * conj(x1.x())) + real(x1.y() * conj(x1.y())) + real(x1.z() * conj(x1.z())); double c2 = real(x2.t() * conj(x2.t())) + real(x2.x() * conj(x2.x())) + real(x2.y() * conj(x2.y())) + real(x2.z() * conj(x2.z())); double c3 = real(x3.t() * conj(x3.t())) + real(x3.x() * conj(x3.x())) + real(x3.y() * conj(x3.y())) + real(x3.z() * conj(x3.z())); double c4 = real(x4.t() * conj(x4.t())) + real(x4.x() * conj(x4.x())) + real(x4.y() * conj(x4.y())) + real(x4.z() * conj(x4.z())); ostream& ncheck = checkStream("qqbargRightLoopCurrentNChoice"); ncheck << (c1 != 0. ? log10(abs(c1)) : 0.) << " " << (c2 != 0. ? log10(abs(c2)) : 0.) << " " << (c3 != 0. ? log10(abs(c3)) : 0.) << " " << (c4 != 0. ? log10(abs(c4)) : 0.) << " " << "\n" << flush; #endif cacheCurrent(Complex(0.,0.5) * qqbargFixedRightLoopCurrent(q,qHel,qbar,qbarHel,g1,g1Hel)); } #ifdef CHECK_MatchboxCurrents checkCurrent("qqbargRightLoopCurrent",cachedCurrent(),momentum(q)+momentum(qbar)+momentum(g1)); #endif return cachedCurrent(); } #ifdef CHECK_MatchboxCurrents map& MatchboxCurrents::checkStreams() { static map theMap; return theMap; } ostream& MatchboxCurrents::checkStream(const string& id) { map::iterator ret = checkStreams().find(id); if ( ret == checkStreams().end() ) { checkStreams()[id] = new ofstream(id.c_str()); ret = checkStreams().find(id); } return *(ret->second); } void MatchboxCurrents::checkCurrent(const string& id, const LorentzVector& current, const LorentzVector& q) { Complex c = current.dot(q); double ac = abs(real(conj(c) * c)); if ( ! isfinite(ac) ) { cerr << "ooops ... nan encountered in current conservation\n" << flush; return; } checkStream(id) << (ac > 0. ? log10(ac) : 0.) << "\n"; } #endif // CHECK_MatchboxCurrents diff --git a/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc b/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc --- a/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc +++ b/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc @@ -1,2047 +1,2047 @@ // -*- 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/RealEmissionProcess.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 ) { + catch ( ImpossibleKinematics & e ) { 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()->CC(), f1[ihel1],v1[ohel1]); diag[0] = FFPvertex_->evaluate(ZERO,inter,a1[ihel2],v2[ohel2]); inter = FFPvertex_->evaluate(ZERO,5,f1[ihel1].particle()->CC(), 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]->CC(), 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]->CC(), 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()->CC(),qin[ihel1],pout[phel]); SpinorBarWaveFunction inters2 = FFPvertex_->evaluate(ZERO,5,qin[ihel1].particle(), qbarin[ihel2],wout[whel]); diag[0] = FFGvertex_->evaluate(mu2,inters1,inters2,gout[ghel]); // second diagram SpinorWaveFunction inters3 = FFGvertex_->evaluate(mu2,5,qin[ihel1].particle()->CC(),qin[ihel1],gout[ghel]); SpinorBarWaveFunction inters4 = FFPvertex_->evaluate(ZERO,5,qbarin[ihel2].particle()->CC(), 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()->CC(), qbarin[ihel2],gout[ghel]); diag[3] = FFPvertex_->evaluate(ZERO,inters1,inters5,wout[whel]); // sixth diagram SpinorWaveFunction inters6 = FFPvertex_->evaluate(ZERO,5,qbarin[ihel2].particle(), 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_); } RealEmissionProcessPtr MEPP2GammaGammaPowheg:: generateHardest(RealEmissionProcessPtr born, ShowerInteraction inter) { beams_.clear(); partons_.clear(); bool QCDAllowed = inter !=ShowerInteraction::QED; bool QEDAllowed = inter !=ShowerInteraction::QCD; // find the incoming particles // and get the particles to be showered ParticleVector incoming,particlesToShower; pair x; for(unsigned int ix=0;ixbornIncoming().size();++ix) { incoming.push_back( born->bornIncoming()[ix] ); beams_.push_back(dynamic_ptr_cast(born->hadrons()[ix]->dataPtr())); partons_.push_back( born->bornIncoming()[ix]->dataPtr() ); particlesToShower.push_back( born->bornIncoming()[ix] ); if(ix==0) x.first = incoming.back()->momentum().rho()/born->hadrons()[ix]->momentum().rho(); else x.second = incoming.back()->momentum().rho()/born->hadrons()[ix]->momentum().rho(); } // find the parton which should be first if( ( particlesToShower[1]->id() > 0 && particlesToShower[0]->id() < 0 ) || ( particlesToShower[0]->id() == ParticleID::g && particlesToShower[1]->id() < 6 && particlesToShower[1]->id() > 0 ) ) { swap(particlesToShower[0],particlesToShower[1]); swap(partons_[0],partons_[1]); swap(beams_ [0],beams_ [1]); swap(x.first ,x.second ); } // check that quark is along +ve z direction quarkplus_ = particlesToShower[0]->momentum().z() > ZERO; // outgoing partons for(unsigned int ix=0;ixbornOutgoing().size();++ix) { particlesToShower.push_back( born->bornOutgoing()[ix] ); } if(particlesToShower.size()!=4) return RealEmissionProcessPtr(); if(particlesToShower[2]->id()!=ParticleID::gamma) swap(particlesToShower[2],particlesToShower[3]); if(particlesToShower[3]->id()==ParticleID::gamma) { if(QCDAllowed) return hardQCDEmission(born,particlesToShower,x); } else { if(QEDAllowed) return hardQEDEmission(born,particlesToShower,x); } return born; } RealEmissionProcessPtr MEPP2GammaGammaPowheg:: hardQCDEmission(RealEmissionProcessPtr born, ParticleVector particlesToShower, pair x) { Energy rootS = sqrt(lastS()); // limits on the rapidity of the jet double minyj = -8.0,maxyj = 8.0; // generate the hard emission 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;iydataPtr()); 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]->momentum()/z; momenta[1] = particlesToShower[1]->momentum(); } else { momenta[0] = particlesToShower[0]->momentum(); momenta[1] = particlesToShower[1]->momentum()/z; } double phi = Constants::twopi*UseRandom::rnd(); momenta[2] = particlesToShower[2]->momentum(); momenta[3] = particlesToShower[3]->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(pTmaxpT()[ShowerInteraction::QCD] = minpT_; return born; } // construct the HardTree object needed to perform the showers // create the partons ParticleVector newparticles; newparticles.push_back(selectedParticles[0]->produceParticle(selectedMomenta[0])); newparticles.push_back(selectedParticles[1]->produceParticle(selectedMomenta[1])); for(unsigned int ix=2;ixdataPtr()-> produceParticle(selectedMomenta[ix])); } newparticles.push_back(selectedParticles[4]->produceParticle(selectedMomenta[4])); // identify the type of process // gluon emission if(newparticles.back()->id()==ParticleID::g) { newparticles[4]->incomingColour(newparticles[0]); newparticles[4]->incomingColour(newparticles[1],true); } // quark else if(newparticles.back()->id()>0) { iemit=1; newparticles[4]->incomingColour(newparticles[1]); newparticles[1]-> colourConnect(newparticles[0]); } // antiquark else { iemit=0; newparticles[4]->incomingColour(newparticles[0],true); newparticles[1]-> colourConnect(newparticles[0]); } // add incoming int ispect = iemit==0 ? 1 : 0; if(particlesToShower[0]==born->bornIncoming()[0]) { born->incoming().push_back(newparticles[0]); born->incoming().push_back(newparticles[1]); } else { born->incoming().push_back(newparticles[1]); born->incoming().push_back(newparticles[0]); swap(iemit,ispect); } // add the outgoing for(unsigned int ix=2;ixoutgoing().push_back(newparticles[ix]); // emitter spectator etc born->emitter (iemit ); born->spectator(ispect); born->emitted(4); // x values pair xnew; for(unsigned int ix=0;ix<2;++ix) { double x = born->incoming()[ix]->momentum().rho()/born->hadrons()[ix]->momentum().rho(); if(ix==0) xnew.first = x; else xnew.second = x; } born->x(xnew); // max pT born->pT()[ShowerInteraction::QCD] = pTmax; born->interaction(ShowerInteraction::QCD); // return the process return born; } RealEmissionProcessPtr MEPP2GammaGammaPowheg:: hardQEDEmission(RealEmissionProcessPtr born, ParticleVector particlesToShower, pair x) { // return if not emission from quark if(particlesToShower[0]->id()!=ParticleID::g && particlesToShower[1]->id()!=ParticleID::g ) return RealEmissionProcessPtr(); // generate the hard emission vector pT; Energy pTmax(-GeV); cPDVector selectedParticles; vector selectedMomenta; int iemit(-1); pair mewgt(make_pair(0.,0.)); for(unsigned int ix=0;ixdataPtr()); selectedMomenta.push_back(particlesToShower[ix]->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]->dataPtr()->charged()) { pin = particlesToShower[0]->momentum(); xB = x.first; iloc = 6; } else { pin = particlesToShower[1]->momentum(); xB = x.second; iloc = 7; } pout = particlesToShower[3]->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(xTpT()[ShowerInteraction::QED] = minpT_; return born; } pTmax = 0.5*xT*Q; iemit = mewgt.first>mewgt.second ? 2 : 3; // construct the object needed to perform the showers // create the partons ParticleVector newparticles; newparticles.push_back(selectedParticles[0]->produceParticle(selectedMomenta[0])); newparticles.push_back(selectedParticles[1]->produceParticle(selectedMomenta[1])); for(unsigned int ix=2;ix dataPtr()->produceParticle(selectedMomenta[ix==2 ? 2 : 4 ])); } newparticles.push_back(selectedParticles[3]->produceParticle(selectedMomenta[3])); // make the colour connections bool col = newparticles[3]->id()<0; if(particlesToShower[0]->dataPtr()->charged()) { newparticles[3]->incomingColour(newparticles[1],col); newparticles[1]->colourConnect (newparticles[0],col); } else { newparticles[3]->incomingColour(newparticles[0],col); newparticles[0]->colourConnect (newparticles[1],col); } bool FSR = iemit==3; // add incoming particles if(particlesToShower[0]==born->bornIncoming()[0]) { born->incoming().push_back(newparticles[0]); born->incoming().push_back(newparticles[1]); } else { born->incoming().push_back(newparticles[1]); born->incoming().push_back(newparticles[0]); } // IS radiatng particle unsigned int iemitter = born->incoming()[0]->dataPtr()->charged() ? 0 : 1; // add outgoing particles if(particlesToShower[2]==born->bornOutgoing()[0]) { born->outgoing().push_back(newparticles[2]); born->outgoing().push_back(newparticles[3]); } else { born->outgoing().push_back(newparticles[3]); born->outgoing().push_back(newparticles[2]); } born->outgoing().push_back(newparticles[4]); // outgoing radiating particle unsigned int ispectator = born->outgoing()[0]->dataPtr()->charged() ? 2 : 3; // get emitter and spectator right if(FSR) swap(iemitter,ispectator); born->emitter (iemitter ); born->spectator(ispectator); born->emitted(4); // x values pair xnew; for(unsigned int ix=0;ix<2;++ix) { double x = born->incoming()[ix]->momentum().rho()/born->hadrons()[ix]->momentum().rho(); if(ix==0) xnew.first = x; else xnew.second = x; } born->x(xnew); // max pT born->pT()[ShowerInteraction::QED] = pTmax; // return the process born->interaction(ShowerInteraction::QED); return born; } diff --git a/Models/ADD/ADDModelFFWGRVertex.cc b/Models/ADD/ADDModelFFWGRVertex.cc --- a/Models/ADD/ADDModelFFWGRVertex.cc +++ b/Models/ADD/ADDModelFFWGRVertex.cc @@ -1,199 +1,199 @@ // -*- C++ -*- // // ADDModelFFWGRVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 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 ADDModelFFWGRVertex class. // #include "ADDModelFFWGRVertex.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Models/StandardModel/StandardCKM.h" using namespace Herwig; using namespace ThePEG; ADDModelFFWGRVertex::ADDModelFFWGRVertex() : charge_(17,0.), gl_(17,0.), gr_(17,0.), ckm_(3,vector(3,0.0)), couplast_(0.), q2last_(ZERO), kappa_(ZERO), r_(ZERO) { orderInGem(2); orderInGs (0); colourStructure(ColourStructure::DELTA); } void ADDModelFFWGRVertex::doinit() { for(int ix=1;ix<7;++ix) { addToList(-ix,ix,22,39); addToList(-ix,ix,23,39); } for(int ix=11;ix<17;++ix) { addToList(-ix,ix,22,39); addToList(-ix,ix,23,39); } // particles for outgoing W- // quarks for(int ix=1;ix<6;ix+=2) { for(int iy=2;iy<7;iy+=2) { addToList(-ix, iy, -24,39); } } // leptons for(int ix=11;ix<17;ix+=2) { addToList(-ix, ix+1, -24,39); } // particles for outgoing W+ // quarks for(int ix=2;ix<7;ix+=2) { for(int iy=1;iy<6;iy+=2) { addToList(-ix, iy, 24,39); } } // leptons for(int ix=11;ix<17;ix+=2) { addToList(-ix-1, ix, 24,39); } FFVTVertex::doinit(); tcHwADDPtr hwADD=dynamic_ptr_cast(generator()->standardModel()); if(!hwADD) throw Exception() << "Must have ADDModel in ADDModelFFWGRVertex::doinit()" << Exception::runerror; double sw2 = sin2ThetaW(); double fact = 0.25/sqrt(sw2*(1.-sw2)); for(int ix=1;ix<4;++ix) { charge_[2*ix-1] = hwADD->ed(); charge_[2*ix ] = hwADD->eu(); charge_[2*ix+9 ] = hwADD->ee(); charge_[2*ix+10] = hwADD->enu(); gl_[2*ix-1] = fact*(hwADD->vd() + hwADD->ad() ); gl_[2*ix ] = fact*(hwADD->vu() + hwADD->au() ); gl_[2*ix+9 ] = fact*(hwADD->ve() + hwADD->ae() ); gl_[2*ix+10] = fact*(hwADD->vnu() + hwADD->anu()); gr_[2*ix-1] = fact*(hwADD->vd() - hwADD->ad() ); gr_[2*ix ] = fact*(hwADD->vu() - hwADD->au() ); gr_[2*ix+9 ] = fact*(hwADD->ve() - hwADD->ae() ); gr_[2*ix+10] = fact*(hwADD->vnu() - hwADD->anu()); } kappa_=2./hwADD->MPlanckBar(); r_ = sqr(hwADD->LambdaT())/hwADD->MPlanckBar(); Ptr::transient_pointer CKM = generator()->standardModel()->CKM(); // cast the CKM object to the HERWIG one ThePEG::Ptr::transient_const_pointer hwCKM = ThePEG::dynamic_ptr_cast< ThePEG::Ptr:: transient_const_pointer>(CKM); if(hwCKM) { vector< vector > CKM; CKM = hwCKM->getUnsquaredMatrix(generator()->standardModel()->families()); for(unsigned int ix=0;ix<3;++ix) { for(unsigned int iy=0;iy<3;++iy) { ckm_[ix][iy]=CKM[ix][iy]; } } } else { throw Exception() << "Must have access to the Herwig::StandardCKM object" << "for the CKM matrix in SMFFWVertex::doinit()" << Exception::runerror; } } void ADDModelFFWGRVertex::persistentOutput(PersistentOStream & os) const { os << charge_ << gl_ << gr_ << ounit(kappa_,InvGeV) << ckm_ << ounit(r_,GeV); } void ADDModelFFWGRVertex::persistentInput(PersistentIStream & is, int) { is >> charge_ >> gl_ >> gr_ >> iunit(kappa_,InvGeV) >> ckm_ >> iunit(r_,GeV); } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigADDModelFFWGRVertex("Herwig::ADDModelFFWGRVertex", "HwADDModel.so"); void ADDModelFFWGRVertex::Init() { static ClassDocumentation documentation ("The ADDModelFFWGRVertexxs class is the implementation" " of the two fermion vector coupling for the ADD model."); } void ADDModelFFWGRVertex::setCoupling(Energy2 q2,tcPDPtr aa,tcPDPtr bb, tcPDPtr cc, tcPDPtr) { // work out the particles int iferm= abs(aa->id()); int ibos = abs(cc->id()); Complex coup; // overall factor assert( ibos >= 22 && ibos <= 24 ); if( q2last_ != q2 || couplast_ == 0. ) { couplast_ = electroMagneticCoupling(q2); q2last_ = q2; } // photon if(ibos==22) { // alpha coup = UnitRemoval::E * kappa_ * couplast_; // _charge of particle assert((iferm>=1 && iferm<=6)||(iferm>=11 &&iferm<=16)); coup *= charge_[iferm]; left (1.); right(1.); } // Z boson else if(ibos==23) { coup = UnitRemoval::E * kappa_ * couplast_; // _charge of particle assert((iferm>=1 && iferm<=6)||(iferm>=11 &&iferm<=16)); left (gl_[iferm]); right(gr_[iferm]); } else if(ibos==24) { - coup = UnitRemoval::E * kappa_ * couplast_ * + coup = Complex(UnitRemoval::E * kappa_ * couplast_) * sqrt(0.5) / sqrt(sin2ThetaW()); // the left and right couplings int iferm=abs(aa->id()); int ianti=abs(bb->id()); // quarks if(iferm>=1 && iferm <=6) { int iu,id; // up type first if(iferm%2==0) { iu = iferm/2; id = (ianti+1)/2; } // down type first else { iu = ianti/2; id = (iferm+1)/2; } assert( iu>=1 && iu<=3 && id>=1 && id<=3); left(ckm_[iu-1][id-1]); right(0.); } // leptons else if(iferm>=11 && iferm <=16) { left(1.); right(0.); } else assert(false); } // set the coupling norm(coup); } Complex ADDModelFFWGRVertex::propagator(int iopt, Energy2 q2,tcPDPtr part, Energy mass, Energy width) { if(part->id()!=ParticleID::Graviton) return VertexBase::propagator(iopt,q2,part,mass,width); else return Complex(4.*Constants::pi*UnitRemoval::E2/sqr(r_)); } diff --git a/Models/RSModel/RSModelFFWGRVertex.cc b/Models/RSModel/RSModelFFWGRVertex.cc --- a/Models/RSModel/RSModelFFWGRVertex.cc +++ b/Models/RSModel/RSModelFFWGRVertex.cc @@ -1,191 +1,191 @@ // -*- C++ -*- // // RSModelFFWGRVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 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 RSModelFFWGRVertex class. // #include "RSModelFFWGRVertex.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Models/StandardModel/StandardCKM.h" using namespace Herwig; using namespace ThePEG; RSModelFFWGRVertex::RSModelFFWGRVertex() : charge_(17,0.), gl_(17,0.), gr_(17,0.), ckm_(3,vector(3,0.0)), couplast_(0.), q2last_(ZERO), kappa_(ZERO) { orderInGem(2); orderInGs (0); colourStructure(ColourStructure::DELTA); } void RSModelFFWGRVertex::doinit() { for(int ix=11;ix<17;++ix) { addToList(-ix,ix,22,39); addToList(-ix,ix,23,39); } for(int ix=1;ix<7;++ix) { addToList(-ix,ix,22,39); addToList(-ix,ix,23,39); } // particles for outgoing W- // quarks for(int ix=1;ix<6;ix+=2) { for(int iy=2;iy<7;iy+=2) { addToList(-ix, iy, -24,39); } } // leptons for(int ix=11;ix<17;ix+=2) { addToList(-ix, ix+1, -24,39); } // particles for outgoing W+ // quarks for(int ix=2;ix<7;ix+=2) { for(int iy=1;iy<6;iy+=2) { addToList(-ix, iy, 24,39); } } // leptons for(int ix=11;ix<17;ix+=2) { addToList(-ix-1, ix, 24,39); } FFVTVertex::doinit(); tcHwRSPtr hwRS=dynamic_ptr_cast(generator()->standardModel()); if(!hwRS) throw Exception() << "Must have RSModel in RSModelFFWGRVertex::doinit()" << Exception::runerror; double sw2 = sin2ThetaW(); double fact = 0.25/sqrt(sw2*(1.-sw2)); for(int ix=1;ix<4;++ix) { charge_[2*ix-1] = hwRS->ed(); charge_[2*ix ] = hwRS->eu(); charge_[2*ix+9 ] = hwRS->ee(); charge_[2*ix+10] = hwRS->enu(); gl_[2*ix-1] = fact*(hwRS->vd() + hwRS->ad() ); gl_[2*ix ] = fact*(hwRS->vu() + hwRS->au() ); gl_[2*ix+9 ] = fact*(hwRS->ve() + hwRS->ae() ); gl_[2*ix+10] = fact*(hwRS->vnu() + hwRS->anu()); gr_[2*ix-1] = fact*(hwRS->vd() - hwRS->ad() ); gr_[2*ix ] = fact*(hwRS->vu() - hwRS->au() ); gr_[2*ix+9 ] = fact*(hwRS->ve() - hwRS->ae() ); gr_[2*ix+10] = fact*(hwRS->vnu() - hwRS->anu()); } kappa_ = 2./hwRS->lambda_pi(); Ptr::transient_pointer CKM = generator()->standardModel()->CKM(); // cast the CKM object to the HERWIG one ThePEG::Ptr::transient_const_pointer hwCKM = ThePEG::dynamic_ptr_cast< ThePEG::Ptr:: transient_const_pointer>(CKM); if(hwCKM) { vector< vector > CKM; CKM = hwCKM->getUnsquaredMatrix(generator()->standardModel()->families()); for(unsigned int ix=0;ix<3;++ix) { for(unsigned int iy=0;iy<3;++iy) { ckm_[ix][iy]=CKM[ix][iy]; } } } else { throw Exception() << "Must have access to the Herwig::StandardCKM object" << "for the CKM matrix in SMFFWVertex::doinit()" << Exception::runerror; } } void RSModelFFWGRVertex::persistentOutput(PersistentOStream & os) const { os << charge_ << gl_ << gr_ << ounit(kappa_,InvGeV) << ckm_; } void RSModelFFWGRVertex::persistentInput(PersistentIStream & is, int) { is >> charge_ >> gl_ >> gr_ >> iunit(kappa_,InvGeV) >> ckm_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigRSModelFFWGRVertex("Herwig::RSModelFFWGRVertex", "HwRSModel.so"); void RSModelFFWGRVertex::Init() { static ClassDocumentation documentation ("The RSModelFFWGRVertexxs class is the implementation" " of the two fermion vector coupling for the RS model."); } // FFWGR coupling void RSModelFFWGRVertex::setCoupling(Energy2 q2,tcPDPtr aa,tcPDPtr bb, tcPDPtr cc, tcPDPtr) { // work out the particles int iferm= abs(aa->id()); int ibos = abs(cc->id()); Complex coup; // overall factor assert( ibos >= 22 && ibos <= 24 ); if( q2last_ != q2 || couplast_ == 0. ) { couplast_ = electroMagneticCoupling(q2); q2last_ = q2; } // photon if(ibos==22) { // alpha coup = UnitRemoval::E * kappa_ * couplast_; // _charge of particle assert((iferm>=1 && iferm<=6)||(iferm>=11 &&iferm<=16)); coup *= charge_[iferm]; left (1.); right(1.); } // Z boson else if(ibos==23) { coup = UnitRemoval::E * kappa_ * couplast_; // _charge of particle assert((iferm>=1 && iferm<=6)||(iferm>=11 &&iferm<=16)); left (gl_[iferm]); right(gr_[iferm]); } else if(ibos==24) { - coup = UnitRemoval::E * kappa_ * couplast_ * + coup = Complex(UnitRemoval::E * kappa_ * couplast_) * sqrt(0.5) / sqrt(sin2ThetaW()); // the left and right couplings int iferm=abs(aa->id()); int ianti=abs(bb->id()); // quarks if(iferm>=1 && iferm <=6) { int iu,id; // up type first if(iferm%2==0) { iu = iferm/2; id = (ianti+1)/2; } // down type first else { iu = ianti/2; id = (iferm+1)/2; } assert( iu>=1 && iu<=3 && id>=1 && id<=3); left(ckm_[iu-1][id-1]); right(0.); } // leptons else if(iferm>=11 && iferm <=16) { left(1.); right(0.); } else assert(false); } // set the coupling norm(coup); } diff --git a/Models/UED/UEDF1F0H1Vertex.cc b/Models/UED/UEDF1F0H1Vertex.cc --- a/Models/UED/UEDF1F0H1Vertex.cc +++ b/Models/UED/UEDF1F0H1Vertex.cc @@ -1,206 +1,206 @@ // -*- C++ -*- // // UEDF1F0H1Vertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 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 UEDF1F0H1Vertex class. // #include "UEDF1F0H1Vertex.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" using namespace ThePEG::Helicity; using namespace Herwig; UEDF1F0H1Vertex::UEDF1F0H1Vertex() : theRadius(ZERO), theMw(ZERO), theSinThetaW(0.), theq2Last(ZERO), theCoupLast(0.), theLeftLast(0.), theRightLast(0.), theAntiLast(0), theFermLast(0), theHLast(0) { orderInGs(0); orderInGem(1); colourStructure(ColourStructure::DELTA); } void UEDF1F0H1Vertex::doinit() { long heavy[3] = {5, 6, 15}; //h0 - for( unsigned int i = 0; i < 3; ++i ) { + for( int i = 0; i < 3; ++i ) { addToList(-5100000 - i, 5100000 + i, 25); addToList(-6100000 - i, 6100000 + i, 25); addToList(-5100000 - i, 6100000 + i, 25); addToList(-6100000 - i, 5100000 + i, 25); } // Neutral KK-Higgs long higgs[2] = {5100025, 5100036}; for( unsigned int h = 0; h < 2; ++h ) { - for( unsigned int i = 0; i < 3; ++i ) { + for( int i = 0; i < 3; ++i ) { addToList(-heavy[i], 5100000 + heavy[i], higgs[h]); addToList(-5100000 - heavy[i], heavy[i], higgs[h]); addToList(-heavy[i], 6100000 + heavy[i], higgs[h]); addToList(-6100000 - heavy[i], heavy[i], higgs[h]); } } //KK-charged higgs //outgoing H+ addToList(-5100006, 5, 5100037); addToList(-6100006, 5, 5100037); addToList(-6, 5100005, 5100037); addToList(-6, 6100005, 5100037); addToList(-5100016, 15, 5100037); addToList(-6100016, 15, 5100037); addToList(-16, 5100015, 5100037); addToList(-16, 6100015, 5100037); //outgoing H- addToList(-5100005, 6,-5100037); addToList(-6100005, 6,-5100037); addToList(-5, 5100006,-5100037); addToList(-5, 6100006,-5100037); addToList(-5100015, 16,-5100037); addToList(-6100015, 16,-5100037); addToList(-15, 5100016,-5100037); addToList(-15, 6100016,-5100037); FFSVertex::doinit(); tUEDBasePtr UEDBase = dynamic_ptr_cast(generator()->standardModel()); if(!UEDBase) throw InitException() << "UEDF1F0H1Vertex::doinit() - The pointer to " << "the UEDBase object is null!" << Exception::runerror; theRadius = UEDBase->compactRadius(); theSinThetaW = sqrt(sin2ThetaW()); theCosThetaW = sqrt(1. - sin2ThetaW()); theMw = getParticleData(24)->mass(); theMz = getParticleData(23)->mass(); } void UEDF1F0H1Vertex::persistentOutput(PersistentOStream & os) const { os << ounit(theRadius,1/GeV) << ounit(theMw,GeV) << theSinThetaW << ounit(theMz, GeV) << theCosThetaW; } void UEDF1F0H1Vertex::persistentInput(PersistentIStream & is, int) { is >> iunit(theRadius,1/GeV) >> iunit(theMw,GeV) >> theSinThetaW >> iunit(theMz, GeV) >> theCosThetaW; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigUEDF1F0H1Vertex("Herwig::UEDF1F0H1Vertex", "HwUED.so"); void UEDF1F0H1Vertex::Init() { static ClassDocumentation documentation ("The coupling involving a KK-Higgs and a pair of fermions."); } void UEDF1F0H1Vertex::setCoupling(Energy2 q2, tcPDPtr part1, tcPDPtr part2, tcPDPtr part3) { long anti(abs(part1->id())), ferm(abs(part2->id())), higgs(part3->id()); if( ferm > 17 ) swap( ferm, anti); if( anti != theAntiLast || ferm != theFermLast || higgs != theHLast ) { theAntiLast = anti; theFermLast = ferm; theHLast = higgs; tcPDPtr pd; if( higgs != 25 ) { pd = getParticleData(ferm); } else { long smid = ( ferm/1000000 == 5 ) ? ferm - 5100000 : ferm - 6100000; pd = getParticleData(smid); } Energy mf = pd->mass(); double alpha = mf*theRadius/2.; double salpha = sin(alpha); double calpha = cos(alpha); double fact(0.); if( abs(higgs) == 5100037 ) { fact = theRadius/2./sqrt(1. + sqr(theMw*theRadius)) * UnitRemoval::E; theRightLast = theRadius*theMw; if(anti/1000000 == 5) { Energy mfk = getParticleData(anti - 5100000)->mass(); theLeftLast = (theMw*calpha - (mfk*salpha/theRadius/theMw)) * UnitRemoval::InvE; theRightLast *= calpha*mfk* UnitRemoval::InvE; } else { Energy mfk = getParticleData(anti - 6100000)->mass(); theLeftLast = (theMw*salpha +(mfk*calpha/theRadius/theMw)) * UnitRemoval::InvE; theRightLast *= -salpha*mfk*UnitRemoval::InvE; } theLeftLast *= fact; theRightLast *= fact; if( higgs < 0 ) swap( theLeftLast, theRightLast ); } else if( higgs == 5100025 ) { fact = mf/theMw/2.; if( anti/1000000 == 5 ) theLeftLast = salpha + calpha; else theLeftLast = salpha - calpha; theRightLast = theLeftLast; theLeftLast *= fact; theRightLast *= fact; } else if( higgs == 5100036 ) { fact = theRadius/theCosThetaW/sqrt(1.+sqr(theMz*theRadius))*UnitRemoval::E; double i3f = ( ferm % 2 == 0 ) ? 0.5 : -0.5; double qf = pd->charge()/eplus; if( anti/1000000 == 5 ) { theLeftLast = (theMz*calpha*(i3f - qf*sqr(theSinThetaW)) - mf*salpha/theRadius/theMw) * UnitRemoval::InvE; theRightLast = (-theMz*salpha*qf*sqr(theSinThetaW) + mf*calpha/theRadius/theMw) * UnitRemoval::InvE; } else { theLeftLast = (theMz*salpha*(i3f - qf*sqr(theSinThetaW)) - mf*calpha/theRadius/theMw) * UnitRemoval::InvE; theRightLast = (-theMz*calpha*qf*sqr(theSinThetaW) + mf*salpha/theRadius/theMw)*UnitRemoval::InvE; } theLeftLast *= fact; theRightLast *= fact; } else { theLeftLast = mf*calpha*salpha/2./theMw; if( ferm/1000000 == 5 ) theLeftLast *= -1.; theRightLast = theLeftLast; } } if(q2 != theq2Last || theCoupLast == 0.) { theq2Last = q2; theCoupLast = weakCoupling(q2); } norm(theCoupLast); left(theLeftLast); right(theRightLast); } diff --git a/Sampling/exsample/binary_tree.h b/Sampling/exsample/binary_tree.h --- a/Sampling/exsample/binary_tree.h +++ b/Sampling/exsample/binary_tree.h @@ -1,883 +1,877 @@ // -*- C++ -*- // // binary_tree.h is part of ExSample -- A Library for Sampling Sudakov-Type Distributions // // Copyright (C) 2008-2017 Simon Platzer -- simon.plaetzer@desy.de, The Herwig Collaboration // // ExSample is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // #ifndef EXSAMPLE_binary_tree_h_included #define EXSAMPLE_binary_tree_h_included #include "utility.h" namespace exsample { /// \brief binary_tree represents a binary tree with the ability to /// `cascade' visitor objects down the tree template class binary_tree { public: ///@name type definitions //@{ /// define the object type typedef Value value_type; //@} public: ///@name constructors //@{ /// default constructor binary_tree() : neighbours_(), parent_(), value_(), children_() { } /// construct giving key/cell and parent binary_tree(const value_type& thevalue, binary_tree * theparent = 0) : neighbours_(), parent_(theparent), value_(new value_type(thevalue)), children_() { } /// binary_tree has a strict ownership; on copying /// binary trees ownership is transferred binary_tree(const binary_tree& x) : neighbours_(x.neighbours_), parent_(x.parent_), value_(), children_() { assert(x.root()); binary_tree& nc_x = const_cast(x); value_.swap(nc_x.value_); children_.first.swap(nc_x.children_.first); children_.second.swap(nc_x.children_.second); nc_x.parent_ = 0; nc_x.neighbours_.first = 0; nc_x.neighbours_.second = 0; } /// binary_tree has a strict ownership; on copying /// binary trees ownership is transferred binary_tree& operator=(const binary_tree& x) { if (this == &x) return *this; assert(x.root()); binary_tree& nc_x = const_cast(x); value_.swap(nc_x.value_); children_.first.swap(nc_x.children_.first); children_.second.swap(nc_x.children_.second); neighbours_ = x.neighbours_; parent_ = x.parent_; nc_x.parent_ = 0; nc_x.neighbours_.first = 0; nc_x.neighbours_.second = 0; return *this; } //@} ///@name standard-conforming leaf iterators //@{ public: class const_iterator; /// iterator class iterator { public: ///@name type definitions for iterator traits //@{ /// define the iterator category typedef std::bidirectional_iterator_tag iterator_category; /// define the difference_type typedef int difference_type; /// define the value type typedef Value value_type; /// define the reference type typedef value_type& reference; /// define the pointer type typedef value_type * pointer; //@} public: ///@name constructors //@{ /// default constructor iterator() : pointee(0), post_end(0), pre_begin(0) { } /// constructor taking pointee iterator(binary_tree * p, std::size_t end = 0) : pointee(p), post_end(end), pre_begin(0) { } //@ public: ///@name comparisons //@{ /// comparison bool operator==(const iterator& x) const { return ((pointee == x.pointee) && (post_end == x.post_end) && (pre_begin == x.pre_begin)); } /// comparison bool operator!=(const iterator& x) const { return !(*this == x); } //@} public: ///@name derefrence and indirection //@{ /// dereference reference operator*() { return pointee->value(); } /// indirection pointer operator->() { return &**this; } /// return reference to the node binary_tree& node() { return *pointee; } //@} /// return raw pointer to the element pointed to binary_tree * get() const { return pointee; } ///@name biderectional iterator increment/decrements //@{ /// pre-increment iterator& operator++() { if (post_end) { ++post_end; return *this; } if (pre_begin) { --pre_begin; return *this; } if(!(pointee->right_neighbour())) { post_end = 1; return *this; } pointee = pointee->right_neighbour(); return *this; } /// pre-decrement iterator& operator--() { if (post_end) { --post_end; return *this; } if (pre_begin) { ++pre_begin; return *this; } if(!(pointee->left_neighbour())) { pre_begin = 1; return *this; } pointee = pointee->left_neighbour(); return *this; } /// post-increment iterator operator++(int) { iterator tmp = *this; ++(*this); return tmp; } /// post-decrement iterator operator--(int) { iterator tmp = *this; --(*this); return tmp; } //@} private: /// friend for conversion friend class const_iterator; /// the node pointed to binary_tree * pointee; /// the distance from --end() (if above --end()) std::size_t post_end; /// the distance from begin() (if below begin()) std::size_t pre_begin; }; /// return begin iterator iterator begin() { return iterator(left_most()); } /// return end iterator iterator end() { return iterator(right_most(),1); } /// return global begin iterator iterator global_begin() { if (!root()) return parent().global_begin(); return iterator(left_most()); } /// return global end iterator iterator global_end() { if (!root()) return parent().global_end(); return iterator(right_most(),1); } /// const_iterator class const_iterator { public: ///@name type definitions for iterator traits //@{ /// define the iterator category typedef std::bidirectional_iterator_tag iterator_category; /// define the difference type typedef int difference_type; /// define the value type typedef const Value value_type; /// define the reference type typedef const value_type& reference; /// define the pointer type typedef const value_type * pointer; //@} public: ///@name constructors //@{ /// default constructor const_iterator() : pointee(0), post_end(0), pre_begin(0) { } /// constructor taking pointee const_iterator(const binary_tree * p, std::size_t end = 0) : pointee(p), post_end(end), pre_begin(0) { } /// conversion from iterator const_iterator(const iterator& x) : pointee(x.pointee), post_end(x.post_end), pre_begin(x.pre_begin) { } //@} public: ///@name comparisons //@{ /// comparison bool operator==(const const_iterator& x) const { return ((pointee == x.pointee) && (post_end == x.post_end) && (pre_begin == x.pre_begin)); } /// comparison bool operator!=(const const_iterator& x) const { return !(*this == x); } //@} public: ///@name dereference and indirection //@{ /// dereference reference operator*() const { return pointee->value(); } /// indirection pointer operator->() const { return &**this; } /// return reference to the node const binary_tree& node() const { return *pointee; } //@} ///@name biderectional iterator increment/decrements //@{ /// pre-increment const_iterator& operator++() { if (post_end) { ++post_end; return *this; } if (pre_begin) { --pre_begin; return *this; } if(!(pointee->right_neighbour())) { post_end = 1; return *this; } pointee = pointee->right_neighbour(); return *this; } /// pre-decrement const_iterator& operator--() { if (post_end) { --post_end; return *this; } if (pre_begin) { ++pre_begin; return *this; } if(!(pointee->left_neighbour())) { pre_begin = 1; return *this; } pointee = pointee->left_neighbour(); return *this; } /// post-increment const_iterator operator++(int) { const_iterator tmp = *this; ++(*this); return tmp; } /// post-decrement const_iterator operator--(int) { const_iterator tmp = *this; --(*this); return tmp; } //@} private: /// the node pointed to const binary_tree * pointee; /// the distance from --end() (if above --end()) std::size_t post_end; /// the distance from begin() (if below begin()) std::size_t pre_begin; }; /// return begin const_iterator const_iterator begin() const { return const_iterator(left_most()); } /// return end const_iterator const_iterator end() const { return const_iterator(right_most(),1); } /// return global begin iterator const_iterator global_begin() const { if (!root()) return parent().global_begin(); return iterator(left_most()); } /// return global end iterator const_iterator global_end() const { if (!root()) return parent().global_end(); return iterator(right_most(),1); } private: /// set the left neighbour void left_neighbour(binary_tree * n) { neighbours_.first = n; } /// set the right neighbour void right_neighbour(binary_tree * n) { neighbours_.second = n; } /// get the left neighbour binary_tree * left_neighbour() const { return neighbours_.first; } /// get the right neighbour binary_tree * right_neighbour() const { return neighbours_.second; } /// return the left-most leaf binary_tree * left_most() { if(leaf()) return this; return left_child().left_most(); } /// return the right-most leaf binary_tree * right_most() { if(leaf()) return this; return right_child().right_most(); } /// return the left-most leaf const binary_tree * left_most() const { if(leaf()) return this; return left_child().left_most(); } /// return the right-most leaf const binary_tree * right_most() const { if(leaf()) return this; return right_child().right_most(); } - /// the iterator is a good friend - friend class binary_tree::iterator; - - /// the iterator is a good friend - friend class binary_tree::const_iterator; - /// the left and right neighbours of this node std::pair neighbours_; //@} public: /// return true, if this node is empty bool empty() const { return root() && leaf() && !value_; } /// clear this node void clear() { neighbours_ = std::make_pair(0,0); parent_ = 0; value_.reset(0); if (!leaf()) { left_child().clear(); right_child().clear(); } children_.first.reset(0); children_.second.reset(0); } public: /// split this node std::pair split(std::pair children) { assert(leaf()); children_.first.reset(new binary_tree(children.first,this)); children_.second.reset(new binary_tree(children.second,this)); children_.first->left_neighbour(neighbours_.first); children_.first->right_neighbour(children_.second.get()); children_.second->left_neighbour(children_.first.get()); children_.second->right_neighbour(neighbours_.second); // adjust original neighbours if(neighbours_.first) { neighbours_.first->right_neighbour(children_.first.get()); } if (neighbours_.second) { neighbours_.second->left_neighbour(children_.second.get()); } neighbours_.first = 0; neighbours_.second = 0; return std::make_pair(iterator(children_.first.get()),iterator(children_.second.get())); } public: /// select using a selector template iterator select(const Selector& selector) { if(leaf()) { bool use = selector.use(value()); if (use) return iterator(this); return global_end(); } std::pair which(selector.use(value(),left_child().value(),right_child().value())); assert(!which.first || !which.second); if (!which.first && !which.second) { return global_end(); } if (which.first) { return left_child().select(selector); } else { return right_child().select(selector); } return global_end(); } /// generate a hash value for the sub-tree /// selected by the given selector object template void subtree_hash(const Selector& selector, bit_container& bhash) { bhash = bit_container(); unsigned long pos = 0; do_subtree_hash(selector,bhash,pos); } /// accumulate values using a binary function /// and accessor object template typename BinaryOp::result_type accumulate(const Accessor& acc, BinaryOp binary_op) const { if (!leaf()) { return binary_op(left_child().accumulate(acc,binary_op), right_child().accumulate(acc,binary_op)); } return acc.get(value(),true); } /// accumulate values only from branches /// matching a Selector template typename BinaryOp::result_type accumulate(const Selector& selector, const Accessor& acc, BinaryOp binary_op) const { if (!leaf()) { std::pair which(selector.use(value(),left_child().value(),right_child().value())); assert(which.first || which.second); if (which.first && which.second) { return binary_op(left_child().accumulate(selector,acc,binary_op), right_child().accumulate(selector,acc,binary_op)); } else if (which.first) { return left_child().accumulate(selector,acc,binary_op); } else if (which.second) { return right_child().accumulate(selector,acc,binary_op); } } return acc.get(value(),true); } /// accumulate values using a binary function /// and accessor object, storing intermediate /// values in nodes template typename BinaryOp::result_type tree_accumulate(const Accessor& acc, BinaryOp binary_op) { if (!leaf()) { acc.set(value()) = binary_op(left_child().tree_accumulate(acc,binary_op), right_child().tree_accumulate(acc,binary_op)); return acc.get(value(),false); } acc.set(value()) = acc.get(value(),true); return acc.get(value(),true); } /// accumulate values only from branches /// matching a Selector template typename BinaryOp::result_type tree_accumulate(const Selector& selector, const Accessor& acc, BinaryOp binary_op) { if (!leaf()) { std::pair which(selector.use(value(),left_child().value(),right_child().value())); assert(which.first || which.second); if (which.first && which.second) { acc.set(value()) = binary_op(left_child().tree_accumulate(selector,acc,binary_op), right_child().tree_accumulate(selector,acc,binary_op)); } else if (which.first) { acc.set(value()) = left_child().tree_accumulate(selector,acc,binary_op); } else if (which.second) { acc.set(value()) = right_child().tree_accumulate(selector,acc,binary_op); } return acc.get(value(),false); } acc.set(value()) = acc.get(value(),true); return acc.get(value(),true); } /// forward propagate a visitor to all children nodes template void cascade(Visitor visitor) const { if (leaf()) { visitor.visit(value()); return; } else visitor.visit(value(),left_child().value(),right_child().value()); left_child().cascade(visitor); right_child().cascade(visitor); } /// succesively split using a generator template void generate(Generator generator) { if (root()) value_.reset(new value_type(generator.root())); if (generator.split()) { std::pair ch = split(generator.generate(value())); ch.first.node().generate(generator); ch.second.node().generate(generator); } } public: ///@name Public member access //@{ /// return the value held by this node value_type& value() { return *value_; } /// return the value held by this node const value_type& value() const { return *value_; } /// return true, if this is the root node bool root() const { return !parent_; } /// return true, if this node has got children bool leaf() const { return !(children_.first.get() && children_.second.get()); } //@} public: ///@name put and get from streams //@{ /// forward visitor writing out the tree to given ostream template struct ostream_visitor { /// construct from ostream reference explicit ostream_visitor(OStream& os) : os_(&os), first_time_(true) {} /// visit a leaf node void visit(const value_type&) { (*os_) << "end_branch"; ostream_traits::separator(*os_); } /// visit a branching void visit(const value_type& parent, const value_type& left, const value_type& right) { if (first_time_) { (*os_) << "root_node"; ostream_traits::separator(*os_); parent.put(*os_); first_time_ = false; } (*os_) << "left_child"; ostream_traits::separator(*os_); left.put(*os_); (*os_) << "right_child"; ostream_traits::separator(*os_); right.put(*os_); } private: /// pointer to the ostream to write to OStream* os_; /// whether we are at the or not bool first_time_; }; /// generator reading binary tree from istream template struct istream_generator { /// construct from istream reference explicit istream_generator(IStream& is) : is_(&is), children_(), tag_("") {} /// copy constructor istream_generator(const istream_generator& x) : is_(x.is_), children_(), tag_("") {} /// read the root node value_type root() { *is_ >> tag_; assert(tag_ == "root_node"); value_type rnode; rnode.get(*is_); return rnode; } /// read children nodes bool split() { *is_ >> tag_; if (tag_ == "end_branch") { return false; } assert (tag_ == "left_child"); children_.first.get(*is_); *is_ >> tag_; assert(tag_ == "right_child"); children_.second.get(*is_); return true; } /// return the children generated std::pair generate(const value_type&) { return children_; } /// initialize a leaf void initialize_leaf(const value_type&) {} private: /// pointer to the istream used IStream* is_; /// the children currently handled std::pair children_; /// temporary storage for tags std::string tag_; }; /// put to ostream template void put(OStream& os) const { if (empty()) { os << "empty"; ostream_traits::separator(os); return; } else if (root() && leaf()) { os << "root_only"; ostream_traits::separator(os); value().put(os); return; } else { os << "non_empty"; ostream_traits::separator(os); } assert(root()); cascade(ostream_visitor(os)); } /// get from istream template void get(IStream& is) { std::string state; is >> state; if (state == "empty") { return; } if (state == "root_only") { value_.reset(new value_type()); value().get(is); return; } assert(empty()); generate(istream_generator(is)); } //@} private: /// calculate hash value template void do_subtree_hash(const Selector& selector, bit_container& current, unsigned long& position, bool selected = true) const { if (!leaf()) { std::pair which(false,false); if (selected) which = selector.use(value(),left_child().value(),right_child().value()); current.bit(position,which.first); current.bit(position+1,which.second); position += 2; left_child().do_subtree_hash(selector,current,position,which.first && selected); right_child().do_subtree_hash(selector,current,position,which.second && selected); } } private: ///@name private member access //@{ /// return the parent of this node binary_tree& parent() { assert(parent_); return *parent_; } /// return the parent of this node const binary_tree& parent() const { assert(parent_); return *parent_; } /// return the left child of this node binary_tree& left_child() { assert(children_.first.get()); return *children_.first; } /// return the left child of this node const binary_tree& left_child() const { assert(children_.first.get()); return *children_.first; } /// return the right child of this node binary_tree& right_child() { assert(children_.second.get()); return *children_.second; } /// return the right child of this node const binary_tree& right_child() const { assert(children_.second.get()); return *children_.second; } //@} private: /// the parent of this node binary_tree * parent_; /// the cell held by this node std::unique_ptr value_; /// the children of this node std::pair, std::unique_ptr > children_; }; } #endif // EXSAMPLE_binary_tree_h_included diff --git a/Sampling/exsample/cell.icc b/Sampling/exsample/cell.icc --- a/Sampling/exsample/cell.icc +++ b/Sampling/exsample/cell.icc @@ -1,490 +1,490 @@ // -*- C++ -*- // // cell.icc is part of ExSample -- A Library for Sampling Sudakov-Type Distributions // // Copyright (C) 2008-2017 Simon Platzer -- simon.plaetzer@desy.de, The Herwig Collaboration // // ExSample is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // namespace exsample { template void cell_info::select (Random& rnd_gen, std::vector& p) { std::transform(lower_left_.begin(),lower_left_.end(), upper_right_.begin(),p.begin(), rnd_gen); ++attempted_; } template void cell_info::select (Random& rnd_gen, std::vector& p, const std::vector& sample) { conditional_transform(lower_left_.begin(),lower_left_.end(), upper_right_.begin(),sample.begin(), p.begin(),rnd_gen); ++attempted_; } template void cell_info::explore(Random& rnd_gen, const adaption_info& ainfo, Function* function, statistics* stats, SlaveStatistics& opt, double detuning) { function->start_presampling(); unsigned long n_sampled = 0; std::vector ll = lower_left_; std::vector ur = upper_right_; double val = 0.; std::vector pos (ll.size()); std::vector< std::pair > > vals; unsigned long ivalnonzero = 0; while (n_sampled < ainfo.presampling_points) { std::transform(ll.begin(),ll.end(), ur.begin(),pos.begin(), rnd_gen); val = function->evaluate(pos) * detuning; vals.push_back( std::pair > (val,pos) ); if ( val != 0 ) ivalnonzero++; ++n_sampled; } while ( ivalnonzero > 0 ) { double avg = 0; double err = 0; double maxval = 0; std::vector maxpos (ll.size()); - unsigned long imax; + unsigned long imax(0); for ( unsigned long ival=0; ival < vals.size(); ival++ ) { val = std::abs(vals[ival].first); if ( val == 0 ) continue; avg += val; err += sqr(val); if ( val > maxval ) { maxval = val; maxpos = vals[ival].second; imax = ival; } } avg /= ivalnonzero; err /= ivalnonzero; err = sqrt(err-sqr(avg)); if ( maxval <= avg+sqrt(ivalnonzero/2.)*err ) { overestimate_ = maxval; last_max_position_ = maxpos; break; } vals.erase(vals.begin()+imax); ivalnonzero--; } for ( unsigned long ival=0; ival < vals.size(); ival++ ) { val = vals[ival].first; stats->presampled(val); opt.select(val); selected(pos,std::abs(val),ainfo); } function->stop_presampling(); } template void cell_info::explore (Random& rnd_gen, const adaption_info& ainfo, Function* function, double detuning) { function->start_presampling(); unsigned long n_sampled = 0; std::vector ll = lower_left_; std::vector ur = upper_right_; double val = 0.; std::vector pos (ll.size()); std::vector< std::pair > > vals; while (n_sampled < ainfo.presampling_points) { std::transform(ll.begin(),ll.end(), ur.begin(),pos.begin(), rnd_gen); val = function->evaluate(pos) * detuning; if ( std::abs(val) > 0 ) vals.push_back( std::pair > (std::abs(val),pos) ); ++n_sampled; } while ( vals.size() > 0 ) { double avg = 0; double err = 0; double maxval = 0; std::vector maxpos (ll.size()); - unsigned long imax; + unsigned long imax(0); for ( unsigned long ival=0; ival < vals.size(); ival++ ) { double thisval = vals[ival].first; avg += thisval; err += sqr(thisval); if ( thisval > maxval ) { maxval = thisval; maxpos = vals[ival].second; imax = ival; } } avg /= vals.size(); err /= vals.size(); err = sqrt(err-sqr(avg)); if ( maxval <= avg+sqrt(vals.size()/2.)*err ) { overestimate_ = maxval; last_max_position_ = maxpos; break; } vals.erase(vals.begin()+imax); } function->stop_presampling(); } template void cell_info::put (OStream& os) const { os << overestimate_; ostream_traits::separator(os); os << volume_; ostream_traits::separator(os); os << lower_left_.size(); ostream_traits::separator(os); for (std::size_t k = 0; k < lower_left_.size(); ++k) { os << lower_left_[k]; ostream_traits::separator(os); } for (std::size_t k = 0; k < upper_right_.size(); ++k) { os << upper_right_[k]; ostream_traits::separator(os); } for (std::size_t k = 0; k < mid_point_.size(); ++k) { os << mid_point_[k]; ostream_traits::separator(os); } for (std::size_t k = 0; k < last_max_position_.size(); ++k) { os << last_max_position_[k]; ostream_traits::separator(os); } for (std::size_t k = 0; k < avg_weight_.size(); ++k) { os << avg_weight_[k].first; ostream_traits::separator(os); os << avg_weight_[k].second; ostream_traits::separator(os); } os << attempted_; ostream_traits::separator(os); os << accepted_; ostream_traits::separator(os); os << parametric_missing_map_.size(); ostream_traits::separator(os); for ( std::map,int>::const_iterator p = parametric_missing_map_.begin(); p != parametric_missing_map_.end(); ++p ) { p->first.put(os); os << p->second; ostream_traits::separator(os); } } template void cell_info::get (IStream& is) { std::size_t dim; is >> overestimate_ >> volume_ >> dim; lower_left_.resize(dim); for (std::size_t k = 0; k < lower_left_.size(); ++k) { is >> lower_left_[k]; } upper_right_.resize(dim); for (std::size_t k = 0; k < upper_right_.size(); ++k) { is >> upper_right_[k]; } mid_point_.resize(dim); for (std::size_t k = 0; k < mid_point_.size(); ++k) { is >> mid_point_[k]; } last_max_position_.resize(dim); for (std::size_t k = 0; k < last_max_position_.size(); ++k) { is >> last_max_position_[k]; } avg_weight_.resize(dim); for (std::size_t k = 0; k < avg_weight_.size(); ++k) { is >> avg_weight_[k].first >> avg_weight_[k].second; } is >> attempted_ >> accepted_ >> dim; for ( size_t k = 0; k < dim; ++k ) { bit_container in; in.get(is); is >> parametric_missing_map_[in]; } } template std::pair cell::split (std::pair split_d, Random& rnd_gen, Function* function, const adaption_info& ainfo, const std::vector& sampled, double detuning) { assert(!missing_events() && !info().parametric_compensating()); split_dimension_ = split_d.first; split_point_ = split_d.second; std::vector lower_left1 = info().lower_left(); std::vector upper_right1 = info().upper_right(); std::vector lower_left2 = info().lower_left(); std::vector upper_right2 = info().upper_right(); upper_right1[split_dimension_] = split_point_; lower_left2[split_dimension_] = split_point_; std::pair children; if (sampled.empty()) children = std::pair(cell(lower_left1,upper_right1,ainfo), cell(lower_left2,upper_right2,ainfo)); else children = std::pair (cell(lower_left1,upper_right1,sampled,ainfo), cell(lower_left2,upper_right2,sampled,ainfo)); if (info().last_max_position()[split_dimension_] <= split_point_) { children.first.info().overestimate(info().overestimate(),info().last_max_position(),1.0); children.second.info().explore(rnd_gen,ainfo,function,detuning); } else { children.second.info().overestimate(info().overestimate(),info().last_max_position(),1.0); children.first.info().explore(rnd_gen,ainfo,function,detuning); } cell_info_.reset(0); children.first.integral(children.first.info().volume() * children.first.info().overestimate()); children.second.integral(children.second.info().volume() * children.second.info().overestimate()); return children; } template void cell::put (OStream& os) const { os << split_dimension_; ostream_traits::separator(os); os << split_point_; ostream_traits::separator(os); os << integral_; ostream_traits::separator(os); os << missing_events_; ostream_traits::separator(os); if (cell_info_) { os << "has_cell_info"; ostream_traits::separator(os); cell_info_->put(os); } else { os << "has_no_cell_info"; ostream_traits::separator(os); } } template void cell::get (IStream& is) { std::string info_tag; is >> split_dimension_ >> split_point_ >> integral_ >> missing_events_ >> info_tag; if (info_tag == "has_cell_info") { cell_info_.reset(new cell_info()); cell_info_->get(is); } } inline cell_info::cell_info() : overestimate_(0.), volume_(0.), lower_left_(), upper_right_(), mid_point_(), last_max_position_(), avg_weight_(), attempted_(0), accepted_(0) {} inline cell_info::cell_info(const std::vector& ll, const std::vector& ur, const adaption_info& ainfo) : overestimate_(0.), volume_(), lower_left_(ll), upper_right_(ur), mid_point_(), last_max_position_(), avg_weight_(std::vector > (ainfo.dimension,std::make_pair(0.,0.))), attempted_(0), accepted_(0) { std::vector delta; std::transform(ur.begin(),ur.end(), ll.begin(),std::back_inserter(delta), std::minus()); volume_ = std::accumulate(delta.begin(),delta.end(),1.,std::multiplies()); std::transform(ur.begin(),ur.end(), ll.begin(),std::back_inserter(mid_point_), std::plus()); for (std::size_t k = 0; k < ainfo.dimension; ++k) mid_point_[k] /= 2.; } inline cell_info::cell_info(const std::vector& ll, const std::vector& ur, const std::vector& sampled_variables, const adaption_info& ainfo) : overestimate_(0.), volume_(), lower_left_(ll), upper_right_(ur), mid_point_(), last_max_position_(), avg_weight_(std::vector > (ainfo.dimension,std::make_pair(0.,0.))), attempted_(0), accepted_(0) { std::vector delta; conditional_transform(ur.begin(),ur.end(), ll.begin(),sampled_variables.begin(), std::back_inserter(delta), std::minus()); volume_ = std::accumulate(delta.begin(),delta.end(),1.,std::multiplies()); std::transform(ur.begin(),ur.end(), ll.begin(),std::back_inserter(mid_point_), std::plus()); for (std::size_t k = 0; k < ainfo.dimension; ++k) mid_point_[k] /= 2.; } inline int cell_info::parametric_missing(const bit_container& id) const { std::map,int>::const_iterator mit = parametric_missing_map_.find(id); if (mit == parametric_missing_map_.end()) return 0; return mit->second; } inline void cell_info::parametric_missing(const bit_container& id, int n) { if (n == 0) { std::map,int>::iterator mit = parametric_missing_map_.find(id); if (mit != parametric_missing_map_.end()) parametric_missing_map_.erase(mit); return; } parametric_missing_map_[id] = n; } inline void cell_info::increase_parametric_missing(const bit_container& id) { std::map,int>::iterator mit = parametric_missing_map_.find(id); if (mit != parametric_missing_map_.end()) { mit->second += 1; if (mit->second == 0) parametric_missing_map_.erase(mit); } else parametric_missing_map_[id] = 1; } inline void cell_info::decrease_parametric_missing(const bit_container& id) { std::map,int>::iterator mit = parametric_missing_map_.find(id); if (mit != parametric_missing_map_.end()) { mit->second -= 1; if (mit->second == 0) parametric_missing_map_.erase(mit); } else assert(false); } inline void cell_info::selected(const std::vector& p, double weight, const adaption_info& ainfo) { for (std::size_t k = 0; k < p.size(); ++k) { if (ainfo.adapt[k]) { if (p[k] < mid_point_[k]) avg_weight_[k].first += weight; else avg_weight_[k].second += weight; } } } inline std::pair cell_info::get_split (const adaption_info& ainfo, bool& worth) const { std::size_t split_d = 0; double gain = 0.; for (std::size_t k = 0; k < ainfo.dimension; ++k) { double xgain = 0.; double left = avg_weight_[k].first; double right = avg_weight_[k].second; if (left+right > 0.) { xgain = std::abs(left-right)/(left+right); } if (xgain > gain) { gain = xgain; split_d = k; } } worth = (gain >= ainfo.gain_threshold); return std::make_pair(split_d,mid_point_[split_d]); } inline bool cell_info::contains_parameter (const std::vector& point, const std::vector& sampled) const { std::vector::const_iterator p = point.begin(); std::vector::const_iterator l = lower_left_.begin(); std::vector::const_iterator u = upper_right_.begin(); std::vector::const_iterator f = sampled.begin(); for (; p < point.end(); ++p, ++f, ++l, ++u) if (!(*f)) { if (((*l) > (*p)) || ((*u) < (*p))) return false; } return true; } inline cell::cell() : split_dimension_(0), split_point_(0.), integral_(0.), missing_events_(0), cell_info_(nullptr) {} inline cell::cell(const std::vector& ll, const std::vector& ur, const adaption_info& ainfo) : split_dimension_(0), split_point_(0.), integral_(0.), missing_events_(0), cell_info_(new cell_info(ll,ur,ainfo)) {} inline cell::cell(const std::vector& ll, const std::vector& ur, const std::vector& sampled_variables, const adaption_info& ainfo) : split_dimension_(0), split_point_(0.), integral_(0.), missing_events_(0), cell_info_(new cell_info(ll,ur,sampled_variables,ainfo)) {} inline cell::cell(const cell& x) : split_dimension_(x.split_dimension_), split_point_(x.split_point_), integral_(x.integral_), missing_events_(x.missing_events_), cell_info_(nullptr) { if (x.cell_info_) cell_info_.reset(new cell_info(*x.cell_info_)); } inline cell& cell::operator=(const cell& x) { if (this == &x) return *this; split_dimension_ = x.split_dimension_; split_point_ = x.split_point_; integral_ = x.integral_; missing_events_ = x.missing_events_; if (x.cell_info_) cell_info_.reset(new cell_info(*x.cell_info_)); return *this; } } diff --git a/Shower/Dipole/Merging/Merger.h b/Shower/Dipole/Merging/Merger.h --- a/Shower/Dipole/Merging/Merger.h +++ b/Shower/Dipole/Merging/Merger.h @@ -1,408 +1,408 @@ /// -*- C++ -*- // /// Merger.h is a part of Herwig - A multi-purpose Monte Carlo event generator /// Copyright (C) 2002-2017 The Herwig Collaboration // /// Herwig is licenced under version 3 of the GPL, see COPYING for details. /// Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_Merger_H #define HERWIG_Merger_H // /// This is the declaration of the Merger class. // #include "MergingFactory.fh" #include "Node.fh" #include "ThePEG/Handlers/HandlerBase.h" #include "Herwig/Shower/Dipole/DipoleShowerHandler.h" //#include "Herwig/Shower/Dipole/Base/DipoleSplittingGenerator.h" #include "Herwig/MatrixElement/Matchbox/Base/MergerBase.h" #include "Herwig/MatrixElement/Matchbox/Phasespace/FFLightTildeKinematics.h" #include "Herwig/MatrixElement/Matchbox/Phasespace/IFLightTildeKinematics.h" #include "Herwig/MatrixElement/Matchbox/Phasespace/FFMassiveTildeKinematics.h" #include "Herwig/MatrixElement/Matchbox/Phasespace/IFMassiveTildeKinematics.h" #include "Herwig/MatrixElement/Matchbox/Phasespace/FILightTildeKinematics.h" #include "Herwig/MatrixElement/Matchbox/Phasespace/IILightTildeKinematics.h" #include "Herwig/MatrixElement/Matchbox/Phasespace/FIMassiveTildeKinematics.h" #include "ThePEG/Cuts/JetFinder.h" #include "ThePEG/Cuts/Cuts.h" namespace Herwig { using namespace ThePEG; class Merger; ThePEG_DECLARE_POINTERS(Merger , MergerPtr ); typedef vector NodePtrVec; //definition of a history step struct HistoryStep { /// containing the full information NodePtr node; /// current sudakov weight of the history double weight; /// current scale of the history Energy scale; }; typedef vector< HistoryStep > History; typedef multimap::ptr> GeneratorMap2; /** * \ingroup DipoleShower * \author Johannes Bellm * * \brief Merger handles the Merger ....... //TODO . * * @see \ref MergerInterfaces "The interfaces" * defined for Merger. */ class Merger: public MergerBase { friend class MergingFactory; friend class Node; public: // define the ME region for a particle vector. bool matrixElementRegion(PVector incoming, PVector outgoing, Energy winnerScale = ZERO, Energy cutscale = ZERO)const; /// return the current merging scale, /// gets smeared around the central merging scale in generate kinematics. Energy mergingScale()const{return theMergePt;} /// return the current merging pt (should be unified with mergingScale) Energy mergePt()const {return theMergePt;} /// legsize of highest process with NLO corrections int M()const; /// legsize of the highest LO merged process int N()const; /// legsize of the production process int N0()const{return theN0;} /// cross section of as given by the merging CrossSection MergingDSigDR(); /// ***** virtual functions of the base class ****/// /// set the current xcomb, called from ME void setXComb( tStdXCombPtr ); /// set kinematics, called from ME void setKinematics(); /// clear kinematics, called from ME void clearKinematics(); /// generate kinematics, called from ME bool generateKinematics( const double * ); /// generate kinematics, called from ME void flushCaches(); /// return the current maximum legs, the shower should veto size_t maxLegs() const {return theCurrentMaxLegs;} /// set the current ME void setME(MatchboxMEBasePtr me){ theCurrentME=me; assert(theFirstNodeMap.count(theCurrentME)); theCurrentNode=theFirstNodeMap[theCurrentME]; } /// allow emissions with a given probability.in the ME region double emissionProbability() const{ return theEmissionProbability; } /// set a probability of allowed emission into ME region. void setEmissionProbability(double x){theEmissionProbability=x;} protected: /// the merging factory needs to set the legsize of the production process void N0(int n){ theN0=n;} /// return the large-N basis (TODO: implement check if born ME works with the choice) Ptr::ptr largeNBasis()const{return theLargeNBasis;} /// smear the merging pt void smearMergePt(){ const double factor = 1. + (-1. + 2.*UseRandom::rnd() ) * smear(); theMergePt = factor * centralMergePt(); } /// true if the phase space for initial emissions should not be restricted in z. int openZBoundaries()const{return DSH()->showerPhaseSpaceOption();} /// return the current ME MatchboxMEBasePtr currentME() const { return theCurrentME; } /// return the current Node NodePtr currentNode() const { return theCurrentNode; } /// the gamma parameter to subtract dipoles above a alpha parameter /// and subtract the corresponding IPK operator double gamma()const{return theGamma;} private: /// calculate a single sudakov step for a given dipole double singlesudakov(Dipole, Energy, Energy, pair); /// calculate the sudakov supression for a clusternode between /// the current running scale and next scale bool dosudakov(NodePtr Born, Energy running, Energy next, double& sudakov0_n); /// cleanup void cleanup(NodePtr); /// return true if the cluster node has the matching number of /// legs to the current projector stage bool isProjectorStage( NodePtr , int )const; /** * Calculate the staring scale: * if Node is part of the production process, calculate according to the * scale choice object in the merging scale objekt, else * return max(scale as scalechoice , min(Mass(i, j))) */ Energy CKKW_StartScale(NodePtr) const; /// prepare the sudakov calculation void CKKW_PrepareSudakov(NodePtr, Energy); /// number of active flavours as given by the shower double Nf(Energy scale)const{return DSH()->Nf(scale);} /// pointer to the factory MergingFactoryPtr treefactory() const; /// map from ME to first clusternode map firstNodeMap() const ; /// set the current merging pt, smeared in generate kinematics void mergePt(Energy x) {theMergePt = x;} /// return the central merging pt Energy centralMergePt() const {return theCentralMergePt;} private: /// calculate the history weighted born cross section CrossSection MergingDSigDRBornStandard(); /** * calculate the history weighted born cross section * add the difference of IPK with and without alpha parameter * subtract the dipoles above the alpha parameter */ CrossSection MergingDSigDRBornGamma(); /// calculate the history weighted virtual contribution CrossSection MergingDSigDRVirtualStandard(); /** * calculate the history weighted real contribution * splitted into 3 differnt contibutions */ CrossSection MergingDSigDRRealStandard(); /// calculate the history weighted real contribution /// all dipoles above: /// N*(R rnd(i)-Dip_i) history_i U(\phi^n_i) CrossSection MergingDSigDRRealAllAbove(); /// calculate the history weighted real contribution /// not all dipoles above: /// (R - sum PS_i) history_rnd U(\phi^n+1) CrossSection MergingDSigDRRealBelowSubReal(); /// calculate the history weighted real contribution /// not all dipoles above: /// rnd(i)-> N*(PS_i - Dip_i) history_i U(\phi^n_i) CrossSection MergingDSigDRRealBelowSubInt(); /// max legssize the shower should veto for LO size_t maxLegsLO() const {return N0()+N();} /// Calculate the LO partonic cross section. /// if diffalpha != 1, add the difference of IPK(1)-IPK(diffalpha) CrossSection TreedSigDR(Energy startscale, double diffalpha=1.); /// fill the projecting xcomb Energy fillProjector(int); /// fill the history, including calculation of sudakov supression void fillHistory(Energy, NodePtr, NodePtr ); /// calculate the pdf ratio for the given clusternode double pdfratio(NodePtr, Energy, Energy, int, bool fromIsME, bool toIsME); /// return the pdf-ratio reweight for the history double pdfReweight(); /// return the alpha_s reweight for the history double alphaReweight(bool nocmw=false); /// max legssize the shower should veto for NLO size_t maxLegsNLO()const {return N0()+M();} /// calculate the virtual contribution. CrossSection LoopdSigDR(Energy startscale ); /// calculate alpha_s expansion of the pdf-ratios double sumPdfReweightExpansion()const; /// calculate alpha_s expansion of the alpha_s-ratios, including K_g double sumAlphaSReweightExpansion()const; /// calculate alpha_s expansion of the sudakov exponents double sumFillHistoryExpansion(); /// calculate alpha_s expansion of the single step alpha_s-ratio, including K_g double alphasExpansion( Energy next, Energy fixedScale)const; /// calculate alpha_s expansion of the single step pdf-ratio double pdfExpansion(NodePtr, int, Energy, Energy, double, int, Energy)const; /// calculate alpha_s expansion of the single step sudakov exponent bool doHistExpansion(NodePtr Born, Energy running, Energy next, Energy fixedScale, double& HistExpansion); /// calculate alpha_s expansion of the single dipole sudakov exponent double singleHistExpansion(Dipole, Energy, Energy, Energy, pair); //alpha_s as given in the shower double as(Energy q)const{return DSH()->as(q);} // set the pointer to the Mergingfactory. void setFactory(MergingFactoryPtr f){theTreeFactory=f;} // set the pointer to the DipoleShower. void setDipoleShower(DipoleShowerHandlerPtr dsh){theDipoleShowerHandler=dsh;} //return the dipole shower handler DipoleShowerHandlerPtr DSH(){return theDipoleShowerHandler;} //return the const dipole shower handler cDipoleShowerHandlerPtr DSH()const{return theDipoleShowerHandler;} /// insert map from ME to first clusternode void firstNodeMap(MatchboxMEBasePtr, NodePtr); /// history choice: weighted history choice int chooseHistory()const {return theChooseHistory;} /// the smearing factor for the merging scale double smear()const{return theSmearing;} /// return the large-N colour basis void largeNBasis(Ptr::ptr x){theLargeNBasis=x;} /// helper function to check the only multi condition. bool notOnlyMulti()const; /// Calculate the CMW AlphaS double cmwAlphaS(Energy q)const; /// debug output for virtual void debugVirt(double, double, double, double, CrossSection, double, double, double, NodePtr,CrossSection) const; /// debug output for reals void debugReal( string, double, CrossSection, CrossSection) const; private: /// calculate the history expansion unsigned int theShowerExpansionWeights = 2; /// use CMW scheme unsigned int theCMWScheme = 0; /// true if current point should be projected bool projected = true; /// true if LO cross sections should be unitarised bool isUnitarized = true; /// true if NLO contributions should be unitarised bool isNLOUnitarized = true; /// history weight choice int theChooseHistory = 0; /// legsize of production process int theN0 = 0; /// calculate only the N particle contribution int theOnlyN = -1; /// the current maxlegs (either LO or NLO maxlegs) - size_t theCurrentMaxLegs = -1; + int theCurrentMaxLegs = -1; /// current weight and weight of clustered born double weight = 1.0; double weightCB = 1.0; /// subtract the dipole contribution above a given gamma double theGamma = 1.0; /// smearing factor for merging scale double theSmearing = 0.; /** * Allow emissions for the unitarising LO contributions * according to the prob 1-min(B_n/sum Dip_n,Dip_n/B_n) */ bool emitDipoleMEDiff = false; /// The conditional emission probability if emitDipoleMEDiff is true. double theEmissionProbability = 0.; /// cutoff for real emission contribution Energy theIRSafePT = 1_GeV; /// current merging scale Energy theMergePt = 4_GeV; /// central merging scale Energy theCentralMergePt = 4_GeV; /// below mergingscale/theRealSubtractionRatio the dipoles are used to subtract. /// above the shower approximation is in use. double theRealSubtractionRatio=3.; /// current cluster histoy including sudakov weights History history; /// pointer to the large-N basis Ptr::ptr theLargeNBasis; /// current Node NodePtr theCurrentNode; /// current ME MatchboxMEBasePtr theCurrentME; /// Tilde kinematics pointers, only to use lastPt(emitter, emission, spectator) Ptr::ptr FFLTK = new_ptr( FFLightTildeKinematics() ); Ptr::ptr FILTK = new_ptr( FILightTildeKinematics() ); Ptr::ptr IFLTK = new_ptr( IFLightTildeKinematics() ); Ptr::ptr IILTK = new_ptr( IILightTildeKinematics() ); Ptr::ptr FFMTK = new_ptr( FFMassiveTildeKinematics() ); Ptr::ptr FIMTK = new_ptr( FIMassiveTildeKinematics() ); Ptr::ptr IFMTK = new_ptr( IFMassiveTildeKinematics() ); //pointer to the shower handler DipoleShowerHandlerPtr theDipoleShowerHandler; /// pointer to the MergingFactory MergingFactoryPtr theTreeFactory; /// map from ME to first Node map theFirstNodeMap; /// map from ME to highest ME weight so far map theHighMeWeightMap; 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: /** @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; /** 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; //@} // If needed, insert declarations of virtual function defined in the // InterfacedBase class here (using ThePEG-interfaced-decl in Emacs). private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ Merger & operator=(const Merger &) = delete; }; } #endif /* HERWIG_Merger_H */ diff --git a/Shower/Dipole/Merging/MergingFactory.h b/Shower/Dipole/Merging/MergingFactory.h --- a/Shower/Dipole/Merging/MergingFactory.h +++ b/Shower/Dipole/Merging/MergingFactory.h @@ -1,179 +1,179 @@ /// -*- C++ -*- // /// MergingFactory.h is a part of Herwig - A multi-purpose Monte Carlo event generator /// Copyright (C) 2002-2017 The Herwig Collaboration // /// Herwig is licenced under version 3 of the GPL, see COPYING for details. /// Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_MergingFactory_H #define HERWIG_MergingFactory_H // /// This is the declaration of the MergingFactory class. // #include "MergingFactory.fh" #include "Herwig/MatrixElement/Matchbox/MatchboxFactory.h" #include "Node.fh" #include "Merger.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" namespace Herwig { using namespace ThePEG; /** * \ingroup Matchbox * \author Johannes Bellm * * \brief MergingFactory automatically sets up a NLO * QCD merging. * * @see \ref MergingFactoryInterfaces "The interfaces" * defined for MergeboxFactory. */ class MergingFactory : public MatchboxFactory { public: ///Check consistency and switch to porduction mode. void productionMode(); /// main method to setup the ME vector virtual void setup(); /// fill all amplitudes, stored in pureMEsMap void fillMEsMap(); /// prepare the Born and virtual matrix elements. void prepare_BV(int i); /// prepare the real emission matrix elements. void prepare_R(int i); /// push the born contributions to the ME vector. void pushB(MatchboxMEBasePtr, int); //push the virtual contributions to the ME vector. void pushV(MatchboxMEBasePtr, int); /// push the real contributions to the ME vector. void pushR(MatchboxMEBasePtr, int); /// order matrix elements from one loop provider. void orderOLPs(); /// Debugging: push only multiplicities to the ME vector /// in range of specified mulltiplicity. int onlymulti()const { - return theonlymulti==-1?-1:(theonlymulti+processMap.find(0)->second.size()); + return theonlymulti==-1?-1:(theonlymulti+int(processMap.find(0)->second.size())); } /// pointer to the merging helper. MergerPtr MH() {return theMergingHelper;} /// maximal NLO mulitplicity: 0=NLO corrections to the productio process. int M() const {return theM-1;} /// leg size of highest multiplicity. int N() const {return theN;} /// Return the Map of matrix elements to be considered /// (the Key is the number of additional jets) const map >& pureMEsMap() const { return thePureMEsMap; } /// Access the Map of matrix elements to be considered /// (the Key is the number of additional jets) map >& pureMEsMap() { return thePureMEsMap; } //Parse a process description virtual vector parseProcess(string); // fill the virtuals vector (these are IPK-operators) void getVirtuals(MatchboxMEBasePtr nlo, bool clone ); // In the merged setup we only produce single phase space points. bool subProcessGroups() const { return false;} // Cut on non-QCD observables. Ptr::ptr nonQCDCuts(){return theNonQCDCuts;} 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); //@} static void Init(); protected: /** @name Standard Interfaced functions. */ //@{ /** * Initialize this object after the setup phase before saving an * EventGenerator to disk. * @throws InitException if object could not be initialized properly. */ virtual void doinit(); //@} protected: /** @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; //@} private: /// unitarise the LO contributions. bool unitarized = true; /// did run setup. bool ransetup = false; /// Debugging: push only multiplicities to the ME vector /// in range of specified mulltiplicity. int theonlymulti = -1; /// maximal legsize for NLO corrections. int theM = -1; /// maximal legsize for LO contributions. int theN = -1; /// map for processes. map< int, vector > processMap; //The matrix elements: int = number of additional jets map< int, vector > thePureMEsMap; /// the merging helper MergerPtr theMergingHelper; /// Cut on non-QCD modified observables. Ptr::ptr theNonQCDCuts; /// For more complicated processes the number of subprocesses is large. /// This parameter allows to chunk the suprocesses into same sized cunks. /// It is in the responsibility of the user to add all chunk parts afterwards. /// The user also needs to take care that, e.g. output can be compined. int theChunk=0; /// This parameter selects a part chunkpart of the chunked subprocesses. /// The user needs to take care to sum all chunkparts afterwards. int theChunkPart=0; /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ MergingFactory & operator=(const MergingFactory &) = delete; }; } #endif /* HERWIG_MergingFactory_H */ diff --git a/Shower/QTilde/Base/FullShowerVeto.cc b/Shower/QTilde/Base/FullShowerVeto.cc --- a/Shower/QTilde/Base/FullShowerVeto.cc +++ b/Shower/QTilde/Base/FullShowerVeto.cc @@ -1,158 +1,158 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the FullShowerVeto class. // #include "FullShowerVeto.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/EventRecord/Particle.h" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Utilities/DescribeClass.h" #include "Herwig/Shower/ShowerHandler.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" using namespace Herwig; void FullShowerVeto::persistentOutput(PersistentOStream & os) const { os << type_ << behaviour_; } void FullShowerVeto::persistentInput(PersistentIStream & is, int) { is >> type_ >> behaviour_; } void FullShowerVeto::doinit() { Interfaced::doinit(); // check reweighting if(behaviour_==1&&type_!=2) throw Exception() << "Reweighting in the FullShowerVeto is only" << " supported for the primary hard process\n" << Exception::runerror; } DescribeAbstractClass describeHerwigFullShowerVeto("Herwig::FullShowerVeto", "HwShower.so"); void FullShowerVeto::Init() { static ClassDocumentation documentation ("The FullShowerVeto class allows the parton shower generated from a configuration to be vetoed."); static Switch interfaceType ("Type", "Which type of processes to consider", &FullShowerVeto::type_, 1, false, false); static SwitchOption interfaceTypeAll (interfaceType, "All", "All Processes", 0); static SwitchOption interfaceTypeScattering (interfaceType, "Scattering", "Only apply to scattering processes and not decays", 1); static SwitchOption interfaceTypePrimary (interfaceType, "Primary", "Only apply to the primary scattering process", 2); static SwitchOption interfaceTypeDecay (interfaceType, "Decay", "Only apply to decays", 3); static Switch interfaceBehaviour ("Behaviour", "What to do if the shower if vetoed", &FullShowerVeto::behaviour_, 0, false, false); static SwitchOption interfaceBehaviourShower (interfaceBehaviour, "Shower", "Veto the shower and try showering the process again", 0); static SwitchOption interfaceBehaviourShowerReweight (interfaceBehaviour, "ShowerReweight", "Veto the shower and reweight the event to take this into account, only supported for the primary process", 1); static SwitchOption interfaceBehaviourEvent (interfaceBehaviour, "Event", "Veto the event, cross section automatically reweigted", 2); } int FullShowerVeto::applyVeto(ShowerTreePtr tree) { // return if veto should not be calculated // decay process and only doing hard processes // or vice versa if(((type_ == 1 || type_ ==2 ) && tree->isDecay() ) || ( type_ == 3 && tree->isHard())) return -1; // not primary process and only doing those if( type_ == 2 && !ShowerHandler::currentHandler()->firstInteraction() ) return -1; // extract the incoming and outgoing particles from the ShowerTree finalState_.clear(); incoming_.clear(); outgoing_.clear(); // incoming for(map::const_iterator it=tree->incomingLines().begin(); it!=tree->incomingLines().end();++it) { incoming_.push_back(it->first->progenitor()); } // outgoing for(map::const_iterator it=tree->outgoingLines().begin(); it!=tree->outgoingLines().end();++it) { outgoing_.push_back(it->first->progenitor()); } // call function in inheriting class to decide what to do bool vetoed = vetoShower(); // clear storage finalState_.clear(); incoming_.clear(); outgoing_.clear(); // return the answer - return vetoed ? behaviour_ : -1; + return vetoed ? int(behaviour_) : -1; } namespace { void addFinal(vector & finalState, tPPtr particle) { if(particle->children().empty()) { finalState.push_back(particle); return; } for(unsigned int ix=0;ixchildren().size();++ix) { addFinal(finalState,particle->children()[ix]); } } } // extract the incoming and outgoing particles const vector & FullShowerVeto::finalState() { if(!finalState_.empty()) return finalState_; // incoming for(unsigned int ix=0;ixparents().empty()) continue; tPPtr parent = incoming_[ix]->parents()[0]; while (parent) { addFinal(finalState_,parent->children()[1]); if(parent->parents().empty()) break; parent = parent->parents()[0]; } } // outgoing for(unsigned int ix=0;ix using namespace Herwig; PPtr ShowerParticle::clone() const { return new_ptr(*this); } PPtr ShowerParticle::fullclone() const { return new_ptr(*this); } ClassDescription ShowerParticle::initShowerParticle; // Definition of the static class description member. void ShowerParticle::vetoEmission(ShowerPartnerType, Energy scale) { scales_.QED = min(scale,scales_.QED ); scales_.QED_noAO = min(scale,scales_.QED_noAO ); scales_.QCD_c = min(scale,scales_.QCD_c ); scales_.QCD_c_noAO = min(scale,scales_.QCD_c_noAO ); scales_.QCD_ac = min(scale,scales_.QCD_ac ); scales_.QCD_ac_noAO = min(scale,scales_.QCD_ac_noAO); if(spinInfo()) spinInfo()->undecay(); } void ShowerParticle::addPartner(EvolutionPartner in ) { partners_.push_back(in); } namespace { LorentzRotation boostToShower(Lorentz5Momentum & porig, tShowerBasisPtr basis) { LorentzRotation output; assert(basis); if(basis->frame()==ShowerBasis::BackToBack) { // we are doing the evolution in the back-to-back frame // work out the boostvector Boost boostv(-(basis->pVector()+basis->nVector()).boostVector()); // momentum of the parton Lorentz5Momentum ptest(basis->pVector()); // construct the Lorentz boost output = LorentzRotation(boostv); ptest *= output; Axis axis(ptest.vect().unit()); // now rotate so along the z axis as needed for the splitting functions if(axis.perp2()>1e-10) { double sinth(sqrt(1.-sqr(axis.z()))); output.rotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); } else if(axis.z()<0.) { output.rotate(Constants::pi,Axis(1.,0.,0.)); } porig = output*basis->pVector(); porig.setX(ZERO); porig.setY(ZERO); } else { output = LorentzRotation(-basis->pVector().boostVector()); porig = output*basis->pVector(); porig.setX(ZERO); porig.setY(ZERO); porig.setZ(ZERO); } return output; } RhoDMatrix bosonMapping(ShowerParticle & particle, const Lorentz5Momentum & porig, VectorSpinPtr vspin, const LorentzRotation & rot, Helicity::Direction dir) { // rotate the original basis vector sbasis; for(unsigned int ix=0;ix<3;++ix) { sbasis.push_back(vspin->getProductionBasisState(ix)); sbasis.back().transform(rot); } // splitting basis vector fbasis; bool massless(particle.id()==ParticleID::g||particle.id()==ParticleID::gamma); VectorWaveFunction wave(porig,particle.dataPtr(),dir==outgoing ? incoming : outgoing); for(unsigned int ix=0;ix<3;++ix) { if(massless&&ix==1) { fbasis.push_back(LorentzPolarizationVector()); } else { wave.reset(ix,vector_phase); fbasis.push_back(wave.wave()); } } // work out the mapping RhoDMatrix mapping=RhoDMatrix(PDT::Spin1,false); for(unsigned int ix=0;ix<3;++ix) { for(unsigned int iy=0;iy<3;++iy) { mapping(ix,iy)= -conj(sbasis[ix].dot(fbasis[iy])); if(particle.id()<0) mapping(ix,iy)=conj(mapping(ix,iy)); } } return mapping; } RhoDMatrix fermionMapping(ShowerParticle & particle, const Lorentz5Momentum & porig, FermionSpinPtr fspin, const LorentzRotation & rot) { // extract the original basis states vector > sbasis; for(unsigned int ix=0;ix<2;++ix) { sbasis.push_back(fspin->getProductionBasisState(ix)); sbasis.back().transform(rot); } // calculate the states in the splitting basis vector > fbasis; SpinorWaveFunction wave(porig,particle.dataPtr(), particle.id()>0 ? incoming : outgoing); for(unsigned int ix=0;ix<2;++ix) { wave.reset(ix); fbasis.push_back(wave.dimensionedWave()); } RhoDMatrix mapping=RhoDMatrix(PDT::Spin1Half,false); for(unsigned int ix=0;ix<2;++ix) { if(fbasis[0].s2()==complex()) { mapping(ix,0) = sbasis[ix].s3()/fbasis[0].s3(); mapping(ix,1) = sbasis[ix].s2()/fbasis[1].s2(); } else { mapping(ix,0) = sbasis[ix].s2()/fbasis[0].s2(); mapping(ix,1) = sbasis[ix].s3()/fbasis[1].s3(); } } return mapping; } FermionSpinPtr createFermionSpinInfo(ShowerParticle & particle, const Lorentz5Momentum & porig, const LorentzRotation & rot, Helicity::Direction dir) { // calculate the splitting basis for the branching // and rotate back to construct the basis states LorentzRotation rinv = rot.inverse(); SpinorWaveFunction wave; if(particle.id()>0) wave=SpinorWaveFunction(porig,particle.dataPtr(),incoming); else wave=SpinorWaveFunction(porig,particle.dataPtr(),outgoing); FermionSpinPtr fspin = new_ptr(FermionSpinInfo(particle.momentum(),dir==outgoing)); for(unsigned int ix=0;ix<2;++ix) { wave.reset(ix); LorentzSpinor basis = wave.dimensionedWave(); basis.transform(rinv); fspin->setBasisState(ix,basis); } particle.spinInfo(fspin); return fspin; } VectorSpinPtr createVectorSpinInfo(ShowerParticle & particle, const Lorentz5Momentum & porig, const LorentzRotation & rot, Helicity::Direction dir) { // calculate the splitting basis for the branching // and rotate back to construct the basis states LorentzRotation rinv = rot.inverse(); bool massless(particle.id()==ParticleID::g||particle.id()==ParticleID::gamma); VectorWaveFunction wave(porig,particle.dataPtr(),dir); VectorSpinPtr vspin = new_ptr(VectorSpinInfo(particle.momentum(),dir==outgoing)); for(unsigned int ix=0;ix<3;++ix) { LorentzPolarizationVector basis; if(massless&&ix==1) { basis = LorentzPolarizationVector(); } else { wave.reset(ix,vector_phase); basis = wave.wave(); } basis *= rinv; vspin->setBasisState(ix,basis); } particle.spinInfo(vspin); vspin-> DMatrix() = RhoDMatrix(PDT::Spin1); vspin->rhoMatrix() = RhoDMatrix(PDT::Spin1); if(massless) { vspin-> DMatrix()(0,0) = 0.5; vspin->rhoMatrix()(0,0) = 0.5; vspin-> DMatrix()(2,2) = 0.5; vspin->rhoMatrix()(2,2) = 0.5; } return vspin; } } RhoDMatrix ShowerParticle::extractRhoMatrix(bool forward) { // get the spin density matrix and the mapping RhoDMatrix mapping; SpinPtr inspin; bool needMapping = getMapping(inspin,mapping); // set the decayed flag inspin->decay(); // get the spin density matrix RhoDMatrix rho = forward ? inspin->rhoMatrix() : inspin->DMatrix(); // map to the shower basis if needed if(needMapping) { RhoDMatrix rhop(rho.iSpin(),false); for(int ixb=0;ixbperturbative()) { // mapping is the identity output=this->spinInfo(); mapping=RhoDMatrix(this->dataPtr()->iSpin()); if(output) { return false; } else { Lorentz5Momentum porig; LorentzRotation rot = boostToShower(porig,showerBasis()); Helicity::Direction dir = this->isFinalState() ? outgoing : incoming; if(this->dataPtr()->iSpin()==PDT::Spin0) { assert(false); } else if(this->dataPtr()->iSpin()==PDT::Spin1Half) { output = createFermionSpinInfo(*this,porig,rot,dir); } else if(this->dataPtr()->iSpin()==PDT::Spin1) { output = createVectorSpinInfo(*this,porig,rot,dir); } else { assert(false); } return false; } } // if particle is final-state and is from the hard process else if(this->isFinalState()) { assert(this->perturbative()==1 || this->perturbative()==2); // get transform to shower frame Lorentz5Momentum porig; LorentzRotation rot = boostToShower(porig,showerBasis()); // the rest depends on the spin of the particle PDT::Spin spin(this->dataPtr()->iSpin()); mapping=RhoDMatrix(spin,false); // do the spin dependent bit if(spin==PDT::Spin0) { ScalarSpinPtr sspin=dynamic_ptr_cast(this->spinInfo()); if(!sspin) { ScalarWaveFunction::constructSpinInfo(this,outgoing,true); } output=this->spinInfo(); return false; } else if(spin==PDT::Spin1Half) { FermionSpinPtr fspin=dynamic_ptr_cast(this->spinInfo()); // spin info exists get information from it if(fspin) { output=fspin; mapping = fermionMapping(*this,porig,fspin,rot); return true; } // spin info does not exist create it else { output = createFermionSpinInfo(*this,porig,rot,outgoing); return false; } } else if(spin==PDT::Spin1) { VectorSpinPtr vspin=dynamic_ptr_cast(this->spinInfo()); // spin info exists get information from it if(vspin) { output=vspin; mapping = bosonMapping(*this,porig,vspin,rot,outgoing); return true; } else { output = createVectorSpinInfo(*this,porig,rot,outgoing); return false; } } // not scalar/fermion/vector else assert(false); } // incoming to hard process else if(this->perturbative()==1 && !this->isFinalState()) { // get the basis vectors // get transform to shower frame Lorentz5Momentum porig; LorentzRotation rot = boostToShower(porig,showerBasis()); porig *= this->x(); // the rest depends on the spin of the particle PDT::Spin spin(this->dataPtr()->iSpin()); mapping=RhoDMatrix(spin); // do the spin dependent bit if(spin==PDT::Spin0) { cerr << "testing spin 0 not yet implemented " << endl; assert(false); } // spin-1/2 else if(spin==PDT::Spin1Half) { FermionSpinPtr fspin=dynamic_ptr_cast(this->spinInfo()); // spin info exists get information from it if(fspin) { output=fspin; mapping = fermionMapping(*this,porig,fspin,rot); return true; } // spin info does not exist create it else { output = createFermionSpinInfo(*this,porig,rot,incoming); return false; } } // spin-1 else if(spin==PDT::Spin1) { VectorSpinPtr vspin=dynamic_ptr_cast(this->spinInfo()); // spinInfo exists map it if(vspin) { output=vspin; mapping = bosonMapping(*this,porig,vspin,rot,incoming); return true; } // create the spininfo else { output = createVectorSpinInfo(*this,porig,rot,incoming); return false; } } assert(false); } // incoming to decay else if(this->perturbative() == 2 && !this->isFinalState()) { // get the basis vectors Lorentz5Momentum porig; - LorentzRotation rot=boostToShower(porig,showerBasis()); + //LorentzRotation rot=boostToShower(porig,showerBasis()); // the rest depends on the spin of the particle PDT::Spin spin(this->dataPtr()->iSpin()); mapping=RhoDMatrix(spin); // do the spin dependent bit if(spin==PDT::Spin0) { cerr << "testing spin 0 not yet implemented " << endl; assert(false); } // spin-1/2 else if(spin==PDT::Spin1Half) { // FermionSpinPtr fspin=dynamic_ptr_cast(this->spinInfo()); // // spin info exists get information from it // if(fspin) { // output=fspin; // mapping = fermionMapping(*this,porig,fspin,rot); // return true; // // spin info does not exist create it // else { // output = createFermionSpinInfo(*this,porig,rot,incoming); // return false; // } // } assert(false); } // // spin-1 // else if(spin==PDT::Spin1) { // VectorSpinPtr vspin=dynamic_ptr_cast(this->spinInfo()); // // spinInfo exists map it // if(vspin) { // output=vspin; // mapping = bosonMapping(*this,porig,vspin,rot); // return true; // } // // create the spininfo // else { // output = createVectorSpinInfo(*this,porig,rot,incoming); // return false; // } // } // assert(false); assert(false); } else assert(false); return true; } void ShowerParticle::constructSpinInfo(bool timeLike) { // now construct the required spininfo and calculate the basis states PDT::Spin spin(dataPtr()->iSpin()); if(spin==PDT::Spin0) { ScalarWaveFunction::constructSpinInfo(this,outgoing,timeLike); } // calculate the basis states and construct the SpinInfo for a spin-1/2 particle else if(spin==PDT::Spin1Half) { // outgoing particle if(id()>0) { vector > stemp; SpinorBarWaveFunction::calculateWaveFunctions(stemp,this,outgoing); SpinorBarWaveFunction::constructSpinInfo(stemp,this,outgoing,timeLike); } // outgoing antiparticle else { vector > stemp; SpinorWaveFunction::calculateWaveFunctions(stemp,this,outgoing); SpinorWaveFunction::constructSpinInfo(stemp,this,outgoing,timeLike); } } // calculate the basis states and construct the SpinInfo for a spin-1 particle else if(spin==PDT::Spin1) { bool massless(id()==ParticleID::g||id()==ParticleID::gamma); vector vtemp; VectorWaveFunction::calculateWaveFunctions(vtemp,this,outgoing,massless,vector_phase); VectorWaveFunction::constructSpinInfo(vtemp,this,outgoing,timeLike,massless); } else { throw Exception() << "Spins higher than 1 are not yet implemented in " << "FS_QtildaShowerKinematics1to2::constructVertex() " << Exception::runerror; } } void ShowerParticle::initializeDecay() { Lorentz5Momentum p, n, ppartner, pcm; assert(perturbative()!=1); // this is for the initial decaying particle if(perturbative()==2) { ShowerBasisPtr newBasis; p = momentum(); Lorentz5Momentum ppartner(partner()->momentum()); // removed to make inverse recon work properly //if(partner->thePEGBase()) ppartner=partner->thePEGBase()->momentum(); pcm=ppartner; Boost boost(p.findBoostToCM()); pcm.boost(boost); n = Lorentz5Momentum( ZERO,0.5*p.mass()*pcm.vect().unit()); n.boost( -boost); newBasis = new_ptr(ShowerBasis()); newBasis->setBasis(p,n,ShowerBasis::Rest); showerBasis(newBasis,false); } else { showerBasis(dynamic_ptr_cast(parents()[0])->showerBasis(),true); } } void ShowerParticle::initializeInitialState(PPtr parent) { // For the time being we are considering only 1->2 branching Lorentz5Momentum p, n, pthis, pcm; assert(perturbative()!=2); if(perturbative()==1) { ShowerBasisPtr newBasis; // find the partner and its momentum if(!partner()) return; if(partner()->isFinalState()) { Lorentz5Momentum pa = -momentum()+partner()->momentum(); Lorentz5Momentum pb = momentum(); Energy scale=parent->momentum().t(); Lorentz5Momentum pbasis(ZERO,parent->momentum().vect().unit()*scale); Axis axis(pa.vect().unit()); LorentzRotation rot; double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); if(axis.perp2()>1e-20) { rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); rot.rotateX(Constants::pi); } if(abs(1.-pa.e()/pa.vect().mag())>1e-6) rot.boostZ( pa.e()/pa.vect().mag()); pb *= rot; if(pb.perp2()/GeV2>1e-20) { Boost trans = -1./pb.e()*pb.vect(); trans.setZ(0.); rot.boost(trans); } pbasis *=rot; rot.invert(); n = rot*Lorentz5Momentum(ZERO,-pbasis.vect()); p = rot*Lorentz5Momentum(ZERO, pbasis.vect()); } else { pcm = parent->momentum(); p = Lorentz5Momentum(ZERO, pcm.vect()); n = Lorentz5Momentum(ZERO, -pcm.vect()); } newBasis = new_ptr(ShowerBasis()); newBasis->setBasis(p,n,ShowerBasis::BackToBack); showerBasis(newBasis,false); } else { showerBasis(dynamic_ptr_cast(children()[0])->showerBasis(),true); } } void ShowerParticle::initializeFinalState() { // set the basis vectors Lorentz5Momentum p,n; if(perturbative()!=0) { ShowerBasisPtr newBasis; // find the partner() and its momentum if(!partner()) return; Lorentz5Momentum ppartner(partner()->momentum()); // momentum of the emitting particle p = momentum(); Lorentz5Momentum pcm; // if the partner is a final-state particle then the reference // vector is along the partner in the rest frame of the pair if(partner()->isFinalState()) { Boost boost=(p + ppartner).findBoostToCM(); pcm = ppartner; pcm.boost(boost); n = Lorentz5Momentum(ZERO,pcm.vect()); n.boost( -boost); } else if(!partner()->isFinalState()) { // if the partner is an initial-state particle then the reference // vector is along the partner which should be massless if(perturbative()==1) { n = Lorentz5Momentum(ZERO,ppartner.vect()); } // if the partner is an initial-state decaying particle then the reference // vector is along the backwards direction in rest frame of decaying particle else { Boost boost=ppartner.findBoostToCM(); pcm = p; pcm.boost(boost); n = Lorentz5Momentum( ZERO, -pcm.vect()); n.boost( -boost); } } newBasis = new_ptr(ShowerBasis()); newBasis->setBasis(p,n,ShowerBasis::BackToBack); showerBasis(newBasis,false); } else if(initiatesTLS()) { showerBasis(dynamic_ptr_cast(parents()[0]->children()[0])->showerBasis(),true); } else { showerBasis(dynamic_ptr_cast(parents()[0])->showerBasis(),true); } } void ShowerParticle::setShowerMomentum(bool timeLike) { Energy m = this->mass() > ZERO ? this->mass() : this->data().mass(); // calculate the momentum of the assuming on-shell Energy2 pt2 = sqr(this->showerParameters().pt); double alpha = timeLike ? this->showerParameters().alpha : this->x(); double beta = 0.5*(sqr(m) + pt2 - sqr(alpha)*showerBasis()->pVector().m2())/(alpha*showerBasis()->p_dot_n()); Lorentz5Momentum porig=showerBasis()->sudakov2Momentum(alpha,beta, this->showerParameters().ptx, this->showerParameters().pty); porig.setMass(m); this->set5Momentum(porig); } diff --git a/Shower/QTilde/Kinematics/ShowerBasis.fh b/Shower/QTilde/Kinematics/ShowerBasis.fh --- a/Shower/QTilde/Kinematics/ShowerBasis.fh +++ b/Shower/QTilde/Kinematics/ShowerBasis.fh @@ -1,21 +1,21 @@ // -*- C++ -*- // // This is the forward declaration of the ShowerBasis class. // #ifndef Herwig_ShowerBasis_FH #define Herwig_ShowerBasis_FH #include "ThePEG/Config/ThePEG.h" namespace Herwig { class ShowerBasis; } namespace ThePEG { ThePEG_DECLARE_POINTERS(Herwig::ShowerBasis,ShowerBasisPtr); } -#endif \ No newline at end of file +#endif