diff --git a/Decay/General/FFSDecayer.cc b/Decay/General/FFSDecayer.cc --- a/Decay/General/FFSDecayer.cc +++ b/Decay/General/FFSDecayer.cc @@ -1,463 +1,465 @@ // -*- C++ -*- // // FFSDecayer.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 FFSDecayer class. // #include "FFSDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr FFSDecayer::clone() const { return new_ptr(*this); } IBPtr FFSDecayer::fullclone() const { return new_ptr(*this); } void FFSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map & inV, const vector > & outV, map ) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_ .push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { incomingVertex_[inter] = dynamic_ptr_cast(inV.at(inter)); outgoingVertexF_[inter] = AbstractFFVVertexPtr(); outgoingVertexS_[inter] = AbstractVSSVertexPtr(); if(outV[0].at(inter)) { if (outV[0].at(inter)->getName()==VertexType::FFV) outgoingVertexF_[inter] = dynamic_ptr_cast(outV[0].at(inter)); else outgoingVertexS_[inter] = dynamic_ptr_cast(outV[0].at(inter)); } if(outV[1].at(inter)) { if (outV[1].at(inter)->getName()==VertexType::FFV) outgoingVertexF_[inter] = dynamic_ptr_cast(outV[1].at(inter)); else outgoingVertexS_[inter] = dynamic_ptr_cast(outV[1].at(inter)); } } } void FFSDecayer::persistentOutput(PersistentOStream & os) const { os << perturbativeVertex_ << vertex_ << incomingVertex_ << outgoingVertexF_ << outgoingVertexS_; } void FFSDecayer::persistentInput(PersistentIStream & is, int) { is >> perturbativeVertex_ >> vertex_ >> incomingVertex_ >> outgoingVertexF_ >> outgoingVertexS_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigFFSDecayer("Herwig::FFSDecayer", "Herwig.so"); void FFSDecayer::Init() { static ClassDocumentation documentation ("The FFSDecayer class implements the decay of a fermion to " "a fermion and a scalar."); } double FFSDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin1Half,PDT::Spin0))); //Need to use different barred or unbarred spinors depending on //whether particle is cc or not. int itype[2]; if(inpart.dataPtr()->CC()) itype[0] = inpart.id() > 0? 0:1; else itype[0] = 2; if(decay[0]->dataPtr()->CC()) itype[1] = decay[0]->id() > 0? 0:1; else itype[1] = 2; bool ferm(itype[0] == 0 || itype[1] == 0 || (itype[0] == 2 && itype[1] == 2)); if(meopt==Initialize) { // spinors and rho if(ferm) { SpinorWaveFunction ::calculateWaveFunctions(wave_,rho_, const_ptr_cast(&inpart), incoming); if(wave_[0].wave().Type() != SpinorType::u) for(unsigned int ix = 0; ix < 2; ++ix) wave_ [ix].conjugate(); } else { SpinorBarWaveFunction::calculateWaveFunctions(wavebar_,rho_, const_ptr_cast(&inpart), incoming); if(wavebar_[0].wave().Type() != SpinorType::v) for(unsigned int ix = 0; ix < 2; ++ix) wavebar_[ix].conjugate(); } + // fix rho if no correlations + fixRho(rho_); } // setup spin info when needed if(meopt==Terminate) { // for the decaying particle if(ferm) { SpinorWaveFunction:: constructSpinInfo(wave_,const_ptr_cast(&inpart),incoming,true); SpinorBarWaveFunction::constructSpinInfo(wavebar_,decay[0],outgoing,true); } else { SpinorBarWaveFunction:: constructSpinInfo(wavebar_,const_ptr_cast(&inpart),incoming,true); SpinorWaveFunction::constructSpinInfo(wave_,decay[0],outgoing,true); } ScalarWaveFunction::constructSpinInfo(decay[1],outgoing,true); } if(ferm) SpinorBarWaveFunction:: calculateWaveFunctions(wavebar_,decay[0],outgoing); else SpinorWaveFunction:: calculateWaveFunctions(wave_ ,decay[0],outgoing); ScalarWaveFunction scal(decay[1]->momentum(),decay[1]->dataPtr(),outgoing); Energy2 scale(sqr(inpart.mass())); for(unsigned int if1 = 0; if1 < 2; ++if1) { for(unsigned int if2 = 0; if2 < 2; ++if2) { if(ferm) (*ME())(if1, if2, 0) = 0.; else (*ME())(if2, if1, 0) = 0.; for(auto vert : vertex_) { if(ferm) (*ME())(if1, if2, 0) += vert->evaluate(scale,wave_[if1],wavebar_[if2],scal); else (*ME())(if2, if1, 0) += vert->evaluate(scale,wave_[if1],wavebar_[if2],scal); } } } double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy FFSDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { double mu1(0.),mu2(0.); tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; if(outa.first->iSpin() == PDT::Spin1Half) { mu1 = outa.second/inpart.second; mu2 = outb.second/inpart.second; perturbativeVertex_[0]->setCoupling(sqr(inpart.second), in, outa.first, outb.first); } else { mu1 = outb.second/inpart.second; mu2 = outa.second/inpart.second; perturbativeVertex_[0]->setCoupling(sqr(inpart.second), in, outb.first, outa.first); } double c2 = norm(perturbativeVertex_[0]->norm()); Complex cl = perturbativeVertex_[0]->left(); Complex cr = perturbativeVertex_[0]->right(); double me2 = c2*( (norm(cl) + norm(cr))*(1. + sqr(mu1) - sqr(mu2)) + 2.*mu1*(conj(cl)*cr + conj(cr)*cl).real() ); Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second, outa.second, outb.second); Energy output = me2*pcm/16./Constants::pi; // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } double FFSDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { int iscal (0), iferm (1), iglu (2); // get location of outgoing fermion/scalar if(decay[1]->dataPtr()->iSpin()==PDT::Spin0) swap(iscal,iferm); // work out whether inpart is a fermion or antifermion int itype[2]; if(inpart.dataPtr()->CC()) itype[0] = inpart.id() > 0 ? 0 : 1; else itype[0] = 2; if(decay[iferm]->dataPtr()->CC()) itype[1] = decay[iferm]->id() > 0 ? 0 : 1; else itype[1] = 2; bool ferm(false); if(itype[0] == itype[1] ) { ferm = itype[0]==0 || (itype[0]==2 && decay[iscal]->id() < 0); } else if(itype[0] == 2) { ferm = itype[1]==0; } else if(itype[1] == 2) { ferm = itype[0]==0; } else if((itype[0] == 1 && itype[1] == 0) || (itype[0] == 0 && itype[1] == 1)) { if(abs(inpart.id())<=16) { ferm = itype[0]==0; } else if(abs(decay[iferm]->id())<=16) { ferm = itype[1]==0; } else { ferm = true; } } else assert(false); if(meopt==Initialize) { // create spinor (bar) for decaying particle if(ferm) { SpinorWaveFunction::calculateWaveFunctions(wave3_, rho3_, const_ptr_cast(&inpart), incoming); if(wave3_[0].wave().Type() != SpinorType::u) for(unsigned int ix = 0; ix < 2; ++ix) wave3_[ix].conjugate(); } else { SpinorBarWaveFunction::calculateWaveFunctions(wavebar3_,rho3_, const_ptr_cast(&inpart), incoming); if(wavebar3_[0].wave().Type() != SpinorType::v) for(unsigned int ix = 0; ix < 2; ++ix) wavebar3_[ix].conjugate(); } } // setup spin information when needed if(meopt==Terminate) { if(ferm) { SpinorWaveFunction:: constructSpinInfo(wave3_,const_ptr_cast(&inpart),incoming,true); SpinorBarWaveFunction::constructSpinInfo(wavebar3_,decay[iferm],outgoing,true); } else { SpinorBarWaveFunction:: constructSpinInfo(wavebar3_,const_ptr_cast(&inpart),incoming,true); SpinorWaveFunction::constructSpinInfo(wave3_,decay[iferm],outgoing,true); } ScalarWaveFunction::constructSpinInfo( decay[iscal],outgoing,true); VectorWaveFunction::constructSpinInfo(gluon_, decay[iglu ],outgoing,true,false); return 0.; } // calulate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half, PDT::Spin0, PDT::Spin1Half, PDT::Spin1))); // create wavefunctions if (ferm) SpinorBarWaveFunction::calculateWaveFunctions(wavebar3_, decay[iferm],outgoing); else SpinorWaveFunction:: calculateWaveFunctions(wave3_ , decay[iferm],outgoing); ScalarWaveFunction swave3_(decay[iscal]->momentum(), decay[iscal]->dataPtr(),outgoing); VectorWaveFunction::calculateWaveFunctions(gluon_, decay[iglu ],outgoing,true); // gauge invariance test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(),decay[iglu ]->dataPtr(),10, outgoing)); } } #endif if (! ((incomingVertex_[inter] && (outgoingVertexF_[inter] || outgoingVertexS_[inter])) || (outgoingVertexF_[inter] && outgoingVertexS_[inter]))) throw Exception() << "Invalid vertices for radiation in FFS decay in FFSDecayer::threeBodyME" << Exception::runerror; // sort out colour flows int F(1), S(2); if (decay[iscal]->dataPtr()->iColour()==PDT::Colour3 && decay[iferm]->dataPtr()->iColour()==PDT::Colour8) swap(F,S); else if (decay[iferm]->dataPtr()->iColour()==PDT::Colour3bar && decay[iscal]->dataPtr()->iColour()==PDT::Colour8) swap(F,S); Complex diag; Energy2 scale(sqr(inpart.mass())); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int ifi = 0; ifi < 2; ++ifi) { for(unsigned int ifo = 0; ifo < 2; ++ifo) { for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from the incoming fermion if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(incomingVertex_[inter]); if (ferm) { SpinorWaveFunction spinorInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),wave3_[ifi], gluon_[2*ig],inpart.mass()); assert(wave3_[ifi].particle()->id()==spinorInter.particle()->id()); diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,spinorInter,wavebar3_[ifo],swave3_); } else { SpinorBarWaveFunction spinorBarInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),wavebar3_[ifi], gluon_[2*ig],inpart.mass()); assert(wavebar3_[ifi].particle()->id()==spinorBarInter.particle()->id()); diag = 0.; for(auto vertex :vertex_) diag+= vertex->evaluate(scale,wave3_[ifo], spinorBarInter,swave3_); } if(!couplingSet) { gs = abs(incomingVertex_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[iferm]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexF_[inter]); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[iferm]->dataPtr(); if(off->CC()) off = off->CC(); if (ferm) { SpinorBarWaveFunction spinorBarInter = outgoingVertexF_[inter]->evaluate(scale,3,off,wavebar3_[ifo], gluon_[2*ig],decay[iferm]->mass()); assert(wavebar3_[ifo].particle()->id()==spinorBarInter.particle()->id()); diag = 0.; for(auto vertex :vertex_) diag+= vertex->evaluate(scale,wave3_[ifi],spinorBarInter,swave3_); } else { SpinorWaveFunction spinorInter = outgoingVertexF_[inter]->evaluate(scale,3,off,wave3_[ifo], gluon_[2*ig],decay[iferm]->mass()); assert(wave3_[ifo].particle()->id()==spinorInter.particle()->id()); diag = 0.; for(auto vertex :vertex_) diag+= vertex->evaluate(scale,spinorInter,wavebar3_[ifi],swave3_); } if(!couplingSet) { gs = abs(outgoingVertexF_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[iscal]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexS_[inter]); // ensure you get correct ougoing particle from first vertex tcPDPtr off = decay[iscal]->dataPtr(); if(off->CC()) off = off->CC(); ScalarWaveFunction scalarInter = outgoingVertexS_[inter]->evaluate(scale,3,off,gluon_[2*ig], swave3_,decay[iscal]->mass()); assert(swave3_.particle()->id()==scalarInter.particle()->id()); if (ferm){ diag = 0.; for(auto vertex :vertex_) diag += vertex->evaluate(scale,wave3_[ifi],wavebar3_[ifo],scalarInter); } else { diag = 0.; for(auto vertex :vertex_) diag += vertex->evaluate(scale,wave3_[ifo],wavebar3_[ifi],scalarInter); } if(!couplingSet) { gs = abs(outgoingVertexS_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha(S,EM) output*=(4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif // return the answer return output; } diff --git a/Decay/General/FFVCurrentDecayer.cc b/Decay/General/FFVCurrentDecayer.cc --- a/Decay/General/FFVCurrentDecayer.cc +++ b/Decay/General/FFVCurrentDecayer.cc @@ -1,200 +1,202 @@ // -*- C++ -*- // // FFVCurrentDecayer.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 FFVCurrentDecayer class. // #include "FFVCurrentDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "ThePEG/StandardModel/StandardModelBase.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using ThePEG::Helicity::VectorWaveFunction; using ThePEG::Helicity::SpinorWaveFunction; using ThePEG::Helicity::SpinorBarWaveFunction; using ThePEG::Helicity::Direction; using ThePEG::Helicity::incoming; using ThePEG::Helicity::outgoing; IBPtr FFVCurrentDecayer::clone() const { return new_ptr(*this); } IBPtr FFVCurrentDecayer::fullclone() const { return new_ptr(*this); } void FFVCurrentDecayer::doinit() { FFVPtr_ = dynamic_ptr_cast(vertex()); GeneralCurrentDecayer::doinit(); } void FFVCurrentDecayer::rebind(const TranslationMap & trans) { FFVPtr_ = trans.translate(FFVPtr_); GeneralCurrentDecayer::rebind(trans); } IVector FFVCurrentDecayer::getReferences() { IVector ret = GeneralCurrentDecayer::getReferences(); ret.push_back(FFVPtr_); return ret; } void FFVCurrentDecayer::persistentOutput(PersistentOStream & os) const { os << FFVPtr_; } void FFVCurrentDecayer::persistentInput(PersistentIStream & is, int) { is >> FFVPtr_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigFFVCurrentDecayer("Herwig::FFVCurrentDecayer", "Herwig.so"); void FFVCurrentDecayer::Init() { static ClassDocumentation documentation ("There is no documentation for the FFVCurrentDecayer class"); } double FFVCurrentDecayer::me2(const int ichan, const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { // get the particles for the hadronic curret Energy q; ParticleVector hadpart(decay.begin()+1,decay.end()); // fermion types int itype[2]; if(inpart.dataPtr()->CC()) itype[0] = inpart.id() > 0 ? 0 : 1; else itype[0] = 2; if(decay[0]->dataPtr()->CC()) itype[1] = decay[0]->id() > 0 ? 0 : 1; else itype[1] = 2; //Need to use different barred or unbarred spinors depending on //whether particle is cc or not. bool ferm(itype[0] == 0 || itype[1] == 0 || (itype[0] == 2 && itype[1] == 2)); if(meopt==Initialize) { // spinors and rho if(ferm) { SpinorWaveFunction ::calculateWaveFunctions(wave_,rho_, const_ptr_cast(&inpart), incoming); if(wave_[0].wave().Type() != SpinorType::u) for(unsigned int ix = 0; ix < 2; ++ix) wave_ [ix].conjugate(); } else { SpinorBarWaveFunction::calculateWaveFunctions(wavebar_,rho_, const_ptr_cast(&inpart), incoming); if(wavebar_[0].wave().Type() != SpinorType::v) for(unsigned int ix = 0; ix < 2; ++ix) wavebar_[ix].conjugate(); } + // fix rho if no correlations + fixRho(rho_); } // setup spin info when needed if(meopt==Terminate) { // for the decaying particle if(ferm) { SpinorWaveFunction:: constructSpinInfo(wave_,const_ptr_cast(&inpart),incoming,true); SpinorBarWaveFunction::constructSpinInfo(wavebar_,decay[0],outgoing,true); } else { SpinorBarWaveFunction:: constructSpinInfo(wavebar_,const_ptr_cast(&inpart),incoming,true); SpinorWaveFunction::constructSpinInfo(wave_,decay[0],outgoing,true); } weakCurrent()->current(mode(),ichan,q,hadpart,meopt); return 0.; } Energy2 scale(sqr(inpart.mass())); if(ferm) SpinorBarWaveFunction:: calculateWaveFunctions(wavebar_,decay[0],outgoing); else SpinorWaveFunction:: calculateWaveFunctions(wave_ ,decay[0],outgoing); // calculate the hadron current vector hadron(weakCurrent()->current(mode(),ichan,q,hadpart,meopt)); // prefactor double pre = sqr(pow(inpart.mass()/q,int(hadpart.size()-2))); // work out the mapping for the hadron vector vector constants(decay.size()+1),ihel(decay.size()+1); vector ispin(decay.size()); int itemp(1); unsigned int hhel,ix(decay.size()); do { --ix; ispin[ix]=decay[ix]->data().iSpin(); itemp*=ispin[ix]; constants[ix]=itemp; } while(ix>0); constants[decay.size()]=1; constants[0]=constants[1]; // compute the matrix element GeneralDecayMEPtr newME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,ispin))); VectorWaveFunction vWave; tcPDPtr vec= inpart.dataPtr()->iCharge()-decay[0]->dataPtr()->iCharge() > 0 ? getParticleData(ParticleID::Wplus) : getParticleData(ParticleID::Wminus); Lorentz5Momentum vmom=inpart.momentum()-decay[0]->momentum(); vmom.rescaleMass(); for(hhel=0;hhel1;--ix) ihel[ix]=(hhel%constants[ix-1])/constants[ix]; vWave=VectorWaveFunction(vmom,vec,hadron[hhel]*UnitRemoval::InvE,outgoing); for(unsigned int if1 = 0; if1 < 2; ++if1) { for(unsigned int if2 = 0; if2 < 2; ++if2) { ihel[0]=if1; ihel[1]=if2; if(!ferm) swap(ihel[0],ihel[1]); (*newME)(ihel) = FFVPtr_->evaluate(scale,wave_[if1],wavebar_[if2],vWave); } } } // store the matrix element ME(newME); // multiply by the CKM element int iq,ia; weakCurrent()->decayModeInfo(mode(),iq,ia); double ckm(1.); if(iq<=6) { if(iq%2==0) ckm = SM().CKM(iq/2-1,(abs(ia)-1)/2); else ckm = SM().CKM(abs(ia)/2-1,(iq-1)/2); } pre /= 0.125*sqr(FFVPtr_->weakCoupling(scale)); double output(0.5*pre*ckm*(ME()->contract(rho_)).real()* sqr(SM().fermiConstant()*UnitRemoval::E2)); return output; } Energy FFVCurrentDecayer::partialWidth(tPDPtr inpart, tPDPtr outa, vector currout) { vector id; id.push_back(inpart->id()); id.push_back(outa->id()); for(unsigned int ix=0;ixid()); bool cc; int mode=modeNumber(cc,id); imode(mode); return initializePhaseSpaceMode(mode,true,true); } diff --git a/Decay/General/FFVDecayer.cc b/Decay/General/FFVDecayer.cc --- a/Decay/General/FFVDecayer.cc +++ b/Decay/General/FFVDecayer.cc @@ -1,456 +1,458 @@ // -*- C++ -*- // // FFVDecayer.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 FFVDecayer class. // #include "FFVDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr FFVDecayer::clone() const { return new_ptr(*this); } IBPtr FFVDecayer::fullclone() const { return new_ptr(*this); } void FFVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map & inV, const vector > & outV, map ) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_ .push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { incomingVertex_[inter] = dynamic_ptr_cast(inV.at(inter)); if(outV[0].at(inter)) { if (outV[0].at(inter)->getName()==VertexType::FFV) outgoingVertexF_[inter] = dynamic_ptr_cast(outV[0].at(inter)); else outgoingVertexV_[inter] = dynamic_ptr_cast(outV[0].at(inter)); } if(outV[1].at(inter)) { if (outV[1].at(inter)->getName()==VertexType::FFV) outgoingVertexF_[inter] = dynamic_ptr_cast(outV[1].at(inter)); else outgoingVertexV_[inter] = dynamic_ptr_cast(outV[1].at(inter)); } } } void FFVDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_ << incomingVertex_ << outgoingVertexF_ << outgoingVertexV_; } void FFVDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_ >> incomingVertex_ >> outgoingVertexF_ >> outgoingVertexV_; } double FFVDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin1Half,PDT::Spin1))); // type of process int itype[2]; if(inpart.dataPtr()->CC()) itype[0] = inpart.id() > 0 ? 0 : 1; else itype[0] = 2; if(decay[0]->dataPtr()->CC()) itype[1] = decay[0]->id() > 0 ? 0 : 1; else itype[1] = 2; //Need to use different barred or unbarred spinors depending on //whether particle is cc or not. bool ferm(itype[0] == 0 || itype[1] == 0 || (itype[0] == 2 && itype[1] == 2)); if(meopt==Initialize) { // spinors and rho if(ferm) { SpinorWaveFunction ::calculateWaveFunctions(wave_,rho_, const_ptr_cast(&inpart), incoming); if(wave_[0].wave().Type() != SpinorType::u) for(unsigned int ix = 0; ix < 2; ++ix) wave_ [ix].conjugate(); } else { SpinorBarWaveFunction::calculateWaveFunctions(wavebar_,rho_, const_ptr_cast(&inpart), incoming); if(wavebar_[0].wave().Type() != SpinorType::v) for(unsigned int ix = 0; ix < 2; ++ix) wavebar_[ix].conjugate(); } + // fix rho if no correlations + fixRho(rho_); } // setup spin info when needed if(meopt==Terminate) { // for the decaying particle if(ferm) { SpinorWaveFunction:: constructSpinInfo(wave_,const_ptr_cast(&inpart),incoming,true); SpinorBarWaveFunction::constructSpinInfo(wavebar_,decay[0],outgoing,true); } else { SpinorBarWaveFunction:: constructSpinInfo(wavebar_,const_ptr_cast(&inpart),incoming,true); SpinorWaveFunction::constructSpinInfo(wave_,decay[0],outgoing,true); } VectorWaveFunction:: constructSpinInfo(vector_,decay[1],outgoing,true,false); } Energy2 scale(sqr(inpart.mass())); if(ferm) SpinorBarWaveFunction:: calculateWaveFunctions(wavebar_,decay[0],outgoing); else SpinorWaveFunction:: calculateWaveFunctions(wave_ ,decay[0],outgoing); bool massless = decay[1]->dataPtr()->mass()==ZERO; VectorWaveFunction:: calculateWaveFunctions(vector_,decay[1],outgoing,massless); for(unsigned int if1 = 0; if1 < 2; ++if1) { for(unsigned int if2 = 0; if2 < 2; ++if2) { for(unsigned int vhel = 0; vhel < 3; ++vhel) { if(massless && vhel == 1) ++vhel; if(ferm) (*ME())(if1, if2,vhel) = 0.; else (*ME())(if2, if1, vhel) = 0.; for(auto vertex : vertex_) { if(ferm) (*ME())(if1, if2,vhel) += vertex->evaluate(scale,wave_[if1],wavebar_[if2],vector_[vhel]); else (*ME())(if2, if1, vhel) += vertex->evaluate(scale,wave_[if1],wavebar_[if2],vector_[vhel]); } } } } double output=(ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),decay[1]->dataPtr()); // return the answer return output; } Energy FFVDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { double mu1(outa.second/inpart.second),mu2(outb.second/inpart.second); tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; if( outa.first->iSpin() == PDT::Spin1Half) perturbativeVertex_[0]->setCoupling(sqr(inpart.second), in, outa.first, outb.first); else { swap(mu1,mu2); perturbativeVertex_[0]->setCoupling(sqr(inpart.second),in, outb.first,outa.first); } Complex cl(perturbativeVertex_[0]->left()),cr(perturbativeVertex_[0]->right()); double me2(0.); if( mu2 > 0. ) { me2 = (norm(cl) + norm(cr))*(1. + sqr(mu1*mu2) + sqr(mu2) - 2.*sqr(mu1) - 2.*sqr(mu2*mu2) + sqr(mu1*mu1)) - 6.*mu1*sqr(mu2)*(conj(cl)*cr + conj(cr)*cl).real(); me2 /= sqr(mu2); } else me2 = 2.*( (norm(cl) + norm(cr))*(sqr(mu1) + 1.) - 4.*mu1*(conj(cl)*cr + conj(cr)*cl).real() ); Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second, outa.second, outb.second); Energy output = norm(perturbativeVertex_[0]->norm())*me2*pcm/16./Constants::pi; // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigFFVDecayer("Herwig::FFVDecayer", "Herwig.so"); void FFVDecayer::Init() { static ClassDocumentation documentation ("The FFVDecayer class implements the decay of a fermion to a fermion and a vector boson"); } double FFVDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { int iferm (0), ivect (1), iglu (2); // get location of outgoing lepton/vector if(decay[1]->dataPtr()->iSpin()==PDT::Spin1Half) swap(iferm,ivect); // work out whether inpart is a fermion or antifermion int itype[2]; if(inpart.dataPtr()->CC()) itype[0] = inpart.id() > 0 ? 0 : 1; else itype[0] = 2; if(decay[iferm]->dataPtr()->CC()) itype[1] = decay[iferm]->id() > 0 ? 0 : 1; else itype[1] = 2; bool ferm(itype[0] == 0 || itype[1] == 0 || (itype[0] == 2 && itype[1] == 2 && decay[ivect]->id() < 0)); // no emissions from massive vectors bool massless = decay[ivect]->dataPtr()->mass()==ZERO; if(meopt==Initialize) { // create spinor (bar) for decaying particle if(ferm) { SpinorWaveFunction::calculateWaveFunctions(wave3_, rho3_, const_ptr_cast(&inpart), incoming); if(wave3_[0].wave().Type() != SpinorType::u) for(unsigned int ix = 0; ix < 2; ++ix) wave3_[ix].conjugate(); } else { SpinorBarWaveFunction::calculateWaveFunctions(wavebar3_,rho3_, const_ptr_cast(&inpart), incoming); if(wavebar3_[0].wave().Type() != SpinorType::v) for(unsigned int ix = 0; ix < 2; ++ix) wavebar3_[ix].conjugate(); } } // setup spin information when needed if(meopt==Terminate) { if(ferm) { SpinorWaveFunction:: constructSpinInfo(wave3_,const_ptr_cast(&inpart),incoming,true); SpinorBarWaveFunction::constructSpinInfo(wavebar3_,decay[iferm],outgoing,true); } else { SpinorBarWaveFunction:: constructSpinInfo(wavebar3_,const_ptr_cast(&inpart),incoming,true); SpinorWaveFunction::constructSpinInfo(wave3_,decay[iferm],outgoing,true); } VectorWaveFunction::constructSpinInfo(vector3_, decay[ivect],outgoing,true,massless); VectorWaveFunction::constructSpinInfo(gluon_, decay[iglu ],outgoing,true,false); return 0.; } // calulate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half, PDT::Spin1Half, PDT::Spin1, PDT::Spin1))); // create wavefunctions if (ferm) SpinorBarWaveFunction::calculateWaveFunctions(wavebar3_, decay[iferm],outgoing); else SpinorWaveFunction:: calculateWaveFunctions(wave3_ , decay[iferm],outgoing); VectorWaveFunction::calculateWaveFunctions(vector3_, decay[ivect],outgoing,massless); VectorWaveFunction::calculateWaveFunctions(gluon_, decay[iglu ],outgoing,true ); // gauge invariance test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(), decay[iglu ]->dataPtr(),10, outgoing)); } } #endif if (! ((incomingVertex_[inter] && (outgoingVertexF_[inter] || outgoingVertexV_[inter])) || (outgoingVertexF_[inter] && outgoingVertexV_[inter]))) throw Exception() << "Invalid vertices for QCD radiation in FFV decay in FFVDecayer::threeBodyME" << Exception::runerror; // sort out colour flows int F(1), V(2); if (decay[iferm]->dataPtr()->iColour()==PDT::Colour3bar && decay[ivect]->dataPtr()->iColour()==PDT::Colour8) swap(F,V); else if (decay[ivect]->dataPtr()->iColour()==PDT::Colour3 && decay[iferm]->dataPtr()->iColour()==PDT::Colour8) swap(F,V); Complex diag; Energy2 scale(sqr(inpart.mass())); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int ifi = 0; ifi < 2; ++ifi) { for(unsigned int ifo = 0; ifo < 2; ++ifo) { for(unsigned int iv = 0; iv < 3; ++iv) { for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from the incoming fermion if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(incomingVertex_[inter]); if (ferm){ SpinorWaveFunction spinorInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),wave3_[ifi], gluon_[2*ig],inpart.mass()); assert(wave3_[ifi].particle()->id()==spinorInter.particle()->id()); diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,spinorInter,wavebar3_[ifo],vector3_[iv]); } else { SpinorBarWaveFunction spinorBarInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),wavebar3_[ifi], gluon_[2*ig],inpart.mass()); assert(wavebar3_[ifi].particle()->id()==spinorBarInter.particle()->id()); diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,wave3_[ifo], spinorBarInter,vector3_[iv]); } if(!couplingSet) { gs = abs(incomingVertex_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[iferm]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexF_[inter]); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[iferm]->dataPtr(); if(off->CC()) off = off->CC(); if (ferm) { SpinorBarWaveFunction spinorBarInter = outgoingVertexF_[inter]->evaluate(scale,3,off,wavebar3_[ifo], gluon_[2*ig],decay[iferm]->mass()); assert(wavebar3_[ifo].particle()->id()==spinorBarInter.particle()->id()); diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,wave3_[ifi],spinorBarInter,vector3_[iv]); } else { SpinorWaveFunction spinorInter = outgoingVertexF_[inter]->evaluate(scale,3,off,wave3_[ifo], gluon_[2*ig],decay[iferm]->mass()); assert(wave3_[ifo].particle()->id()==spinorInter.particle()->id()); diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,spinorInter,wavebar3_[ifi],vector3_[iv]); } if(!couplingSet) { gs = abs(outgoingVertexF_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[ivect]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexV_[inter]); // ensure you get correct ougoing particle from first vertex tcPDPtr off = decay[ivect]->dataPtr(); if(off->CC()) off = off->CC(); VectorWaveFunction vectorInter = outgoingVertexV_[inter]->evaluate(scale,3,off,gluon_[2*ig], vector3_[iv],decay[ivect]->mass()); assert(vector3_[iv].particle()->id()==vectorInter.particle()->id()); if (ferm) { diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,wave3_[ifi],wavebar3_[ifo],vectorInter); } else { diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,wave3_[ifo],wavebar3_[ifi],vectorInter); } if(!couplingSet) { gs = abs(outgoingVertexV_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha(S,eM) output *= (4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif // return the answer return output; } diff --git a/Decay/General/FRSDecayer.cc b/Decay/General/FRSDecayer.cc --- a/Decay/General/FRSDecayer.cc +++ b/Decay/General/FRSDecayer.cc @@ -1,189 +1,191 @@ // -*- C++ -*- // // FRSDecayer.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 FRSDecayer class. // #include "FRSDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr FRSDecayer::clone() const { return new_ptr(*this); } IBPtr FRSDecayer::fullclone() const { return new_ptr(*this); } void FRSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map &, const vector > &, map) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_.push_back(dynamic_ptr_cast (vert)); } } void FRSDecayer::persistentOutput(PersistentOStream & os) const { os << perturbativeVertex_ << vertex_; } void FRSDecayer::persistentInput(PersistentIStream & is, int) { is >> perturbativeVertex_ >> vertex_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigFRSDecayer("Herwig::FRSDecayer", "Herwig.so"); void FRSDecayer::Init() { static ClassDocumentation documentation ("The FRSDecayer class implements the decay of a fermion to " "a spin-3/2 fermion and a scalar."); } double FRSDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { bool ferm = inpart.id() > 0; if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin3Half,PDT::Spin0))); if(meopt==Initialize) { // spinors and rho if(ferm) { SpinorWaveFunction ::calculateWaveFunctions(wave_,rho_, const_ptr_cast(&inpart), incoming); if(wave_[0].wave().Type() != SpinorType::u) for(unsigned int ix = 0; ix < 2; ++ix) wave_ [ix].conjugate(); } else { SpinorBarWaveFunction::calculateWaveFunctions(wavebar_,rho_, const_ptr_cast(&inpart), incoming); if(wavebar_[0].wave().Type() != SpinorType::v) for(unsigned int ix = 0; ix < 2; ++ix) wavebar_[ix].conjugate(); } + // fix rho if no correlations + fixRho(rho_); } // setup spin info when needed if(meopt==Terminate) { // for the decaying particle if(ferm) { SpinorWaveFunction:: constructSpinInfo(wave_,const_ptr_cast(&inpart),incoming,true); RSSpinorBarWaveFunction::constructSpinInfo(RSwavebar_,decay[0],outgoing,true); } else { SpinorBarWaveFunction:: constructSpinInfo(wavebar_,const_ptr_cast(&inpart),incoming,true); RSSpinorWaveFunction::constructSpinInfo(RSwave_,decay[0],outgoing,true); } ScalarWaveFunction::constructSpinInfo(decay[1],outgoing,true); } if(ferm) RSSpinorBarWaveFunction:: calculateWaveFunctions(RSwavebar_,decay[0],outgoing); else RSSpinorWaveFunction:: calculateWaveFunctions(RSwave_ ,decay[0],outgoing); ScalarWaveFunction scal(decay[1]->momentum(),decay[1]->dataPtr(),outgoing); Energy2 scale(sqr(inpart.mass())); for(unsigned int if1 = 0; if1 < 2; ++if1) { for(unsigned int if2 = 0; if2 < 4; ++if2) { (*ME())(if1, if2, 0) = 0.; for(auto vert : vertex_) { if(ferm) (*ME())(if1, if2, 0) += vert->evaluate(scale,wave_[if1],RSwavebar_[if2],scal); else (*ME())(if1, if2, 0) += vert->evaluate(scale,RSwave_[if2],wavebar_[if1],scal); } } } double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // test code // Energy q = inpart.mass(); // Energy m1 = decay[0]->mass(); // Energy m2 = decay[1]->mass(); // Energy2 q2(q*q),m12(m1*m1),m22(m2*m2); // Energy2 pcm2(0.25*(q2*(q2-2.*m12-2.*m22)+(m12-m22)*(m12-m22))/q2); // Energy pcm(sqrt(pcm2)); // Energy Qp(sqrt((q+m1)*(q+m1)-m22)),Qm(sqrt((q-m1)*(q-m1)-m22)); // double r23(sqrt(2./3.)); // // couplings // Complex left = perturbativeVertex_-> left()*perturbativeVertex_-> norm(); // Complex right = perturbativeVertex_->right()*perturbativeVertex_-> norm(); // complex A1 = 0.5*(left+right)*UnitRemoval::InvE; // complex B1 = 0.5*(right-left)*UnitRemoval::InvE; // complex h1(-2.*r23*pcm*q/m1*Qm*B1); // complex h2( 2.*r23*pcm*q/m1*Qp*A1); // cout << "testing 1/2->3/2 0 " // << output*scale/GeV2 << " " // << real(h1*conj(h1)+h2*conj(h2))/4./GeV2 << " " // << real(h1*conj(h1)+h2*conj(h2))/4./(output*scale) << endl; // return the answer return output; } Energy FRSDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { Energy q = inpart.second; Energy m1 = outa.second; Energy m2 = outb.second; Energy2 q2(q*q),m12(m1*m1),m22(m2*m2); Energy2 pcm2(0.25*(q2*(q2-2.*m12-2.*m22)+(m12-m22)*(m12-m22))/q2); Energy pcm(sqrt(pcm2)); Energy Qp(sqrt((q+m1)*(q+m1)-m22)),Qm(sqrt((q-m1)*(q-m1)-m22)); double r23(sqrt(2./3.)); // couplings tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; perturbativeVertex_[0]->setCoupling(sqr(inpart.second), outa.first, in, outb.first); Complex left = perturbativeVertex_[0]-> left()*perturbativeVertex_[0]-> norm(); Complex right = perturbativeVertex_[0]->right()*perturbativeVertex_[0]-> norm(); complex A1 = 0.5*(left+right)*UnitRemoval::InvE; complex B1 = 0.5*(right-left)*UnitRemoval::InvE; complex h1(-2.*r23*pcm*q/m1*Qm*B1); complex h2( 2.*r23*pcm*q/m1*Qp*A1); double me2 = real(h1*conj(h1)+h2*conj(h2))/4./sqr(inpart.second); Energy output = me2*pcm/8./Constants::pi; // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } diff --git a/Decay/General/FRVDecayer.cc b/Decay/General/FRVDecayer.cc --- a/Decay/General/FRVDecayer.cc +++ b/Decay/General/FRVDecayer.cc @@ -1,219 +1,221 @@ // -*- C++ -*- // // FRVDecayer.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 FRVDecayer class. // #include "FRVDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr FRVDecayer::clone() const { return new_ptr(*this); } IBPtr FRVDecayer::fullclone() const { return new_ptr(*this); } void FRVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map &, const vector > &, map) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_.push_back(dynamic_ptr_cast (vert)); } } void FRVDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_; } void FRVDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_; } double FRVDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin3Half,PDT::Spin1))); // decaying fermion or antifermion bool ferm = inpart.id() > 0; // initialize if(meopt==Initialize) { // spinors and rho if(ferm) { SpinorWaveFunction ::calculateWaveFunctions(wave_,rho_, const_ptr_cast(&inpart), incoming); if(wave_[0].wave().Type() != SpinorType::u) for(unsigned int ix = 0; ix < 2; ++ix) wave_ [ix].conjugate(); } else { SpinorBarWaveFunction::calculateWaveFunctions(wavebar_,rho_, const_ptr_cast(&inpart), incoming); if(wavebar_[0].wave().Type() != SpinorType::v) for(unsigned int ix = 0; ix < 2; ++ix) wavebar_[ix].conjugate(); } + // fix rho if no correlations + fixRho(rho_); } // setup spin info when needed if(meopt==Terminate) { // for the decaying particle if(ferm) { SpinorWaveFunction:: constructSpinInfo(wave_,const_ptr_cast(&inpart),incoming,true); RSSpinorBarWaveFunction::constructSpinInfo(RSwavebar_,decay[0],outgoing,true); } else { SpinorBarWaveFunction:: constructSpinInfo(wavebar_,const_ptr_cast(&inpart),incoming,true); RSSpinorWaveFunction::constructSpinInfo(RSwave_,decay[0],outgoing,true); } VectorWaveFunction:: constructSpinInfo(vector_,decay[1],outgoing,true,false); } Energy2 scale(sqr(inpart.mass())); if(ferm) RSSpinorBarWaveFunction:: calculateWaveFunctions(RSwavebar_,decay[0],outgoing); else RSSpinorWaveFunction:: calculateWaveFunctions(RSwave_ ,decay[0],outgoing); bool massless = decay[1]->dataPtr()->mass()==ZERO; VectorWaveFunction:: calculateWaveFunctions(vector_,decay[1],outgoing,massless); // loop over helicities for(unsigned int if1 = 0; if1 < 2; ++if1) { for(unsigned int if2 = 0; if2 < 4; ++if2) { for(unsigned int vhel = 0; vhel < 3; ++vhel) { if(massless && vhel == 1) ++vhel; (*ME())(if1, if2,vhel) = 0.; for(auto vert : vertex_) { if(ferm) (*ME())(if1, if2,vhel) += vert->evaluate(scale,wave_[if1], RSwavebar_[if2],vector_[vhel]); else (*ME())(if1, if2, vhel) += vert->evaluate(scale,RSwave_[if2], wavebar_[if1],vector_[vhel]); } } } } double output=(ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // test // Energy m1(inpart.mass()),m2(decay[0]->mass()),m3(decay[1]->mass()); // Energy2 m12(m1*m1),m22(m2*m2),m32(m3*m3); // Energy Qp(sqrt(sqr(m1+m2)-sqr(m3))),Qm(sqrt(sqr(m1-m2)-sqr(m3))); // double r2(sqrt(2.)),r3(sqrt(3.)); // Energy pcm(Kinematics::pstarTwoBodyDecay(m1,m2,m3)); // vector left = perturbativeVertex_-> left(); // vector right = perturbativeVertex_->right(); // Complex A1 = 0.5*(left [0]+right[0])*perturbativeVertex_-> norm(); // Complex B1 = 0.5*(right[0]- left[0])*perturbativeVertex_-> norm(); // complex A2 = 0.5*(left [1]+right[1])*perturbativeVertex_-> norm()*UnitRemoval::InvE; // complex B2 = 0.5*(right[1]- left[1])*perturbativeVertex_-> norm()*UnitRemoval::InvE; // complex A3 = 0.5*(left [2]+right[2])*perturbativeVertex_-> norm()*UnitRemoval::InvE2; // complex B3 = 0.5*(right[2]- left[2])*perturbativeVertex_-> norm()*UnitRemoval::InvE2; // complex h1(-2.*Qp*A1),h2(2.*Qm*B1); // complex h3(-2./r3*Qp*(A1-Qm*Qm/m2*A2)); // complex h4( 2./r3*Qm*(B1-Qp*Qp/m2*B2)); // complex h5(ZERO),h6(ZERO); // if(decay[1]->mass()>ZERO) { // h5 = -2.*r2/r3/m2/m3*Qp*(0.5*(m12-m22-m32)*A1+0.5*Qm*Qm*(m1+m2)*A2 // +m12*pcm*pcm*A3); // h6 = 2.*r2/r3/m2/m3*Qm*(0.5*(m12-m22-m32)*B1-0.5*Qp*Qp*(m1-m2)*B2 // +m12*pcm*pcm*B3); // } // cout << "testing 1/2->3/2 1 " << inpart.id() << " " // << output << " " // << 0.25*(h1*conj(h1)+h2*conj(h2)+h3*conj(h3)+ // h4*conj(h4)+h5*conj(h5)+h6*conj(h6))/sqr(inpart.mass()) << " " // << 0.25*(h1*conj(h1)+h2*conj(h2)+h3*conj(h3)+ // h4*conj(h4)+h5*conj(h5)+h6*conj(h6))/sqr(inpart.mass())/output << endl; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),decay[1]->dataPtr()); // return the answer return output; } Energy FRVDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { Energy m1(inpart.second),m2(outa.second),m3(outb.second); Energy2 m12(m1*m1),m22(m2*m2),m32(m3*m3); Energy Qp(sqrt(sqr(m1+m2)-sqr(m3))),Qm(sqrt(sqr(m1-m2)-sqr(m3))); double r2(sqrt(2.)),r3(sqrt(3.)); Energy pcm(Kinematics::pstarTwoBodyDecay(m1,m2,m3)); // couplings tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; perturbativeVertex_[0]->setCoupling(sqr(inpart.second), outa.first, in, outb.first); vector left = perturbativeVertex_[0]-> left(); vector right = perturbativeVertex_[0]->right(); Complex A1 = 0.5*(left [0]+right[0])*perturbativeVertex_[0]-> norm(); Complex B1 = 0.5*(right[0]- left[0])*perturbativeVertex_[0]-> norm(); complex A2 = 0.5*(left [1]+right[1])*perturbativeVertex_[0]-> norm()*UnitRemoval::InvE; complex B2 = 0.5*(right[1]- left[1])*perturbativeVertex_[0]-> norm()*UnitRemoval::InvE; complex A3 = 0.5*(left [2]+right[2])*perturbativeVertex_[0]-> norm()*UnitRemoval::InvE2; complex B3 = 0.5*(right[2]- left[2])*perturbativeVertex_[0]-> norm()*UnitRemoval::InvE2; complex h1(-2.*Qp*A1),h2(2.*Qm*B1); complex h3(-2./r3*Qp*(A1-Qm*Qm/m2*A2)); complex h4( 2./r3*Qm*(B1-Qp*Qp/m2*B2)); complex h5(ZERO),h6(ZERO); if(outb.second>ZERO) { h5 = -2.*r2/r3/m2/m3*Qp*(0.5*(m12-m22-m32)*A1+0.5*Qm*Qm*(m1+m2)*A2 +m12*pcm*pcm*A3); h6 = 2.*r2/r3/m2/m3*Qm*(0.5*(m12-m22-m32)*B1-0.5*Qp*Qp*(m1-m2)*B2 +m12*pcm*pcm*B3); } double me2 = 0.25*real(h1*conj(h1)+h2*conj(h2)+h3*conj(h3)+ h4*conj(h4)+h5*conj(h5)+h6*conj(h6))/sqr(inpart.second); Energy output = me2*pcm/8./Constants::pi; // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigFRVDecayer("Herwig::FRVDecayer", "Herwig.so"); void FRVDecayer::Init() { static ClassDocumentation documentation ("The FRVDecayer class handles the decay of a fermion to " "a spin-3/2 particle and a vector boson."); } diff --git a/Decay/General/FtoFFFDecayer.cc b/Decay/General/FtoFFFDecayer.cc --- a/Decay/General/FtoFFFDecayer.cc +++ b/Decay/General/FtoFFFDecayer.cc @@ -1,309 +1,311 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the FtoFFFDecayer class. // #include "FtoFFFDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Decay/DecayPhaseSpaceMode.h" #include "Herwig/PDT/ThreeBodyAllOnCalculator.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include using namespace Herwig; IBPtr FtoFFFDecayer::clone() const { return new_ptr(*this); } IBPtr FtoFFFDecayer::fullclone() const { return new_ptr(*this); } void FtoFFFDecayer::persistentOutput(PersistentOStream & os) const { os << sca_ << vec_ << ten_; } void FtoFFFDecayer::persistentInput(PersistentIStream & is, int) { is >> sca_ >> vec_ >> ten_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigFtoFFFDecayer("Herwig::FtoFFFDecayer", "Herwig.so"); void FtoFFFDecayer::Init() { static ClassDocumentation documentation ("The FtoFFFDecayer class implements the general decay of a fermion to " "three fermions."); } void FtoFFFDecayer::doinit() { GeneralThreeBodyDecayer::doinit(); if(outgoing().empty()) return; unsigned int ndiags = getProcessInfo().size(); sca_.resize(ndiags); vec_.resize(ndiags); ten_.resize(ndiags); for(unsigned int ix = 0;ix < ndiags; ++ix) { TBDiagram current = getProcessInfo()[ix]; tcPDPtr offshell = current.intermediate; if( offshell->CC() ) offshell = offshell->CC(); if(offshell->iSpin() == PDT::Spin0) { AbstractFFSVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFSVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() << "Invalid vertices for a scalar diagram in FtoFFFDecayer::doinit()" << Exception::runerror; sca_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin1) { AbstractFFVVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFVVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() << "Invalid vertices for a vector diagram in FtoFFFDecayer::doinit()" << Exception::runerror; vec_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin2) { AbstractFFTVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFTVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() << "Invalid vertices for a tensor diagram in FtoFFFDecayer::doinit()" << Exception::runerror; ten_[ix] = make_pair(vert1, vert2); } } } double FtoFFFDecayer::me2(const int ichan, const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { // particle or CC of particle bool cc = (*getProcessInfo().begin()).incoming != inpart.id(); // special handling or first/last call const vector > cfactors(getColourFactors()); const vector > nfactors(getLargeNcColourFactors()); const size_t ncf(numberOfFlows()); Energy2 scale(sqr(inpart.mass())); if(meopt==Initialize) { SpinorWaveFunction:: calculateWaveFunctions(inwave_.first,rho_,const_ptr_cast(&inpart), Helicity::incoming); inwave_.second.resize(2); if(inwave_.first[0].wave().Type() == SpinorType::u) { for(unsigned int ix = 0; ix < 2; ++ix) { inwave_.second[ix] = inwave_.first[ix].bar(); inwave_.second[ix].conjugate(); } } else { for(unsigned int ix = 0; ix < 2; ++ix) { inwave_.second[ix] = inwave_.first[ix].bar(); inwave_.first[ix].conjugate(); } } + // fix rho if no correlations + fixRho(rho_); } // setup spin info when needed if(meopt==Terminate) { // for the decaying particle if(inpart.id()<0) SpinorWaveFunction::constructSpinInfo(inwave_.first, const_ptr_cast(&inpart), Helicity::incoming,true); else SpinorBarWaveFunction::constructSpinInfo(inwave_.second, const_ptr_cast(&inpart), Helicity::incoming,true); // outgoing particles for(unsigned int ix = 0; ix < 3; ++ix) { SpinorWaveFunction:: constructSpinInfo(outwave_[ix].first,decay[ix],Helicity::outgoing,true); } } // outgoing particles for(unsigned int ix = 0; ix < 3; ++ix) { SpinorWaveFunction:: calculateWaveFunctions(outwave_[ix].first,decay[ix],Helicity::outgoing); outwave_[ix].second.resize(2); if(outwave_[ix].first[0].wave().Type() == SpinorType::u) { for(unsigned int iy = 0; iy < 2; ++iy) { outwave_[ix].second[iy] = outwave_[ix].first[iy].bar(); outwave_[ix].first[iy].conjugate(); } } else { for(unsigned int iy = 0; iy < 2; ++iy) { outwave_[ix].second[iy] = outwave_[ix].first[iy].bar(); outwave_[ix].second[iy].conjugate(); } } } bool ferm = inpart.id()>0; vector flows(ncf, Complex(0.)),largeflows(ncf, Complex(0.)); static const unsigned int out2[3]={1,0,0},out3[3]={2,2,1}; vector mes(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half))); vector mel(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half))); unsigned int ihel[4]; for(ihel[0] = 0; ihel[0] < 2; ++ihel[0]) { for(ihel[1] = 0; ihel[1] < 2; ++ihel[1]) { for(ihel[2] = 0; ihel[2] < 2; ++ihel[2]) { for(ihel[3] = 0; ihel[3] < 2; ++ihel[3]) { flows = vector(ncf, Complex(0.)); largeflows = vector(ncf, Complex(0.)); unsigned int idiag=0; for(vector::const_iterator dit=getProcessInfo().begin(); dit!=getProcessInfo().end();++dit) { if(ichan>=0&&diagramMap()[ichan]!=idiag) { ++idiag; continue; } // the sign from normal ordering double sign = ferm ? 1. : -1; // outgoing wavefunction and NO sign if (dit->channelType==TBDiagram::channel23) sign *= -1.; else if(dit->channelType==TBDiagram::channel13) sign *= 1.; else if(dit->channelType==TBDiagram::channel12) sign *= -1.; else throw Exception() << "Unknown diagram type in FtoFFFDecayer::me2()" << Exception::runerror; // wavefunctions SpinorWaveFunction w0,w3; SpinorBarWaveFunction w1,w2; // incoming wavefunction if(ferm) { w0 = inwave_.first [ihel[0]]; w1 = outwave_[dit->channelType].second[ihel[dit->channelType+1]]; } else { w0 = outwave_[dit->channelType].first [ihel[dit->channelType+1]]; w1 = inwave_.second[ihel[0]]; } if(decay[out2[dit->channelType]]->id()<0&& decay[out3[dit->channelType]]->id()>0) { w2 = outwave_[out3[dit->channelType]].second[ihel[out3[dit->channelType]+1]]; w3 = outwave_[out2[dit->channelType]].first [ihel[out2[dit->channelType]+1]]; sign *= -1.; } else { w2 = outwave_[out2[dit->channelType]].second[ihel[out2[dit->channelType]+1]]; w3 = outwave_[out3[dit->channelType]].first [ihel[out3[dit->channelType]+1]]; } tcPDPtr offshell = dit->intermediate; if(cc&&offshell->CC()) offshell=offshell->CC(); Complex diag(0.); // intermediate scalar if (offshell->iSpin() == PDT::Spin0) { ScalarWaveFunction inters = sca_[idiag].first-> evaluate(scale, widthOption(), offshell, w0, w1); diag = sca_[idiag].second->evaluate(scale,w3,w2,inters); } // intermediate vector else if(offshell->iSpin() == PDT::Spin1) { VectorWaveFunction interv = vec_[idiag].first-> evaluate(scale, widthOption(), offshell, w0, w1); diag = vec_[idiag].second->evaluate(scale,w3,w2,interv); } // intermediate tensor else if(offshell->iSpin() == PDT::Spin2) { TensorWaveFunction intert = ten_[idiag].first-> evaluate(scale, widthOption(), offshell, w0, w1); diag = ten_[idiag].second->evaluate(scale,w3,w2,intert); } // unknown else throw Exception() << "Unknown intermediate in FtoFFFDecayer::me2()" << Exception::runerror; // apply NO sign diag *= sign; // matrix element for the different colour flows if(ichan<0) { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } else { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1!=colourFlow()) continue; flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1!=colourFlow()) continue; largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } ++idiag; } // now add the flows to the me2 with appropriate colour factors for(unsigned int ix = 0; ix < ncf; ++ix) { (*mes[ix])(ihel[0],ihel[1],ihel[2],ihel[3]) = flows[ix]; (*mel[ix])(ihel[0],ihel[1],ihel[2],ihel[3]) = largeflows[ix]; } } } } } double me2(0.); if(ichan<0) { vector pflows(ncf,0.); for(unsigned int ix = 0; ix < ncf; ++ix) { for(unsigned int iy = 0; iy < ncf; ++ iy) { double con = cfactors[ix][iy]*(mes[ix]->contract(*mes[iy],rho_)).real(); me2 += con; if(ix==iy) { con = nfactors[ix][iy]*(mel[ix]->contract(*mel[iy],rho_)).real(); pflows[ix] += con; } } } double ptotal(std::accumulate(pflows.begin(),pflows.end(),0.)); ptotal *=UseRandom::rnd(); for(unsigned int ix=0;ixcontract(*mel[iflow],rho_)).real(); } // return the matrix element squared return me2; } WidthCalculatorBasePtr FtoFFFDecayer:: threeBodyMEIntegrator(const DecayMode & ) const { vector intype; vector inmass,inwidth; vector inpow,inweights; constructIntegratorChannels(intype,inmass,inwidth,inpow,inweights); return new_ptr(ThreeBodyAllOnCalculator (inweights,intype,inmass,inwidth,inpow,*this,0, outgoing()[0]->mass(),outgoing()[1]->mass(),outgoing()[2]->mass(), relativeError())); } diff --git a/Decay/General/FtoFVVDecayer.cc b/Decay/General/FtoFVVDecayer.cc --- a/Decay/General/FtoFVVDecayer.cc +++ b/Decay/General/FtoFVVDecayer.cc @@ -1,401 +1,403 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the FtoFVVDecayer class. // #include "FtoFVVDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Decay/DecayPhaseSpaceMode.h" #include "Herwig/PDT/ThreeBodyAllOnCalculator.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include using namespace Herwig; IBPtr FtoFVVDecayer::clone() const { return new_ptr(*this); } IBPtr FtoFVVDecayer::fullclone() const { return new_ptr(*this); } void FtoFVVDecayer::persistentOutput(PersistentOStream & os) const { os << sca_ << fer_ << vec_ << ten_; } void FtoFVVDecayer::persistentInput(PersistentIStream & is, int) { is >> sca_ >> fer_ >> vec_ >> ten_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigFtoFVVDecayer("Herwig::FtoFVVDecayer", "Herwig.so"); void FtoFVVDecayer::Init() { static ClassDocumentation documentation ("The FtoFVVDecayer class implements the general decay of a fermion to " "a fermion and a pair of vectors."); } void FtoFVVDecayer::doinit() { GeneralThreeBodyDecayer::doinit(); if(outgoing().empty()) return; unsigned int ndiags = getProcessInfo().size(); sca_.resize(ndiags); fer_.resize(ndiags); vec_.resize(ndiags); ten_.resize(ndiags); for(unsigned int ix = 0;ix < ndiags; ++ix) { TBDiagram current = getProcessInfo()[ix]; tcPDPtr offshell = current.intermediate; if(offshell->iSpin() == PDT::Spin0) { AbstractFFSVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractVVSVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() << "Invalid vertices for a scalar diagram in FtoFVVDecayer::doinit()" << Exception::runerror; sca_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin1Half) { AbstractFFVVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFVVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() << "Invalid vertices for a scalar diagram in FtoFVVDecayer::doinit()" << Exception::runerror; fer_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin1) { AbstractFFVVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractVVVVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() << "Invalid vertices for a vector diagram in FtoFVVDecayer::doinit()" << Exception::runerror; vec_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin2) { AbstractFFTVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractVVTVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() << "Invalid vertices for a tensor diagram in FtoFVVDecayer::doinit()" << Exception::runerror; ten_[ix] = make_pair(vert1, vert2); } } } double FtoFVVDecayer::me2(const int ichan, const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { // particle or CC of particle bool cc = (*getProcessInfo().begin()).incoming != inpart.id(); // special handling or first/last call //Set up wave-functions bool ferm( inpart.id() > 0 ); if(meopt==Initialize) { if( ferm ) { SpinorWaveFunction:: calculateWaveFunctions(fwave_,rho_,const_ptr_cast(&inpart), Helicity::incoming); if( fwave_[0].wave().Type() != SpinorType::u ) fwave_[0].conjugate(); if( fwave_[1].wave().Type() != SpinorType::u ) fwave_[1].conjugate(); } else { SpinorBarWaveFunction:: calculateWaveFunctions(fbwave_, rho_, const_ptr_cast(&inpart), Helicity::incoming); if( fbwave_[0].wave().Type() != SpinorType::v ) fbwave_[0].conjugate(); if( fbwave_[1].wave().Type() != SpinorType::v ) fbwave_[1].conjugate(); } + // fix rho if no correlations + fixRho(rho_); } // setup spin info when needed if(meopt==Terminate) { // for the decaying particle if(ferm) SpinorWaveFunction::constructSpinInfo(fwave_, const_ptr_cast(&inpart), Helicity::incoming,true); else SpinorBarWaveFunction::constructSpinInfo(fbwave_, const_ptr_cast(&inpart), Helicity::incoming,true); int ivec(-1); // outgoing particles for(int ix = 0; ix < 3; ++ix) { tPPtr p = decay[ix]; if( p->dataPtr()->iSpin() == PDT::Spin1Half ) { if( ferm ) { SpinorBarWaveFunction:: constructSpinInfo(fbwave_, p, Helicity::outgoing,true); } else { SpinorWaveFunction:: constructSpinInfo(fwave_ , p, Helicity::outgoing,true); } } else if( p->dataPtr()->iSpin() == PDT::Spin1 ) { if( ivec < 0 ) { ivec = ix; VectorWaveFunction:: constructSpinInfo(vwave_.first , p, Helicity::outgoing, true, false); } else { VectorWaveFunction:: constructSpinInfo(vwave_.second, p, Helicity::outgoing, true, false); } } } return 0.; } // outgoing, keep track of fermion and first occurrence of vector positions int isp(-1), ivec(-1); // outgoing particles pair mass = make_pair(false,false); for(int ix = 0; ix < 3; ++ix) { tPPtr p = decay[ix]; if( p->dataPtr()->iSpin() == PDT::Spin1Half ) { isp = ix; if( ferm ) { SpinorBarWaveFunction:: calculateWaveFunctions(fbwave_, p, Helicity::outgoing); if( fbwave_[0].wave().Type() != SpinorType::u ) fbwave_[0].conjugate(); if( fbwave_[1].wave().Type() != SpinorType::u ) fbwave_[1].conjugate(); } else { SpinorWaveFunction:: calculateWaveFunctions(fwave_, p, Helicity::outgoing); if( fwave_[0].wave().Type() != SpinorType::v ) fwave_[0].conjugate(); if( fwave_[1].wave().Type() != SpinorType::v ) fwave_[1].conjugate(); } } else if( p->dataPtr()->iSpin() == PDT::Spin1 ) { bool massless = p->id() == ParticleID::gamma || p->id() == ParticleID::g; if( ivec < 0 ) { ivec = ix; VectorWaveFunction:: calculateWaveFunctions(vwave_.first , p, Helicity::outgoing, massless); mass.first = massless; } else { VectorWaveFunction:: calculateWaveFunctions(vwave_.second, p, Helicity::outgoing, massless); mass.second = massless; } } } assert(isp >= 0 && ivec >= 0); Energy2 scale(sqr(inpart.mass())); const vector > cfactors(getColourFactors()); const vector > nfactors(getLargeNcColourFactors()); const size_t ncf(numberOfFlows()); vector flows(ncf, Complex(0.)), largeflows(ncf, Complex(0.)); vector mes(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half, (isp == 0) ? PDT::Spin1Half : PDT::Spin1, (isp == 1) ? PDT::Spin1Half : PDT::Spin1, (isp == 2) ? PDT::Spin1Half : PDT::Spin1))); vector mel(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half, (isp == 0) ? PDT::Spin1Half : PDT::Spin1, (isp == 1) ? PDT::Spin1Half : PDT::Spin1, (isp == 2) ? PDT::Spin1Half : PDT::Spin1))); //Helicity calculation for( unsigned int if1 = 0; if1 < 2; ++if1 ) { for( unsigned int if2 = 0; if2 < 2; ++if2 ) { for( unsigned int iv1 = 0; iv1 < 3; ++iv1 ) { if ( mass.first && iv1 == 1 ) continue; for( unsigned int iv2 = 0; iv2 < 3; ++iv2 ) { if ( mass.second && iv2 == 1 ) continue; flows = vector(ncf, Complex(0.)); largeflows = vector(ncf, Complex(0.)); unsigned int idiag(0); for(vector::const_iterator dit = getProcessInfo().begin(); dit != getProcessInfo().end(); ++dit) { // If we are selecting a particular channel if( ichan >= 0 && diagramMap()[ichan] != idiag ) { ++idiag; continue; } tcPDPtr offshell = (*dit).intermediate; if(cc&&offshell->CC()) offshell=offshell->CC(); Complex diag; if( offshell->iSpin() == PDT::Spin1Half ) { // Make sure we connect the correct particles VectorWaveFunction vw1, vw2; if( (*dit).channelType == TBDiagram::channel23 ) { vw1 = vwave_.first[iv1]; vw2 = vwave_.second[iv2]; } else if( (*dit).channelType == TBDiagram::channel12 ) { vw1 = vwave_.second[iv2]; vw2 = vwave_.first[iv1]; } else { if( ivec < isp ) { vw1 = vwave_.second[iv2]; vw2 = vwave_.first[iv1]; } else { vw1 = vwave_.first[iv1]; vw2 = vwave_.second[iv2]; } } if( ferm ) { SpinorWaveFunction inters = fer_[idiag].first->evaluate(scale, widthOption(), offshell, fwave_[if1], vw1); diag = fer_[idiag].second->evaluate(scale, inters, fbwave_[if2], vw2); } else { SpinorBarWaveFunction inters = fer_[idiag].first->evaluate(scale, widthOption(), offshell, fbwave_[if2], vw1); diag = fer_[idiag].second->evaluate(scale, fwave_[if1], inters, vw2); } } else if( offshell->iSpin() == PDT::Spin0 ) { ScalarWaveFunction inters = sca_[idiag].first->evaluate(scale, widthOption(), offshell, fwave_[if1], fbwave_[if2]); diag = sca_[idiag].second->evaluate(scale, vwave_.first[iv1], vwave_.second[iv2], inters); } else if( offshell->iSpin() == PDT::Spin1 ) { VectorWaveFunction interv = vec_[idiag].first->evaluate(scale, widthOption(), offshell, fwave_[if1], fbwave_[if2]); diag = vec_[idiag].second->evaluate(scale, vwave_.first[iv1], vwave_.second[iv2], interv); } else if( offshell->iSpin() == PDT::Spin2 ) { TensorWaveFunction intert = ten_[idiag].first->evaluate(scale, widthOption(), offshell, fwave_[if1], fbwave_[if2]); diag = ten_[idiag].second->evaluate(scale, vwave_.first[iv1], vwave_.second[iv2], intert); } else throw Exception() << "Unknown intermediate in FtoFVVDecayer::me2()" << Exception::runerror; //NO sign if( !ferm ) diag *= -1; if(ichan<0) { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } else { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1!=colourFlow()) continue; flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1!=colourFlow()) continue; largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } ++idiag; }// end diagram loop // now add the flows to the me2 unsigned int h1(if1), h2(if2); if( !ferm ) swap(h1,h2); for(unsigned int ix = 0; ix < ncf; ++ix) { if(isp == 0) { (*mes[ix])(h1, h2, iv1, iv2) = flows[ix]; (*mel[ix])(h1, h2, iv1, iv2) = largeflows[ix]; } else if(isp == 1) { (*mes[ix])(h1, iv1, h2, iv2) = flows[ix]; (*mel[ix])(h1, iv1, h2, iv2) = largeflows[ix]; } else if(isp == 2) { (*mes[ix])(h1, iv1, iv2, h2) = flows[ix]; (*mel[ix])(h1, iv1, h2, iv2) = largeflows[ix]; } } }//v2 }//v1 }//f2 }//f1 //Finally, work out me2. This depends on whether we are selecting channels //or not double me2(0.); if(ichan<0) { vector pflows(ncf,0.); for(unsigned int ix = 0; ix < ncf; ++ix) { for(unsigned int iy = 0; iy < ncf; ++ iy) { double con = cfactors[ix][iy]*(mes[ix]->contract(*mes[iy],rho_)).real(); me2 += con; if(ix==iy) { con = nfactors[ix][iy]*(mel[ix]->contract(*mel[iy],rho_)).real(); pflows[ix] += con; } } } double ptotal(std::accumulate(pflows.begin(),pflows.end(),0.)); ptotal *= UseRandom::rnd(); for(unsigned int ix=0;ixcontract(*mel[iflow],rho_)).real(); } // return the matrix element squared return me2; } WidthCalculatorBasePtr FtoFVVDecayer:: threeBodyMEIntegrator(const DecayMode & ) const { vector intype; vector inmass,inwidth; vector inpow,inweights; constructIntegratorChannels(intype,inmass,inwidth,inpow,inweights); return new_ptr(ThreeBodyAllOnCalculator (inweights,intype,inmass,inwidth,inpow,*this,0, outgoing()[0]->mass(),outgoing()[1]->mass(), outgoing()[2]->mass(),relativeError())); } diff --git a/Decay/General/SFFDecayer.cc b/Decay/General/SFFDecayer.cc --- a/Decay/General/SFFDecayer.cc +++ b/Decay/General/SFFDecayer.cc @@ -1,491 +1,493 @@ // -*- C++ -*- // // SFFDecayer.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 SFFDecayer class. // #include "SFFDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr SFFDecayer::clone() const { return new_ptr(*this); } IBPtr SFFDecayer::fullclone() const { return new_ptr(*this); } void SFFDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map & inV, const vector > & outV, map ) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_ .push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { incomingVertex_[inter] = dynamic_ptr_cast(inV.at(inter)); outgoingVertex1_[inter] = dynamic_ptr_cast(outV[0].at(inter)); outgoingVertex2_[inter] = dynamic_ptr_cast(outV[1].at(inter)); } } void SFFDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_ << incomingVertex_ << outgoingVertex1_ << outgoingVertex2_; } void SFFDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_ >> incomingVertex_ >> outgoingVertex1_ >> outgoingVertex2_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSFFDecayer("Herwig::SFFDecayer", "Herwig.so"); void SFFDecayer::Init() { static ClassDocumentation documentation ("This class implements to decay of a scalar to 2 fermions"); } double SFFDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay,MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin1Half,PDT::Spin1Half))); // work out which is the fermion and antifermion int iferm(1),ianti(0); int itype[2]; for(unsigned int ix=0;ix<2;++ix) { if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1; else itype[ix] = 2; } if(itype[0]==0||itype[1]==1||(itype[0]==2&&itype[1]==2)) swap(iferm,ianti); if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(rho_,const_ptr_cast(&inpart),incoming); swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart),incoming,true); SpinorBarWaveFunction:: constructSpinInfo(wavebar_,decay[iferm],outgoing,true); SpinorWaveFunction:: constructSpinInfo(wave_ ,decay[ianti],outgoing,true); return 0.; } SpinorBarWaveFunction:: calculateWaveFunctions(wavebar_,decay[iferm],outgoing); SpinorWaveFunction:: calculateWaveFunctions(wave_ ,decay[ianti],outgoing); Energy2 scale(sqr(inpart.mass())); for(unsigned int ifm = 0; ifm < 2; ++ifm){ for(unsigned int ia = 0; ia < 2; ++ia) { if(iferm > ianti) (*ME())(0, ia, ifm) = 0.; else (*ME())(0, ifm, ia) = 0.; for(auto vert : vertex_) { if(iferm > ianti){ (*ME())(0, ia, ifm) += vert->evaluate(scale,wave_[ia], wavebar_[ifm],swave_); } else { (*ME())(0, ifm, ia) += vert->evaluate(scale,wave_[ia], wavebar_[ifm],swave_); } } } } double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy SFFDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; perturbativeVertex_[0]->setCoupling(sqr(inpart.second), outb.first, outa.first, in); double mu1(outa.second/inpart.second),mu2(outb.second/inpart.second); double c2 = norm(perturbativeVertex_[0]->norm()); Complex al(perturbativeVertex_[0]->left()), ar(perturbativeVertex_[0]->right()); double me2 = -c2*( (norm(al) + norm(ar))*( sqr(mu1) + sqr(mu2) - 1.) + 2.*(ar*conj(al) + al*conj(ar)).real()*mu1*mu2 ); Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second, outa.second, outb.second); Energy output = me2*pcm/(8*Constants::pi); // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } double SFFDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { // work out which is the fermion and antifermion int ianti(0), iferm(1), iglu(2); int itype[2]; for(unsigned int ix=0;ix<2;++ix) { if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1; else itype[ix] = 2; } if(itype[0]==0 && itype[1]!=0) swap(iferm, ianti); if(itype[0]==2 && itype[1]==1) swap(iferm, ianti); if(itype[0]==0 && itype[1]==0 && decay[0]->dataPtr()->id()dataPtr()->id()) swap(iferm, ianti); if(itype[0]==1 && itype[1]==1 && decay[0]->dataPtr()->id()dataPtr()->id()) swap(iferm, ianti); if(meopt==Initialize) { // create scalar wavefunction for decaying particle ScalarWaveFunction:: calculateWaveFunctions(rho3_,const_ptr_cast(&inpart),incoming); swave3_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming); } // setup spin information when needed if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart),incoming,true); SpinorBarWaveFunction:: constructSpinInfo(wavebar3_ ,decay[iferm],outgoing,true); SpinorWaveFunction:: constructSpinInfo(wave3_ ,decay[ianti],outgoing,true); VectorWaveFunction:: constructSpinInfo(gluon_ ,decay[iglu ],outgoing,true,false); return 0.; } // calculate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, PDT::Spin1Half, PDT::Spin1Half, PDT::Spin1))); // create wavefunctions SpinorBarWaveFunction:: calculateWaveFunctions(wavebar3_, decay[iferm],outgoing); SpinorWaveFunction:: calculateWaveFunctions(wave3_ , decay[ianti],outgoing); VectorWaveFunction:: calculateWaveFunctions(gluon_ , decay[iglu ],outgoing,true); // gauge invariance test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(), decay[iglu ]->dataPtr(),10, outgoing)); } } #endif // identify fermion and/or anti-fermion vertex AbstractFFVVertexPtr outgoingVertexF; AbstractFFVVertexPtr outgoingVertexA; identifyVertices(iferm, ianti, inpart, decay, outgoingVertexF, outgoingVertexA, inter); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); Energy2 scale(sqr(inpart.mass())); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int ifm = 0; ifm < 2; ++ifm) { for(unsigned int ia = 0; ia < 2; ++ia) { for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from the incoming scalar if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(incomingVertex_[inter]); ScalarWaveFunction scalarInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(), gluon_[2*ig],swave3_,inpart.mass()); assert(swave3_.particle()->id()==scalarInter.particle()->id()); if(!couplingSet) { gs = abs(incomingVertex_[inter]->norm()); couplingSet = true; } Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,wave3_[ia], wavebar3_[ifm],scalarInter); for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[iferm]->dataPtr()->charged() && inter==ShowerInteraction::QED)) { assert(outgoingVertexF); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[iferm]->dataPtr(); if(off->CC()) off = off->CC(); SpinorBarWaveFunction interS = outgoingVertexF->evaluate(scale,3,off,wavebar3_[ifm], gluon_[2*ig],decay[iferm]->mass()); assert(wavebar3_[ifm].particle()->id()==interS.particle()->id()); if(!couplingSet) { gs = abs(outgoingVertexF->norm()); couplingSet = true; } Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,wave3_[ia], interS,swave3_); for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[ianti]->dataPtr()->charged() && inter==ShowerInteraction::QED)) { assert(outgoingVertexA); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[ianti]->dataPtr(); if(off->CC()) off = off->CC(); SpinorWaveFunction interS = outgoingVertexA->evaluate(scale,3,off,wave3_[ia], gluon_[2*ig],decay[ianti]->mass()); assert(wave3_[ia].particle()->id()==interS.particle()->id()); if(!couplingSet) { gs = abs(outgoingVertexA->norm()); couplingSet = true; } Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,interS,wavebar3_[ifm],swave3_); for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha(S,EM) output *= (4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif // return the answer return output; } void SFFDecayer::identifyVertices(const int iferm, const int ianti, const Particle & inpart, const ParticleVector & decay, AbstractFFVVertexPtr & outgoingVertexF, AbstractFFVVertexPtr & outgoingVertexA, ShowerInteraction inter) { // QCD if(inter==ShowerInteraction::QCD) { // work out which fermion each outgoing vertex corresponds to // two outgoing vertices if( inpart.dataPtr() ->iColour()==PDT::Colour0 && ((decay[iferm]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar) || (decay[iferm]->dataPtr()->iColour()==PDT::Colour8 && decay[ianti]->dataPtr()->iColour()==PDT::Colour8))) { if(outgoingVertex1_[inter]==outgoingVertex2_[inter]) { outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))) { outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))) { outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } else if(inpart.dataPtr() ->iColour()==PDT::Colour8 && decay[iferm]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar) { if(outgoingVertex1_[inter]==outgoingVertex2_[inter]) { outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))) { outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))) { outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } // one outgoing vertex else if(inpart.dataPtr()->iColour()==PDT::Colour3){ if(decay[iferm]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertexF = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertexF = outgoingVertex2_[inter]; } else if (decay[iferm]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour8) { if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[ianti]->dataPtr()))) { outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } else { outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } } else if(decay[iferm]->dataPtr()->iColour()==PDT::Colour3bar && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar) { if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))) { outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else { outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } } else if(inpart.dataPtr()->iColour()==PDT::Colour3bar){ if(decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar && decay[iferm]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertexA = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertexA = outgoingVertex2_[inter]; } else if (decay[iferm]->dataPtr()->iColour()==PDT::Colour8 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){ if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))) { outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else { outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } else if(decay[iferm]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3) { if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))) { outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else { outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } } else if(inpart.dataPtr()->iColour()==PDT::Colour6 || inpart.dataPtr()->iColour()==PDT::Colour6bar) { if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))) { outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else { outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } if (! ((incomingVertex_[inter] && (outgoingVertexF || outgoingVertexA)) || ( outgoingVertexF && outgoingVertexA))) { throw Exception() << "Invalid vertices for QCD radiation in SFF decay in SFFDecayer::identifyVertices" << Exception::runerror; } } // QED else { if(decay[iferm]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))) outgoingVertexF = outgoingVertex1_[inter]; else outgoingVertexF = outgoingVertex2_[inter]; } if(decay[ianti]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[ianti]->dataPtr()))) outgoingVertexA = outgoingVertex1_[inter]; else outgoingVertexA = outgoingVertex2_[inter]; } } } diff --git a/Decay/General/SRFDecayer.cc b/Decay/General/SRFDecayer.cc --- a/Decay/General/SRFDecayer.cc +++ b/Decay/General/SRFDecayer.cc @@ -1,196 +1,198 @@ // -*- C++ -*- // // SRFDecayer.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 SRFDecayer class. // #include "SRFDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr SRFDecayer::clone() const { return new_ptr(*this); } IBPtr SRFDecayer::fullclone() const { return new_ptr(*this); } void SRFDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map &, const vector > &, map) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_ .push_back(dynamic_ptr_cast (vert)); } } void SRFDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_; } void SRFDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSRFDecayer("Herwig::SRFDecayer", "Herwig.so"); void SRFDecayer::Init() { static ClassDocumentation documentation ("This class implements to decay of a scalar to a spin-3/2 and" " spin-1/2 fermion"); } double SRFDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay,MEOption meopt) const { unsigned int irs=0,ifm=1; if(decay[0]->dataPtr()->iSpin()==PDT::Spin1Half) swap(irs,ifm); if(!ME()) { if(irs==0) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin3Half,PDT::Spin1Half))); else ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin1Half,PDT::Spin3Half))); } bool ferm = decay[ifm]->id()<0; if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(rho_,const_ptr_cast(&inpart),incoming); swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart),incoming,true); if(ferm) { RSSpinorBarWaveFunction:: constructSpinInfo(RSwavebar_,decay[irs],outgoing,true); SpinorWaveFunction:: constructSpinInfo(wave_ ,decay[ifm],outgoing,true); } else { RSSpinorWaveFunction:: constructSpinInfo(RSwave_ ,decay[irs],outgoing,true); SpinorBarWaveFunction:: constructSpinInfo(wavebar_,decay[ifm],outgoing,true); } return 0.; } if(ferm) { RSSpinorBarWaveFunction:: calculateWaveFunctions(RSwavebar_,decay[irs],outgoing); SpinorWaveFunction:: calculateWaveFunctions(wave_ ,decay[ifm],outgoing); } else { RSSpinorWaveFunction:: calculateWaveFunctions(RSwave_ ,decay[irs],outgoing); SpinorBarWaveFunction:: calculateWaveFunctions(wavebar_,decay[ifm],outgoing); } Energy2 scale(sqr(inpart.mass())); for(unsigned int ifm = 0; ifm < 4; ++ifm){ for(unsigned int ia = 0; ia < 2; ++ia) { if(irs==0) { if(ferm) { (*ME())(0, ifm, ia) = 0.; for(auto vert : vertex_) (*ME())(0, ifm, ia) += vert->evaluate(scale,wave_[ia], RSwavebar_[ifm],swave_); } else { (*ME())(0, ifm, ia) = 0.; for(auto vert : vertex_) (*ME())(0, ifm, ia) += vert->evaluate(scale,RSwave_[ifm], wavebar_[ia],swave_); } } else { if(ferm) { (*ME())(0, ia, ifm) = 0.; for(auto vert : vertex_) (*ME())(0, ia, ifm) += vert->evaluate(scale,wave_[ia], RSwavebar_[ifm],swave_); } else { (*ME())(0, ia, ifm) = 0.; for(auto vert : vertex_) (*ME())(0, ia, ifm) += vert->evaluate(scale,RSwave_[ifm], wavebar_[ia],swave_); } } } } double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[irs]->dataPtr(), decay[ifm]->dataPtr()); // return the answer return output; } Energy SRFDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { Energy q = inpart.second; Energy m1 = outa.second, m2 = outb.second; // couplings tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; if(outa.first->iSpin()==PDT::Spin1Half) { swap(m1,m2); perturbativeVertex_[0]->setCoupling(sqr(inpart.second),outb.first, outa.first, in); } else { perturbativeVertex_[0]->setCoupling(sqr(inpart.second),outa.first, outb.first, in); } Complex left = perturbativeVertex_[0]-> left()*perturbativeVertex_[0]-> norm(); Complex right = perturbativeVertex_[0]->right()*perturbativeVertex_[0]-> norm(); complex A1 = 0.5*(left+right)*UnitRemoval::InvE; complex B1 = 0.5*(right-left)*UnitRemoval::InvE; Energy2 q2(q*q),m12(m1*m1),m22(m2*m2); Energy2 pcm2(0.25*(q2*(q2-2.*m12-2.*m22)+(m12-m22)*(m12-m22))/q2); Energy pcm(sqrt(pcm2)); Energy Qp(sqrt(-sqr(m2+m1)+q2)),Qm(sqrt(-sqr(m2-m1)+q2)); double r23(sqrt(2./3.)); complex h1(-2.*r23*pcm*q/m1*Qm*B1); complex h2( 2.*r23*pcm*q/m1*Qp*A1); double me2 = real(h1*conj(h1)+h2*conj(h2))/2./sqr(inpart.second); Energy output = me2*pcm/8./Constants::pi; // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } diff --git a/Decay/General/SSSDecayer.cc b/Decay/General/SSSDecayer.cc --- a/Decay/General/SSSDecayer.cc +++ b/Decay/General/SSSDecayer.cc @@ -1,410 +1,412 @@ // -*- C++ -*- // // SSSDecayer.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 SSSDecayer class. // #include "SSSDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr SSSDecayer::clone() const { return new_ptr(*this); } IBPtr SSSDecayer::fullclone() const { return new_ptr(*this); } void SSSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map & inV, const vector > & outV, map ) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_.push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { incomingVertex_[inter] = dynamic_ptr_cast(inV.at(inter)); outgoingVertex1_[inter] = dynamic_ptr_cast(outV[0].at(inter)); outgoingVertex2_[inter] = dynamic_ptr_cast(outV[1].at(inter)); } } void SSSDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_ << incomingVertex_ << outgoingVertex1_ << outgoingVertex2_; } void SSSDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_ >> incomingVertex_ >> outgoingVertex1_ >> outgoingVertex2_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSSSDecayer("Herwig::SSSDecayer", "Herwig.so"); void SSSDecayer::Init() { static ClassDocumentation documentation ("This class implements the decay of a scalar to 2 scalars."); } double SSSDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin0,PDT::Spin0))); if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(rho_,const_ptr_cast(&inpart),incoming); swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart),incoming,true); for(unsigned int ix=0;ix<2;++ix) ScalarWaveFunction:: constructSpinInfo(decay[ix],outgoing,true); } ScalarWaveFunction s1(decay[0]->momentum(),decay[0]->dataPtr(),outgoing); ScalarWaveFunction s2(decay[1]->momentum(),decay[1]->dataPtr(),outgoing); Energy2 scale(sqr(inpart.mass())); (*ME())(0,0,0) = 0.; for(auto vert : vertex_) { (*ME())(0,0,0) += vert->evaluate(scale,s1,s2,swave_); } double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy SSSDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0] && !perturbativeVertex_[0]->kinematics()) { Energy2 scale(sqr(inpart.second)); tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; perturbativeVertex_[0]->setCoupling(scale, in, outa.first, outb.first); Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second, outa.second, outb.second); double c2 = norm(perturbativeVertex_[0]->norm()); Energy pWidth = c2*pcm/8./Constants::pi/scale*UnitRemoval::E2; // colour factor pWidth *= colourFactor(inpart.first,outa.first,outb.first); return pWidth; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } double SSSDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { // work out which is the scalar and anti scalar int ianti(0), iscal(1), iglu(2); int itype[2]; for(unsigned int ix=0;ix<2;++ix) { if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1; else itype[ix] = 2; } if(itype[0]==0 && itype[1]!=0) swap(ianti, iscal); if(itype[0]==2 && itype[1]==1) swap(ianti, iscal); if(itype[0]==0 && itype[1]==0 && abs(decay[0]->dataPtr()->id())>abs(decay[1]->dataPtr()->id())) swap(iscal, ianti); if(itype[0]==1 && itype[1]==1 && abs(decay[0]->dataPtr()->id())dataPtr()->id())) swap(iscal, ianti); if(meopt==Initialize) { // create scalar wavefunction for decaying particle ScalarWaveFunction::calculateWaveFunctions(rho3_,const_ptr_cast(&inpart),incoming); swave3_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming); } // setup spin information when needed if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart),incoming,true); ScalarWaveFunction:: constructSpinInfo(decay[iscal],outgoing,true); ScalarWaveFunction:: constructSpinInfo(decay[ianti],outgoing,true); VectorWaveFunction:: constructSpinInfo(gluon_,decay[iglu ],outgoing,true,false); return 0.; } // calculate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, PDT::Spin0, PDT::Spin0, PDT::Spin1))); // create wavefunctions ScalarWaveFunction scal(decay[iscal]->momentum(), decay[iscal]->dataPtr(),outgoing); ScalarWaveFunction anti(decay[ianti]->momentum(), decay[ianti]->dataPtr(),outgoing); VectorWaveFunction::calculateWaveFunctions(gluon_,decay[iglu ],outgoing,true); // gauge invariance test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(), decay[iglu ]->dataPtr(),10, outgoing)); } } #endif AbstractVSSVertexPtr outgoingVertexS; AbstractVSSVertexPtr outgoingVertexA; identifyVertices(iscal, ianti, inpart, decay, outgoingVertexS, outgoingVertexA,inter); Energy2 scale(sqr(inpart.mass())); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from the incoming scalar if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(incomingVertex_[inter]); ScalarWaveFunction scalarInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(), gluon_[2*ig],swave3_,inpart.mass()); assert(swave3_.particle()->id()==scalarInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,scal,anti,scalarInter); if(!couplingSet) { gs = abs(incomingVertex_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[iscal]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexS); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[iscal]->dataPtr(); if(off->CC()) off = off->CC(); ScalarWaveFunction scalarInter = outgoingVertexS->evaluate(scale,3,off,gluon_[2*ig],scal,decay[iscal]->mass()); assert(scal.particle()->id()==scalarInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,swave3_,anti,scalarInter); if(!couplingSet) { gs = abs(outgoingVertexS->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[ianti]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexA); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[ianti]->dataPtr(); if(off->CC()) off = off->CC(); ScalarWaveFunction scalarInter = outgoingVertexA->evaluate(scale,3,off, gluon_[2*ig],anti,decay[ianti]->mass()); assert(anti.particle()->id()==scalarInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,swave3_,scal,scalarInter); if(!couplingSet) { gs = abs(outgoingVertexA->norm()); couplingSet = true; } for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha_(S,EM) output*=(4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif // return the answer return output; } void SSSDecayer::identifyVertices(const int iscal, const int ianti, const Particle & inpart, const ParticleVector & decay, AbstractVSSVertexPtr & outgoingVertexS, AbstractVSSVertexPtr & outgoingVertexA, ShowerInteraction inter){ // QCD if(inter==ShowerInteraction::QCD) { // work out which scalar each outgoing vertex corresponds to // two outgoing vertices if( inpart.dataPtr() ->iColour()==PDT::Colour0 && ((decay[iscal]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar) || (decay[iscal]->dataPtr()->iColour()==PDT::Colour8 && decay[ianti]->dataPtr()->iColour()==PDT::Colour8))){ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){ outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){ outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){ outgoingVertexS = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } else if(inpart.dataPtr() ->iColour()==PDT::Colour8 && decay[iscal]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){ outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){ outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){ outgoingVertexS = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } // one outgoing vertex else if(inpart.dataPtr() ->iColour()==PDT::Colour3){ if(decay[iscal]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertexS = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertexS = outgoingVertex2_[inter]; } else if (decay[iscal]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour8){ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[ianti]->dataPtr()->id()))){ outgoingVertexS = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } else { outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } } } else if(inpart.dataPtr() ->iColour()==PDT::Colour3bar){ if(decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar && decay[iscal]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertexA = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertexA = outgoingVertex2_[inter]; } else if (decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar && decay[iscal]->dataPtr()->iColour()==PDT::Colour8){ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->dataPtr()->id()))){ outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else { outgoingVertexS = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } } if (! ((incomingVertex_[inter] && (outgoingVertexS || outgoingVertexA)) || ( outgoingVertexS && outgoingVertexA))) throw Exception() << "Invalid vertices for QCD radiation in SSS decay in SSSDecayer::identifyVertices" << Exception::runerror; } // QED else { if(decay[iscal]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iscal]->dataPtr()))) outgoingVertexS = outgoingVertex1_[inter]; else outgoingVertexS = outgoingVertex2_[inter]; } if(decay[ianti]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[ianti]->dataPtr()))) outgoingVertexA = outgoingVertex1_[inter]; else outgoingVertexA = outgoingVertex2_[inter]; } } } diff --git a/Decay/General/SSVDecayer.cc b/Decay/General/SSVDecayer.cc --- a/Decay/General/SSVDecayer.cc +++ b/Decay/General/SSVDecayer.cc @@ -1,366 +1,368 @@ // -*- C++ -*- // // SSVDecayer.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 SSVDecayer class. // #include "SSVDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "Herwig/Utilities/Kinematics.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr SSVDecayer::clone() const { return new_ptr(*this); } IBPtr SSVDecayer::fullclone() const { return new_ptr(*this); } void SSVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map & inV, const vector > & outV, map fourV) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_.push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { incomingVertex_[inter] = dynamic_ptr_cast(inV.at(inter)); fourPointVertex_[inter] = dynamic_ptr_cast(fourV.at(inter)); outgoingVertexS_[inter] = AbstractVSSVertexPtr(); outgoingVertexV_[inter] = AbstractVVVVertexPtr(); if(outV[0].at(inter)) { if (outV[0].at(inter)->getName()==VertexType::VSS) outgoingVertexS_[inter] = dynamic_ptr_cast(outV[0].at(inter)); else outgoingVertexV_[inter] = dynamic_ptr_cast(outV[0].at(inter)); } if(outV[1].at(inter)) { if (outV[1].at(inter)->getName()==VertexType::VSS) outgoingVertexS_[inter] = dynamic_ptr_cast(outV[1].at(inter)); else outgoingVertexV_[inter] = dynamic_ptr_cast(outV[1].at(inter)); } } } void SSVDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_ << incomingVertex_ << outgoingVertexS_ << outgoingVertexV_ << fourPointVertex_; } void SSVDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_ >> incomingVertex_ >> outgoingVertexS_ >> outgoingVertexV_ >> fourPointVertex_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSSVDecayer("Herwig::SSVDecayer", "Herwig.so"); void SSVDecayer::Init() { static ClassDocumentation documentation ("This implements the decay of a scalar to a vector and a scalar"); } double SSVDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { unsigned int isc(0),ivec(1); if(decay[0]->dataPtr()->iSpin() != PDT::Spin0) swap(isc,ivec); if(!ME()) { if(ivec==1) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin0,PDT::Spin1))); else ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin1,PDT::Spin0))); } if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(rho_,const_ptr_cast(&inpart),incoming); swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart),incoming,true); ScalarWaveFunction:: constructSpinInfo(decay[isc],outgoing,true); VectorWaveFunction:: constructSpinInfo(vector_,decay[ivec],outgoing,true,false); } VectorWaveFunction:: calculateWaveFunctions(vector_,decay[ivec],outgoing,false); ScalarWaveFunction sca(decay[isc]->momentum(),decay[isc]->dataPtr(),outgoing); Energy2 scale(sqr(inpart.mass())); //make sure decay matrix element is in the correct order double output(0.); if(ivec == 0) { for(unsigned int ix = 0; ix < 3; ++ix) { (*ME())(0, ix, 0) = 0.; for(auto vert : vertex_) (*ME())(0, ix, 0) += vert->evaluate(scale,vector_[ix],sca, swave_); } } else { for(unsigned int ix = 0; ix < 3; ++ix) { (*ME())(0, 0, ix) = 0.; for(auto vert : vertex_) (*ME())(0, 0, ix) += vert->evaluate(scale,vector_[ix],sca,swave_); } } output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy SSVDecayer:: partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { double mu1sq(sqr(outa.second/inpart.second)), mu2sq(sqr(outb.second/inpart.second)); tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; if(outa.first->iSpin() == PDT::Spin0) { perturbativeVertex_[0]->setCoupling(sqr(inpart.second), outb.first, outa.first,in); } else { swap(mu1sq,mu2sq); perturbativeVertex_[0]->setCoupling(sqr(inpart.second), outa.first, outb.first,in); } double me2(0.); if(mu2sq == 0.) me2 = -2.*mu1sq - 2.; else me2 = ( sqr(mu2sq - mu1sq) - 2.*(mu2sq + mu1sq) + 1. )/mu2sq; Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second, outa.second, outb.second); Energy output = pcm*me2*norm(perturbativeVertex_[0]->norm())/8./Constants::pi; // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } double SSVDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { int iscal (0), ivect (1), iglu (2); // get location of outgoing scalar/vector if(decay[1]->dataPtr()->iSpin()==PDT::Spin0) swap(iscal,ivect); if(meopt==Initialize) { // create scalar wavefunction for decaying particle ScalarWaveFunction::calculateWaveFunctions(rho3_,const_ptr_cast(&inpart),incoming); swave3_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming); } // setup spin information when needed if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart),incoming,true); ScalarWaveFunction:: constructSpinInfo(decay[iscal],outgoing,true); VectorWaveFunction:: constructSpinInfo(vector3_,decay[ivect],outgoing,true,false); VectorWaveFunction:: constructSpinInfo(gluon_, decay[iglu ],outgoing,true,false); return 0.; } // calculate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, PDT::Spin0, PDT::Spin1, PDT::Spin1))); // create wavefunctions ScalarWaveFunction scal(decay[iscal]->momentum(), decay[iscal]->dataPtr(),outgoing); VectorWaveFunction::calculateWaveFunctions(vector3_,decay[ivect],outgoing,false); VectorWaveFunction::calculateWaveFunctions(gluon_, decay[iglu ],outgoing,true ); // gauge invariance test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(), decay[iglu ]->dataPtr(),10, outgoing)); } } #endif if (! ((incomingVertex_[inter] && (outgoingVertexS_[inter] || outgoingVertexV_[inter])) || (outgoingVertexS_[inter] && outgoingVertexV_[inter]))) throw Exception() << "Invalid vertices for radiation in SSV decay in SSVDecayer::threeBodyME" << Exception::runerror; // sort out colour flows int S(1), V(2); if (decay[iscal]->dataPtr()->iColour()==PDT::Colour3bar && decay[ivect]->dataPtr()->iColour()==PDT::Colour8) swap(S,V); else if (decay[ivect]->dataPtr()->iColour()==PDT::Colour3 && decay[iscal]->dataPtr()->iColour()==PDT::Colour8) swap(S,V); Energy2 scale(sqr(inpart.mass())); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int iv = 0; iv < 3; ++iv) { for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from the incoming scalar if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(incomingVertex_[inter]); ScalarWaveFunction scalarInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(), gluon_[2*ig],swave3_,inpart.mass()); assert(swave3_.particle()->id()==scalarInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vector3_[iv],scal,scalarInter); if(!couplingSet) { gs = abs(incomingVertex_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[iscal]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexS_[inter]); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[iscal]->dataPtr(); if(off->CC()) off = off->CC(); ScalarWaveFunction scalarInter = outgoingVertexS_[inter]->evaluate(scale,3,off,gluon_[2*ig],scal,decay[iscal]->mass()); assert(scal.particle()->id()==scalarInter.particle()->id()); if(!couplingSet) { gs = abs(outgoingVertexS_[inter]->norm()); couplingSet = true; } Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vector3_[iv],scalarInter,swave3_); for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[ivect]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexV_[inter]); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[ivect]->dataPtr(); if(off->CC()) off = off->CC(); VectorWaveFunction vectorInter = outgoingVertexV_[inter]->evaluate(scale,3,off,gluon_[2*ig], vector3_[iv],decay[ivect]->mass()); assert(vector3_[iv].particle()->id()==vectorInter.particle()->id()); if(!couplingSet) { gs = abs(outgoingVertexV_[inter]->norm()); couplingSet = true; } Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vectorInter,scal,swave3_); for(unsigned int ix=0;ixevaluate(scale, gluon_[2*ig], vector3_[iv], scal, swave3_); for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha_(S,EM) output*=(4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif // return the answer return output; } diff --git a/Decay/General/SVVDecayer.cc b/Decay/General/SVVDecayer.cc --- a/Decay/General/SVVDecayer.cc +++ b/Decay/General/SVVDecayer.cc @@ -1,432 +1,434 @@ // -*- C++ -*- // // SVVDecayer.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 SVVDecayer class. // #include "SVVDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/Vertex/Scalar/VVSVertex.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr SVVDecayer::clone() const { return new_ptr(*this); } IBPtr SVVDecayer::fullclone() const { return new_ptr(*this); } void SVVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map & inV, const vector > & outV, map ) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_.push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { incomingVertex_[inter] = dynamic_ptr_cast(inV.at(inter)); outgoingVertex1_[inter] = dynamic_ptr_cast(outV[0].at(inter)); outgoingVertex2_[inter] = dynamic_ptr_cast(outV[1].at(inter)); } } void SVVDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_ << incomingVertex_ << outgoingVertex1_ << outgoingVertex2_; } void SVVDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_ >> incomingVertex_ >> outgoingVertex1_ >> outgoingVertex2_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSVVDecayer("Herwig::SVVDecayer", "Herwig.so"); void SVVDecayer::Init() { static ClassDocumentation documentation ("This implements the decay of a scalar to 2 vector bosons."); } double SVVDecayer::me2(const int , const Particle & inpart, const ParticleVector& decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin1,PDT::Spin1))); bool photon[2]; for(unsigned int ix=0;ix<2;++ix) photon[ix] = decay[ix]->mass()==ZERO; if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(rho_,const_ptr_cast(&inpart),incoming); swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart),incoming,true); for(unsigned int ix=0;ix<2;++ix) VectorWaveFunction:: constructSpinInfo(vectors_[ix],decay[ix],outgoing,true,photon[ix]); } for(unsigned int ix=0;ix<2;++ix) VectorWaveFunction:: calculateWaveFunctions(vectors_[ix],decay[ix],outgoing,photon[ix]); Energy2 scale(sqr(inpart.mass())); unsigned int iv1,iv2; for(iv2 = 0; iv2 < 3; ++iv2) { if( photon[1] && iv2 == 1 ) ++iv2; for(iv1=0;iv1<3;++iv1) { if( photon[0] && iv1 == 1) ++iv1; (*ME())(0, iv1, iv2) = 0.; for(auto vert : vertex_) (*ME())(0, iv1, iv2) += vert->evaluate(scale,vectors_[0][iv1], vectors_[1][iv2],swave_); } } double output = ME()->contract(rho_).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy SVVDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { Energy2 scale(sqr(inpart.second)); tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; perturbativeVertex_[0]->setCoupling(scale, outa.first , outb.first, in); double mu1sq = sqr(outa.second/inpart.second); double mu2sq = sqr(outb.second/inpart.second); double m1pm2 = mu1sq + mu2sq; double me2(0.); if( mu1sq > 0. && mu2sq > 0.) me2 = ( m1pm2*(m1pm2 - 2.) + 8.*mu1sq*mu2sq + 1.)/4./mu1sq/mu2sq; else if( mu1sq == 0. || mu2sq == 0. ) me2 = 3.; else me2 = 4.; Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second, outb.second); Energy output = norm(perturbativeVertex_[0]->norm())* me2*pcm/(8*Constants::pi)/scale*UnitRemoval::E2; // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } double SVVDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { if(meopt==Initialize) { // create scalar wavefunction for decaying particle ScalarWaveFunction:: calculateWaveFunctions(rho3_,const_ptr_cast(&inpart),incoming); swave3_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming); } if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart),incoming,true); VectorWaveFunction:: constructSpinInfo(vectors3_[0],decay[0],outgoing,true,false); VectorWaveFunction:: constructSpinInfo(vectors3_[1],decay[1],outgoing,true,false); VectorWaveFunction:: constructSpinInfo(gluon_ ,decay[2],outgoing,true,false); return 0.; } // calculate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, PDT::Spin1, PDT::Spin1, PDT::Spin1))); bool massless[2]; for(unsigned int ix=0;ix<2;++ix) massless[ix] = decay[ix]->mass()!=ZERO; // create wavefunctions VectorWaveFunction::calculateWaveFunctions(vectors3_[0],decay[0],outgoing,massless[0]); VectorWaveFunction::calculateWaveFunctions(vectors3_[1],decay[1],outgoing,massless[1]); VectorWaveFunction::calculateWaveFunctions(gluon_ ,decay[2],outgoing,true); // gauge test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[2]->momentum(), decay[2]->dataPtr(),10, outgoing)); } } #endif // get the outgoing vertices AbstractVVVVertexPtr outgoingVertex1; AbstractVVVVertexPtr outgoingVertex2; identifyVertices(inpart,decay, outgoingVertex1, outgoingVertex2,inter); Energy2 scale(sqr(inpart.mass())); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int iv1 = 0; iv1 < 3; ++iv1) { if(massless[0] && iv1==1) continue; for(unsigned int iv2 = 0; iv2 < 3; ++iv2) { if(massless[1] && iv2==1) continue; for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from the incoming vector if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(incomingVertex_[inter]); ScalarWaveFunction scalarInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),gluon_[2*ig], swave3_,inpart.mass()); assert(swave3_.particle()->id()==scalarInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vectors3_[0][iv1], vectors3_[1][iv2],scalarInter); if(!couplingSet) { gs = abs(incomingVertex_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[0]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertex1); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[0]->dataPtr(); if(off->CC()) off = off->CC(); VectorWaveFunction vectorInter = outgoingVertex1->evaluate(scale,3,off,gluon_[2*ig],vectors3_[0][iv1],decay[0]->mass()); assert(vectors3_[0][iv1].particle()->id()==vectorInter.particle()->id()); Complex diag =0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vectorInter,vectors3_[1][iv2],swave3_); if(!couplingSet) { gs = abs(outgoingVertex1->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[1]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertex2); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[1]->dataPtr(); if(off->CC()) off = off->CC(); VectorWaveFunction vectorInter = outgoingVertex2->evaluate(scale,3,off, gluon_[2*ig],vectors3_[1][iv2],decay[1]->mass()); assert(vectors3_[1][iv2].particle()->id()==vectorInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vectors3_[0][iv1],vectorInter,swave3_); if(!couplingSet) { gs = abs(outgoingVertex2->norm()); couplingSet = true; } for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha_(S,EM) output*=(4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif // return the answer return output; } void SVVDecayer::identifyVertices(const Particle & inpart, const ParticleVector & decay, AbstractVVVVertexPtr & outgoingVertex1, AbstractVVVVertexPtr & outgoingVertex2, ShowerInteraction inter) { if(inter==ShowerInteraction::QCD) { // work out which scalar each outgoing vertex corresponds to // two outgoing vertices if( inpart.dataPtr() ->iColour()==PDT::Colour0 && ((decay[0]->dataPtr()->iColour()==PDT::Colour3 && decay[1]->dataPtr()->iColour()==PDT::Colour3bar) || (decay[0]->dataPtr()->iColour()==PDT::Colour8 && decay[1]->dataPtr()->iColour()==PDT::Colour8))){ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){ outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[0]->id()))){ outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[0]->id()))){ outgoingVertex1 = outgoingVertex2_[inter]; outgoingVertex2 = outgoingVertex1_[inter]; } } else if(inpart.dataPtr() ->iColour()==PDT::Colour8 && decay[0]->dataPtr()->iColour()==PDT::Colour3 && decay[1]->dataPtr()->iColour()==PDT::Colour3bar){ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){ outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[0]->id()))){ outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[0]->id()))){ outgoingVertex1 = outgoingVertex2_[inter]; outgoingVertex2 = outgoingVertex1_[inter]; } } // one outgoing vertex else if(inpart.dataPtr()->iColour()==PDT::Colour3){ if(decay[0]->dataPtr()->iColour()==PDT::Colour3 && decay[1]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertex1 = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertex1 = outgoingVertex2_[inter]; } else if (decay[0]->dataPtr()->iColour()==PDT::Colour3 && decay[1]->dataPtr()->iColour()==PDT::Colour8){ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[1]->dataPtr()->id()))){ outgoingVertex1 = outgoingVertex2_[inter]; outgoingVertex2 = outgoingVertex1_[inter]; } else { outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } } } else if(inpart.dataPtr()->iColour()==PDT::Colour3bar){ if(decay[1]->dataPtr()->iColour()==PDT::Colour3bar && decay[0]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertex2 = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertex2 = outgoingVertex2_[inter]; } else if (decay[0]->dataPtr()->iColour()==PDT::Colour8 && decay[1]->dataPtr()->iColour()==PDT::Colour3bar){ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[0]->dataPtr()->id()))){ outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } else { outgoingVertex1 = outgoingVertex2_[inter]; outgoingVertex2 = outgoingVertex1_[inter]; } } } if (! ((incomingVertex_[inter] && (outgoingVertex1 || outgoingVertex2)) || ( outgoingVertex1 && outgoingVertex2))) throw Exception() << "Invalid vertices for QCD radiation in SVV decay in SVVDecayer::identifyVertices" << Exception::runerror; } else { if(decay[0]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[0]->dataPtr()))) outgoingVertex1 = outgoingVertex1_[inter]; else outgoingVertex1 = outgoingVertex2_[inter]; } if(decay[1]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[1]->dataPtr()))) outgoingVertex2 = outgoingVertex1_[inter]; else outgoingVertex2 = outgoingVertex2_[inter]; } } } diff --git a/Decay/General/StoFFFFDecayer.cc b/Decay/General/StoFFFFDecayer.cc --- a/Decay/General/StoFFFFDecayer.cc +++ b/Decay/General/StoFFFFDecayer.cc @@ -1,1306 +1,1308 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the StoFFFFDecayer class. // #include "StoFFFFDecayer.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/EventRecord/Particle.h" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Decay/DecayPhaseSpaceMode.h" #include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h" #include "ThePEG/Helicity/Vertex/Scalar/FFSVertex.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include using namespace Herwig; using namespace ThePEG::Helicity; namespace { inline bool isParticle(tPPtr part) { return part->id()>0 && part->dataPtr()->CC(); } inline bool isAntiParticle(tPPtr part) { return part->id()<0 && part->dataPtr()->CC(); } inline bool isMajorana(tPPtr part) { return !part->dataPtr()->CC(); } } IBPtr StoFFFFDecayer::clone() const { return new_ptr(*this); } IBPtr StoFFFFDecayer::fullclone() const { return new_ptr(*this); } void StoFFFFDecayer::persistentOutput(PersistentOStream & os) const { os << firstVVS_ << firstVSS_ << firstSSS_ << firstFFS_ << secondFFV_ << secondFFS_ << thirdFFV_ << thirdFFS_ << sign_; } void StoFFFFDecayer::persistentInput(PersistentIStream & is, int) { is >> firstVVS_ >> firstVSS_ >> firstSSS_ >> firstFFS_ >> secondFFV_ >> secondFFS_ >> thirdFFV_ >> thirdFFS_ >> sign_; } DescribeClass describeStoFFFFDecayer("Herwig::StoFFFFDecayer", "Herwig.so"); void StoFFFFDecayer::Init() { static ClassDocumentation documentation ("The StoFFFFDecayer class performs the 4-fermion " "decays of scalar particles in BSM models"); } void StoFFFFDecayer::doinit() { GeneralFourBodyDecayer::doinit(); unsigned int ndiags = getProcessInfo().size(); firstVVS_ .resize(ndiags); firstVSS_ .resize(ndiags); firstSSS_ .resize(ndiags); firstFFS_ .resize(ndiags); secondFFV_.resize(ndiags); secondFFS_.resize(ndiags); thirdFFV_ .resize(ndiags); thirdFFS_ .resize(ndiags); for(unsigned int ix = 0;ix < ndiags; ++ix) { const NBDiagram & current = getProcessInfo()[ix]; // first vertex firstVVS_[ix] = dynamic_ptr_cast(current.vertex); firstVSS_[ix] = dynamic_ptr_cast(current.vertex); firstSSS_[ix] = dynamic_ptr_cast(current.vertex); firstFFS_[ix] = dynamic_ptr_cast(current.vertex); // get the other vertices const NBVertex & second = current.vertices.begin()->second.incoming ? current.vertices.begin()->second : (++current.vertices.begin())->second; // get the other vertices const NBVertex & third = current.vertices.begin()->second.incoming ? (++current.vertices.begin())->second : (++second.vertices.begin())->second; // second vertex secondFFV_[ix] = dynamic_ptr_cast(second.vertex); secondFFS_[ix] = dynamic_ptr_cast(second.vertex); // third vertex thirdFFV_ [ix] = dynamic_ptr_cast(third .vertex); thirdFFS_ [ix] = dynamic_ptr_cast(third .vertex); assert( ( firstVVS_[ix] || firstVSS_[ix] || firstSSS_[ix] || firstFFS_[ix] ) && (secondFFV_[ix] || secondFFS_[ix] ) && ( thirdFFV_[ix] || thirdFFS_[ix] )); // NO sign int order = current.channelType[0]*1000+current.channelType[1]*100+ current.channelType[2]*10 +current.channelType[3]; switch(order) { case 1234: case 1342: case 1423: case 2143: case 2314: case 2431: case 3124: case 3241: case 3412: case 4132: case 4213: case 4321: sign_.push_back( 1.); break; case 1243: case 1324: case 1432: case 2134: case 2341: case 2413: case 3142: case 3214: case 3421: case 4123: case 4231: case 4312: sign_.push_back(-1.); break; default: assert(false); } } } double StoFFFFDecayer::me2(const int ichan, const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { // particle or CC of particle bool cc = (*getProcessInfo().begin()).incoming->id() != inpart.id(); // special handling or first/last call const vector > & cfactors(getColourFactors()); const vector > & nfactors(getLargeNcColourFactors()); const size_t ncf(numberOfFlows()); Energy2 scale(sqr(inpart.mass())); if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(rho_,const_ptr_cast(&inpart), Helicity::incoming); swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(), Helicity::incoming); + // fix rho if no correlations + fixRho(rho_); } // setup spin info when needed if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart), Helicity::incoming,true); // outgoing particles for(unsigned int ix = 0; ix < 4; ++ix) { SpinorWaveFunction:: constructSpinInfo(outwave_[ix].first,decay[ix],Helicity::outgoing,true); } } // outgoing particles for(unsigned int ix = 0; ix < 4; ++ix) { SpinorWaveFunction:: calculateWaveFunctions(outwave_[ix].first,decay[ix],Helicity::outgoing); outwave_[ix].second.resize(2); if(outwave_[ix].first[0].wave().Type() == SpinorType::u) { for(unsigned int iy = 0; iy < 2; ++iy) { outwave_[ix].second[iy] = outwave_[ix].first[iy].bar(); outwave_[ix].first[iy].conjugate(); } } else { for(unsigned int iy = 0; iy < 2; ++iy) { outwave_[ix].second[iy] = outwave_[ix].first[iy].bar(); outwave_[ix].second[iy].conjugate(); } } } // matrix element for the colour flows vector flows(ncf, Complex(0.)),largeflows(ncf, Complex(0.)); vector mes(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half))); vector mel(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half))); // calculate the matrix element unsigned int ihel[4]; for(ihel[0] = 0; ihel[0] < 2; ++ihel[0]) { for(ihel[1] = 0; ihel[1] < 2; ++ihel[1]) { for(ihel[2] = 0; ihel[2] < 2; ++ihel[2]) { for(ihel[3] = 0; ihel[3] < 2; ++ihel[3]) { flows = vector(ncf, Complex(0.)); largeflows = vector(ncf, Complex(0.)); unsigned int idiag=0; for(vector::const_iterator dit=getProcessInfo().begin(); dit!=getProcessInfo().end();++dit) { if(ichan>=0&&diagramMap()[ichan]!=idiag) { ++idiag; continue; } // location of the particles int iloc[4]; for(unsigned int ix=0;ix<4;++ix) iloc[ix] = dit->channelType[ix]-1; // NO sign double sign = sign_[idiag]; // work out the type of topology bool topo = dit->vertices.begin()->second.incoming; const NBVertex & second = topo ? dit->vertices.begin() ->second : (++(dit->vertices.begin()))->second; const NBVertex & third = topo ? (++(dit-> vertices.begin()))->second : (++(second.vertices.begin()))->second; // extract the intermediates tPDPair inter = make_pair(second.incoming, third .incoming); if( inter.second->CC()) inter.second = inter.second->CC(); if(cc&&inter.first ->CC()) inter.first = inter.first ->CC(); if(cc&&inter.second->CC()) inter.second = inter.second->CC(); // value for the diagram Complex diag(0.); // first compute the last part of the diagram VectorWaveFunction offVector2; ScalarWaveFunction offScalar2; // intermediate scalar if(inter.second->iSpin()==PDT::Spin0) { if( (isAntiParticle(decay[iloc[2]]) || isMajorana(decay[iloc[2]])) && (isParticle (decay[iloc[3]]) || isMajorana(decay[iloc[3]])) ) { sign *= -1.; offScalar2 = thirdFFS_[idiag]-> evaluate(scale, widthOption(),inter.second, outwave_[iloc[2]].first [ihel[iloc[2]]], outwave_[iloc[3]].second[ihel[iloc[3]]]); } else { offScalar2 = thirdFFS_[idiag]-> evaluate(scale, widthOption(),inter.second, outwave_[iloc[3]].first [ihel[iloc[3]]], outwave_[iloc[2]].second[ihel[iloc[2]]]); } } // intermediate vector else if(inter.second->iSpin()==PDT::Spin1) { if( (isAntiParticle(decay[iloc[2]]) || isMajorana(decay[iloc[2]])) && (isParticle(decay[iloc[3]])||isMajorana(decay[iloc[3]]))) { sign *= -1.; offVector2 = thirdFFV_[idiag]-> evaluate(scale, widthOption(),inter.second, outwave_[iloc[2]].first [ihel[iloc[2]]], outwave_[iloc[3]].second[ihel[iloc[3]]]); } else { offVector2 = thirdFFV_[idiag]-> evaluate(scale, widthOption(),inter.second, outwave_[iloc[3]].first [ihel[iloc[3]]], outwave_[iloc[2]].second[ihel[iloc[2]]]); } } // unknown else assert(false); // first topology if(topo) { // first intermediate if(inter.first->CC()) inter.first = inter.first->CC(); VectorWaveFunction offVector1; ScalarWaveFunction offScalar1; // intermeidate scalar if(inter.first->iSpin()==PDT::Spin0) { if(decay[iloc[0]]->id()<0&& decay[iloc[1]]->id()>0) { sign *= -1.; offScalar1 = secondFFS_[idiag]-> evaluate(scale, widthOption(),inter.first, outwave_[iloc[0]].first [ihel[iloc[0]]], outwave_[iloc[1]].second[ihel[iloc[1]]]); } else { offScalar1 = secondFFS_[idiag]-> evaluate(scale, widthOption(),inter.first, outwave_[iloc[1]].first [ihel[iloc[1]]], outwave_[iloc[0]].second[ihel[iloc[0]]]); } } // intermediate vector else if(inter.first->iSpin()==PDT::Spin1) { if(decay[iloc[0]]->id()<0&& decay[iloc[1]]->id()>0) { sign *= -1.; offVector1 = secondFFV_[idiag]-> evaluate(scale, widthOption(),inter.first, outwave_[iloc[0]].first [ihel[iloc[0]]], outwave_[iloc[1]].second[ihel[iloc[1]]]); } else { offVector1 = secondFFV_[idiag]-> evaluate(scale, widthOption(),inter.first, outwave_[iloc[1]].first [ihel[iloc[1]]], outwave_[iloc[0]].second[ihel[iloc[0]]]); } } // unknown else assert(false); // put it all together if(inter.first->iSpin()==PDT::Spin0) { if(inter.second->iSpin()==PDT::Spin0) { diag = firstSSS_[idiag]-> evaluate(scale,swave_,offScalar1,offScalar2); } else if(inter.second->iSpin()==PDT::Spin1) { diag = firstVSS_[idiag]-> evaluate(scale,offVector2,offScalar1,swave_); } } else if(inter.first->iSpin()==PDT::Spin1) { if(inter.second->iSpin()==PDT::Spin0) { diag = firstVSS_[idiag]-> evaluate(scale,offVector1,offScalar2,swave_); } else if(inter.second->iSpin()==PDT::Spin1) { diag = firstVVS_[idiag]-> evaluate(scale,offVector1,offVector2,swave_); } } } // second topology else { if(((isAntiParticle(decay[iloc[0]]) || isMajorana(decay[iloc[0]]))&& (isParticle (decay[iloc[1]]) || isMajorana(decay[iloc[1]])))) { sign *= -1.; SpinorWaveFunction inters = firstFFS_[idiag]-> evaluate(scale,widthOption(),inter.first, outwave_[iloc[0]].first [ihel[iloc[0]]],swave_); if(inter.second->iSpin()==PDT::Spin0) { diag = secondFFS_[idiag]-> evaluate(scale,inters,outwave_[iloc[1]].second[ihel[iloc[1]]], offScalar2); } else { diag = secondFFV_[idiag]-> evaluate(scale,inters,outwave_[iloc[1]].second[ihel[iloc[1]]], offVector2); } } else { SpinorBarWaveFunction inters = firstFFS_[idiag]-> evaluate(scale,widthOption(),inter.first, outwave_[iloc[0]].second[ihel[iloc[0]]],swave_); if(inter.second->iSpin()==PDT::Spin0) { diag = secondFFS_[idiag]-> evaluate(scale,outwave_[iloc[1]].first [ihel[iloc[1]]],inters, offScalar2); } else { diag = secondFFV_[idiag]-> evaluate(scale,outwave_[iloc[1]].first [ihel[iloc[1]]],inters, offVector2); } } } // apply NO sign diag *= sign; // matrix element for the different colour flows if(ichan<0) { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } else { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1!=colourFlow()) continue; flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1!=colourFlow()) continue; largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } ++idiag; } // now add the flows to the me2 with appropriate colour factors for(unsigned int ix = 0; ix < ncf; ++ix) { (*mes[ix])(0,ihel[0],ihel[1],ihel[2],ihel[3]) = flows[ix]; (*mel[ix])(0,ihel[0],ihel[1],ihel[2],ihel[3]) = largeflows[ix]; } } } } } double me2(0.); if(ichan<0) { vector pflows(ncf,0.); for(unsigned int ix = 0; ix < ncf; ++ix) { for(unsigned int iy = 0; iy < ncf; ++ iy) { double con = cfactors[ix][iy]*(mes[ix]->contract(*mes[iy],rho_)).real(); me2 += con; if(ix==iy) { con = nfactors[ix][iy]*(mel[ix]->contract(*mel[iy],rho_)).real(); pflows[ix] += con; } } } double ptotal(std::accumulate(pflows.begin(),pflows.end(),0.)); ptotal *=UseRandom::rnd(); for(unsigned int ix=0;ixcontract(*mel[iflow],rho_)).real(); } // return the matrix element squared return me2*scale*UnitRemoval::InvE2; } // OLD TESTING CODE // extracted from StandardModel.h // public: // virtual void StopCouplings(Energy2 &,tcPDPtr, tcPDPtr, // double &, double &, double &, // Complex &, Complex &, // vector &, vector &, // vector &, // vector &, vector &, // vector &, vector &, // vector &, vector &, // vector > &, vector > &, // vector > &, vector > &, // vector &, vector &, // vector &, vector &, // double &, double &) { // assert(false); // } // extracted from RunningMass.cc // if(id==5) return 4.8787783899999999*GeV; // if(id==15) return 1.7770999999999999*GeV; // extracted from MSSM.h // public: // virtual void StopCouplings(Energy2 &, tcPDPtr, tcPDPtr, // double & g, double & sw, double & cw, // Complex & aL, Complex & aR, // vector & cL, vector & cR, // vector & d, // vector & bL, vector & bR, // vector & kL, vector & kR, // vector & fL, vector & fR, // vector > & eL, vector > & eR, // vector > & gL, vector > & gR, // vector & hL, vector & hR, // vector & lL, vector & lR, // double & ytop, double & ytau); // extracted from MSSM.cc // void MSSM::StopCouplings(Energy2 & scale, tcPDPtr ferm, tcPDPtr anti, double & g, double & sw, double & cw, // Complex & aL, Complex & aR, // vector & cL, vector & cR, // vector & d, // vector & bL, vector & bR, // vector & kL, vector & kR, // vector & fL, vector & fR, // vector > & eL, vector > & eR, // vector > & gL, vector > & gR, // vector & hL, vector & hR, // vector & lL, vector & lR, // double & ytop, double & ytau) { // MixingMatrixPtr stop = stopMix(); // MixingMatrixPtr sbot = sbottomMix(); // MixingMatrixPtr stau = stauMix(); // MixingMatrixPtr neut = neutralinoMix(); // MixingMatrixPtr vmix = charginoVMix(); // MixingMatrixPtr umix = charginoUMix(); // sw = sqrt( sin2ThetaW()); // cw = sqrt(1.-sin2ThetaW()); // g = sqrt(4.0*Constants::pi*alphaEMMZ()/sin2ThetaW()); // Energy mb = mass(scale,getParticleData(ParticleID::b)); // Energy mt = mass(scale,getParticleData(ParticleID::t)); // Energy mw = getParticleData(ParticleID::Wplus)->mass(); // double tb = tanBeta(); // double sb = tb/sqrt(1 + sqr(tb)); // double cb = sqrt(1 - sqr(sb)); // Complex n1prime = (*neut)(0,0)*cw + (*neut)(0,1)*sw; // Complex n2prime = (*neut)(0,1)*cw - (*neut)(0,0)*sw; // double yt = double(mt/mw)/sb/sqrt(2.); // Complex bracketl = 2./ 3.*sw*( conj(n1prime) - sw*conj(n2prime)/cw ); // Complex bracketr = 2./3.*sw*n1prime - n2prime*(-0.5 + 2./3.*sqr(sw))/cw; // ytop = mt/tb/mw; // aL = -yt*conj((*neut)(0,3))*(*stop)(0,0) + sqrt(2.)*(*stop)(0,1)*bracketl; // aR = -yt* (*neut)(0,3) *(*stop)(0,1) - sqrt(2.)*(*stop)(0,0)*bracketr; // cL.resize(2); cR.resize(2); d.resize(2.); // kL.resize(2); kR.resize(2); // bL.resize(2); bR.resize(2); // double yb = double(mb/mw)/cb/sqrt(2.); // bracketl = -1./3.*sw*( conj(n1prime) - sw*conj(n2prime)/cw ); // bracketr = -1./3.*sw*n1prime - n2prime*(0.5 -1./3.*sqr(sw))/cw; // for(unsigned int k=0;k<2;++k) { // cL[k] =-yb*conj((*neut)(0,2))*(*sbot)(k,0) + sqrt(2.)*(*sbot)(k,1)*bracketl; // cR[k] =-yb* (*neut)(0,2) *(*sbot)(k,1) - sqrt(2.)*(*sbot)(k,0)*bracketr; // d[k] = (*stop)(0,0)*(*sbot)(k,0); // bL[k] = mb*conj((*umix)(k,1))/sqrt(2.)/mw/cb*(*stop)(0,0); // bR[k] = -(*vmix)(k,0)*(*stop)(0,0)+mt*(*vmix)(k,1)/sqrt(2.)/mw/sb*(*stop)(0,1); // kR[k] = - (*neut)(0,3)*conj((*vmix)(k,1))/sqrt(2.) // + (*neut)(0,1) *conj((*vmix)(k,0)); // kL[k] = conj((*neut)(0,2))* (*umix)(k,1) /sqrt(2.) // +conj((*neut)(0,1))* (*umix)(k,0) ; // } // fL.resize(2); fR.resize(2); // double qf = ferm->charge()/eplus; // Energy mf = (abs(ferm->id())<5||(abs(ferm->id())>=11&&abs(ferm->id())<=14)) ? ZERO : mass(scale, ferm); // Energy ma = (abs(anti->id())<5||(abs(anti->id())>=11&&abs(anti->id())<=14)) ? ZERO : mass(scale, anti); // fL[0] = 0.; // fR[0] = - sqrt(2.)*(qf*sw*n1prime - n2prime*(-0.5 + qf*sqr(sw))/cw); // fL[1] = + sqrt(2.)*qf*sw*( conj(n1prime) - sw*conj(n2prime)/cw ); // fR[1] = 0.; // eL.resize(2,vector(2,0.)); // eR.resize(2,vector(2,0.)); // for(unsigned int i=0;i<2;++i) { // eR[i][0] = ma*conj((*umix)(i,1))/sqrt(2.)/mw/cb; // eL[i][0] = -(*vmix)(i,0); // eL[i][1] = 0.; // eR[i][1] = 0.; // } // hL.resize(2); hR.resize(2); // double ya = double(ma/mw)/cb/sqrt(2.); // qf =-anti->charge()/eplus; // bracketl = qf*sw*( conj(n1prime) - sw*conj(n2prime)/cw ); // bracketr = qf*sw*n1prime - n2prime*(0.5 +qf*sqr(sw))/cw; // if(abs(anti->id())==ParticleID::tauminus) { // for(unsigned int k=0;k<2;++k) { // hR[k] =-ya*conj((*neut)(0,2))*(*stau)(k,0) + sqrt(2.)*(*stau)(k,1)*bracketl; // hL[k] =-ya* (*neut)(0,2) *(*stau)(k,1) - sqrt(2.)*(*stau)(k,0)*bracketr; // } // } // else { // hR[0] = 0.; // hL[0] = - sqrt(2.)*bracketr; // hR[1] = + sqrt(2.)*bracketl; // hL[1] = 0.; // } // gL.resize(2,vector(2,0.)); // gR.resize(2,vector(2,0.)); // double y = ma/mw/sqrt(2.)/cb; // ytau = ma/mw*tb; // for(unsigned int i=0;i<2;++i) { // if(abs(anti->id())==ParticleID::tauminus) { // for(unsigned int j=0;j<2;++j) { // gL[i][j] = 0.; // gR[i][j] = -(*umix)(i,0)*(*stau)(j,0) + ya*(*stau)(j,1)*(*umix)(i,1); // } // } // else { // gL[i][0] = 0.; // gR[i][0] = -(*umix)(i,0); // gL[i][1] = 0.; // gR[i][1] = 0.; // } // } // double tw = sw/cw; // lL.resize(2); // lR.resize(2); // for(unsigned int j = 0; j < 2; ++j) { // lL[j] = -(conj((*neut)(0, 3)*(*vmix)(j,0) + ((*neut)(0,1) + (*neut)(0,0)*tw)*(*vmix)(j,1)/sqrt(2)))*cb; // lR[j] = -( (*neut)(0, 2)*(*umix)(j,0) - ((*neut)(0,1) + (*neut)(0,0)*tw)*(*umix)(j,1)/sqrt(2) )*sb; // } // } // extracted from SSFFHVertex.cc // if(particle1->id()!=ParticleID::b) theMassLast.first = theMSSM->mass(q2,particle1); // if(particle2->id()!=ParticleID::b) theMassLast.second = theMSSM->mass(q2,particle2); // extracted from FourBodyDecayConstructor.cc // from createDecayMode // unsigned int nferm=0; // tcPDPtr bottom,ferm,anti,chi; // for(OrderedParticles::const_iterator it=diagrams[0].outgoing.begin(); // it!=diagrams[0].outgoing.end();++it) { // if((**it).iSpin()==PDT::Spin1Half) ++nferm; // if(abs((**it).id())==ParticleID::b) // bottom = *it; // else if(abs((**it).id())>1000000) // chi = *it; // else if((**it).id()<0) // anti = *it; // else // ferm = *it; // } // if(!bottom||!chi||!ferm||!anti) return; // if(ferm->id()-abs(anti->id())!=1) return; //if(anti->id()!=ParticleID::tauplus) return; // from decayList // set new_particles; // for(set::iterator it=particles.begin();it!=particles.end();++it) { // if((**it).id()==ParticleID::SUSY_t_1) new_particles.insert(*it); // } // NBodyDecayConstructorBase::DecayList(new_particles); // extracted from StoFFFFDecayer.h // private : // InvEnergy2 stopMatrixElement(const Particle & inpart, // const ParticleVector & decay, // InvEnergy2 me2) const; // #include "Herwig/Models/StandardModel/StandardModel.h" // InvEnergy2 StoFFFFDecayer::stopMatrixElement(const Particle & inpart, // const ParticleVector & decay, // InvEnergy2 me2) const { // // extract the momenta and check the process // bool found[4]={false,false,false,false}; // Lorentz5Momentum pb,pf,pfp,pChi; // double col = 1.; // tcPDPtr ferm,anti; // for(unsigned int ix=0;ixid(); // if(id==ParticleID::b) { // found[0] = true; // pb = decay[ix]->momentum(); // } // else if(id==ParticleID::SUSY_chi_10) { // found[1] = true; // pChi = decay[ix]->momentum(); // } // else if(abs(id)%2==0) { // if(decay[ix]->dataPtr()->coloured()) col = 3.; // found[2] = true; // pf = decay[ix]->momentum(); // ferm = decay[ix]->dataPtr(); // } // else { // found[3] = true; // pfp = decay[ix]->momentum(); // anti = decay[ix]->dataPtr(); // } // } // // check the process // if(!found[0]||!found[1]||!found[2]||!found[3]) return ZERO; // // extract the couplings we need // HwSMPtr model = dynamic_ptr_cast(generator()->standardModel()); // double sw(0.),cw(0.),g(0.); // Energy mb = getParticleData(ParticleID::b)->mass(); // Energy mt = getParticleData(ParticleID::t)->mass(); // Energy mChi = getParticleData(ParticleID::SUSY_chi_10)->mass(); // Energy mw = getParticleData(ParticleID::Wplus)->mass(); // Energy mbt[2] = {getParticleData(ParticleID::SUSY_b_1)->mass(), // getParticleData(ParticleID::SUSY_b_2)->mass()}; // Energy mP[2] = {getParticleData(ParticleID::SUSY_chi_1plus)->mass(), // getParticleData(ParticleID::SUSY_chi_2plus)->mass()}; // Energy msf[2]={ZERO,ZERO}; // tcPDPtr sf = getParticleData(1000000+abs(ferm->id())); // msf[0] = sf->mass(); // sf = getParticleData(2000000+abs(ferm->id())); // msf[1] = sf ? sf->mass() : 1e30*GeV; // Energy msfp[2]={getParticleData(1000000+abs(anti->id()))->mass(), // getParticleData(2000000+abs(anti->id()))->mass()}; // Complex aL(0.),aR(0.); // vector cL,cR,d,bL,bR,kL,kR,fL,fR,hL,hR,lL,lR; // vector > eL,eR,gL,gR; // double ytop,ytau; // Energy2 scale = sqr(inpart.mass()); // model->StopCouplings(scale,ferm,anti,g,sw,cw,aL,aR,cL,cR,d,bL,bR,kL,kR,fL,fR,eL,eR,gL,gR,hL,hR, // lL,lR,ytop,ytau); // // compute the matrix element // Lorentz5Momentum pw = pf+pfp; pw.rescaleMass(); // Lorentz5Momentum ptop = pw+pb; ptop.rescaleMass(); // Lorentz5Momentum ptt = inpart.momentum(); // Lorentz5Momentum pbt = inpart.momentum()-pw; pbt.rescaleMass(); // Lorentz5Momentum pChiP= inpart.momentum()-pb; pb.rescaleMass(); // Lorentz5Momentum psf = pChi+pf;psf.rescaleMass(); // Lorentz5Momentum psfp = pChi+pfp;psfp.rescaleMass(); // Energy2 ptpt = ptop*ptop; // Energy2 pChipfp = pChi*pfp; // Energy2 ptopptop = ptop.m2(); // Energy2 pbpf = pb*pf; // Energy2 pbpfp = pb*pfp; // Energy2 ptoppfp = ptop*pfp; // Energy2 pChipt = pChi*ptop; // Energy2 pChiptt = pChi*ptt; // Energy2 pfpfp = pf*pfp; // Energy2 pChipb = pChi*pb; // Energy2 pChipf = pChi*pf; // Energy2 pttptt = ptt.m2(); // Energy2 pbptt = pb*ptt; // Energy2 pfpptt = pfp*ptt; // Energy2 pfppt = pfp*ptop; // Energy2 pfptt = pf*ptt; // Energy2 ptptt = ptop*ptt; // Energy2 pfpt = pf*ptop; // Energy2 pbpt = pb*ptop; // Energy2 pChiPpChiP=pChiP*pChiP; // Energy2 pChipChiP=pChi*pChiP; // Energy2 pbpChiP = pb*pChiP; // Energy2 pfppChiP = pfp*pChiP; // Energy2 ptpChiP = ptop*pChiP; // Energy2 pttpChiP = ptt*pChiP; // Energy2 pfpChiP = pf*pChiP; // Energy mf = pf.mass(); // Energy mfp = pfp.mass(); // assert(model); // InvEnergy2 pTop = 1./(ptop.m2()-sqr(mt)); // InvEnergy2 pW = 1./(pw .m2()-sqr(mw)); // InvEnergy2 pBT[2] = {1./(pbt.m2()-sqr(mbt[0])),1./(pbt.m2()-sqr(mbt[1]))}; // InvEnergy2 pP[2] = {1./(pChiP.m2()-sqr(mP[0])),1./(pChiP.m2()-sqr(mP[1]))}; // InvEnergy2 pSF [2] = {1./(psf .m2()-sqr(msf [0])),1./(psf .m2()-sqr(msf [1]))}; // if(abs(ferm->id())==ParticleID::nu_e||abs(ferm->id())==ParticleID::nu_mu||abs(ferm->id())==ParticleID::nu_tau) // pSF[1] = ZERO; // InvEnergy2 pSFP[2] = {1./(psfp.m2()-sqr(msfp[0])),1./(psfp.m2()-sqr(msfp[1]))}; // // top squared // InvEnergy2 mett = pow(g,6)*sqr(pTop*pW)* // ( norm(aR) * ( -4.*pChipfp*pbpf*ptopptop + 8.*pChipt*pbpf*ptoppfp ) + // norm(aL) * ( 4.*pChipfp*pbpf*sqr(mt)) // + real(aL*conj(aR)) * ( - 8*pbpf*ptoppfp*mChi*mt ) // ); // // colour factors // mett *=col; // // sbottom squared // complex mebb(ZERO); // for(unsigned int i=0;i<2;++i) { // for(unsigned int j=0;j<2;++j) { // mebb += pow(g,6)*d[i]*d[j]*pBT[i]*pBT[j]*sqr(pW)* // (pChipb*(cR[i]*cR[j]+cL[i]*cL[j])- mChi*mb*(cL[j]*cR[i]+cL[i]*cR[j]))* // ( - 4*pfpfp*pttptt + 8*pfptt*pfpptt + pfpfp*sqr(mfp) + pfpfp*sqr(mf) // - 4*pfptt*sqr(mfp) - 4*pfpptt*sqr(mf) + 2*sqr(mf)*sqr(mfp) ); // } // } // // colour factors // mebb *=col; // // stop sbottom // complex metb(ZERO); // for(unsigned int i=0;i<2;++i) { // metb += pow(g,6)*d[i]*pTop*pBT[i]*sqr(pW)*cR[i]* // ( // + aR*( - 2*pChipb*pfpfp*ptptt + 2*pChipb*pfpt* // pfpptt + 2*pChipb*pfptt*pfppt + 2*pChipf*pbpfp*ptptt - // 2*pChipf*pbpt*pfpptt - 2*pChipf*pbptt*pfppt - 2*pChipfp // *pbpf*ptptt - 2*pChipfp*pbpt*pfptt + 2*pChipfp*pbptt* // pfpt + 2*pChipt*pbpf*pfpptt + 2*pChipt*pbpfp*pfptt - 2* // pChipt*pbptt*pfpfp + 2*pChiptt*pbpf*pfppt - 2*pChiptt* // pbpfp*pfpt + 2*pChiptt*pbpt*pfpfp) // + aL*mChi*mt*( - 2*pbpf*pfpptt - 2*pbpfp*pfptt + 2*pbptt*pfpfp )); // } // // colour factors // metb *=col; // complex mecc(ZERO); // for(unsigned int i=0;i<2;++i) { // for(unsigned int j=0;j<2;++j) { // mecc += pow(g,6)*pP[i]*pP[j]*sqr(pW)* // (+ bR[i]*bR[j]*kR[i]*kR[j] * ( 16*pChipb*pChipf*pChipfp + 16*pChipb*pChipf*pfpfp + 16*pChipb*pChipf*sqr(mfp) + 16*pChipf* // pChipfp*pbpf + 16*pChipf*pbpf*pfpfp + 16*pChipf*pbpf*sqr(mfp) + 8*pChipf*pbpfp*sqr(mfp) - 8*pChipf*pbpfp*sqr(mf) - 16*sqr(pChipf)*pbpfp ) // + bR[i]*bR[j]*kL[i]*kL[j] * ( 8*pChipfp*pbpf*mP[i]*mP[j] ) // + bL[i]*bL[j]*kR[i]*kR[j] * ( 8*pChipf*pbpfp*mP[i]*mP[j] ) // + bL[i]*bL[j]*kL[i]*kL[j] * ( 16*pChipb*pChipf*pChipfp + 16*pChipb* // pChipfp*pfpfp + 16*pChipb*pChipfp*sqr(mf) + 16*pChipf* // pChipfp*pbpfp - 8*pChipfp*pbpf*sqr(mfp) + 8*pChipfp*pbpf* // sqr(mf) + 16*pChipfp*pbpfp*pfpfp + 16*pChipfp*pbpfp*sqr(mf) - // 16*sqr(pChipfp)*pbpf ) // + mb*bL[j]*bR[i]*kR[i]*kR[j] * ( - 8*pChipf*pChipfp*mP[j] - 8*pChipf*pfpfp*mP[j] - 8*pChipf*sqr(mfp)*mP[j] ) // + mb*bL[j]*bR[i]*kL[i]*kL[j] * ( - 8*pChipf*pChipfp*mP[i] - 8*pChipfp*pfpfp*mP[i] - 8*pChipfp*sqr(mf)*mP[i] ) // + mb*bL[i]*bR[j]*kR[i]*kR[j] * ( - 8*pChipf*pChipfp*mP[i] - 8*pChipf*pfpfp*mP[i] - 8*pChipf*sqr(mfp)*mP[i] ) // + mb*bL[i]*bR[j]*kL[i]*kL[j] * ( - 8*pChipf*pChipfp*mP[j] - 8*pChipfp*pfpfp*mP[j] - 8*pChipfp*sqr(mf)*mP[j] ) // + mChi*bR[i]*bR[j]*kR[i]*kL[j] * ( - 4*pChipb*pfpfp*mP[j] + 4*pChipf*pbpfp*mP[j] - 4*pChipfp*pbpf*mP[j] - 8*pbpf*pfpfp*mP[j] - 4*pbpf*sqr(mfp)*mP[j] + 4*pbpfp*sqr(mf)*mP[j] ) // + mChi*bR[i]*bR[j]*kL[i]*kR[j] * ( - 4*pChipb*pfpfp*mP[i] + 4*pChipf*pbpfp*mP[i] - 4*pChipfp*pbpf*mP[i] - 8*pbpf*pfpfp*mP[i] - 4* // pbpf*sqr(mfp)*mP[i] + 4*pbpfp*sqr(mf)*mP[i] ) // + mChi*bL[i]*bL[j]*kR[i]*kL[j] * ( - 4*pChipb*pfpfp*mP[i] - 4*pChipf*pbpfp*mP[i] + 4*pChipfp*pbpf*mP[i] + 4*pbpf*sqr(mfp)*mP[i] - 8*pbpfp*pfpfp*mP[i] - 4*pbpfp*sqr(mf)*mP[i] ) // + mChi*bL[i]*bL[j]*kL[i]*kR[j] * ( - 4*pChipb*pfpfp*mP[j] - 4*pChipf*pbpfp*mP[j] + 4*pChipfp*pbpf*mP[j] + 4*pbpf*sqr(mfp)*mP[j] - 8* // pbpfp*pfpfp*mP[j] - 4*pbpfp*sqr(mf)*mP[j] ) // + mChi*mb*bL[j]*bR[i]*kR[i]*kL[j] * ( 8*pChipf*pfpfp + 8*pChipfp* // pfpfp + 4*pfpfp*sqr(mfp) + 4*pfpfp*sqr(mf) + 8*sqr(pfpfp) ) // + mChi*mb*bL[j]*bR[i]*kL[i]*kR[j] * ( 4*pfpfp*mP[i]*mP[j] ) // + mChi*mb*bL[i]*bR[j]*kR[i]*kL[j] * ( 4*pfpfp*mP[i]*mP[j] ) // + mChi*mb*bL[i]*bR[j]*kL[i]*kR[j] * ( 8*pChipf*pfpfp + 8*pChipfp* // pfpfp + 4*pfpfp*sqr(mfp) + 4*pfpfp*sqr(mf) + 8*sqr(pfpfp) ) // + sqr(mChi)*bR[i]*bR[j]*kR[i]*kR[j] * ( - 8*pChipf*pbpfp ) // + sqr(mChi)*bL[i]*bL[j]*kL[i]*kL[j] * ( - 8*pChipfp*pbpf ) // + mChi*sqr(mChi)*mb*bL[j]*bR[i]*kR[i]*kL[j] * ( 4*pfpfp ) // + mChi*sqr(mChi)*mb*bL[i]*bR[j]*kL[i]*kR[j] * ( 4*pfpfp )); // } // } // mecc *=col; // complex metc(ZERO); // for(unsigned int j=0;j<2;++j) { // metc += pow(g,6)*pP[j]*pTop*sqr(pW)/sqrt(2.)*( // + aR*bR[j]*kR[j] * ( - 8*pChipb*pChipf*pbpfp + 8*pChipb*pChipf*pfpfp - 8*pChipb* // pChipfp*pbpf - 8*pChipb*pChipfp*sqr(mf) + 8*pChipb*pbpf*pfpfp - 8*pChipb*pbpfp* // sqr(mf) - 4*pChipb*pfpfp*sqr(mfp) - 4* // pChipb*pfpfp*sqr(mf) - 8*pChipb*sqr(mf)*sqr(mfp) + 8*sqr(pChipb)*pfpfp + 8*pChipf*pChipfp* // pbpf + 8*pChipf*pbpf*pbpfp + 16* // pChipf*pbpf*pfpfp + 16*pChipf*pbpf*sqr(mfp) + 4*pChipf*pbpfp*sqr(mfp) - 4*pChipf*pbpfp* // sqr(mf) - 8*sqr(pChipf)*pbpfp + 4*pChipfp* // pbpf*sqr(mfp) - 4*pChipfp*pbpf*sqr(mf) - 8* // pChipfp*sqr(pbpf) ) // + aR*mb*bL[j]*kR[j] * ( - 4*pChipb*pfpfp*mP[j] - 4*pChipf*pbpfp*mP[j] - 8*pChipf*pfpfp*mP[j] // - 4*pChipf*sqr(mfp)*mP[j] + 4*pChipfp* // pbpf*mP[j] + 4*pChipfp*sqr(mf)*mP[j] ) // + aR*sqr(mb)*bR[j]*kR[j] * ( 8*pChipf*pChipfp + 4*pChipf*sqr(mfp) + 4*pChipfp*sqr(mf) ) // + aR*mChi*bR[j]*kL[j] * ( - 8*pbpf*pbpfp*mP[j] - 8*pbpf*pfpfp*mP[j] - 8*pbpf*sqr(mfp)*mP[j] ) // + aR*mChi*mb*bL[j]*kL[j] * ( 8*sqr(mf)*sqr(mfp) + 8* // pChipf*pbpfp + 8*pChipf*pfpfp + 8* // pChipf*sqr(mfp) + 8*pbpfp*pfpfp + 8* // pbpfp*sqr(mf) + 8*pfpfp*sqr(mfp) + 8*pfpfp* // sqr(mf) + 8*sqr(pfpfp) ) // + aR*sqr(mChi)*bR[j]*kR[j] * ( 8*pbpf*pbpfp + 4 // *pbpf*sqr(mfp) + 4*pbpfp*sqr(mf) ) // + aR*sqr(mChi)*sqr(mb)*bR[j]*kR[j] * ( - 4*pfpfp ) // + aL*mt*bR[j]*kL[j] * ( 8*pChipfp*pbpf*mP[j] ) // + aL*mb*mt*bL[j]*kL[j] * ( - 8*pChipf*pChipfp - 8*pChipfp*pfpfp - 8*pChipfp*sqr(mf) ) // + aL*mChi*mt*bR[j]*kR[j] * ( - 4*pChipb*pfpfp + 4*pChipf*pbpfp - 4*pChipfp*pbpf - 8*pbpf*pfpfp - 4*pbpf*sqr(mfp) + 4*pbpfp*sqr(mf) ) // + aL*mChi*mb*mt*bL[j]*kR[j] * ( 4*pfpfp*mP[j] )); // } // metc *= col; // complex mebc(ZERO); // for(unsigned int i=0;i<2;++i) { // for(unsigned int j=0;j<2;++j) { // mebc += pow(g,6)*pP[j]*sqr(pW)*d[i]*pBT[i]/sqrt(2.)* // (+ cR[i]*bR[j]*kR[j] * ( - 8*pChipb*pChipf*pfpptt + 4 // *pChipb*pChipf*sqr(mfp) - 8*pChipb* // pChipfp*pfptt + 4*pChipb*pChipfp*sqr(mf) + 8*pChipb*pChiptt*pfpfp + 2*pChipb* // pfpfp*sqr(mfp) + 2*pChipb*pfpfp*sqr(mf) - 4 // *pChipb*pfptt*sqr(mfp) - 4*pChipb*pfpptt*sqr(mf) + 4 // *pChipb*sqr(mf)*sqr(mfp) + 8*pChipf*pbpfp* // pfptt + 2*pChipf*pbpfp*sqr(mfp) - 2* // pChipf*pbpfp*sqr(mf) - 8*pChipf*pbptt*pfpfp - 4*pChipf*pbptt*sqr(mfp) - 8*pChipfp*pbpf* // pfptt - 2*pChipfp*pbpf*sqr(mfp) + 2* // pChipfp*pbpf*sqr(mf) + 4*pChipfp*pbptt*sqr(mf) + 8*pChiptt*pbpf*pfpfp + 4*pChiptt*pbpf* // sqr(mfp) - 4*pChiptt*pbpfp*sqr(mf)) // + cL[i]*bL[j]*kL[j] * ( - 8*pChipb*pChipf*pfpptt + 4 // *pChipb*pChipf*sqr(mfp) - 8*pChipb* // pChipfp*pfptt + 4*pChipb*pChipfp*sqr(mf) + 8*pChipb*pChiptt*pfpfp + 2*pChipb* // pfpfp*sqr(mfp) + 2*pChipb*pfpfp*sqr(mf) - 4 // *pChipb*pfptt*sqr(mfp) - 4*pChipb*pfpptt*sqr(mf) + 4 // *pChipb*sqr(mf)*sqr(mfp) - 8*pChipf*pbpfp* // pfpptt + 2*pChipf*pbpfp*sqr(mfp) - 2* // pChipf*pbpfp*sqr(mf) + 4*pChipf*pbptt*sqr(mfp) + 8*pChipfp*pbpf*pfpptt - 2*pChipfp*pbpf // *sqr(mfp) + 2*pChipfp*pbpf*sqr(mf) - 8* // pChipfp*pbptt*pfpfp - 4*pChipfp*pbptt*sqr(mf) - 4*pChiptt*pbpf*sqr(mfp) + 8*pChiptt* // pbpfp*pfpfp + 4*pChiptt*pbpfp*sqr(mf)) // + mb*cR[i]*bL[j]*kR[j] * ( 4*pChipf*pfpptt*mP[j] - 2*pChipf*sqr(mfp)*mP[j] + 4*pChipfp*pfptt*mP[j] // - 2*pChipfp*sqr(mf)*mP[j] - 4*pChiptt*pfpfp*mP[j] ) // + mb*cL[i]*bR[j]*kL[j] * ( 4*pChipf*pfpptt*mP[j] - 2*pChipf*sqr(mfp)*mP[j] + 4*pChipfp*pfptt*mP[j] // - 2*pChipfp*sqr(mf)*mP[j] - 4*pChiptt*pfpfp*mP[j] ) // + mChi*cR[i]*bR[j]*kL[j] * ( - 4*pbpf*pfpptt*mP[j] + 2*pbpf*sqr(mfp)*mP[j] - 4*pbpfp*pfptt*mP[j] // + 2*pbpfp*sqr(mf)*mP[j] + 4*pbptt*pfpfp*mP[j] ) // + mChi*cL[i]*bL[j]*kR[j] * ( - 4*pbpf*pfpptt*mP[j] + 2*pbpf*sqr(mfp)*mP[j] - 4*pbpfp*pfptt*mP[j] + 2*pbpfp*sqr(mf)*mP[j] + 4*pbptt*pfpfp*mP[j] ) // + mChi*mb*cR[i]*bL[j]*kL[j] * ( - 4*sqr(mf)*sqr(mfp) + 4*pChipf*pfpptt - 2*pChipf*sqr(mfp) + 4*pChipfp*pfptt - 2*pChipfp*sqr(mf) - 4*pChiptt*pfpfp - 2*pfpfp*sqr(mfp) - 2*pfpfp*sqr(mf) + 4*pfptt*sqr(mfp) + 4*pfpptt*sqr(mf) ) // + mChi*mb*cL[i]*bR[j]*kR[j] * ( - 4*sqr(mf)*sqr(mfp) + 4*pChipf*pfpptt - 2*pChipf*sqr(mfp) + 4*pChipfp*pfptt - 2*pChipfp*sqr(mf) - 4*pChiptt*pfpfp - 2*pfpfp*sqr(mfp) - 2*pfpfp*sqr(mf) + 4*pfptt*sqr(mfp) + 4*pfpptt*sqr(mf) ) // + sqr(mChi)*cR[i]*bR[j]*kR[j] * ( 4*pbpf*pfpptt - 2*pbpf*sqr(mfp) + 4*pbpfp*pfptt - 2*pbpfp*sqr(mf) - 4*pbptt*pfpfp ) // + sqr(mChi)*cL[i]*bL[j]*kL[j] * ( 4*pbpf*pfpptt - 2*pbpf*sqr(mfp) + 4*pbpfp*pfptt - 2*pbpfp*sqr(mf) - 4*pbptt*pfpfp )); // } // } // mebc *= col; // complex meff(ZERO); // for(unsigned int i=0;i<2;++i) { // for(unsigned int j=0;j<2;++j) { // for(unsigned int k=0;k<2;++k) { // for(unsigned int l=0;l<2;++l) { // meff += pow(g,6)*pP[i]*pP[j]*pSF[k]*pSF[l]*pChipf*(fR[k]*fR[l]+fL[k]*fL[l])* // ( // + ( eR[i][k]*eR[j][l]*bR[i]*bR[j] + eL[i][k]*eL[j][l]*bL[i]*bL[j] )* ( 4.*pbpfp*mP[i]*mP[j] ) // + ( eR[i][k]*eR[j][l]*bL[i]*bL[j] + eL[i][k]*eL[j][l]*bR[i]*bR[j] )* ( - 4*pbpfp*pChiPpChiP + // 8*pbpChiP*pfppChiP ) // +mb*mP[i]*( eR[i][k]*eR[j][l]*bL[j]*bR[i] + eL[i][k]*eL[j][l]*bL[i]*bR[j] ) * ( - 4*pfppChiP ) // +mb*mP[j]*( eR[i][k]*eR[j][l]*bL[i]*bR[j] + eL[i][k]*eL[j][l]*bL[j]*bR[i] ) * ( - 4*pfppChiP )); // } // } // } // } // meff *= col; // complex mepp(ZERO); // for(unsigned int i=0;i<2;++i) { // for(unsigned int j=0;j<2;++j) { // for(unsigned int k=0;k<2;++k) { // for(unsigned int l=0;l<2;++l) { // mepp += pow(g,6)*pP[i]*pP[j]*pSFP[k]*pSFP[l]*pChipfp*(hR[k]*hR[l]+hL[k]*hL[l])* // ((gR[i][k]*gR[j][l]*bR[i]*bR[j] + gL[i][k]*gL[j][l]*bL[i]*bL[j]) * ( 4*pbpf*mP[i]*mP[j] ) + // (gR[i][k]*gR[j][l]*bL[i]*bL[j] + gL[i][k]*gL[j][l]*bR[i]*bR[j]) * // ( - 4*pbpf*pChiPpChiP + 8*pbpChiP*pfpChiP )); // } // } // } // } // mepp *= col; // complex metf(ZERO); // for(unsigned int j=0;j<2;++j) { // for(unsigned int l=0;l<2;++l) { // metf += pow(g,6)*pTop*pW*pP[j]*pSF[l]* // (+ aR*eL[j][l]*fR[l]*bR[j] * ( 2*pChipb*pfpfp*ptpChiP - 2*pChipb*pfpt*pfppChiP // - 2*pChipb*pfpChiP*pfppt - 2*pChipf*pbpfp*ptpChiP // + 2*pChipf*pbpt*pfppChiP + 2*pChipf*pbpChiP*pfppt // - 2*pChipfp*pbpf*ptpChiP + 2*pChipfp*pbpt*pfpChiP // - 2*pChipfp*pbpChiP*pfpt + 2*pChipt*pbpf*pfppChiP // - 2*pChipt*pbpfp*pfpChiP + 2*pChipt*pbpChiP*pfpfp // + 2*pChipChiP*pbpf*pfppt + 2*pChipChiP*pbpfp*pfpt // - 2*pChipChiP*pbpt*pfpfp ) // + aL*mChi*mt*eL[j][l]*fR[l]*bR[j] * ( - 2*pbpf*pfppChiP + 2*pbpfp*pfpChiP - 2*pbpChiP*pfpfp ) // ); // } // } // metf *= col; // // sbottom sfermion interference // complex mebf(ZERO); // for(unsigned int i=0;i<2;++i) { // for(unsigned int j=0;j<2;++j) { // for(unsigned int l=0;l<2;++l) { // mebf += 2.*pow(g,6)*d[i]*pBT[i]*pW*pP[j]*pSF[l]* // (cR[i]*eL[j][l]*fR[l]*bR[j] * ( pChipb*pfpfp*pttpChiP - pChipb*pfptt*pfppChiP - pChipb*pfpChiP*pfpptt + // pChipf*pbpfp*pttpChiP - pChipf*pbptt*pfppChiP - pChipf*pbpChiP*pfpptt - // pChipfp*pbpf*pttpChiP + pChipfp*pbptt*pfpChiP - pChipfp*pbpChiP*pfptt + // pChiptt*pbpf*pfppChiP - pChiptt*pbpfp*pfpChiP + pChiptt*pbpChiP*pfpfp + // pChipChiP*pbpf*pfpptt + pChipChiP*pbpfp*pfptt - pChipChiP*pbptt*pfpfp) // + mChi*mP[j]*cL[i]*eL[j][l]*fR[l]*bL[j] * ( - pbpf*pfpptt - pbpfp*pfptt + pbptt*pfpfp )); // } // } // } // mebf *= col; // // chi W sfermion interference // complex mecf(ZERO); // for(unsigned int i=0;i<2;++i) { // for(unsigned int j=0;j<2;++j) { // for(unsigned int l=0;l<2;++l) { // mecf -= pow(g,6)*pP[i]*pW*pP[j]*pSF[l]*eL[j][l]*fR[l]/sqrt(2.)* // (+ bR[i]*bR[j]*kR[i] * ( 8*pChipf*pbpfp*pChiPpChiP - 16*pChipf*pbpChiP*pfppChiP ) // + bR[i]*bR[j]*kL[i]*mChi*mP[i] * ( 4*pbpf*pfppChiP - 4*pbpfp*pfpChiP + 4*pbpChiP*pfpfp) // + bL[i]*bL[j]*kR[i]*mP[i]*mP[j] * ( - 8*pChipf*pbpfp ) // + bL[i]*bL[j]*kL[i]*mChi*mP[j] * (-4*pbpf*pfppChiP + 4*pbpfp*pfpChiP + 4*pbpChiP*pfpfp) // ); // } // } // } // mecf *= col; // complex mebp(ZERO); // for(unsigned int i=0;i<2;++i) { // for(unsigned int j=0;j<2;++j) { // for(unsigned int l=0;l<2;++l) { // mebp += pow(g,6)*d[i]*pBT[i]*pW*pP[j]*pSFP[l]* // ( // + cL[i]*gR[j][l]*hL[l]*bL[j] * // ( - 2*pChipb*pfpfp*pttpChiP + 2*pChipb*pfptt*pfppChiP // + 2*pChipb*pfpChiP*pfpptt + 2*pChipf*pbpfp*pttpChiP // - 2*pChipf*pbptt*pfppChiP + 2*pChipf*pbpChiP*pfpptt // - 2*pChipfp*pbpf*pttpChiP + 2*pChipfp*pbptt*pfpChiP // + 2*pChipfp*pbpChiP*pfptt + 2*pChiptt*pbpf*pfppChiP // - 2*pChiptt*pbpfp*pfpChiP - 2*pChiptt*pbpChiP*pfpfp // - 2*pChipChiP*pbpf*pfpptt - 2*pChipChiP*pbpfp*pfptt // + 2*pChipChiP*pbptt*pfpfp) // + mChi*cR[i]*gR[j][l]*hL[l]*bR[j]*mP[j] * // ( 2*pbpf*pfpptt + 2*pbpfp*pfptt - 2*pbptt*pfpfp )); // } // } // } // mebp *= col; // // chi W anti sfermion interference // complex mecp(ZERO); // for(unsigned int i=0;i<2;++i) { // for(unsigned int j=0;j<2;++j) { // for(unsigned int l=0;l<1;++l) { // mecp +=pow(g,6)*pP[i]*pW*pP[j]*pSFP[l]/sqrt(2.)*gR[j][l]*hL[l]* // ( // + bR[i]*bR[j]*kL[i] * ( - 8*pChipfp*pbpf*mP[i]*mP[j] ) // + bL[i]*bL[j]*kL[i] * ( 8*pChipfp*pbpf*pfppChiP + 8*pChipfp*pbpf*pChiPpChiP - 8*pChipfp*pbpfp*pfpChiP - 8*pChipfp*pbpChiP*pfpfp - 16*pChipfp*pbpChiP*pfpChiP) // + mChi*bR[i]*bR[j]*kR[i]*mP[j]*( 4*pbpf*pfppChiP - 4*pbpfp*pfpChiP + 4*pbpChiP*pfpfp) // + mChi*bL[i]*bL[j]*kR[i]*mP[i]*( - 4*pbpf*pfppChiP + 8*pbpfp*pfpfp + 4*pbpfp*pfpChiP + 4*pbpChiP*pfpfp)); // } // } // } // mecp *= col; // // sfermion antisfermion interferences // complex mefp(ZERO); // for(unsigned int i=0;i<2;++i) { // for(unsigned int j=0;j<2;++j) { // for(unsigned int k=0;k<1;++k) { // for(unsigned int l=0;l<2;++l) { // mefp +=pow(g,6)*pP[i]*pP[j]*pSF[k]*pSFP[l]*fR[k]*gR[j][l]* // ( // + eR[i][k]*hR[l]*bR[i]*bR[j]*mP[i]*mP[j] * // ( 2*pChipb*pfpfp - 2*pChipf*pbpfp - 2*pChipfp*pbpf ) // + eR[i][k]*hR[l]*bL[i]*bL[j]* // ( - 2*pChipb*pfpfp*pChiPpChiP + 2*pChipf*pbpfp*pChiPpChiP // - 4*pChipf*pbpChiP*pfppChiP + 2*pChipfp*pbpf*pChiPpChiP // - 4*pChipfp*pbpChiP*pfpChiP + 4*pChipChiP*pbpChiP*pfpfp) // + eL[i][k]*hL[l]*bL[i]*bL[j]*mChi*mP[i] * // (-2*pbpf*pfppChiP + 2*pbpfp*pfpChiP + 2*pbpChiP*pfpfp ) // + eL[i][k]*hL[l]*bR[i]*bR[j]*mChi*mP[j] * // ( 2*pbpf*pfppChiP - 2*pbpfp*pfpChiP + 2*pbpChiP*pfpfp )); // } // } // } // } // mefp *= col; // // top higgs // Energy mHiggs = getParticleData(ParticleID::Hplus)->mass(); // InvEnergy2 pH = 1./(pw.m2()-sqr(mHiggs)); // InvEnergy2 meht = 0.25*sqr(ytop*ytau)*pow(g,6)*sqr(pTop*pH)*pfpfp* // ( norm(aR) *sqr(mt)*4*pChipb + // norm(aL) * ( - 4*pChipb*ptpt + 8*pChipt*pbpt ) // + real(aL*conj(aR)) * mChi*mt * ( - 8*pbpt )); // // colour factors // meht *=col; // // chargino higgs // complex mehc(ZERO); // for(unsigned int i=0;i<2;++i) { // for(unsigned int j=0;j<2;++j) { // mehc += pow(g,6)*pP[i]*pP[j]*sqr(pH)*sqr(ytau)*pfpfp* // ( + (bR[i]*bR[j]*lR[i]*lR[j]+bL[i]*bL[j]*lL[i]*lL[j])*mP[i]*mP[j]*2*pChipb // + (bR[i]*bR[j]*lL[i]*lL[j]+bL[i]*bL[j]*lR[i]*lR[j])*(-2*pChipb*pChiPpChiP+4*pChipChiP*pbpChiP) // + (bR[i]*bR[j]*lR[i]*lL[j]+bL[i]*bL[j]*lL[i]*lR[j])*mChi*mP[i]*2*pbpChiP // + (bR[i]*bR[j]*lL[i]*lR[j]+bL[i]*bL[j]*lR[i]*lL[j])*mChi*mP[j]*2*pbpChiP); // } // } // // hehbc = // // + cR1*d1*bR2*kR2 * ( 2*pChi.pb*pf.pfp*mP2 ) // // + cL1*d1*bL2*kL2 * ( 2*pChi.pb*pf.pfp*mP2 ) // // + mChi*cR1*d1*bR2*kL2 * ( 2*pb.pChiP*pf.pfp ) // // + mChi*cL1*d1*bL2*kR2 * ( 2*pb.pChiP*pf.pfp ); // // InvEnergy2 meTotal = meff.real()+mecc.real()+2.*mecf.real(); // InvEnergy2 meTotal = abs(mehc.real()); // // if(abs(anti->id())==ParticleID::tauminus) { // // cerr << "testing inter " << (me2-mepp.real()-meff.real())*GeV2 << " " << 2.*mefp.real()*GeV2 // // << " " << 0.5*(me2-mepp.real()-meff.real())/mefp.real() << "\n"; // // cerr << "testing the matrix element " << meTotal*GeV2 << " " // // << me2*GeV2 << " " << meTotal/me2 << "\n"; // // } // return meTotal; // } // extracted from main diagram loop // //\todo remove testing // top // if(!(abs(inter.first ->id())==ParticleID::t&& // abs(inter.second->id())==ParticleID::Wplus)) { // ++idiag; // continue; // } // sbottom // if(!((abs(inter.first ->id())==ParticleID::SUSY_b_1|| // abs(inter.first ->id())==ParticleID::SUSY_b_2)&& // abs(inter.second->id())==ParticleID::Wplus)) { // ++idiag; // continue; // } // chargino W // if(!((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())==ParticleID::Wplus)) { // ++idiag; // continue; // } // sneutrino // if(!((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())!=ParticleID::Wplus&& // inter.second->id()<0)) { // ++idiag; // continue; // } // sneutrino // if(!((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())!=ParticleID::Wplus&& // inter.second->id()<0)) { // ++idiag; // continue; // } // charged slepton // if(!((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())!=ParticleID::Wplus&& // inter.second->id()>0)) { // ++idiag; // continue; // } // slepton sneutrino // if(!((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())!=ParticleID::Wplus&& // abs(inter.second->id())!=ParticleID::Hplus&& // inter.second->id()>0) && // !((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())!=ParticleID::Wplus&& // abs(inter.second->id())!=ParticleID::Hplus&& // inter.second->id()<0)) { // ++idiag; // continue; // } // chi W and charged slepton // if(!((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())==ParticleID::Wplus) && // !((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())!=ParticleID::Wplus&& // inter.second->id()>0) ) { // ++idiag; // continue; // } // chi W and sneutrino // if(!((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())==ParticleID::Wplus) && // !((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())!=ParticleID::Wplus&& // inter.second->id()<0) ) { // ++idiag; // continue; // } // top/sbottom interference // if(!(abs(inter.first ->id())==ParticleID::t&& // abs(inter.second->id())==ParticleID::Wplus)&& // !((abs(inter.first ->id())==ParticleID::SUSY_b_1|| // abs(inter.first ->id())==ParticleID::SUSY_b_2)&& // abs(inter.second->id())==ParticleID::Wplus)) { // ++idiag; // continue; // } // top chiW interference // if(!(abs(inter.first ->id())==ParticleID::t&& // abs(inter.second->id())==ParticleID::Wplus)&& // !((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())==ParticleID::Wplus)) { // ++idiag; // continue; // } // bottom chiW interference // if(!((abs(inter.first ->id())==ParticleID::SUSY_b_1|| // abs(inter.first ->id())==ParticleID::SUSY_b_2)&& // abs(inter.second->id())==ParticleID::Wplus)&& // !((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())==ParticleID::Wplus)) { // ++idiag; // continue; // } // top charged slepton // if(!(abs(inter.first ->id())==ParticleID::t&& // abs(inter.second->id())==ParticleID::Wplus) && // !((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())!=ParticleID::Wplus&& // inter.second->id()>0)) { // ++idiag; // continue; // } // top sneutrino // if(!(abs(inter.first ->id())==ParticleID::t&& // abs(inter.second->id())==ParticleID::Wplus) && // !((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())!=ParticleID::Wplus&& // inter.second->id()<0)) { // ++idiag; // continue; // } // ~b sneutrino // if(!((abs(inter.first ->id())==ParticleID::SUSY_b_1|| // abs(inter.first ->id())==ParticleID::SUSY_b_2)&& // abs(inter.second->id())==ParticleID::Wplus)&& // !((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())!=ParticleID::Wplus&& // inter.second->id()<0)) { // ++idiag; // continue; // } // ~b slepton // if(!((abs(inter.first ->id())==ParticleID::SUSY_b_1|| // abs(inter.first ->id())==ParticleID::SUSY_b_2)&& // abs(inter.second->id())==ParticleID::Wplus)&& // !((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())!=ParticleID::Wplus&& // inter.second->id()>0)) { // ++idiag; // continue; // } // top H // if(!(abs(inter.first ->id())==ParticleID::t&& // abs(inter.second->id())==ParticleID::Hplus)) { // ++idiag; // continue; // } // sbottom H // if(!((abs(inter.first ->id())==ParticleID::SUSY_b_1|| // abs(inter.first ->id())==ParticleID::SUSY_b_2)&& // abs(inter.second->id())==ParticleID::Hplus)) { // ++idiag; // continue; // } // chargino H // if(!((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())==ParticleID::Hplus)) { // ++idiag; // continue; // } // top/sbottom interference // if(!(abs(inter.first ->id())==ParticleID::t&& // abs(inter.second->id())==ParticleID::Hplus)&& // !((abs(inter.first ->id())==ParticleID::SUSY_b_1|| // abs(inter.first ->id())==ParticleID::SUSY_b_2)&& // abs(inter.second->id())==ParticleID::Hplus)) { // ++idiag; // continue; // } // top chiH interference // if(!(abs(inter.first ->id())==ParticleID::t&& // abs(inter.second->id())==ParticleID::Hplus)&& // !((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())==ParticleID::Hplus)) { // ++idiag; // continue; // } // bottom chiH interference // if(!((abs(inter.first ->id())==ParticleID::SUSY_b_1|| // abs(inter.first ->id())==ParticleID::SUSY_b_2)&& // abs(inter.second->id())==ParticleID::Hplus)&& // !((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())==ParticleID::Hplus)) { // ++idiag; // continue; // } // all Higgs // if(abs(inter.second->id())==ParticleID::Hplus) { // ++idiag; // continue; // } //reomved from end of me2() //InvEnergy2 output = stopMatrixElement(inpart,decay,me2*UnitRemoval::InvE2); // return output*scale; diff --git a/Decay/General/StoFFVDecayer.cc b/Decay/General/StoFFVDecayer.cc --- a/Decay/General/StoFFVDecayer.cc +++ b/Decay/General/StoFFVDecayer.cc @@ -1,387 +1,389 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the StoFFVDecayer class. // #include "StoFFVDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/PDT/ThreeBodyAllOnCalculator.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include using namespace Herwig; using namespace ThePEG; using namespace ThePEG::Helicity; IBPtr StoFFVDecayer::clone() const { return new_ptr(*this); } IBPtr StoFFVDecayer::fullclone() const { return new_ptr(*this); } void StoFFVDecayer::persistentOutput(PersistentOStream & os) const { os << sca_ << fer_ << vec_ << RSfer_ << four_; } void StoFFVDecayer::persistentInput(PersistentIStream & is, int) { is >> sca_ >> fer_ >> vec_ >> RSfer_ >> four_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigStoFFVDecayer("Herwig::StoFFVDecayer", "Herwig.so"); void StoFFVDecayer::Init() { static ClassDocumentation documentation ("The StoFFVDecayer class implements the general decay of a scalar to " "a two fermions and a vector."); } WidthCalculatorBasePtr StoFFVDecayer:: threeBodyMEIntegrator(const DecayMode & ) const { vector intype; vector inmass,inwidth; vector inpow,inweights; constructIntegratorChannels(intype,inmass,inwidth,inpow,inweights); return new_ptr(ThreeBodyAllOnCalculator (inweights,intype,inmass,inwidth,inpow,*this,0, outgoing()[0]->mass(),outgoing()[1]->mass(), outgoing()[2]->mass(),relativeError())); } void StoFFVDecayer::doinit() { GeneralThreeBodyDecayer::doinit(); if(outgoing().empty()) return; unsigned int ndiags = getProcessInfo().size(); sca_.resize(ndiags); fer_.resize(ndiags); RSfer_.resize(ndiags); vec_.resize(ndiags); four_.resize(ndiags); for(unsigned int ix = 0;ix < ndiags; ++ix) { TBDiagram current = getProcessInfo()[ix]; tcPDPtr offshell = current.intermediate; // four point vertex if(!offshell) { four_[ix] = dynamic_ptr_cast(current.vertices.first); continue; } if( offshell->CC() ) offshell = offshell->CC(); if(offshell->iSpin() == PDT::Spin0) { AbstractVSSVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFSVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() << "Invalid vertices for a scalar diagram in StoFFVDecayer::doinit()" << Exception::runerror; sca_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin1Half) { AbstractFFSVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFVVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() << "Invalid vertices for a fermion diagram in StoFFVDecayer::doinit()" << Exception::runerror; fer_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin1) { AbstractVVSVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFVVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() << "Invalid vertices for a vector diagram in StoFFVDecayer::doinit()" << Exception::runerror; vec_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin3Half) { AbstractRFSVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractRFVVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() << "Invalid vertices for a RS fermion diagram in StoFFVDecayer::doinit()" << Exception::runerror; RSfer_[ix] = make_pair(vert1, vert2); } } } double StoFFVDecayer::me2(const int ichan, const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { // particle or CC of particle bool cc = (*getProcessInfo().begin()).incoming != inpart.id(); // special handling or first/last call if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(rho_,const_ptr_cast(&inpart), Helicity::incoming); swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(), Helicity::incoming); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart), Helicity::incoming,true); for(unsigned int ix=0;ixdataPtr()->iSpin()==PDT::Spin1) { VectorWaveFunction::constructSpinInfo(outVector_,decay[ix], Helicity::outgoing,true,false); } else { SpinorWaveFunction:: constructSpinInfo(outspin_[ix].first,decay[ix],Helicity::outgoing,true); } } } unsigned int ivec(0); bool massless(false); for(unsigned int ix = 0; ix < decay.size();++ix) { if(decay[ix]->dataPtr()->iSpin() == PDT::Spin1) { ivec = ix; massless = decay[ivec]->mass()==ZERO; VectorWaveFunction:: calculateWaveFunctions(outVector_, decay[ix], Helicity::outgoing,massless); } else { SpinorWaveFunction:: calculateWaveFunctions(outspin_[ix].first,decay[ix],Helicity::outgoing); outspin_[ix].second.resize(2); // Need a ubar and a v spinor if(outspin_[ix].first[0].wave().Type() == SpinorType::u) { for(unsigned int iy = 0; iy < 2; ++iy) { outspin_[ix].second[iy] = outspin_[ix].first[iy].bar(); outspin_[ix].first[iy].conjugate(); } } else { for(unsigned int iy = 0; iy < 2; ++iy) { outspin_[ix].second[iy] = outspin_[ix].first[iy].bar(); outspin_[ix].second[iy].conjugate(); } } } } const vector > cfactors(getColourFactors()); const vector > nfactors(getLargeNcColourFactors()); Energy2 scale(sqr(inpart.mass())); const size_t ncf(numberOfFlows()); vector flows(ncf, Complex(0.)), largeflows(ncf, Complex(0.)); // setup the DecayMatrixElement vector mes(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, ivec == 0 ? PDT::Spin1 : PDT::Spin1Half, ivec == 1 ? PDT::Spin1 : PDT::Spin1Half, ivec == 2 ? PDT::Spin1 : PDT::Spin1Half))); vector mel(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, ivec == 0 ? PDT::Spin1 : PDT::Spin1Half, ivec == 1 ? PDT::Spin1 : PDT::Spin1Half, ivec == 2 ? PDT::Spin1 : PDT::Spin1Half))); //the channel possiblities static const unsigned int out2[3] = {1,0,0}, out3[3] = {2,2,1}; for(unsigned int s1 = 0; s1 < 2; ++s1) { for(unsigned int s2 = 0; s2 < 2; ++s2) { for(unsigned int v1 = 0; v1 < 3; ++v1) { if(massless&&v1==1) ++v1; flows = vector(ncf, Complex(0.)); largeflows = vector(ncf, Complex(0.)); unsigned int idiag(0); Complex diag; for(vector::const_iterator dit=getProcessInfo().begin(); dit!=getProcessInfo().end();++dit) { // channels if selecting if( ichan >= 0 && diagramMap()[ichan] != idiag ) { ++idiag; continue; } tcPDPtr offshell = dit->intermediate; if(offshell) { if(cc&&offshell->CC()) offshell=offshell->CC(); unsigned int o2(out2[dit->channelType]), o3(out3[dit->channelType]); double sign = (o3 < o2) ? 1. : -1.; // intermediate scalar if(offshell->iSpin() == PDT::Spin0) { ScalarWaveFunction inters = sca_[idiag].first-> evaluate(scale, widthOption(), offshell, outVector_[v1], swave_); unsigned int h1(s1),h2(s2); if(o2 > o3) swap(h1, h2); if(decay[o2]->id() < 0 && decay[o3]->id() > 0) { diag = -sign*sca_[idiag].second-> evaluate(scale,outspin_[o2].first[h1], outspin_[o3].second[h2],inters); } else { diag = sign*sca_[idiag].second-> evaluate(scale, outspin_[o3].first [h2], outspin_[o2].second[h1],inters); } } // intermediate fermion else if(offshell->iSpin() == PDT::Spin1Half) { int iferm = (decay[o2]->dataPtr()->iSpin() == PDT::Spin1Half) ? o2 : o3; unsigned int h1(s1),h2(s2); if(dit->channelType > iferm) swap(h1, h2); sign = iferm < dit->channelType ? 1. : -1.; if((decay[dit->channelType]->id() < 0 && decay[iferm]->id() > 0 ) || (decay[dit->channelType]->id()*offshell->id()>0)) { SpinorWaveFunction inters = fer_[idiag].first-> evaluate(scale,widthOption(),offshell, outspin_[dit->channelType].first[h1], swave_); diag = -sign*fer_[idiag].second-> evaluate(scale,inters,outspin_[iferm].second[h2], outVector_[v1]); } else { SpinorBarWaveFunction inters = fer_[idiag].first-> evaluate(scale,widthOption(),offshell, outspin_[dit->channelType].second[h1],swave_); diag = sign*fer_[idiag].second-> evaluate(scale,outspin_[iferm].first [h2],inters, outVector_[v1]); } } // intermediate vector else if(offshell->iSpin() == PDT::Spin1) { VectorWaveFunction interv = vec_[idiag].first-> evaluate(scale, widthOption(), offshell, outVector_[v1], swave_); unsigned int h1(s1),h2(s2); if(o2 > o3) swap(h1,h2); if(decay[o2]->id() < 0 && decay[o3]->id() > 0) { diag =-sign*vec_[idiag].second-> evaluate(scale, outspin_[o2].first[h1], outspin_[o3].second[h2], interv); } else { diag = sign*vec_[idiag].second-> evaluate(scale, outspin_[o3].first[h2], outspin_[o2].second[h1], interv); } } // intermediate RS fermion else if(offshell->iSpin() == PDT::Spin3Half) { int iferm = (decay[o2]->dataPtr()->iSpin() == PDT::Spin1Half) ? o2 : o3; unsigned int h1(s1),h2(s2); if(dit->channelType > iferm) swap(h1, h2); sign = iferm < dit->channelType ? 1. : -1.; if((decay[dit->channelType]->id() < 0 && decay[iferm]->id() > 0 ) || (decay[dit->channelType]->id()*offshell->id()>0)) { RSSpinorWaveFunction inters = RSfer_[idiag].first-> evaluate(scale,widthOption(),offshell, outspin_[dit->channelType].first[h1], swave_); diag = -sign*RSfer_[idiag].second-> evaluate(scale,inters,outspin_[iferm].second[h2], outVector_[v1]); } else { RSSpinorBarWaveFunction inters = RSfer_[idiag].first-> evaluate(scale,widthOption(),offshell, outspin_[dit->channelType].second[h1],swave_); diag = sign*RSfer_[idiag].second-> evaluate(scale,outspin_[iferm].first [h2],inters, outVector_[v1]); } } // unknown else throw Exception() << "Unknown intermediate in StoFFVDecayer::me2()" << Exception::runerror; } else { unsigned int o2 = ivec > 0 ? 0 : 1; unsigned int o3 = ivec < 2 ? 2 : 1; if(decay[o2]->id() < 0 && decay[o3]->id() > 0) { diag =-four_[idiag]-> evaluate(scale, outspin_[o2].first[s1], outspin_[o3].second[s2], outVector_[v1], swave_); } else { diag = four_[idiag]-> evaluate(scale, outspin_[o3].first[s2], outspin_[o2].second[s1], outVector_[v1], swave_); } } // matrix element for the different colour flows if(ichan < 0) { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } else { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1 != colourFlow()) continue; flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1!=colourFlow()) continue; largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } ++idiag; } //end of diagrams // now add the flows to the me2 with appropriate colour factors for(unsigned int ix = 0; ix < ncf; ++ix) { if ( ivec == 0 ) { (*mes[ix])(0, v1, s1, s2) = flows[ix]; (*mel[ix])(0, v1, s1, s2) = largeflows[ix]; } else if( ivec == 1 ) { (*mes[ix])(0, s1, v1, s2) = flows[ix]; (*mel[ix])(0, s1, v1, s2) = largeflows[ix]; } else if( ivec == 2 ) { (*mes[ix])(0, s1, s2, v1) = flows[ix]; (*mel[ix])(0, s1, s2, v1) = largeflows[ix]; } } } } } double me2(0.); if(ichan < 0) { vector pflows(ncf,0.); for(unsigned int ix = 0; ix < ncf; ++ix) { for(unsigned int iy = 0; iy < ncf; ++ iy) { double con = cfactors[ix][iy]*(mes[ix]->contract(*mes[iy],rho_)).real(); me2 += con; if(ix == iy) { con = nfactors[ix][iy]*(mel[ix]->contract(*mel[iy],rho_)).real(); pflows[ix] += con; } } } double ptotal(std::accumulate(pflows.begin(),pflows.end(),0.)); ptotal *= UseRandom::rnd(); for(unsigned int ix = 0;ix < pflows.size(); ++ix) { if(ptotal <= pflows[ix]) { colourFlow(ix); ME(mes[ix]); break; } ptotal -= pflows[ix]; } } else { unsigned int iflow = colourFlow(); me2 = nfactors[iflow][iflow]*(mel[iflow]->contract(*mel[iflow],rho_)).real(); } // return the matrix element squared return me2; } diff --git a/Decay/General/StoSFFDecayer.cc b/Decay/General/StoSFFDecayer.cc --- a/Decay/General/StoSFFDecayer.cc +++ b/Decay/General/StoSFFDecayer.cc @@ -1,422 +1,424 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the StoSFFDecayer class. // #include "StoSFFDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/PDT/ThreeBodyAllOnCalculator.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include using namespace Herwig; using namespace ThePEG; using namespace ThePEG::Helicity; IBPtr StoSFFDecayer::clone() const { return new_ptr(*this); } IBPtr StoSFFDecayer::fullclone() const { return new_ptr(*this); } void StoSFFDecayer::persistentOutput(PersistentOStream & os) const { os << sca_ << fer_ << vec_ << ten_ << RSfer_ << four_; } void StoSFFDecayer::persistentInput(PersistentIStream & is, int) { is >> sca_ >> fer_ >> vec_ >> ten_ >> RSfer_ >> four_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigStoSFFDecayer("Herwig::StoSFFDecayer", "Herwig.so"); void StoSFFDecayer::Init() { static ClassDocumentation documentation ("The StoSFFDecayer class implements the general decay of a scalar to " "a scalar and two fermions."); } WidthCalculatorBasePtr StoSFFDecayer:: threeBodyMEIntegrator(const DecayMode & ) const { vector intype; vector inmass,inwidth; vector inpow,inweights; constructIntegratorChannels(intype,inmass,inwidth,inpow,inweights); return new_ptr(ThreeBodyAllOnCalculator (inweights,intype,inmass,inwidth,inpow,*this,0, outgoing()[0]->mass(),outgoing()[1]->mass(),outgoing()[2]->mass(), relativeError())); } void StoSFFDecayer::doinit() { GeneralThreeBodyDecayer::doinit(); if(outgoing().empty()) return; unsigned int ndiags = getProcessInfo().size(); sca_.resize(ndiags); fer_.resize(ndiags); RSfer_.resize(ndiags); vec_.resize(ndiags); ten_.resize(ndiags); four_.resize(ndiags); for(unsigned int ix = 0;ix < ndiags; ++ix) { TBDiagram current = getProcessInfo()[ix]; tcPDPtr offshell = current.intermediate; // four point vertex if(!offshell) { four_[ix] = dynamic_ptr_cast(current.vertices.first); continue; } if( offshell->CC() ) offshell = offshell->CC(); if(offshell->iSpin() == PDT::Spin0) { AbstractSSSVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFSVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() << "Invalid vertices for a scalar diagram in StoSFFDecayer::doinit()" << Exception::runerror; sca_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin1Half) { AbstractFFSVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFSVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() << "Invalid vertices for a fermion diagram in StoSFFDecayer::doinit()" << Exception::runerror; fer_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin1) { AbstractVSSVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFVVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() << "Invalid vertices for a vector diagram in StoSFFDecayer::doinit()" << Exception::runerror; vec_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin2) { AbstractSSTVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFTVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() << "Invalid vertices for a tensor diagram in StoSFFDecayer::doinit()" << Exception::runerror; ten_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin3Half) { AbstractRFSVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractRFSVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() << "Invalid vertices for a RS fermion diagram in StoSFFDecayer::doinit()" << Exception::runerror; RSfer_[ix] = make_pair(vert1, vert2); } } } double StoSFFDecayer::me2(const int ichan, const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { // particle or CC of particle bool cc = (*getProcessInfo().begin()).incoming != inpart.id(); // special handling or first/last call if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(rho_,const_ptr_cast(&inpart), Helicity::incoming); swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(), Helicity::incoming); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart), Helicity::incoming,true); for(unsigned int ix=0;ixdataPtr()->iSpin()==PDT::Spin0) { ScalarWaveFunction::constructSpinInfo(decay[ix],Helicity::outgoing,true); } else { SpinorWaveFunction:: constructSpinInfo(outspin_[ix].first,decay[ix],Helicity::outgoing,true); } } return 0.; } // get the wavefunctions for all the particles ScalarWaveFunction outScalar; unsigned int isca(0); for(unsigned int ix=0;ixdataPtr()->iSpin()==PDT::Spin0) { isca = ix; outScalar = ScalarWaveFunction(decay[ix]->momentum(), decay[ix]->dataPtr(),Helicity::outgoing); } else { SpinorWaveFunction:: calculateWaveFunctions(outspin_[ix].first,decay[ix],Helicity::outgoing); outspin_[ix].second.resize(2); if(outspin_[ix].first[0].wave().Type() == SpinorType::u) { for(unsigned int iy = 0; iy < 2; ++iy) { outspin_[ix].second[iy] = outspin_[ix].first[iy].bar(); outspin_[ix].first[iy].conjugate(); } } else { for(unsigned int iy = 0; iy < 2; ++iy) { outspin_[ix].second[iy] = outspin_[ix].first[iy].bar(); outspin_[ix].second[iy].conjugate(); } } } } const vector > cfactors(getColourFactors()); const vector > nfactors(getLargeNcColourFactors()); Energy2 scale(sqr(inpart.mass())); const size_t ncf(numberOfFlows()); vector flows(ncf, Complex(0.)), largeflows(ncf, Complex(0.)); vector mes(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, isca==0 ? PDT::Spin0 : PDT::Spin1Half, isca==1 ? PDT::Spin0 : PDT::Spin1Half, isca==2 ? PDT::Spin0 : PDT::Spin1Half))); vector mel(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, isca == 0 ? PDT::Spin0 : PDT::Spin1Half, isca == 1 ? PDT::Spin0 : PDT::Spin1Half, isca == 2 ? PDT::Spin0 : PDT::Spin1Half))); static const unsigned int out2[3]={1,0,0},out3[3]={2,2,1}; for(unsigned int s1 = 0;s1 < 2; ++s1) { for(unsigned int s2 = 0;s2 < 2; ++s2) { flows = vector(ncf, Complex(0.)); largeflows = vector(ncf, Complex(0.)); unsigned int idiag(0); for(vector::const_iterator dit = getProcessInfo().begin(); dit != getProcessInfo().end(); ++dit) { // channels if selecting if( ichan >= 0 && diagramMap()[ichan] != idiag ) { ++idiag; continue; } tcPDPtr offshell = dit->intermediate; Complex diag; if(offshell) { if(cc&&offshell->CC()) offshell=offshell->CC(); double sign = out3[dit->channelType] < out2[dit->channelType] ? 1. : -1.; // intermediate scalar if (offshell->iSpin() == PDT::Spin0) { ScalarWaveFunction inters = sca_[idiag].first-> evaluate(scale, widthOption(), offshell, swave_, outScalar); unsigned int h1(s1),h2(s2); if(out2[dit->channelType]>out3[dit->channelType]) swap(h1,h2); if(decay[out2[dit->channelType]]->id()<0&& decay[out3[dit->channelType]]->id()>0) { diag =-sign*sca_[idiag].second-> evaluate(scale, outspin_[out2[dit->channelType]].first [h1], outspin_[out3[dit->channelType]].second[h2],inters); } else { diag = sign*sca_[idiag].second-> evaluate(scale, outspin_[out3[dit->channelType]].first [h2], outspin_[out2[dit->channelType]].second[h1],inters); } } // intermediate fermion else if(offshell->iSpin() == PDT::Spin1Half) { int iferm = decay[out2[dit->channelType]]->dataPtr()->iSpin()==PDT::Spin1Half ? out2[dit->channelType] : out3[dit->channelType]; unsigned int h1(s1),h2(s2); if(dit->channelType>iferm) swap(h1,h2); sign = ifermchannelType ? 1. : -1.; if((decay[dit->channelType]->id() < 0 &&decay[iferm]->id() > 0 ) || (decay[dit->channelType]->id()*offshell->id()>0)) { SpinorWaveFunction inters = fer_[idiag].first-> evaluate(scale,widthOption(),offshell, outspin_[dit->channelType].first [h1],swave_); diag = -sign*fer_[idiag].second-> evaluate(scale,inters,outspin_[iferm].second[h2],outScalar); } else { SpinorBarWaveFunction inters = fer_[idiag].first-> evaluate(scale,widthOption(),offshell, outspin_[dit->channelType].second[h1],swave_); diag = sign*fer_[idiag].second-> evaluate(scale,outspin_[iferm].first [h2],inters,outScalar); } } // intermediate vector else if(offshell->iSpin() == PDT::Spin1) { VectorWaveFunction interv = vec_[idiag].first-> evaluate(scale, widthOption(), offshell, swave_, outScalar); unsigned int h1(s1),h2(s2); if(out2[dit->channelType]>out3[dit->channelType]) swap(h1,h2); if(decay[out2[dit->channelType]]->id()<0&& decay[out3[dit->channelType]]->id()>0) { diag =-sign*vec_[idiag].second-> evaluate(scale, outspin_[out2[dit->channelType]].first [h1], outspin_[out3[dit->channelType]].second[h2],interv); } else { diag = sign*vec_[idiag].second-> evaluate(scale, outspin_[out3[dit->channelType]].first [h2], outspin_[out2[dit->channelType]].second[h1],interv); } } // intermediate tensor else if(offshell->iSpin() == PDT::Spin2) { TensorWaveFunction intert = ten_[idiag].first-> evaluate(scale, widthOption(), offshell, swave_, outScalar); unsigned int h1(s1),h2(s2); if(out2[dit->channelType]>out3[dit->channelType]) swap(h1,h2); if(decay[out2[dit->channelType]]->id()<0&& decay[out3[dit->channelType]]->id()>0) { diag =-sign*ten_[idiag].second-> evaluate(scale, outspin_[out2[dit->channelType]].first [h1], outspin_[out3[dit->channelType]].second[h2],intert); } else { diag = sign*ten_[idiag].second-> evaluate(scale, outspin_[out3[dit->channelType]].first [h2], outspin_[out2[dit->channelType]].second[h1],intert); } } // intermediate RS fermion else if(offshell->iSpin() == PDT::Spin3Half) { int iferm = decay[out2[dit->channelType]]->dataPtr()->iSpin()==PDT::Spin1Half ? out2[dit->channelType] : out3[dit->channelType]; unsigned int h1(s1),h2(s2); if(dit->channelType>iferm) swap(h1,h2); sign = ifermchannelType ? 1. : -1.; if((decay[dit->channelType]->id() < 0 &&decay[iferm]->id() > 0 ) || (decay[dit->channelType]->id()*offshell->id()>0)) { RSSpinorWaveFunction inters = RSfer_[idiag].first-> evaluate(scale,widthOption(),offshell, outspin_[dit->channelType].first [h1],swave_); diag = -sign*RSfer_[idiag].second-> evaluate(scale,inters,outspin_[iferm].second[h2],outScalar); } else { RSSpinorBarWaveFunction inters = RSfer_[idiag].first-> evaluate(scale,widthOption(),offshell, outspin_[dit->channelType].second[h1],swave_); diag = sign*RSfer_[idiag].second-> evaluate(scale,outspin_[iferm].first [h2],inters,outScalar); } } // unknown else throw Exception() << "Unknown intermediate in StoSFFDecayer::me2()" << Exception::runerror; } // four point diagram else { unsigned int o2 = isca > 0 ? 0 : 1; unsigned int o3 = isca < 2 ? 2 : 1; if(decay[o2]->id() < 0 && decay[o3]->id() > 0) { diag =-four_[idiag]-> evaluate(scale, outspin_[o2].first[s1], outspin_[o3].second[s2], outScalar, swave_); } else { diag = four_[idiag]-> evaluate(scale, outspin_[o3].first[s2], outspin_[o2].second[s1], outScalar, swave_); } } // matrix element for the different colour flows if(ichan < 0) { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } else { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1 != colourFlow()) continue; flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1!=colourFlow()) continue; largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } ++idiag; } for(unsigned int ix = 0; ix < ncf; ++ix) { if(isca == 0) { (*mes[ix])(0, 0, s1, s2) = flows[ix]; (*mel[ix])(0, 0, s1, s2) = largeflows[ix]; } else if(isca == 1 ) { (*mes[ix])(0, s1, 0, s2) = flows[ix]; (*mel[ix])(0, s1, 0, s2) = largeflows[ix]; } else if(isca == 2) { (*mes[ix])(0, s1,s2, 0) = flows[ix]; (*mel[ix])(0, s1,s2, 0) = largeflows[ix] ; } } } } double me2(0.); if(ichan < 0) { vector pflows(ncf,0.); for(unsigned int ix = 0; ix < ncf; ++ix) { for(unsigned int iy = 0; iy < ncf; ++ iy) { double con = cfactors[ix][iy]*(mes[ix]->contract(*mes[iy],rho_)).real(); me2 += con; if(ix == iy) { con = nfactors[ix][iy]*(mel[ix]->contract(*mel[iy],rho_)).real(); pflows[ix] += con; } } } double ptotal(std::accumulate(pflows.begin(),pflows.end(),0.)); ptotal *= UseRandom::rnd(); for(unsigned int ix = 0;ix < pflows.size(); ++ix) { if(ptotal <= pflows[ix]) { colourFlow(ix); ME(mes[ix]); break; } ptotal -= pflows[ix]; } } else { unsigned int iflow = colourFlow(); me2 = nfactors[iflow][iflow]*(mel[iflow]->contract(*mel[iflow],rho_)).real(); } // return the matrix element squared return me2; } diff --git a/Decay/General/TFFDecayer.cc b/Decay/General/TFFDecayer.cc --- a/Decay/General/TFFDecayer.cc +++ b/Decay/General/TFFDecayer.cc @@ -1,351 +1,353 @@ // -*- C++ -*- // // TFFDecayer.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 TFFDecayer class. // #include "TFFDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/WaveFunction/TensorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr TFFDecayer::clone() const { return new_ptr(*this); } IBPtr TFFDecayer::fullclone() const { return new_ptr(*this); } void TFFDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map &, const vector > & outV, map fourV) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_.push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { fourPointVertex_[inter] = dynamic_ptr_cast(fourV.at(inter)); outgoingVertex1_[inter] = dynamic_ptr_cast (outV[0].at(inter)); outgoingVertex2_[inter] = dynamic_ptr_cast (outV[1].at(inter)); } } void TFFDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_ << outgoingVertex1_ << outgoingVertex2_ << fourPointVertex_; } void TFFDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_ >> outgoingVertex1_ >> outgoingVertex2_ >> fourPointVertex_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigTFFDecayer("Herwig::TFFDecayer", "Herwig.so"); void TFFDecayer::Init() { static ClassDocumentation documentation ("The TFFDecayer class implements the decay of a tensor particle " "to 2 fermions "); } double TFFDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { unsigned int iferm(0),ianti(1); if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin2,PDT::Spin1Half,PDT::Spin1Half))); if(decay[0]->id()>=0) swap(iferm,ianti); if(meopt==Initialize) { TensorWaveFunction:: calculateWaveFunctions(tensors_,rho_,const_ptr_cast(&inpart), incoming,false); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { TensorWaveFunction:: constructSpinInfo(tensors_,const_ptr_cast(&inpart), incoming,true,false); SpinorBarWaveFunction:: constructSpinInfo(wavebar_,decay[iferm],outgoing,true); SpinorWaveFunction:: constructSpinInfo(wave_ ,decay[ianti],outgoing,true); return 0.; } SpinorBarWaveFunction:: calculateWaveFunctions(wavebar_,decay[iferm],outgoing); SpinorWaveFunction:: calculateWaveFunctions(wave_ ,decay[ianti],outgoing); Energy2 scale(sqr(inpart.mass())); unsigned int thel,fhel,ahel; for(thel=0;thel<5;++thel) { for(fhel=0;fhel<2;++fhel) { for(ahel=0;ahel<2;++ahel) { if(iferm > ianti) { (*ME())(thel,fhel,ahel) = 0.; for(auto vert : vertex_) (*ME())(thel,fhel,ahel) += vert->evaluate(scale,wave_[ahel], wavebar_[fhel],tensors_[thel]); } else { (*ME())(thel,ahel,fhel) = 0.; for(auto vert : vertex_) (*ME())(thel,ahel,fhel) += vert->evaluate(scale,wave_[ahel], wavebar_[fhel],tensors_[thel]); } } } } double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy TFFDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { Energy2 scale = sqr(inpart.second); tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; perturbativeVertex_[0]->setCoupling(scale, in, outa.first, outb.first); double musq = sqr(outa.second/inpart.second); double b = sqrt(1- 4.*musq); double me2 = b*b*(5-2*b*b)*scale/120.*UnitRemoval::InvE2; Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second, outb.second); Energy output = norm(perturbativeVertex_[0]->norm())*me2*pcm/(8.*Constants::pi); // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } double TFFDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { // work out which is the fermion and antifermion int ianti(0), iferm(1), iglu(2); int itype[2]; for(unsigned int ix=0;ix<2;++ix) { if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1; else itype[ix] = 2; } if(itype[0]==0 && itype[1]!=0) swap(iferm, ianti); if(itype[0]==2 && itype[1]==1) swap(iferm, ianti); if(itype[0]==0 && itype[1]==0 && decay[0]->dataPtr()->id()dataPtr()->id()) swap(iferm, ianti); if(itype[0]==1 && itype[1]==1 && decay[0]->dataPtr()->id()dataPtr()->id()) swap(iferm, ianti); if(meopt==Initialize) { // create tensor wavefunction for decaying particle TensorWaveFunction:: calculateWaveFunctions(tensors3_, rho3_, const_ptr_cast(&inpart), incoming, false); } // setup spin information when needed if(meopt==Terminate) { TensorWaveFunction:: constructSpinInfo(tensors3_, const_ptr_cast(&inpart),incoming,true, false); SpinorBarWaveFunction:: constructSpinInfo(wavebar3_ ,decay[iferm],outgoing,true); SpinorWaveFunction:: constructSpinInfo(wave3_ ,decay[ianti],outgoing,true); VectorWaveFunction:: constructSpinInfo(gluon_ ,decay[iglu ],outgoing,true,false); return 0.; } // calculate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin2, PDT::Spin1Half, PDT::Spin1Half, PDT::Spin1))); // create wavefunctions SpinorBarWaveFunction:: calculateWaveFunctions(wavebar3_, decay[iferm],outgoing); SpinorWaveFunction:: calculateWaveFunctions(wave3_ , decay[ianti],outgoing); VectorWaveFunction:: calculateWaveFunctions(gluon_ , decay[iglu ],outgoing,true); // gauge invariance test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(), decay[iglu ]->dataPtr(),10, outgoing)); } } #endif if (! (outgoingVertex1_[inter] && outgoingVertex2_[inter])) throw Exception() << "Invalid vertices for QCD radiation in TFF decay in TFFDecayer::threeBodyME" << Exception::runerror; // identify fermion and/or anti-fermion vertex AbstractFFVVertexPtr outgoingVertexF = outgoingVertex1_[inter]; AbstractFFVVertexPtr outgoingVertexA = outgoingVertex2_[inter]; if(outgoingVertex1_[inter]!=outgoingVertex2_[inter] && outgoingVertex1_[inter]->isIncoming(getParticleData(decay[ianti]->id()))) swap (outgoingVertexF, outgoingVertexA); if(! (inpart.dataPtr()->iColour()==PDT::Colour0)){ throw Exception() << "Invalid vertices for QCD radiation in TFF decay in TFFDecayer::threeBodyME" << Exception::runerror; } Energy2 scale(sqr(inpart.mass())); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int it = 0; it < 5; ++it) { for(unsigned int ifm = 0; ifm < 2; ++ifm) { for(unsigned int ia = 0; ia < 2; ++ia) { for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from outgoing fermion if((decay[iferm]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[iferm]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexF); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[iferm]->dataPtr(); if(off->CC()) off = off->CC(); SpinorBarWaveFunction interS = outgoingVertexF->evaluate(scale,3,off,wavebar3_[ifm], gluon_[2*ig],decay[iferm]->mass()); assert(wavebar3_[ifm].particle()->id()==interS.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,wave3_[ia], interS,tensors3_[it]); if(!couplingSet) { gs = abs(outgoingVertexF->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[ianti]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexA); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[ianti]->dataPtr(); if(off->CC()) off = off->CC(); SpinorWaveFunction interS = outgoingVertexA->evaluate(scale,3,off,wave3_[ia], gluon_[2*ig],decay[ianti]->mass()); assert(wave3_[ia].particle()->id()==interS.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,interS,wavebar3_[ifm],tensors3_[it]); if(!couplingSet) { gs = abs(outgoingVertexA->norm()); couplingSet = true; } for(unsigned int ix=0;ixevaluate(scale, wave3_[ia], wavebar3_[ifm], gluon_[2*ig], tensors3_[it]); for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha_(s,em) output *= (4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif // return the answer return output; } diff --git a/Decay/General/TSSDecayer.cc b/Decay/General/TSSDecayer.cc --- a/Decay/General/TSSDecayer.cc +++ b/Decay/General/TSSDecayer.cc @@ -1,130 +1,132 @@ // -*- C++ -*- // // TSSDecayer.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 TSSDecayer class. // #include "TSSDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Utilities/Kinematics.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/TensorWaveFunction.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr TSSDecayer::clone() const { return new_ptr(*this); } IBPtr TSSDecayer::fullclone() const { return new_ptr(*this); } void TSSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map & , const vector > & , map ) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_.push_back(dynamic_ptr_cast (vert)); } } void TSSDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_; } void TSSDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigTSSDecayer("Herwig::TSSDecayer", "Herwig.so"); void TSSDecayer::Init() { static ClassDocumentation documentation ("This class implements the decay of a tensor particle into " "2 scalars."); } double TSSDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin2,PDT::Spin0,PDT::Spin0))); if(meopt==Initialize) { TensorWaveFunction:: calculateWaveFunctions(tensors_,rho_,const_ptr_cast(&inpart), incoming,false); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { TensorWaveFunction:: constructSpinInfo(tensors_,const_ptr_cast(&inpart), incoming,true,false); for(unsigned int ix=0;ix<2;++ix) ScalarWaveFunction:: constructSpinInfo(decay[ix],outgoing,true); return 0.; } ScalarWaveFunction sca1(decay[0]->momentum(),decay[0]->dataPtr(),outgoing); ScalarWaveFunction sca2(decay[1]->momentum(),decay[1]->dataPtr(),outgoing); Energy2 scale(sqr(inpart.mass())); for(unsigned int thel=0;thel<5;++thel) { (*ME())(thel,0,0) =0.; for(auto vert : vertex_) (*ME())(thel,0,0) += vert->evaluate(scale,sca1,sca2,tensors_[thel]); } double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy TSSDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { Energy2 scale(sqr(inpart.second)); tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; perturbativeVertex_[0]->setCoupling(scale, outa.first, outb.first, in); double musq = sqr(outa.second/inpart.second); double b = sqrt(1. - 4.*musq); double me2 = scale*pow(b,4)/120*UnitRemoval::InvE2; Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second, outb.second); Energy output = norm(perturbativeVertex_[0]->norm())*me2*pcm/(8.*Constants::pi); // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } diff --git a/Decay/General/TVVDecayer.cc b/Decay/General/TVVDecayer.cc --- a/Decay/General/TVVDecayer.cc +++ b/Decay/General/TVVDecayer.cc @@ -1,338 +1,340 @@ // -*- C++ -*- // // TVVDecayer.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 TVVDecayer class. // #include "TVVDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/TensorWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "ThePEG/Helicity/LorentzTensor.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr TVVDecayer::clone() const { return new_ptr(*this); } IBPtr TVVDecayer::fullclone() const { return new_ptr(*this); } void TVVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map &, const vector > & outV, map fourV) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_.push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { fourPointVertex_[inter] = dynamic_ptr_cast(fourV.at(inter)); outgoingVertex1_[inter] = dynamic_ptr_cast (outV[0].at(inter)); outgoingVertex2_[inter] = dynamic_ptr_cast (outV[1].at(inter)); } } void TVVDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_ << outgoingVertex1_ << outgoingVertex2_ << fourPointVertex_; } void TVVDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_ >> outgoingVertex1_ >> outgoingVertex2_ >> fourPointVertex_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigTVVDecayer("Herwig::TVVDecayer", "Herwig.so"); void TVVDecayer::Init() { static ClassDocumentation documentation ("This class implements the decay of a tensor to 2 vector bosons"); } double TVVDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin2,PDT::Spin1,PDT::Spin1))); bool photon[2]; for(unsigned int ix=0;ix<2;++ix) photon[ix] = decay[ix]->mass()==ZERO; if(meopt==Initialize) { TensorWaveFunction:: calculateWaveFunctions(tensors_,rho_,const_ptr_cast(&inpart), incoming,false); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { TensorWaveFunction:: constructSpinInfo(tensors_,const_ptr_cast(&inpart), incoming,true,false); for(unsigned int ix=0;ix<2;++ix) VectorWaveFunction:: constructSpinInfo(vectors_[ix],decay[ix],outgoing,true,photon[ix]); return 0.; } for(unsigned int ix=0;ix<2;++ix) VectorWaveFunction:: calculateWaveFunctions(vectors_[ix],decay[ix],outgoing,photon[ix]); Energy2 scale(sqr(inpart.mass())); unsigned int thel,v1hel,v2hel; for(thel=0;thel<5;++thel) { for(v1hel=0;v1hel<3;++v1hel) { for(v2hel=0;v2hel<3;++v2hel) { (*ME())(thel,v1hel,v2hel) = 0.; for(auto vert : vertex_) (*ME())(thel,v1hel,v2hel) += vert->evaluate(scale, vectors_[0][v1hel], vectors_[1][v2hel], tensors_[thel]); if(photon[1]) ++v2hel; } if(photon[0]) ++v1hel; } } double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy TVVDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { Energy2 scale(sqr(inpart.second)); tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; perturbativeVertex_[0]->setCoupling(scale, outa.first, outb.first, in); double mu2 = sqr(outa.second/inpart.second); double b = sqrt(1 - 4.*mu2); Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second, outb.second); Energy2 me2; if(outa.second > ZERO && outb.second > ZERO) me2 = scale*(30 - 20.*b*b + 3.*pow(b,4))/120.; else me2 = scale/10.; Energy output = norm(perturbativeVertex_[0]->norm())*me2*pcm /(8.*Constants::pi)*UnitRemoval::InvE2; // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } double TVVDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { bool massless[2]; for(unsigned int ix=0;ix<2;++ix) massless[ix] = decay[ix]->mass()==ZERO; int iglu(2); if(meopt==Initialize) { // create tensor wavefunction for decaying particle TensorWaveFunction:: calculateWaveFunctions(tensors3_, rho3_, const_ptr_cast(&inpart), incoming, false); } // setup spin information when needed if(meopt==Terminate) { TensorWaveFunction:: constructSpinInfo(tensors3_, const_ptr_cast(&inpart),incoming,true, false); for(unsigned int ix=0;ix<2;++ix) VectorWaveFunction:: constructSpinInfo(vectors3_[ix],decay[ix ],outgoing,true, massless[ix]); VectorWaveFunction:: constructSpinInfo(gluon_ ,decay[iglu ],outgoing,true,false); return 0.; } // calculate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin2, PDT::Spin1, PDT::Spin1, PDT::Spin1))); // create wavefunctions for(unsigned int ix=0;ix<2;++ix) VectorWaveFunction:: calculateWaveFunctions(vectors3_[ix],decay[ix ],outgoing,massless[ix]); VectorWaveFunction:: calculateWaveFunctions(gluon_ ,decay[iglu ],outgoing,true); // gauge test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(), decay[iglu ]->dataPtr(),10, outgoing)); } } #endif // work out which vector each outgoing vertex corresponds to if(outgoingVertex1_[inter]!=outgoingVertex2_[inter] && outgoingVertex1_[inter]->isIncoming(getParticleData(decay[1]->id()))) swap(outgoingVertex1_[inter], outgoingVertex2_[inter]); if (! (outgoingVertex1_[inter] && outgoingVertex2_[inter])) throw Exception() << "Invalid vertices for radiation in TVV decay in TVVDecayer::threeBodyME" << Exception::runerror; if( !(!inpart.dataPtr()->coloured() && inter ==ShowerInteraction::QCD) && !(!inpart.dataPtr()->charged() && inter ==ShowerInteraction::QED)) throw Exception() << "Invalid vertices for radiation in TVV decay in TVVDecayer::threeBodyME" << Exception::runerror; Energy2 scale(sqr(inpart.mass())); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int it = 0; it < 5; ++it) { for(unsigned int iv0 = 0; iv0 < 3; ++iv0) { for(unsigned int iv1 = 0; iv1 < 3; ++iv1) { for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from first outgoing vector if((decay[0]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[0]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertex1_[inter]); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[0]->dataPtr(); if(off->CC()) off = off->CC(); VectorWaveFunction vectInter = outgoingVertex1_[inter]->evaluate(scale,3,off,gluon_[2*ig], vectors3_[0][iv0],decay[0]->mass()); assert(vectors3_[0][iv0].particle()->PDGName()==vectInter.particle()->PDGName()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vectors3_[1][iv1], vectInter,tensors3_[it]); if(!couplingSet) { gs = abs(outgoingVertex1_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[1]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertex2_[inter]); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[1]->dataPtr(); if(off->CC()) off = off->CC(); VectorWaveFunction vectInter = outgoingVertex2_[inter]->evaluate(scale,3,off,vectors3_[1][iv1], gluon_[2*ig],decay[1]->mass()); assert(vectors3_[1][iv1].particle()->PDGName()==vectInter.particle()->PDGName()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vectInter,vectors3_[0][iv0], tensors3_[it]); if(!couplingSet) { gs = abs(outgoingVertex2_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixevaluate(scale, vectors3_[0][iv0], vectors3_[1][iv1],gluon_[2*ig], tensors3_[it]); for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha_(s,em) output *= (4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif // return the answer return output; } diff --git a/Decay/General/VFFDecayer.cc b/Decay/General/VFFDecayer.cc --- a/Decay/General/VFFDecayer.cc +++ b/Decay/General/VFFDecayer.cc @@ -1,470 +1,472 @@ // -*- C++ -*- // // VFFDecayer.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 VFFDecayer class. // #include "VFFDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr VFFDecayer::clone() const { return new_ptr(*this); } IBPtr VFFDecayer::fullclone() const { return new_ptr(*this); } void VFFDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map & inV, const vector > & outV, map ) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_.push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { incomingVertex_[inter] = dynamic_ptr_cast(inV.at(inter)); outgoingVertex1_[inter] = dynamic_ptr_cast(outV[0].at(inter)); outgoingVertex2_[inter] = dynamic_ptr_cast(outV[1].at(inter)); } } void VFFDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_ << incomingVertex_ << outgoingVertex1_ << outgoingVertex2_; } void VFFDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_ >> incomingVertex_ >> outgoingVertex1_ >> outgoingVertex2_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigVFFDecayer("Herwig::VFFDecayer", "Herwig.so"); void VFFDecayer::Init() { static ClassDocumentation documentation ("The VFFDecayer implements the matrix element for the" " decay of a vector to fermion-antifermion pair"); } double VFFDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { int iferm(1),ianti(0); if(decay[0]->id()>0) swap(iferm,ianti); if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1Half,PDT::Spin1Half))); if(meopt==Initialize) { VectorWaveFunction::calculateWaveFunctions(vectors_,rho_, const_ptr_cast(&inpart), incoming,false); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { VectorWaveFunction::constructSpinInfo(vectors_,const_ptr_cast(&inpart), incoming,true,false); SpinorBarWaveFunction:: constructSpinInfo(wavebar_,decay[iferm],outgoing,true); SpinorWaveFunction:: constructSpinInfo(wave_ ,decay[ianti],outgoing,true); return 0.; } SpinorBarWaveFunction:: calculateWaveFunctions(wavebar_,decay[iferm],outgoing); SpinorWaveFunction:: calculateWaveFunctions(wave_ ,decay[ianti],outgoing); // compute the matrix element Energy2 scale(inpart.mass()*inpart.mass()); for(unsigned int ifm = 0; ifm < 2; ++ifm) { //loop over fermion helicities for(unsigned int ia = 0; ia < 2; ++ia) {// loop over antifermion helicities for(unsigned int vhel = 0; vhel < 3; ++vhel) {//loop over vector helicities if(iferm > ianti) { (*ME())(vhel, ia, ifm) = 0.; for(auto vert : vertex_) (*ME())(vhel, ia, ifm) += vert->evaluate(scale,wave_[ia], wavebar_[ifm],vectors_[vhel]); } else { (*ME())(vhel,ifm,ia)= 0.; for(auto vert : vertex_) (*ME())(vhel,ifm,ia) += vert->evaluate(scale,wave_[ia], wavebar_[ifm],vectors_[vhel]); } } } } double output=(ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy VFFDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { double mu1(outa.second/inpart.second), mu2(outb.second/inpart.second); tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; perturbativeVertex_[0]->setCoupling(sqr(inpart.second), outa.first, outb.first,in); Complex cl(perturbativeVertex_[0]->left()), cr(perturbativeVertex_[0]->right()); double me2 = (norm(cl) + norm(cr))*( sqr(sqr(mu1) - sqr(mu2)) + sqr(mu1) + sqr(mu2) - 2.) - 6.*(cl*conj(cr) + cr*conj(cl)).real()*mu1*mu2; Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second, outb.second); Energy output = -norm(perturbativeVertex_[0]->norm())*me2*pcm / (24.*Constants::pi); // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } double VFFDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { // work out which is the fermion and antifermion int ianti(0), iferm(1), iglu(2); int itype[2]; for(unsigned int ix=0;ix<2;++ix) { if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1; else itype[ix] = 2; } if(itype[0]==0 && itype[1]!=0) swap(iferm, ianti); if(itype[0]==2 && itype[1]==1) swap(iferm, ianti); if(itype[0]==0 && itype[1]==0 && decay[0]->dataPtr()->id()dataPtr()->id()) swap(iferm, ianti); if(itype[0]==1 && itype[1]==1 && decay[0]->dataPtr()->id()dataPtr()->id()) swap(iferm, ianti); if(meopt==Initialize) { // create vector wavefunction for decaying particle VectorWaveFunction::calculateWaveFunctions(vector3_, rho3_, const_ptr_cast(&inpart), incoming, false); } // setup spin information when needed if(meopt==Terminate) { VectorWaveFunction:: constructSpinInfo(vector3_ ,const_ptr_cast(&inpart),outgoing,true,false); SpinorBarWaveFunction:: constructSpinInfo(wavebar3_,decay[iferm],outgoing,true); SpinorWaveFunction:: constructSpinInfo(wave3_ ,decay[ianti],outgoing,true); VectorWaveFunction:: constructSpinInfo(gluon_ ,decay[iglu ],outgoing,true,false); return 0.; } // calculate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin1, PDT::Spin1Half, PDT::Spin1Half, PDT::Spin1))); // create wavefunctions SpinorBarWaveFunction:: calculateWaveFunctions(wavebar3_, decay[iferm],outgoing); SpinorWaveFunction:: calculateWaveFunctions(wave3_ , decay[ianti],outgoing); VectorWaveFunction:: calculateWaveFunctions(gluon_ , decay[iglu ],outgoing,true); // gauge invariance test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(), decay[iglu ]->dataPtr(),10, outgoing)); } } #endif // identify fermion and/or anti-fermion vertex AbstractFFVVertexPtr outgoingVertexF; AbstractFFVVertexPtr outgoingVertexA; identifyVertices(iferm, ianti, inpart, decay, outgoingVertexF, outgoingVertexA,inter); Energy2 scale(sqr(inpart.mass())); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int iv = 0; iv < 3; ++iv) { for(unsigned int ifm = 0; ifm < 2; ++ifm) { for(unsigned int ia = 0; ia < 2; ++ia) { for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from the incoming vector if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(incomingVertex_[inter]); VectorWaveFunction vectorInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),vector3_[iv], gluon_[2*ig],inpart.mass()); assert(vector3_[iv].particle()->id()==vectorInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,wave3_[ia],wavebar3_[ifm],vectorInter); if(!couplingSet) { gs = abs(incomingVertex_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[iferm]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexF); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[iferm]->dataPtr(); if(off->CC()) off = off->CC(); SpinorBarWaveFunction interS = outgoingVertexF->evaluate(scale,3,off,wavebar3_[ifm], gluon_[2*ig],decay[iferm]->mass()); assert(wavebar3_[ifm].particle()->id()==interS.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,wave3_[ia], interS,vector3_[iv]); if(!couplingSet) { gs = abs(outgoingVertexF->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[ianti]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexA); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[ianti]->dataPtr(); if(off->CC()) off = off->CC(); SpinorWaveFunction interS = outgoingVertexA->evaluate(scale,3,off,wave3_[ia], gluon_[2*ig],decay[ianti]->mass()); assert(wave3_[ia].particle()->id()==interS.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,interS,wavebar3_[ifm],vector3_[iv]); if(!couplingSet) { gs = abs(outgoingVertexA->norm()); couplingSet = true; } for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha_(S,EM) output*=(4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif //return output return output; } void VFFDecayer::identifyVertices(const int iferm, const int ianti, const Particle & inpart, const ParticleVector & decay, AbstractFFVVertexPtr & outgoingVertexF, AbstractFFVVertexPtr & outgoingVertexA, ShowerInteraction inter){ // QCD vertices if(inter==ShowerInteraction::QCD) { // work out which fermion each outgoing vertex corresponds to // two outgoing vertices if( inpart.dataPtr() ->iColour()==PDT::Colour0 && ((decay[iferm]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar) || (decay[iferm]->dataPtr()->iColour()==PDT::Colour8 && decay[ianti]->dataPtr()->iColour()==PDT::Colour8))){ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){ outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))){ outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))){ outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } else if(inpart.dataPtr() ->iColour()==PDT::Colour8 && decay[iferm]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){ outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))){ outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))){ outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } // one outgoing vertex else if(inpart.dataPtr()->iColour()==PDT::Colour3){ if(decay[iferm]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertexF = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertexF = outgoingVertex2_[inter]; } else if (decay[iferm]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour8){ if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[ianti]->dataPtr()))){ outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } else { outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } } } else if(inpart.dataPtr()->iColour()==PDT::Colour3bar){ if(decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar && decay[iferm]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertexA = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertexA = outgoingVertex2_[inter]; } else if (decay[iferm]->dataPtr()->iColour()==PDT::Colour8 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){ if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))){ outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else { outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } } else if(inpart.dataPtr()->iColour()==PDT::Colour6 || inpart.dataPtr()->iColour()==PDT::Colour6bar) { if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))) { outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else { outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } if (! ((incomingVertex_[inter] && (outgoingVertexF || outgoingVertexA)) || ( outgoingVertexF && outgoingVertexA))) throw Exception() << "Invalid vertices for QCD radiation in VFF decay in VFFDecayer::identifyVertices" << Exception::runerror; } // QED else { if(decay[iferm]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))) outgoingVertexF = outgoingVertex1_[inter]; else outgoingVertexF = outgoingVertex2_[inter]; } if(decay[ianti]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[ianti]->dataPtr()))) outgoingVertexA = outgoingVertex1_[inter]; else outgoingVertexA = outgoingVertex2_[inter]; } } } diff --git a/Decay/General/VSSDecayer.cc b/Decay/General/VSSDecayer.cc --- a/Decay/General/VSSDecayer.cc +++ b/Decay/General/VSSDecayer.cc @@ -1,416 +1,418 @@ // -*- C++ -*- // // VSSDecayer.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 VSSDecayer class. // #include "VSSDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "Herwig/Utilities/Kinematics.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr VSSDecayer::clone() const { return new_ptr(*this); } IBPtr VSSDecayer::fullclone() const { return new_ptr(*this); } void VSSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map & inV, const vector > & outV, map ) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_.push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { incomingVertex_[inter] = dynamic_ptr_cast(inV.at(inter)); outgoingVertex1_[inter] = dynamic_ptr_cast(outV[0].at(inter)); outgoingVertex2_[inter] = dynamic_ptr_cast(outV[1].at(inter)); } } void VSSDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_ << incomingVertex_ << outgoingVertex1_ << outgoingVertex2_; } void VSSDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_ >> incomingVertex_ >> outgoingVertex1_ >> outgoingVertex2_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigVSSDecayer("Herwig::VSSDecayer", "Herwig.so"); void VSSDecayer::Init() { static ClassDocumentation documentation ("This implements the decay of a vector to 2 scalars"); } double VSSDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin0,PDT::Spin0))); if(meopt==Initialize) { VectorWaveFunction::calculateWaveFunctions(vectors_,rho_, const_ptr_cast(&inpart), incoming,false); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { VectorWaveFunction::constructSpinInfo(vectors_,const_ptr_cast(&inpart), incoming,true,false); for(unsigned int ix=0;ix<2;++ix) ScalarWaveFunction:: constructSpinInfo(decay[ix],outgoing,true); return 0.; } ScalarWaveFunction sca1(decay[0]->momentum(),decay[0]->dataPtr(),outgoing); ScalarWaveFunction sca2(decay[1]->momentum(),decay[1]->dataPtr(),outgoing); Energy2 scale(sqr(inpart.mass())); for(unsigned int ix=0;ix<3;++ix) { (*ME())(ix,0,0) = 0.; for(auto vert : vertex_) (*ME())(ix,0,0) += vert->evaluate(scale,vectors_[ix],sca1,sca2); } double output=(ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy VSSDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; perturbativeVertex_[0]->setCoupling(sqr(inpart.second), in, outa.first, outb.first); double mu1sq = sqr(outa.second/inpart.second); double mu2sq = sqr(outb.second/inpart.second); double me2 = sqr(mu1sq - mu2sq) - 2.*(mu1sq + mu2sq); Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second, outb.second); Energy output = -norm(perturbativeVertex_[0]->norm())*me2*pcm / (24.*Constants::pi); // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } double VSSDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { // work out which is the scalar and anti-scalar int ianti(0), iscal(1), iglu(2); int itype[2]; for(unsigned int ix=0;ix<2;++ix) { if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1; else itype[ix] = 2; } if(itype[0]==0 && itype[1]!=0) swap(ianti, iscal); if(itype[0]==2 && itype[1]==1) swap(ianti, iscal); if(itype[0]==0 && itype[1]==0 && abs(decay[0]->dataPtr()->id())>abs(decay[1]->dataPtr()->id())) swap(iscal, ianti); if(itype[0]==1 && itype[1]==1 && abs(decay[0]->dataPtr()->id())dataPtr()->id())) swap(iscal, ianti); if(meopt==Initialize) { // create vector wavefunction for decaying particle VectorWaveFunction::calculateWaveFunctions(vector3_, rho3_, const_ptr_cast(&inpart), incoming, false); } // setup spin information when needed if(meopt==Terminate) { VectorWaveFunction:: constructSpinInfo(vector3_ ,const_ptr_cast(&inpart),outgoing,true,false); ScalarWaveFunction::constructSpinInfo( decay[iscal],outgoing,true); ScalarWaveFunction::constructSpinInfo( decay[ianti],outgoing,true); VectorWaveFunction::constructSpinInfo(gluon_,decay[iglu ],outgoing,true,false); return 0.; } // calculate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin1, PDT::Spin0, PDT::Spin0, PDT::Spin1))); // create wavefunctions ScalarWaveFunction scal(decay[iscal]->momentum(), decay[iscal]->dataPtr(),outgoing); ScalarWaveFunction anti(decay[ianti]->momentum(), decay[ianti]->dataPtr(),outgoing); VectorWaveFunction::calculateWaveFunctions(gluon_,decay[iglu ],outgoing,true); // gauge test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(), decay[iglu ]->dataPtr(),10, outgoing)); } } #endif // identify scalar and/or anti-scalar vertex AbstractVSSVertexPtr outgoingVertexS; AbstractVSSVertexPtr outgoingVertexA; identifyVertices(iscal, ianti, inpart, decay, outgoingVertexS, outgoingVertexA,inter); Energy2 scale(sqr(inpart.mass())); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int iv = 0; iv < 3; ++iv) { for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from the incoming vector if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(incomingVertex_[inter]); VectorWaveFunction vectorInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),vector3_[iv], gluon_[2*ig],inpart.mass()); assert(vector3_[iv].particle()->id()==vectorInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vectorInter,scal,anti); if(!couplingSet) { gs = abs(incomingVertex_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[iscal]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexS); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[iscal]->dataPtr(); if(off->CC()) off = off->CC(); ScalarWaveFunction scalarInter = outgoingVertexS->evaluate(scale,3,off,gluon_[2*ig],scal,decay[iscal]->mass()); assert(scal.particle()->id()==scalarInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vector3_[iv],anti,scalarInter); if(!couplingSet) { gs = abs(outgoingVertexS->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[ianti]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexA); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[ianti]->dataPtr(); if(off->CC()) off = off->CC(); ScalarWaveFunction scalarInter = outgoingVertexA->evaluate(scale,3,off, gluon_[2*ig],anti,decay[ianti]->mass()); assert(anti.particle()->id()==scalarInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vector3_[iv],scal,scalarInter); if(!couplingSet) { gs = abs(outgoingVertexA->norm()); couplingSet = true; } for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha_(S,EM) output*=(4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif // return the answer return output; } void VSSDecayer::identifyVertices(const int iscal, const int ianti, const Particle & inpart, const ParticleVector & decay, AbstractVSSVertexPtr & outgoingVertexS, AbstractVSSVertexPtr & outgoingVertexA, ShowerInteraction inter){ if(inter==ShowerInteraction::QCD) { // work out which scalar each outgoing vertex corresponds to // two outgoing vertices if( inpart.dataPtr() ->iColour()==PDT::Colour0 && ((decay[iscal]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar) || (decay[iscal]->dataPtr()->iColour()==PDT::Colour8 && decay[ianti]->dataPtr()->iColour()==PDT::Colour8))){ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){ outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){ outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){ outgoingVertexS = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } else if(inpart.dataPtr() ->iColour()==PDT::Colour8 && decay[iscal]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){ outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){ outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){ outgoingVertexS = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } // one outgoing vertex else if(inpart.dataPtr()->iColour()==PDT::Colour3){ if(decay[iscal]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertexS = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertexS = outgoingVertex2_[inter]; } else if (decay[iscal]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour8){ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[ianti]->dataPtr()->id()))){ outgoingVertexS = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } else { outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } } } else if(inpart.dataPtr()->iColour()==PDT::Colour3bar){ if(decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar && decay[iscal]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertexA = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertexA = outgoingVertex2_[inter]; } else if (decay[iscal]->dataPtr()->iColour()==PDT::Colour8 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->dataPtr()->id()))){ outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else { outgoingVertexS = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } } if (! ((incomingVertex_[inter] && (outgoingVertexS || outgoingVertexA)) || ( outgoingVertexS && outgoingVertexA))) throw Exception() << "Invalid vertices for QCD radiation in VSS decay in VSSDecayer::identifyVertices" << Exception::runerror; } else { if(decay[iscal]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iscal]->dataPtr()))) outgoingVertexS = outgoingVertex1_[inter]; else outgoingVertexS = outgoingVertex2_[inter]; } if(decay[ianti]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[ianti]->dataPtr()))) outgoingVertexA = outgoingVertex1_[inter]; else outgoingVertexA = outgoingVertex2_[inter]; } } } diff --git a/Decay/General/VVSDecayer.cc b/Decay/General/VVSDecayer.cc --- a/Decay/General/VVSDecayer.cc +++ b/Decay/General/VVSDecayer.cc @@ -1,313 +1,315 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the VVSDecayer class. // #include "VVSDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr VVSDecayer::clone() const { return new_ptr(*this); } IBPtr VVSDecayer::fullclone() const { return new_ptr(*this); } void VVSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map & inV, const vector > & outV, map) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_.push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { incomingVertex_[inter] = dynamic_ptr_cast(inV.at(inter)); outgoingVertexS_[inter] = AbstractVSSVertexPtr(); outgoingVertexV_[inter] = AbstractVVVVertexPtr(); if(outV[0].at(inter)) { if (outV[0].at(inter)->getName()==VertexType::VSS) outgoingVertexS_[inter] = dynamic_ptr_cast(outV[0].at(inter)); else outgoingVertexV_[inter] = dynamic_ptr_cast(outV[0].at(inter)); } if(outV[1].at(inter)) { if (outV[1].at(inter)->getName()==VertexType::VSS) outgoingVertexS_[inter] = dynamic_ptr_cast(outV[1].at(inter)); else outgoingVertexV_[inter] = dynamic_ptr_cast(outV[1].at(inter)); } } } void VVSDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_ << incomingVertex_ << outgoingVertexS_ << outgoingVertexV_; } void VVSDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_ >> incomingVertex_ >> outgoingVertexS_ >> outgoingVertexV_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigVVSDecayer("Herwig::VVSDecayer", "Herwig.so"); void VVSDecayer::Init() { static ClassDocumentation documentation ("The VVSDecayer class implements the decay of a vector" " to a vector and a scalar"); } double VVSDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { bool massless = ( decay[0]->id()==ParticleID::gamma || decay[0]->id()==ParticleID::g ); if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1,PDT::Spin0))); if(meopt==Initialize) { VectorWaveFunction::calculateWaveFunctions(vectors_[0],rho_, const_ptr_cast(&inpart), incoming,false); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { VectorWaveFunction::constructSpinInfo(vectors_[0],const_ptr_cast(&inpart), incoming,true,false); VectorWaveFunction:: constructSpinInfo(vectors_[1],decay[0],outgoing,true,massless); ScalarWaveFunction:: constructSpinInfo(decay[1],outgoing,true); return 0.; } VectorWaveFunction:: calculateWaveFunctions(vectors_[1],decay[0],outgoing,massless); ScalarWaveFunction sca(decay[1]->momentum(),decay[1]->dataPtr(),outgoing); Energy2 scale(sqr(inpart.mass())); for(unsigned int in=0;in<3;++in) { for(unsigned int out=0;out<3;++out) { if(massless&&out==1) ++out; (*ME())(in,out,0) = 0.; for(auto vert : vertex_) (*ME())(in,out,0) += vert->evaluate(scale,vectors_[0][in],vectors_[1][out],sca); } } double output=(ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy VVSDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { Energy2 scale(sqr(inpart.second)); double mu1sq = sqr(outa.second/inpart.second); double mu2sq = sqr(outb.second/inpart.second); tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; if( outb.first->iSpin() == PDT::Spin0 ) perturbativeVertex_[0]->setCoupling(sqr(inpart.second), in, outa.first, outb.first); else { perturbativeVertex_[0]->setCoupling(sqr(inpart.second), in, outb.first, outa.first); swap(mu1sq, mu2sq); } double vn = norm(perturbativeVertex_[0]->norm()); if(vn == ZERO || mu1sq == ZERO) return ZERO; double me2 = 2. + 0.25*sqr(1. + mu1sq - mu2sq)/mu1sq; Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second, outb.second); Energy output = vn*me2*pcm/(24.*Constants::pi)/scale*UnitRemoval::E2; // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } double VVSDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { unsigned int ivec(0),isca(1); if(decay[ivec]->dataPtr()->iSpin()!=PDT::Spin1) swap(ivec,isca); if(meopt==Initialize) { // create vector wavefunction for decaying particle VectorWaveFunction::calculateWaveFunctions(vectors3_[0], rho3_, const_ptr_cast(&inpart), incoming, false); } if(meopt==Terminate) { VectorWaveFunction:: constructSpinInfo(vectors3_[0] ,const_ptr_cast(&inpart),outgoing,true,false); VectorWaveFunction:: constructSpinInfo(vectors3_[1],decay[ivec],outgoing,true,false); ScalarWaveFunction:: constructSpinInfo(decay[isca],outgoing,true); VectorWaveFunction:: constructSpinInfo(gluon_ ,decay[2],outgoing,true,false); return 0.; } // calculate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin1, PDT::Spin1, PDT::Spin0, PDT::Spin1))); bool massless= decay[ivec]->mass()!=ZERO; // create wavefunctions VectorWaveFunction::calculateWaveFunctions(vectors3_[1],decay[0],outgoing,massless); ScalarWaveFunction scal(decay[isca]->momentum(), decay[isca]->dataPtr(),outgoing); VectorWaveFunction::calculateWaveFunctions(gluon_ ,decay[2],outgoing,true); // gauge test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[2]->momentum(), decay[2]->dataPtr(),10, outgoing)); } } #endif Energy2 scale(sqr(inpart.mass())); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int iv0 = 0; iv0 < 3; ++iv0) { for(unsigned int iv1 = 0; iv1 < 3; ++iv1) { if(massless && iv1==1) continue; for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from the incoming vector if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(incomingVertex_[inter]); VectorWaveFunction vectorInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),vectors3_[0][iv0], gluon_[2*ig],inpart.mass()); assert(vectors3_[0][iv0].particle()->id()==vectorInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vectorInter,vectors3_[1][iv1],scal); if(!couplingSet) { gs = abs(incomingVertex_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[ivec]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexV_[inter]); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[ivec]->dataPtr(); if(off->CC()) off = off->CC(); VectorWaveFunction vectorInter = outgoingVertexV_[inter]->evaluate(scale,3,off,gluon_[2*ig],vectors3_[1][iv1],decay[ivec]->mass()); assert(vectors3_[1][iv1].particle()->id()==vectorInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vectors3_[0][iv0],vectorInter,scal); if(!couplingSet) { gs = abs(outgoingVertexV_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[isca]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexS_[inter]); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[isca]->dataPtr(); if(off->CC()) off = off->CC(); ScalarWaveFunction scalarInter = outgoingVertexS_[inter]->evaluate(scale,3,off,gluon_[2*ig],scal,decay[isca]->mass()); assert(scal.particle()->id()==scalarInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vectors3_[0][iv0],vectors3_[1][iv1],scalarInter); if(!couplingSet) { gs = abs(outgoingVertexS_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha_(S,EM) output*=(4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif // return the answer return output; } diff --git a/Decay/General/VVVDecayer.cc b/Decay/General/VVVDecayer.cc --- a/Decay/General/VVVDecayer.cc +++ b/Decay/General/VVVDecayer.cc @@ -1,441 +1,443 @@ // -*- C++ -*- // // VVVDecayer.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 VVVDecayer class. // #include "VVVDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr VVVDecayer::clone() const { return new_ptr(*this); } IBPtr VVVDecayer::fullclone() const { return new_ptr(*this); } void VVVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map & inV, const vector > & outV, map fourV) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_ .push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { incomingVertex_[inter] = dynamic_ptr_cast(inV.at(inter)); outgoingVertex1_[inter] = dynamic_ptr_cast(outV[0].at(inter)); outgoingVertex2_[inter] = dynamic_ptr_cast(outV[1].at(inter)); fourPointVertex_[inter] = dynamic_ptr_cast(fourV.at(inter)); } } void VVVDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_ << incomingVertex_ << outgoingVertex1_ << outgoingVertex2_ << fourPointVertex_; } void VVVDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_ >> incomingVertex_ >> outgoingVertex1_ >> outgoingVertex2_ >> fourPointVertex_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigVVVDecayer("Herwig::VVVDecayer", "Herwig.so"); void VVVDecayer::Init() { static ClassDocumentation documentation ("The VVVDecayer class implements the decay of a vector boson " "into 2 vector bosons"); } double VVVDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1,PDT::Spin1))); bool massless[2]; for(unsigned int ix=0;ix<2;++ix) massless[ix] = (decay[ix]->id()==ParticleID::gamma || decay[ix]->id()==ParticleID::g); if(meopt==Initialize) { VectorWaveFunction::calculateWaveFunctions(vectors_[0],rho_, const_ptr_cast(&inpart), incoming,false); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { VectorWaveFunction::constructSpinInfo(vectors_[0],const_ptr_cast(&inpart), incoming,true,false); for(unsigned int ix=0;ix<2;++ix) VectorWaveFunction:: constructSpinInfo(vectors_[ix+1],decay[ix],outgoing,true,massless[ix]); return 0.; } for(unsigned int ix=0;ix<2;++ix) VectorWaveFunction:: calculateWaveFunctions(vectors_[ix+1],decay[ix],outgoing,massless[ix]); Energy2 scale(sqr(inpart.mass())); for(unsigned int iv3=0;iv3<3;++iv3) { for(unsigned int iv2=0;iv2<3;++iv2) { for(unsigned int iv1=0;iv1<3;++iv1) { (*ME())(iv1,iv2,iv3) = 0.; for(auto vert : vertex_) { (*ME())(iv1,iv2,iv3) += vert-> evaluate(scale,vectors_[1][iv2],vectors_[2][iv3],vectors_[0][iv1]); } } } } double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy VVVDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; perturbativeVertex_[0]->setCoupling(sqr(inpart.second), in, outa.first, outb.first); double mu1(outa.second/inpart.second), mu1sq(sqr(mu1)), mu2(outb.second/inpart.second), mu2sq(sqr(mu2)); double vn = norm(perturbativeVertex_[0]->norm()); if(vn == ZERO || mu1sq == ZERO || mu2sq == ZERO) return ZERO; double me2 = (mu1 - mu2 - 1.)*(mu1 - mu2 + 1.)*(mu1 + mu2 - 1.)*(mu1 + mu2 + 1.) * (sqr(mu1sq) + sqr(mu2sq) + 10.*(mu1sq*mu2sq + mu1sq + mu2sq) + 1.) /4./mu1sq/mu2sq; Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second, outb.second); Energy pWidth = vn*me2*pcm/24./Constants::pi; // colour factor pWidth *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return pWidth; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } double VVVDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { if(meopt==Initialize) { // create vector wavefunction for decaying particle VectorWaveFunction::calculateWaveFunctions(vector3_, rho3_, const_ptr_cast(&inpart), incoming, false); } if(meopt==Terminate) { VectorWaveFunction:: constructSpinInfo(vector3_ ,const_ptr_cast(&inpart),outgoing,true,false); VectorWaveFunction:: constructSpinInfo(vectors3_[0],decay[0],outgoing,true,false); VectorWaveFunction:: constructSpinInfo(vectors3_[1],decay[1],outgoing,true,false); VectorWaveFunction:: constructSpinInfo(gluon_ ,decay[2],outgoing,true,false); return 0.; } // calculate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin1, PDT::Spin1, PDT::Spin1, PDT::Spin1))); bool massless[2]; for(unsigned int ix=0;ix<2;++ix) massless[ix] = decay[ix]->mass()!=ZERO; // create wavefunctions VectorWaveFunction::calculateWaveFunctions(vectors3_[0],decay[0],outgoing,massless[0]); VectorWaveFunction::calculateWaveFunctions(vectors3_[1],decay[1],outgoing,massless[1]); VectorWaveFunction::calculateWaveFunctions(gluon_ ,decay[2],outgoing,true); // gauge test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[2]->momentum(), decay[2]->dataPtr(),10, outgoing)); } } #endif // get the outgoing vertices AbstractVVVVertexPtr outgoingVertex1; AbstractVVVVertexPtr outgoingVertex2; identifyVertices(inpart,decay, outgoingVertex1, outgoingVertex2,inter); Energy2 scale(sqr(inpart.mass())); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int iv0 = 0; iv0 < 3; ++iv0) { for(unsigned int iv1 = 0; iv1 < 3; ++iv1) { if(massless[0] && iv1==1) continue; for(unsigned int iv2 = 0; iv2 < 3; ++iv2) { if(massless[1] && iv2==1) continue; for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from the incoming vector if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(incomingVertex_[inter]); VectorWaveFunction vectorInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),vector3_[iv0], gluon_[2*ig],inpart.mass()); assert(vector3_[iv0].particle()->id()==vectorInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vectorInter,vectors3_[0][iv1], vectors3_[1][iv2]); if(!couplingSet) { gs = abs(incomingVertex_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[0]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertex1); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[0]->dataPtr(); if(off->CC()) off = off->CC(); VectorWaveFunction vectorInter = outgoingVertex1->evaluate(scale,3,off,gluon_[2*ig],vectors3_[0][iv1],decay[0]->mass()); assert(vectors3_[0][iv1].particle()->id()==vectorInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vector3_[iv0],vectorInter,vectors3_[1][iv2]); if(!couplingSet) { gs = abs(outgoingVertex1->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[1]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertex2); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[1]->dataPtr(); if(off->CC()) off = off->CC(); VectorWaveFunction vectorInter = outgoingVertex2->evaluate(scale,3,off, gluon_[2*ig],vectors3_[1][iv2],decay[1]->mass()); assert(vectors3_[1][iv2].particle()->id()==vectorInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vector3_[iv0],vectors3_[0][iv1],vectorInter); if(!couplingSet) { gs = abs(outgoingVertex2->norm()); couplingSet = true; } for(unsigned int ix=0;ixevaluate(scale,0, vector3_[iv0], vectors3_[0][iv1], vectors3_[1][iv2],gluon_[2*ig]); for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha_(S,EM) output*=(4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif // return the answer return output; } void VVVDecayer::identifyVertices(const Particle & inpart, const ParticleVector & decay, AbstractVVVVertexPtr & outgoingVertex1, AbstractVVVVertexPtr & outgoingVertex2, ShowerInteraction inter) { if(inter==ShowerInteraction::QCD) { // work out which scalar each outgoing vertex corresponds to // two outgoing vertices if( inpart.dataPtr() ->iColour()==PDT::Colour0 && ((decay[0]->dataPtr()->iColour()==PDT::Colour3 && decay[1]->dataPtr()->iColour()==PDT::Colour3bar) || (decay[0]->dataPtr()->iColour()==PDT::Colour8 && decay[1]->dataPtr()->iColour()==PDT::Colour8))){ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){ outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[0]->id()))){ outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[0]->id()))){ outgoingVertex1 = outgoingVertex2_[inter]; outgoingVertex2 = outgoingVertex1_[inter]; } } else if(inpart.dataPtr() ->iColour()==PDT::Colour8 && decay[0]->dataPtr()->iColour()==PDT::Colour3 && decay[1]->dataPtr()->iColour()==PDT::Colour3bar){ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){ outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[0]->id()))){ outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[0]->id()))){ outgoingVertex1 = outgoingVertex2_[inter]; outgoingVertex2 = outgoingVertex1_[inter]; } } // one outgoing vertex else if(inpart.dataPtr()->iColour()==PDT::Colour3){ if(decay[0]->dataPtr()->iColour()==PDT::Colour3 && decay[1]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertex1 = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertex1 = outgoingVertex2_[inter]; } else if (decay[0]->dataPtr()->iColour()==PDT::Colour3 && decay[1]->dataPtr()->iColour()==PDT::Colour8){ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[1]->dataPtr()->id()))){ outgoingVertex1 = outgoingVertex2_[inter]; outgoingVertex2 = outgoingVertex1_[inter]; } else { outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } } } else if(inpart.dataPtr()->iColour()==PDT::Colour3bar){ if(decay[1]->dataPtr()->iColour()==PDT::Colour3bar && decay[0]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertex2 = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertex2 = outgoingVertex2_[inter]; } else if (decay[0]->dataPtr()->iColour()==PDT::Colour8 && decay[1]->dataPtr()->iColour()==PDT::Colour3bar){ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[0]->dataPtr()->id()))){ outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } else { outgoingVertex1 = outgoingVertex2_[inter]; outgoingVertex2 = outgoingVertex1_[inter]; } } } if (! ((incomingVertex_[inter] && (outgoingVertex1 || outgoingVertex2)) || ( outgoingVertex1 && outgoingVertex2))) throw Exception() << "Invalid vertices for QCD radiation in VVV decay in VVVDecayer::identifyVertices" << Exception::runerror; } else { if(decay[0]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[0]->dataPtr()))) outgoingVertex1 = outgoingVertex1_[inter]; else outgoingVertex1 = outgoingVertex2_[inter]; } if(decay[1]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[1]->dataPtr()))) outgoingVertex2 = outgoingVertex1_[inter]; else outgoingVertex2 = outgoingVertex2_[inter]; } } } diff --git a/Decay/General/VtoFFVDecayer.cc b/Decay/General/VtoFFVDecayer.cc --- a/Decay/General/VtoFFVDecayer.cc +++ b/Decay/General/VtoFFVDecayer.cc @@ -1,369 +1,371 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the VtoFFVDecayer class. // #include "VtoFFVDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/PDT/ThreeBodyAllOnCalculator.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include using namespace Herwig; using namespace ThePEG; using namespace ThePEG::Helicity; IBPtr VtoFFVDecayer::clone() const { return new_ptr(*this); } IBPtr VtoFFVDecayer::fullclone() const { return new_ptr(*this); } void VtoFFVDecayer::persistentOutput(PersistentOStream & os) const { os << sca_ << fer_ << vec_ << ten_; } void VtoFFVDecayer::persistentInput(PersistentIStream & is, int) { is >> sca_ >> fer_ >> vec_ >> ten_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigVtoFFVDecayer("Herwig::VtoFFVDecayer", "Herwig.so"); void VtoFFVDecayer::Init() { static ClassDocumentation documentation ("The VtoFFVDecayer class implements the general three-body " "decay of a vector to a two fermions and a vector."); } WidthCalculatorBasePtr VtoFFVDecayer:: threeBodyMEIntegrator(const DecayMode & ) const { vector intype; vector inmass,inwidth; vector inpow,inweights; constructIntegratorChannels(intype,inmass,inwidth,inpow,inweights); return new_ptr(ThreeBodyAllOnCalculator (inweights,intype,inmass,inwidth,inpow,*this,0, outgoing()[0]->mass(),outgoing()[1]->mass(), outgoing()[2]->mass(),relativeError())); } void VtoFFVDecayer::doinit() { GeneralThreeBodyDecayer::doinit(); if(outgoing().empty()) return; unsigned int ndiags = getProcessInfo().size(); sca_.resize(ndiags); fer_.resize(ndiags); vec_.resize(ndiags); ten_.resize(ndiags); for(unsigned int ix = 0;ix < ndiags; ++ix) { TBDiagram current = getProcessInfo()[ix]; tcPDPtr offshell = current.intermediate; if( offshell->CC() ) offshell = offshell->CC(); if(offshell->iSpin() == PDT::Spin0) { AbstractVVSVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFSVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() << "Invalid vertices for a scalar diagram in VtoFFVDecayer::doinit()" << Exception::runerror; sca_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin1Half) { AbstractFFVVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFVVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() << "Invalid vertices for a fermion diagram in VtoFFVDecayer::doinit()" << Exception::runerror; fer_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin1) { AbstractVVVVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFVVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() << "Invalid vertices for a vector diagram in VtoFFVDecayer::doinit()" << Exception::runerror; vec_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin2) { AbstractVVTVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFTVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() << "Invalid vertices for a tensor diagram in VtoFFVDecayer::doinit()" << Exception::runerror; ten_[ix] = make_pair(vert1, vert2); } } } double VtoFFVDecayer::me2(const int ichan, const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { // particle or CC of particle bool cc = (*getProcessInfo().begin()).incoming != inpart.id(); // special handling or first/last call if(meopt==Initialize) { VectorWaveFunction:: calculateWaveFunctions(inVector_,rho_,const_ptr_cast(&inpart), Helicity::incoming,false); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { VectorWaveFunction:: constructSpinInfo(inVector_,const_ptr_cast(&inpart), Helicity::incoming,true,false); for(unsigned int ix=0;ixdataPtr()->iSpin()==PDT::Spin1) { VectorWaveFunction::constructSpinInfo(outVector_,decay[ix], Helicity::outgoing,true,false); } else { SpinorWaveFunction:: constructSpinInfo(outspin_[ix].first,decay[ix],Helicity::outgoing,true); } } } unsigned int ivec(0); bool massless = false; for(unsigned int ix = 0; ix < decay.size();++ix) { if(decay[ix]->dataPtr()->iSpin() == PDT::Spin1) { massless = decay[ix]->id()==ParticleID::g || decay[ix]->id()==ParticleID::gamma; ivec = ix; VectorWaveFunction:: calculateWaveFunctions(outVector_, decay[ix], Helicity::outgoing, massless ); } else { SpinorWaveFunction:: calculateWaveFunctions(outspin_[ix].first,decay[ix],Helicity::outgoing); outspin_[ix].second.resize(2); // Need a ubar and a v spinor if(outspin_[ix].first[0].wave().Type() == SpinorType::u) { for(unsigned int iy = 0; iy < 2; ++iy) { outspin_[ix].second[iy] = outspin_[ix].first[iy].bar(); outspin_[ix].first[iy].conjugate(); } } else { for(unsigned int iy = 0; iy < 2; ++iy) { outspin_[ix].second[iy] = outspin_[ix].first[iy].bar(); outspin_[ix].second[iy].conjugate(); } } } } const vector > cfactors(getColourFactors()); const vector > nfactors(getLargeNcColourFactors()); Energy2 scale(sqr(inpart.mass())); const size_t ncf(numberOfFlows()); vector flows(ncf, Complex(0.)), largeflows(ncf, Complex(0.)); // setup the DecayMatrixElement vector mes(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin1, ivec == 0 ? PDT::Spin1 : PDT::Spin1Half, ivec == 1 ? PDT::Spin1 : PDT::Spin1Half, ivec == 2 ? PDT::Spin1 : PDT::Spin1Half))); vector mel(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin1, ivec == 0 ? PDT::Spin1 : PDT::Spin1Half, ivec == 1 ? PDT::Spin1 : PDT::Spin1Half, ivec == 2 ? PDT::Spin1 : PDT::Spin1Half))); //the channel possiblities static const unsigned int out2[3] = {1,0,0}, out3[3] = {2,2,1}; for(unsigned int vi = 0; vi < 3; ++vi) { for(unsigned int s1 = 0; s1 < 2; ++s1) { for(unsigned int s2 = 0; s2 < 2; ++s2) { for(unsigned int v1 = 0; v1 < 3; ++v1) { if ( massless && v1 == 1 ) continue; flows = vector(ncf, Complex(0.)); largeflows = vector(ncf, Complex(0.)); unsigned int idiag(0); for(vector::const_iterator dit=getProcessInfo().begin(); dit!=getProcessInfo().end();++dit) { // channels if selecting if( ichan >=0 && diagramMap()[ichan] != idiag ) { ++idiag; continue; } tcPDPtr offshell = dit->intermediate; if(cc&&offshell->CC()) offshell=offshell->CC(); Complex diag; unsigned int o2(out2[dit->channelType]), o3(out3[dit->channelType]); double sign = (o3 < o2) ? 1. : -1.; // intermediate scalar if(offshell->iSpin() == PDT::Spin0) { ScalarWaveFunction inters = sca_[idiag].first-> evaluate(scale, widthOption(), offshell, outVector_[v1], inVector_[vi]); unsigned int h1(s1),h2(s2); if(o2 > o3) swap(h1, h2); if(decay[o2]->id() < 0 && decay[o3]->id() > 0) { diag = -sign*sca_[idiag].second-> evaluate(scale,outspin_[o2].first[h1], outspin_[o3].second[h2],inters); } else { diag = sign*sca_[idiag].second-> evaluate(scale, outspin_[o3].first [h2], outspin_[o2].second[h1],inters); } } // intermediate fermion else if(offshell->iSpin() == PDT::Spin1Half) { int iferm = (decay[o2]->dataPtr()->iSpin() == PDT::Spin1Half) ? o2 : o3; unsigned int h1(s1),h2(s2); if(dit->channelType > iferm) swap(h1, h2); sign = iferm < dit->channelType ? 1. : -1.; if(decay[dit->channelType]->id() < 0 && decay[iferm]->id() > 0 ) { SpinorWaveFunction inters = fer_[idiag].first-> evaluate(scale,widthOption(),offshell, outspin_[dit->channelType].first[h1], inVector_[vi]); diag = -sign*fer_[idiag].second-> evaluate(scale,inters,outspin_[iferm].second[h2], outVector_[v1]); } else { SpinorBarWaveFunction inters = fer_[idiag].first-> evaluate(scale,widthOption(),offshell, outspin_[dit->channelType].second[h1],inVector_[vi]); diag = sign*fer_[idiag].second-> evaluate(scale,outspin_[iferm].first [h2],inters, outVector_[v1]); } } // intermediate vector else if(offshell->iSpin() == PDT::Spin1) { VectorWaveFunction interv = vec_[idiag].first-> evaluate(scale, widthOption(), offshell, outVector_[v1], inVector_[vi]); unsigned int h1(s1),h2(s2); if(o2 > o3) swap(h1,h2); if(decay[o2]->id() < 0 && decay[o3]->id() > 0) { diag =-sign*vec_[idiag].second-> evaluate(scale, outspin_[o2].first[h1], outspin_[o3].second[h2], interv); } else { diag = sign*vec_[idiag].second-> evaluate(scale, outspin_[o3].first[h2], outspin_[o2].second[h1], interv); } } else if(offshell->iSpin() == PDT::Spin2) { TensorWaveFunction intert = ten_[idiag].first-> evaluate(scale, widthOption(), offshell, inVector_[vi], outVector_[v1]); unsigned int h1(s1),h2(s2); if(out2[dit->channelType]>out3[dit->channelType]) swap(h1,h2); if(decay[out2[dit->channelType]]->id()<0&& decay[out3[dit->channelType]]->id()>0) { diag =-sign*ten_[idiag].second-> evaluate(scale, outspin_[out2[dit->channelType]].first [h1], outspin_[out3[dit->channelType]].second[h2],intert); } else { diag = sign*ten_[idiag].second-> evaluate(scale, outspin_[out3[dit->channelType]].first [h2], outspin_[out2[dit->channelType]].second[h1],intert); } } // unknown else throw Exception() << "Unknown intermediate in VtoFFVDecayer::me2()" << Exception::runerror; // matrix element for the different colour flows if(ichan < 0) { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } else { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1 != colourFlow()) continue; flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1!=colourFlow()) continue; largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } ++idiag; } //end of diagrams // now add the flows to the me2 with appropriate colour factors for(unsigned int ix = 0; ix < ncf; ++ix) { if (ivec == 0) { (*mes[ix])(vi, v1, s1, s2) = flows[ix]; (*mel[ix])(vi, v1, s1, s2) = largeflows[ix]; } else if(ivec == 1) { (*mes[ix])(vi, s1, v1, s2) = flows[ix]; (*mel[ix])(vi, s1, v1, s2) = largeflows[ix]; } else if(ivec == 2) { (*mes[ix])(vi, s1, s2, v1) = flows[ix]; (*mel[ix])(vi, s1, s2, v1) = largeflows[ix]; } } } } } } double me2(0.); if(ichan < 0) { vector pflows(ncf,0.); for(unsigned int ix = 0; ix < ncf; ++ix) { for(unsigned int iy = 0; iy < ncf; ++ iy) { double con = cfactors[ix][iy]*(mes[ix]->contract(*mes[iy],rho_)).real(); me2 += con; if(ix == iy) { con = nfactors[ix][iy]*(mel[ix]->contract(*mel[iy],rho_)).real(); pflows[ix] += con; } } } double ptotal(std::accumulate(pflows.begin(),pflows.end(),0.)); ptotal *= UseRandom::rnd(); for(unsigned int ix = 0;ix < pflows.size(); ++ix) { if(ptotal <= pflows[ix]) { colourFlow(ix); ME(mes[ix]); break; } ptotal -= pflows[ix]; } } else { unsigned int iflow = colourFlow(); me2 = nfactors[iflow][iflow]*(mel[iflow]->contract(*mel[iflow],rho_)).real(); } // return the matrix element squared return me2; } diff --git a/Decay/HwDecayerBase.cc b/Decay/HwDecayerBase.cc --- a/Decay/HwDecayerBase.cc +++ b/Decay/HwDecayerBase.cc @@ -1,156 +1,163 @@ // -*- C++ -*- // // HwDecayerBase.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 HwDecayerBase class. // #include "HwDecayerBase.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Repository/CurrentGenerator.h" #include "Herwig/Shower/RealEmissionProcess.h" +#include "Herwig/Shower/ShowerHandler.h" using namespace Herwig; bool HwDecayerBase::accept(const DecayMode & dm) const { // get the primary products tPDVector products=dm.orderedProducts(); // add products for which the decay mode is all ready specified if(!dm.cascadeProducts().empty()) { for(ModeMSet::const_iterator mit=dm.cascadeProducts().begin(); mit!=dm.cascadeProducts().end();++mit) { products.push_back(const_ptr_cast((**mit).parent())); } } // can this mode be handled ? return accept(dm.parent(),products); } ParticleVector HwDecayerBase::decay(const DecayMode & dm, const Particle & p) const { // handling of the decay including the special features of the // DecayMode // get the primary products tPDVector products=dm.orderedProducts(); // add products for which the decay mode is all ready specified if(!dm.cascadeProducts().empty()) { for(ModeMSet::const_iterator mit=dm.cascadeProducts().begin(); mit!=dm.cascadeProducts().end();++mit) { products.push_back(const_ptr_cast((**mit).parent())); } } // perform the primary decay ParticleVector output=decay(p,products); // perform the secondary decays if(!dm.cascadeProducts().empty()) { unsigned int iloc=dm.orderedProducts().size(); for(ModeMSet::const_iterator mit=dm.cascadeProducts().begin(); mit!=dm.cascadeProducts().end();++mit) { if(!(*mit)->decayer()) throw Exception() << "Decay mode " << (**mit).tag() << "does not have a decayer, can't perform" << "decay in HwDecayerBase::decay()" << Exception::eventerror; ParticleVector children=(*mit)->decayer()->decay(**mit,*output[iloc]); for(unsigned int ix=0;ixaddChild(children[ix]); } ++iloc; } } return output; } void HwDecayerBase::persistentOutput(PersistentOStream & os) const { os << _initialize << _dbOutput; } void HwDecayerBase::persistentInput(PersistentIStream & is, int) { is >> _initialize >> _dbOutput; } // The following static variable is needed for the type // description system in ThePEG. DescribeAbstractClass describeHerwigHwDecayerBase("Herwig::HwDecayerBase", "Herwig.so"); void HwDecayerBase::Init() { static ClassDocumentation documentation ("The HwDecayerBase class is the base class for Decayers in Hw++."); static Switch interfaceInitialize ("Initialize", "Initialization of the phase space calculation", &HwDecayerBase::_initialize, false, false, false); static SwitchOption interfaceInitializeon (interfaceInitialize, "Yes", "At initialisation find max weight and optimise the integration", true); static SwitchOption interfaceInitializeoff (interfaceInitialize, "No", "Use the maximum weight and channel weights supplied for the integration", false); static Switch interfaceDatabaseOutput ("DatabaseOutput", "Whether to print the database information", &HwDecayerBase::_dbOutput, false, false, false); static SwitchOption interfaceDatabaseOutputYes (interfaceDatabaseOutput, "Yes", "Output information on the decayer initialization", true); static SwitchOption interfaceDatabaseOutputNo (interfaceDatabaseOutput, "No", "Do not output information about the decayer initialization", false); } void HwDecayerBase::dofinish() { Decayer::dofinish(); if(initialize() && databaseOutput()) { string fname = CurrentGenerator::current().filename() + string("-") + name() + string(".output"); ofstream output(fname.c_str()); dataBaseOutput(output,true); } } bool HwDecayerBase::softMatrixElementVeto(PPtr , PPtr, const bool &, const Energy & , const vector & , const double & , const Energy & , const Energy & ) { return false; } RealEmissionProcessPtr HwDecayerBase::generateHardest(RealEmissionProcessPtr) { return RealEmissionProcessPtr(); } void HwDecayerBase::initializeMECorrection(RealEmissionProcessPtr , double & , double & ) { assert(false); } RealEmissionProcessPtr HwDecayerBase::applyHardMatrixElementCorrection(RealEmissionProcessPtr) { assert(false); return RealEmissionProcessPtr(); } + +void HwDecayerBase::fixRho(RhoDMatrix & rho) const { + if(ShowerHandler::currentHandlerIsSet() && + !ShowerHandler::currentHandler()->spinCorrelations()) + rho.reset(); +} diff --git a/Decay/HwDecayerBase.h b/Decay/HwDecayerBase.h --- a/Decay/HwDecayerBase.h +++ b/Decay/HwDecayerBase.h @@ -1,237 +1,244 @@ // -*- C++ -*- // // HwDecayerBase.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_HwDecayerBase_H #define HERWIG_HwDecayerBase_H // // This is the declaration of the HwDecayerBase class. // #include "ThePEG/PDT/Decayer.h" #include "Herwig/Shower/RealEmissionProcess.fh" #include "HwDecayerBase.fh" namespace Herwig { struct Branching; using namespace ThePEG; /** * The HwDecayerBase class is the base class for Decayers in Herwig. It inherits * from the Decayer class of ThePEG and implements additional functionality for the * output of the results to the particle database and initialization of the datbase. * * It also provide the option of specifying a class based on the DecayRadiationGenerator * which should be used to generate QED radiation in the decay * * @see \ref HwDecayerBaseInterfaces "The interfaces" * defined for HwDecayerBase. */ class HwDecayerBase: public Decayer { public: /** * The default constructor. */ HwDecayerBase() : _initialize(false), _dbOutput(false) {} /** @name Virtual functions required by the Decayer class. */ //@{ /** * Check if this decayer can perfom the decay specified by the * given decay mode. * @param dm the DecayMode describing the decay. * @return true if this decayer can handle the given mode, otherwise false. */ virtual bool accept(const DecayMode & dm) const; /** * Perform a decay for a given DecayMode and a given Particle instance. * @param dm the DecayMode describing the decay. * @param p the Particle instance to be decayed. * @return a ParticleVector containing the decay products. */ virtual ParticleVector decay(const DecayMode & dm, const Particle & p) const; //@} public: /** * Virtual members to be overridden by inheriting classes * which implement hard corrections */ //@{ /** * Type of POWHEG correction */ enum POWHEGType {No, ISR, FSR, Both}; /** * Has a POWHEG style correction */ virtual POWHEGType hasPOWHEGCorrection() {return No;} /** * Has an old fashioned ME correction */ virtual bool hasMECorrection() {return false;} /** * Initialize the ME correction */ virtual void initializeMECorrection(RealEmissionProcessPtr , double & , double & ); /** * Apply the hard matrix element correction to a given hard process or decay */ virtual RealEmissionProcessPtr applyHardMatrixElementCorrection(RealEmissionProcessPtr); /** * Apply the soft matrix element correction * @param parent The initial particle in the current branching * @param progenitor The progenitor particle of the jet * @param fs Whether the emission is initial or final-state * @param highestpT The highest pT so far in the shower * @param ids ids of the particles produced in the branching * @param z The momentum fraction of the branching * @param scale the evolution scale of the branching * @param pT The transverse momentum of the branching * @return If true the emission should be vetoed */ virtual bool softMatrixElementVeto(PPtr parent, PPtr progenitor, const bool & fs, const Energy & highestpT, const vector & ids, const double & z, const Energy & scale, const Energy & pT); /** * Apply the POWHEG style correction */ virtual RealEmissionProcessPtr generateHardest(RealEmissionProcessPtr); //@} protected: /** @name Virtual functions to replaced those from the Decayer class. * This is so that the decay and accept members of this class can handle all * the more complicated features of the DecayMode class */ //@{ /** * Check if this decayer can perfom the decay for a particular mode * @param parent The decaying particle * @param children The decay products * @return true If this decayer can handle the given mode, otherwise false. */ virtual bool accept(tcPDPtr parent, const tPDVector & children) const = 0; /** * Perform the decay of the particle to the specified decay products * @param parent The decaying particle * @param children The decay products * @return a ParticleVector containing the decay products. */ virtual ParticleVector decay(const Particle & parent, const tPDVector & children) const = 0; //@} 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(); public: /** * Functions for the Herwig decayer */ //@{ /** * Output the setup information for the particle database * @param os The stream to output the information to * @param header Whether or not to output the information for MySQL */ virtual void dataBaseOutput(ofstream & os,bool header) const = 0; /** * Access to the initialize variable */ bool initialize() const {return _initialize;} /** * Access the database output variable */ bool databaseOutput() const {return _dbOutput;} //@} protected: + /** + * Set rho to be diagonal if no correlations + */ + void fixRho(RhoDMatrix &) const; + +protected: + /** @name Standard Interfaced functions. */ //@{ /** * Finalize this object. Called in the run phase just after a * run has ended. Used eg. to write out statistics. */ virtual void dofinish(); //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ HwDecayerBase & operator=(const HwDecayerBase &); private: /** * perform initialisation */ bool _initialize; /** * Print out database */ bool _dbOutput; }; } #endif /* HERWIG_HwDecayerBase_H */ diff --git a/Decay/Perturbative/SMHiggsFermionsDecayer.cc b/Decay/Perturbative/SMHiggsFermionsDecayer.cc --- a/Decay/Perturbative/SMHiggsFermionsDecayer.cc +++ b/Decay/Perturbative/SMHiggsFermionsDecayer.cc @@ -1,393 +1,395 @@ // -*- C++ -*- // // SMHiggsFermionsDecayer.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 SMHiggsFermionsDecayer class. // #include "SMHiggsFermionsDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/ParVector.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "Herwig/Decay/DecayVertex.h" #include "ThePEG/Helicity/ScalarSpinInfo.h" #include "ThePEG/Helicity/FermionSpinInfo.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include "Herwig/Utilities/Maths.h" #include "Herwig/Shower/RealEmissionProcess.h" #include "Herwig/Shower/ShowerAlpha.h" using namespace Herwig; using namespace ThePEG::Helicity; SMHiggsFermionsDecayer::SMHiggsFermionsDecayer() : CF_(4./3.), NLO_(false) { _maxwgt.resize(9); _maxwgt[0]=0.; _maxwgt[1]=0; _maxwgt[2]=0; _maxwgt[3]=0.0194397; _maxwgt[4]=0.463542; _maxwgt[5]=0.; _maxwgt[6]=6.7048e-09; _maxwgt[7]=0.00028665; _maxwgt[8]=0.0809643; } void SMHiggsFermionsDecayer::doinit() { PerturbativeDecayer::doinit(); // get the vertices from the Standard Model object tcHwSMPtr hwsm=dynamic_ptr_cast(standardModel()); if(!hwsm) throw InitException() << "SMHiggsFermionsDecayer needs the StandardModel class" << " to be either the Herwig one or a class inheriting" << " from it"; _hvertex = hwsm->vertexFFH(); // make sure they are initialized _hvertex->init(); // get the width generator for the higgs tPDPtr higgs = getParticleData(ParticleID::h0); // set up the decay modes vector wgt(0); unsigned int imode=0; tPDVector extpart(3); DecayPhaseSpaceModePtr mode; int iy; extpart[0]=higgs; for(unsigned int istep=0;istep<11;istep+=10) { for(unsigned ix=1;ix<7;++ix) { if(istep<10||ix%2!=0) { iy = ix+istep; extpart[1]=getParticleData( iy); extpart[2]=getParticleData(-iy); mode = new_ptr(DecayPhaseSpaceMode(extpart,this)); addMode(mode,_maxwgt[imode],wgt); ++imode; } } } // Energy quarkMass = getParticleData(ParticleID::b )->mass(); // Energy higgsMass = getParticleData(ParticleID::h0)->mass(); // double mu = quarkMass/higgsMass; // double beta = sqrt(1.-4.*sqr(mu)); // double beta2 = sqr(beta); // double aS = SM().alphaS(sqr(higgsMass)); // double L = log((1.+beta)/(1.-beta)); // cerr << "testing " << beta << " " << mu << "\n"; // cerr << "testing " << aS << " " << L << "\n"; // double fact = // 6.-0.75*(1.+beta2)/beta2+12.*log(mu)-8.*log(beta) // +(5./beta-2.*beta+0.375*sqr(1.-beta2)/beta2/beta)*L // +(1.+beta2)/beta*(4.*L*log(0.5*(1.+beta)/beta) // -2.*log(0.5*(1.+beta))*log(0.5*(1.-beta)) // +8.*Herwig::Math::ReLi2((1.-beta)/(1.+beta)) // -4.*Herwig::Math::ReLi2(0.5*(1.-beta))); // cerr << "testing correction " // << 1.+4./3.*aS/Constants::twopi*fact // << "\n"; // double real = 4./3.*aS/Constants::twopi* // (8.-0.75*(1.+beta2)/beta2+8.*log(mu)-8.*log(beta) // +(3./beta+0.375*sqr(1.-beta2)/pow(beta,3))*L // +(1.+beta2)/beta*(-0.5*sqr(L)+4.*L*log(0.5*(1.+beta)) // -2.*L*log(beta)-2.*log(0.5*(1.+beta))*log(0.5*(1.-beta)) // +6.*Herwig::Math::ReLi2((1.-beta)/(1.+beta)) // -4.*Herwig::Math::ReLi2(0.5*(1.-beta)) // -2./3.*sqr(Constants::pi))); // double virt = 4./3.*aS/Constants::twopi* // (-2.+4.*log(mu)+(2./beta-2.*beta)*L // +(1.+beta2)/beta*(0.5*sqr(L)-2.*L*log(beta)+2.*sqr(Constants::pi)/3. // +2.*Herwig::Math::ReLi2((1.-beta)/(1.+beta)))); // cerr << "testing real " << real << "\n"; // cerr << "testing virtual " << virt << "\n"; // cerr << "testing total no mb corr " << 1.+real+virt << "\n"; // cerr << "testing total mb corr " << 1.+real+virt +(8./3. - 2.*log(sqr(mu)))*aS/Constants::pi << "\n"; // InvEnergy2 Gf = 1.166371e-5/GeV2; // Gf = sqrt(2.)*4*Constants::pi*SM().alphaEM(sqr(higgsMass))/8./SM().sin2ThetaW()/ // sqr(getParticleData(ParticleID::Wplus)->mass()); // cerr << "testing GF " << Gf*GeV2 << "\n"; // Energy LO = (3./8./Constants::pi)*sqrt(2)*sqr(quarkMass)*Gf*higgsMass*beta*beta*beta; // cerr << "testing LO " << LO/GeV << "\n"; // cerr << "testing quark mass " << quarkMass/GeV << "\n"; // cerr << "testing gamma " << (1.+real+virt)*LO/MeV << "\n"; } bool SMHiggsFermionsDecayer::accept(tcPDPtr parent, const tPDVector & children) const { if(parent->id()!=ParticleID::h0||children.size()!=2) return false; tPDVector::const_iterator pit = children.begin(); int id1=(**pit).id(); ++pit; int id2=(**pit).id(); if(id1==-id2&&(abs(id1)<=6||(abs(id1)>=11&&abs(id1)<=16))) return true; else return false; } ParticleVector SMHiggsFermionsDecayer::decay(const Particle & parent, const tPDVector & children) const { // id's of the decaying particles tPDVector::const_iterator pit(children.begin()); int id1((**pit).id()); int imode=-1; if(abs(id1)<=6) imode = abs(id1)-1; else if(abs(id1)>=11&&abs(id1)<=16) imode = (abs(id1)-11)/2+6; ParticleVector output(generate(false,false,imode,parent)); // set up the colour flow if(output[0]->hasColour()) output[0]->antiColourNeighbour(output[1]); else if(output[1]->hasColour()) output[1]->antiColourNeighbour(output[0]); return output; } void SMHiggsFermionsDecayer::persistentOutput(PersistentOStream & os) const { os << _maxwgt << _hvertex << NLO_; } void SMHiggsFermionsDecayer::persistentInput(PersistentIStream & is, int) { is >> _maxwgt >> _hvertex >> NLO_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSMHiggsFermionsDecayer("Herwig::SMHiggsFermionsDecayer", "HwPerturbativeHiggsDecay.so"); void SMHiggsFermionsDecayer::Init() { static ClassDocumentation documentation ("The SMHiggsFermionsDecayer class implements the decat of the Standard Model" " Higgs boson to the Standard Model fermions"); static ParVector interfaceMaxWeights ("MaxWeights", "Maximum weights for the various decays", &SMHiggsFermionsDecayer::_maxwgt, 9, 1.0, 0.0, 10.0, false, false, Interface::limited); static Switch interfaceNLO ("NLO", "Whether to return the LO or NLO result", &SMHiggsFermionsDecayer::NLO_, false, false, false); static SwitchOption interfaceNLOLO (interfaceNLO, "No", "Leading-order result", false); static SwitchOption interfaceNLONLO (interfaceNLO, "Yes", "NLO result", true); } // return the matrix element squared double SMHiggsFermionsDecayer::me2(const int, const Particle & part, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin1Half,PDT::Spin1Half))); int iferm(1),ianti(0); if(decay[0]->id()>0) swap(iferm,ianti); if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(_rho,const_ptr_cast(&part),incoming); _swave = ScalarWaveFunction(part.momentum(),part.dataPtr(),incoming); + // fix rho if no correlations + fixRho(_rho); } if(meopt==Terminate) { ScalarWaveFunction::constructSpinInfo(const_ptr_cast(&part), incoming,true); SpinorBarWaveFunction:: constructSpinInfo(_wavebar,decay[iferm],outgoing,true); SpinorWaveFunction:: constructSpinInfo(_wave ,decay[ianti],outgoing,true); return 0.; } SpinorBarWaveFunction:: calculateWaveFunctions(_wavebar,decay[iferm],outgoing); SpinorWaveFunction:: calculateWaveFunctions(_wave ,decay[ianti],outgoing); Energy2 scale(sqr(part.mass())); unsigned int ifm,ia; for(ifm=0;ifm<2;++ifm) { for(ia=0;ia<2;++ia) { if(iferm>ianti) (*ME())(0,ia,ifm)=_hvertex->evaluate(scale,_wave[ia], _wavebar[ifm],_swave); else (*ME())(0,ifm,ia)=_hvertex->evaluate(scale,_wave[ia], _wavebar[ifm],_swave); } } int id = abs(decay[0]->id()); double output=(ME()->contract(_rho)).real()*UnitRemoval::E2/scale; if(id <=6) output*=3.; // test of the partial width // Ptr::transient_const_pointer // hwsm=dynamic_ptr_cast::transient_const_pointer>(standardModel()); // double g2(hwsm->alphaEM(scale)*4.*Constants::pi/hwsm->sin2ThetaW()); // Energy mass(hwsm->mass(scale,decay[0]->dataPtr())), // mw(getParticleData(ParticleID::Wplus)->mass()); // double beta(sqrt(1.-4.*decay[0]->mass()*decay[0]->mass()/scale)); // cerr << "testing alpha " << hwsm->alphaEM(scale) << "\n"; // Energy test(g2*mass*mass*beta*beta*beta*part.mass()/32./Constants::pi/mw/mw); // if(abs(decay[0]->id())<=6){test *=3.;} // cout << "testing the answer " << output << " " // << test/GeV // << endl; // leading-order result if(!NLO_) return output; // fermion mass Energy particleMass = decay[0]->dataPtr()->mass(); // check decay products coloured, otherwise return if(!decay[0]->dataPtr()->coloured()|| particleMass==ZERO) return output; // inital masses, couplings etc // higgs mass mHiggs_ = part.mass(); // strong coupling aS_ = SM().alphaS(sqr(mHiggs_)); // reduced mass mu_ = particleMass/mHiggs_; mu2_ = sqr(mu_); // generate y double yminus = 0.; double yplus = 1.-2.*mu_*(1.-mu_)/(1.-2*mu2_); double y = yminus + UseRandom::rnd()*(yplus-yminus); //generate z for D31,2 double v = sqrt(sqr(2.*mu2_+(1.-2.*mu2_)*(1.-y))-4.*mu2_)/(1.-2.*mu2_)/(1.-y); double zplus = (1.+v)*(1.-2.*mu2_)*y/2./(mu2_ +(1.-2.*mu2_)*y); double zminus = (1.-v)*(1.-2.*mu2_)*y/2./(mu2_ +(1.-2.*mu2_)*y); double z = zminus + UseRandom::rnd()*(zplus-zminus); // map y,z to x1,x2 for both possible emissions double x2 = 1. - y*(1.-2.*mu2_); double x1 = 1. - z*(x2-2.*mu2_); //get the dipoles InvEnergy2 D1 = dipoleSubtractionTerm( x1, x2); InvEnergy2 D2 = dipoleSubtractionTerm( x2, x1); InvEnergy2 dipoleSum = abs(D1) + abs(D2); //jacobian double jac = (1.-y)*(yplus-yminus)*(zplus-zminus); //calculate real Energy2 realPrefactor = 0.25*sqr(mHiggs_)*sqr(1.-2.*mu2_) /sqrt(calculateLambda(1,mu2_,mu2_))/sqr(Constants::twopi); InvEnergy2 realEmission = 4.*Constants::pi*aS_*CF_*calculateRealEmission( x1, x2); // calculate the virtual double virtualTerm = calculateVirtualTerm(); // running mass correction virtualTerm += (8./3. - 2.*log(mu2_))*aS_/Constants::pi; //answer = (born + virtual + real)/born * LO output *= 1. + virtualTerm + 2.*jac*realPrefactor*(realEmission*abs(D1)/dipoleSum - D1); // return the answer return output; } void SMHiggsFermionsDecayer::dataBaseOutput(ofstream & os,bool header) const { if(header) os << "update decayers set parameters=\""; // parameters for the PerturbativeDecayer base class for(unsigned int ix=0;ix<_maxwgt.size();++ix) { os << "newdef " << name() << ":MaxWeights " << ix << " " << _maxwgt[ix] << "\n"; } PerturbativeDecayer::dataBaseOutput(os,false); if(header) os << "\n\" where BINARY ThePEGName=\"" << fullName() << "\";" << endl; } void SMHiggsFermionsDecayer::doinitrun() { PerturbativeDecayer::doinitrun(); if(initialize()) { for(unsigned int ix=0;ixmaxWeight(); } } } //calculate lambda double SMHiggsFermionsDecayer::calculateLambda(double x, double y, double z) const{ return sqr(x)+sqr(y)+sqr(z)-2.*x*y-2.*x*z-2.*y*z; } //calculates the dipole subtraction term for x1, D31,2 (Dij,k), // 2 is the spectator anti-fermion and 3 is the gluon InvEnergy2 SMHiggsFermionsDecayer:: dipoleSubtractionTerm(double x1, double x2) const{ InvEnergy2 commonPrefactor = CF_*8.*Constants::pi*aS_/sqr(mHiggs_); return commonPrefactor/(1.-x2)* (2.*(1.-2.*mu2_)/(2.-x1-x2)- sqrt((1.-4.*mu2_)/(sqr(x2)-4.*mu2_))* (x2-2.*mu2_)*(2.+(x1-1.)/(x2-2.*mu2_)+2.*mu2_/(1.-x2))/(1.-2.*mu2_)); } //return ME for real emission InvEnergy2 SMHiggsFermionsDecayer:: calculateRealEmission(double x1, double x2) const { InvEnergy2 prefactor = 2./sqr(mHiggs_)/(1.-4.*mu2_); return prefactor*(2. + (1.-x1)/(1.-x2) + (1.-x2)/(1.-x1) + 2.*(1.-2.*mu2_)*(1.-4.*mu2_)/(1.-x1)/(1.-x2) - 2.*(1.-4.*mu2_)*(1./(1.-x2)+1./(1.-x1)) - 2.*mu2_*(1.-4.*mu2_)*(1./sqr(1.-x2)+1./sqr(1.-x1))); } double SMHiggsFermionsDecayer:: calculateVirtualTerm() const { // logs and prefactors double beta = sqrt(1.-4.*mu2_); double L = log((1.+beta)/(1.-beta)); double prefactor = CF_*aS_/Constants::twopi; // non-singlet piece double nonSingletTerm = calculateNonSingletTerm(beta, L); double virtualTerm = -2.+4.*log(mu_)+(2./beta - 2.*beta)*L + (2.-4.*mu2_)/beta*(0.5*sqr(L) - 2.*L*log(beta) + 2.*Herwig::Math::ReLi2((1.-beta)/(1.+beta)) + 2.*sqr(Constants::pi)/3.); double iEpsilonTerm = 2.*(3.-sqr(Constants::pi)/2. + 0.5*log(mu2_) - 1.5*log(1.-2.*mu2_) -(1.-2.*mu2_)/beta*(0.5*sqr(L)+sqr(Constants::pi)/6. -2.*L*log(1.-2.*mu2_)) + nonSingletTerm); return prefactor*(virtualTerm+iEpsilonTerm); } //non-singlet piece of I(epsilon) insertion operator double SMHiggsFermionsDecayer:: calculateNonSingletTerm(double beta, double L) const { return 1.5*log(1.-2.*mu2_) + (1.-2.*mu2_)/beta*(- 2.*L*log(4.*(1.-2.*mu2_)/sqr(1.+beta))+ + 2.*Herwig::Math::ReLi2(sqr((1.-beta)/(1.+beta))) - 2.*Herwig::Math::ReLi2(2.*beta/(1.+beta)) - sqr(Constants::pi)/6.) + log(1.-mu_) - 2.*log(1.-2.*mu_) - 2.*mu2_/(1.-2.*mu2_)*log(mu_/(1.-mu_)) - mu_/(1.-mu_) + 2.*mu_*(2*mu_-1.)/(1.-2.*mu2_) + 0.5*sqr(Constants::pi); } double SMHiggsFermionsDecayer::matrixElementRatio(const Particle & inpart, const ParticleVector & decay2, const ParticleVector & decay3, MEOption, ShowerInteraction inter) { mHiggs_ = inpart.mass(); mu_ = decay2[0]->mass()/mHiggs_; mu2_ = sqr(mu_); double x1 = 2.*decay3[0]->momentum().t()/mHiggs_; double x2 = 2.*decay3[1]->momentum().t()/mHiggs_; double pre = inter==ShowerInteraction::QCD ? CF_ : sqr(double(decay2[0]->dataPtr()->iCharge())/3.); return pre*calculateRealEmission(x1,x2)*4.*Constants::pi*sqr(mHiggs_); } diff --git a/Decay/Perturbative/SMHiggsGGHiggsPPDecayer.cc b/Decay/Perturbative/SMHiggsGGHiggsPPDecayer.cc --- a/Decay/Perturbative/SMHiggsGGHiggsPPDecayer.cc +++ b/Decay/Perturbative/SMHiggsGGHiggsPPDecayer.cc @@ -1,424 +1,426 @@ // -*- C++ -*- // // SMHiggsGGHiggsPPDecayer.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 SMHiggsGGHiggsPPDecayer class. // #include "SMHiggsGGHiggsPPDecayer.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "ThePEG/PDT/DecayMode.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include "Herwig/Utilities/HiggsLoopFunctions.h" using namespace Herwig; using namespace Herwig::HiggsLoopFunctions; using namespace ThePEG::Helicity; // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSMHiggsGGHiggsPPDecayer("Herwig::SMHiggsGGHiggsPPDecayer", "HwPerturbativeHiggsDecay.so"); bool SMHiggsGGHiggsPPDecayer::accept(tcPDPtr parent, const tPDVector & children) const { int idp = parent->id(); int id0 = children[0]->id(); int id1 = children[1]->id(); if((idp == ParticleID::h0 && id0 == ParticleID::g && id1 == ParticleID::g) || (idp == ParticleID::h0 && id0 == ParticleID::gamma && id1 == ParticleID::gamma)|| (idp == ParticleID::h0 && id0 == ParticleID::Z0 && id1 == ParticleID::gamma)|| (idp == ParticleID::h0 && id0 == ParticleID::gamma && id1 == ParticleID::Z0)) return true; else return false; } ParticleVector SMHiggsGGHiggsPPDecayer::decay(const Particle & parent, const tPDVector & children) const { int imode(2); if(children[0]->id() == ParticleID::gamma && children[1]->id() == ParticleID::gamma) imode = 1; else if(children[0]->id() ==ParticleID::g) imode = 0; ParticleVector out(generate(true,false,imode,parent)); //colour flow if(children[0]->id() == ParticleID::g && children[1]->id() == ParticleID::g) { out[0]->colourNeighbour(out[1]); out[0]->antiColourNeighbour(out[1]); } return out; } void SMHiggsGGHiggsPPDecayer::persistentOutput(PersistentOStream & os) const { os << _hggvertex << _hppvertex << _hzpvertex << _h0wgt << _minloop << _maxloop << _massopt; } void SMHiggsGGHiggsPPDecayer::persistentInput(PersistentIStream & is, int) { is >> _hggvertex >> _hppvertex >> _hzpvertex >> _h0wgt >> _minloop >> _maxloop >> _massopt; } void SMHiggsGGHiggsPPDecayer::Init() { static ClassDocumentation documentation ("This is an implentation of h0->gg or h0->gamma,gamma " "decayer using the SMHGGVertex."); static Reference interfaceSMHGGVertex ("SMHGGVertex", "Pointer to SMHGGVertex", &SMHiggsGGHiggsPPDecayer::_hggvertex, false, false, true, false, false); static Reference interfaceSMHPPVertex ("SMHPPVertex", "Pointer to SMHPPVertex", &SMHiggsGGHiggsPPDecayer::_hppvertex, false, false, true, false, false); static Reference interfaceSMHZPVertex ("SMHZPVertex", "Pointer to SMHZPVertex", &SMHiggsGGHiggsPPDecayer::_hzpvertex, false, false, true, false, false); static ParVector interfaceMaxWeights ("MaxWeights", "Maximum weights for the various decays", &SMHiggsGGHiggsPPDecayer::_h0wgt, 3, 1.0, 0.0, 10.0, false, false, Interface::limited); static Parameter interfaceMinimumInLoop ("MinimumInLoop", "The minimum flavour of the quarks to include in the loops", &SMHiggsGGHiggsPPDecayer::_minloop, 6, 4, 6, false, false, Interface::limited); static Parameter interfaceMaximumInLoop ("MaximumInLoop", "The maximum flavour of the quarks to include in the loops", &SMHiggsGGHiggsPPDecayer::_maxloop, 6, 4, 6, false, false, Interface::limited); static Switch interfaceMassOption ("MassOption", "Option for the treatment of the masses in the loop diagrams", &SMHiggsGGHiggsPPDecayer::_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); } double SMHiggsGGHiggsPPDecayer::me2(const int, const Particle & part, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin1,PDT::Spin1))); if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(_rho,const_ptr_cast(&part),incoming); _swave = ScalarWaveFunction(part.momentum(),part.dataPtr(),incoming); + // fix rho if no correlations + fixRho(_rho); } if(meopt==Terminate) { ScalarWaveFunction::constructSpinInfo(const_ptr_cast(&part), incoming,true); for(unsigned int ix=0;ix<2;++ix) VectorWaveFunction::constructSpinInfo(_vwave[ix],decay[ix], outgoing,true, decay[ix]->id()!=ParticleID::Z0); return 0.; } for(unsigned int ix=0;ix<2;++ix) VectorWaveFunction:: calculateWaveFunctions(_vwave[ix],decay[ix],outgoing,decay[ix]->id()!=ParticleID::Z0); //Set up decay matrix Energy2 scale(sqr(part.mass())); unsigned int v1hel,v2hel; AbstractVVSVertexPtr vertex; unsigned int vstep1(2),vstep2(2); double sym(1.); if(decay[0]->id() == ParticleID::g && decay[1]->id() == ParticleID::g) { vertex = _hggvertex; sym = 2.; } else if(decay[0]->id() == ParticleID::gamma && decay[1]->id() == ParticleID::gamma) { vertex = _hppvertex; sym = 2.; } else if(decay[0]->id() == ParticleID::Z0 && decay[1]->id() == ParticleID::gamma) { vertex = _hzpvertex; vstep1 = 1; } else if(decay[1]->id() == ParticleID::Z0 && decay[0]->id() == ParticleID::gamma) { vertex = _hzpvertex; vstep2 = 1; } else assert(false); // loop over the helicities of the outgoing bosons for(v1hel = 0;v1hel < 3;v1hel+=vstep1) { for(v2hel = 0;v2hel < 3;v2hel+=vstep2) { (*ME())(0,v1hel,v2hel) = vertex->evaluate(scale,_vwave[0][v1hel], _vwave[1][v2hel],_swave); } } //store matrix element double output = ME()->contract(_rho).real()*UnitRemoval::E2/scale; //colour factor (N^2 - 1)/4 if(decay[0]->id() == ParticleID::g) output *= 8.; //symmetric final states output /= sym; // return the answer return output; } void SMHiggsGGHiggsPPDecayer::doinit() { PerturbativeDecayer::doinit(); // get the width generator for the higgs tPDPtr higgs = getParticleData(ParticleID::h0); if(_hggvertex) { _hggvertex->init(); } else { throw InitException() << "SMHiggsGGHiggsPPDecayer::doinit() - " << "_hggvertex is null"; } if(_hppvertex) { _hppvertex->init(); } else { throw InitException() << "SMHiggsGGHiggsPPDecayer::doinit() - " << "_hppvertex is null"; } if(_hzpvertex) { _hzpvertex->init(); } else { throw InitException() << "SMHiggsGGHiggsZPDecayer::doinit() - " << "_hzpvertex is null"; } //set up decay modes DecayPhaseSpaceModePtr mode; tPDVector extpart(3); vector wgt(0); // glu,glu mode extpart[0] = getParticleData(ParticleID::h0); extpart[1] = getParticleData(ParticleID::g); extpart[2] = getParticleData(ParticleID::g); mode = new_ptr(DecayPhaseSpaceMode(extpart,this)); addMode(mode,_h0wgt[0],wgt); // gamma,gamma mode extpart[1] = getParticleData(ParticleID::gamma); extpart[2] = getParticleData(ParticleID::gamma); mode = new_ptr(DecayPhaseSpaceMode(extpart,this)); addMode(mode,_h0wgt[1],wgt); // Z0,gamma mode extpart[1] = getParticleData(ParticleID::Z0); extpart[2] = getParticleData(ParticleID::gamma); mode = new_ptr(DecayPhaseSpaceMode(extpart,this)); addMode(mode,_h0wgt[2],wgt); } void SMHiggsGGHiggsPPDecayer::doinitrun() { _hggvertex->initrun(); _hppvertex->initrun(); _hzpvertex->initrun(); PerturbativeDecayer::doinitrun(); if(initialize()) { for(unsigned int ix=0;ixmaxWeight(); } } } void SMHiggsGGHiggsPPDecayer::dataBaseOutput(ofstream & os,bool header) const { if(header) os << "update decayers set parameters=\""; // parameters for the PerturbativeDecayer base class for(unsigned int ix=0;ix<_h0wgt.size();++ix) { os << "newdef " << name() << ":MaxWeights " << ix << " " << _h0wgt[ix] << "\n"; } os << "newdef " << name() << ":SMHGGVertex " << _hggvertex->fullName() << "\n"; os << "newdef " << name() << ":SMHPPVertex " << _hppvertex->fullName() << "\n"; os << "newdef " << name() << ":SMHZPVertex " << _hzpvertex->fullName() << "\n"; PerturbativeDecayer::dataBaseOutput(os,false); if(header) os << "\n\" where BINARY ThePEGName=\"" << fullName() << "\";" << endl; } double SMHiggsGGHiggsPPDecayer::matrixElementRatio(const Particle & inpart, const ParticleVector & decay2, const ParticleVector & decay3, MEOption, ShowerInteraction inter) { assert(inter==ShowerInteraction::QCD); // extract partons and LO momentas vector partons(1,inpart.dataPtr()); vector lomom(1,inpart.momentum()); for(unsigned int ix=0;ix<2;++ix) { partons.push_back(decay2[ix]->dataPtr()); lomom.push_back(decay2[ix]->momentum()); } vector realmom(1,inpart.momentum()); for(unsigned int ix=0;ix<3;++ix) { if(ix==2) partons.push_back(decay3[ix]->dataPtr()); realmom.push_back(decay3[ix]->momentum()); } Energy2 scale = sqr(inpart.mass()); Energy2 lome = loME(inpart.mass()); double reme = realME(partons,realmom); double ratio = reme/lome*scale; // // analytic value for mt -> infinity // double x1 = 2.*decay3[0]->momentum().t()/inpart.mass(); // double x2 = 2.*decay3[1]->momentum().t()/inpart.mass(); // double x3 = 2.*decay3[2]->momentum().t()/inpart.mass(); // double test = 8.*Constants::pi*3.*(1.+pow(1-x1,4)+pow(1-x2,4)+pow(1-x3,4)) // /(1.-x1)/(1.-x2)/(1.-x3); // generator()->log() << "TESTING RATIO " << test << " " << ratio << " " << ratio/test << "\n"; // remember the symmetry factor return ratio/3.; } double SMHiggsGGHiggsPPDecayer::realME(//const vector & partons, const vector &, const vector & momenta) const { // using std::norm; // ScalarWaveFunction hout(momenta[0],partons[0],outgoing); // LorentzPolarizationVector g[3][2]; // // calculate the polarization vectors for the gluons // for(unsigned int iw=0;iw<3;++iw) { // VectorWaveFunction gwave(momenta[iw+1],partons[iw+1],outgoing); // for(unsigned int ix=0;ix<2;++ix) { // //if(iw==2) gwave.reset(10); // //else // gwave.reset(2*ix); // g[iw][ix] = gwave.wave(); // } // } Energy2 mh2 = momenta[0].mass2(); Energy2 s = (momenta[1]+momenta[2]).m2(); Energy2 t = (momenta[1]+momenta[3]).m2(); Energy2 u = (momenta[2]+momenta[3]).m2(); // calculate the loop functions Complex A4stu(0.),A2stu(0.),A2tsu(0.),A2ust(0.); for(int ix=_minloop;ix<=_maxloop;++ix) { // loop functions if(_massopt==0) { Energy2 mf2=sqr(getParticleData(ix)->mass()); A4stu+=A4(s,t,u,mf2); A2stu+=A2(s,t,u,mf2); A2tsu+=A2(t,s,u,mf2); A2ust+=A2(u,s,t,mf2); } else { A4stu=-1./3.; A2stu=-sqr(s/mh2)/3.; A2tsu=-sqr(t/mh2)/3.; A2ust=-sqr(u/mh2)/3.; } } // Complex A3stu=0.5*(A2stu+A2ust+A2tsu-A4stu); // // compute the dot products for the matrix element // // and polarization vector * momenta // Energy2 pdot[3][3]; // complex eps[3][3][2]; // for(unsigned int ig=0;ig<3;++ig) { // for(unsigned int ip=0;ip<3;++ip) { // pdot[ig][ip]=momenta[ig+1]*momenta[ip+1]; // for(unsigned int ih=0;ih<2;++ih) { // if(ig!=ip) // eps[ig][ip][ih]=g[ig][ih].dot(momenta[ip+1])/pdot[ig][ip]; // else // eps[ig][ip][ih]=ZERO; // } // } // } // prefactors Energy mw(getParticleData(ParticleID::Wplus)->mass()); // Energy3 pre=sqr(mh2)/mw; // // compute the matrix element // double output(0.); // complex wdot[3][3]; // for(unsigned int ghel1=0;ghel1<2;++ghel1) { // for(unsigned int ghel2=0;ghel2<2;++ghel2) { // for(unsigned int ghel3=0;ghel3<2;++ghel3) { // wdot[0][1]=g[0][ghel1].dot(g[1][ghel2])/pdot[0][1]; // wdot[0][2]=g[0][ghel1].dot(g[2][ghel3])/pdot[0][2]; // wdot[1][0]=wdot[0][1]; // wdot[1][2]=g[1][ghel2].dot(g[2][ghel3])/pdot[1][2]; // wdot[2][0]=wdot[0][2]; // wdot[2][1]=wdot[1][2]; // // last piece // Complex diag=pre*A3stu*(eps[0][2][ghel1]*eps[1][0][ghel2]*eps[2][1][ghel3]- // eps[0][1][ghel1]*eps[1][2][ghel2]*eps[2][0][ghel3]+ // (eps[2][0][ghel3]-eps[2][1][ghel3])*wdot[0][1]+ // (eps[1][2][ghel2]-eps[1][0][ghel2])*wdot[0][2]+ // (eps[0][1][ghel1]-eps[0][2][ghel1])*wdot[1][2]); // // first piece // diag+=pre*(+A2stu*(eps[0][1][ghel1]*eps[1][0][ghel2]-wdot[0][1])* // (eps[2][0][ghel3]-eps[2][1][ghel3]) // +A2tsu*(eps[0][2][ghel1]*eps[2][0][ghel3]-wdot[0][2])* // (eps[1][2][ghel2]-eps[1][0][ghel2]) // +A2ust*(eps[1][2][ghel2]*eps[2][1][ghel3]-wdot[1][2])* // (eps[0][1][ghel1]-eps[0][2][ghel1])); // output+=norm(diag); // } // } // } // // colour factor and what's left of the prefactor // output *= 6.; double me=4.*24./s/t/u*pow<4,1>(mh2)/sqr(mw)* (norm(A2stu)+norm(A2ust)+norm(A2tsu)+norm(A4stu)); return me; } Energy2 SMHiggsGGHiggsPPDecayer::loME(Energy mh) const { Complex loop(0.); Energy2 mh2(sqr(mh)); Energy mw(getParticleData(ParticleID::Wplus)->mass()); for(int ix=_minloop;ix<=_maxloop;++ix) { // loop functions if(_massopt==0) { Energy2 mf2=sqr(getParticleData(ix)->mass()); loop += A1(mh2,mf2); } else { loop += 2./3.; } } return 1./Constants::pi*sqr(mh2)/sqr(mw)*norm(loop); } diff --git a/Decay/Perturbative/SMHiggsWWDecayer.cc b/Decay/Perturbative/SMHiggsWWDecayer.cc --- a/Decay/Perturbative/SMHiggsWWDecayer.cc +++ b/Decay/Perturbative/SMHiggsWWDecayer.cc @@ -1,325 +1,327 @@ // -*- C++ -*- // // SMHiggsWWDecayer.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 SMHiggsWWDecayer class. // #include "SMHiggsWWDecayer.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 "Herwig/Models/StandardModel/StandardModel.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/PDT/ParticleData.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; typedef Selector DecaySelector; // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSMHiggsWWDecayer("Herwig::SMHiggsWWDecayer", "HwPerturbativeHiggsDecay.so"); void SMHiggsWWDecayer::Init() { static ClassDocumentation documentation ("The SMHiggsWWDecayer class performs the decay of the Standard Model Higgs" " boson to W+W- and Z0Z0"); static ParVector interfaceWMaximum ("WMaximum", "The maximum weight for H-> W+W- decays", &SMHiggsWWDecayer::_wmax, 2, 1.0, 0.0, 10000.0, false, false, Interface::limited); static ParVector interfaceZMaximum ("ZMaximum", "The maximum weight for H-> Z0Z0 decays", &SMHiggsWWDecayer::_zmax, 2, 1.0, 0.0, 10000.0, false, false, Interface::limited); } SMHiggsWWDecayer::SMHiggsWWDecayer() : _wmax(2,1.00), _zmax(2,1.00) {} void SMHiggsWWDecayer::doinit() { PerturbativeDecayer::doinit(); // get the vertices from the Standard Model object tcHwSMPtr hwsm=dynamic_ptr_cast(standardModel()); if(!hwsm) throw InitException() << "SMHiggsWWDecayer needs the StandardModel class" << " to be either the Herwig one or a class inheriting" << " from it"; _theFFWVertex = hwsm->vertexFFW(); _theFFZVertex = hwsm->vertexFFZ(); _theHVVVertex = hwsm->vertexWWH(); // get the width generator for the higgs tPDPtr higgs = getParticleData(ParticleID::h0); // the W+W- decays for(unsigned int ix=0;ix<2;++ix) { tPDPtr h0 = getParticleData(ParticleID::h0); tPDPtr wplus = getParticleData(ParticleID::Wplus); tPDPtr wminus = getParticleData(ParticleID::Wminus); DecaySelector wpDecay = wplus->decaySelector(); DecaySelector wmDecay = wminus->decaySelector(); tPDVector extpart(5); extpart[0]=h0; DecayPhaseSpaceModePtr mode; DecayPhaseSpaceChannelPtr newchannel; vector wgt(1,1.); unsigned int imode=0; for(DecaySelector::const_iterator wp=wpDecay.begin();wp!=wpDecay.end();++wp) { // extract the decay products of W+ tPDVector prod=(*wp).second->orderedProducts(); if(prod[0]->id()id()) swap(prod[0],prod[1]); extpart[1]=prod[0]; extpart[2]=prod[1]; for(DecaySelector::const_iterator wm=wmDecay.begin();wm!=wmDecay.end();++wm) { // extract the decay products of W- tPDVector prod=(*wm).second->orderedProducts(); if(prod[0]->id()id()) swap(prod[0],prod[1]); extpart[3]=prod[0]; extpart[4]=prod[1]; // create the new mode mode = new_ptr(DecayPhaseSpaceMode(extpart,this)); // create the phase space channel newchannel=new_ptr(DecayPhaseSpaceChannel(mode)); newchannel->addIntermediate(extpart[0],0,0.0,-1,-2); if(ix==0) { newchannel->addIntermediate(wplus ,1,0., 1, 2); newchannel->addIntermediate(wminus ,1,0., 3, 4); } else { newchannel->addIntermediate(wplus ,0,0., 1, 2); newchannel->addIntermediate(wminus ,0,0., 3, 4); } mode->addChannel(newchannel); addMode(mode,_wmax[ix],wgt); // insert mode into selector _ratio.push_back(wp->second->brat()*wm->second->brat()); if(ix==0) _wdecays.insert (_ratio.back(),imode); ++imode; } } // the Z0Z0 decays tPDPtr Z0=getParticleData(ParticleID::Z0); DecaySelector Z0Decay = Z0->decaySelector(); for(DecaySelector::const_iterator z1=Z0Decay.begin();z1!=Z0Decay.end();++z1) { // extract the decay products of Z0 tPDVector prod=(*z1).second->orderedProducts(); if(prod[0]->id()id()) swap(prod[0],prod[1]); extpart[1]=prod[0]; extpart[2]=prod[1]; for(DecaySelector::const_iterator z2=Z0Decay.begin();z2!=Z0Decay.end();++z2) { // extract the decay products of Z0 tPDVector prod=(*z2).second->orderedProducts(); if(prod[0]->id()id()) swap(prod[0],prod[1]); extpart[3]=prod[0]; extpart[4]=prod[1]; // create the new mode mode = new_ptr(DecayPhaseSpaceMode(extpart,this)); // create the phase space channel newchannel=new_ptr(DecayPhaseSpaceChannel(mode)); newchannel->addIntermediate(extpart[0],0,0.0,-1,-2); if(ix==0) { newchannel->addIntermediate(Z0 ,1,0., 1, 2); newchannel->addIntermediate(Z0 ,1,0., 3, 4); } else { newchannel->addIntermediate(Z0 ,0,0., 1, 2); newchannel->addIntermediate(Z0 ,0,0., 3, 4); } mode->addChannel(newchannel); addMode(mode,_zmax[ix],wgt); // insert mode into selector _ratio.push_back(z1->second->brat()*z2->second->brat()); if(ix==0) _zdecays.insert (_ratio.back(),imode); ++imode; } } } } bool SMHiggsWWDecayer::accept(tcPDPtr parent, const tPDVector & children) const { // if not two decay products return false if(children.size()!=2) return false; // if not decaying higgs return false if(parent->id()!=ParticleID::h0) return false; tPDVector::const_iterator pit = children.begin(); int id1=(**pit).id(); ++pit; int id2=(**pit).id(); if((id1==-id2&&abs(id1)==ParticleID::Wplus)|| (id1== id2&& id1 ==ParticleID::Z0)) return true; else return false; } void SMHiggsWWDecayer::persistentOutput(PersistentOStream & os) const { os << _theFFWVertex << _theFFZVertex << _theHVVVertex << _wdecays << _zdecays << _ratio << _wmax << _zmax; } void SMHiggsWWDecayer::persistentInput(PersistentIStream & is, int) { is >> _theFFWVertex >> _theFFZVertex >> _theHVVVertex >> _wdecays >> _zdecays >> _ratio >> _wmax >> _zmax; } ParticleVector SMHiggsWWDecayer::decay(const Particle & parent, const tPDVector & children) const { // select the decay modes of the gauge bosons unsigned int imode; if(abs(children[0]->id())==ParticleID::Wplus) imode=_wdecays.select(UseRandom::rnd()); else imode=_zdecays.select(UseRandom::rnd()); // use different phase space for low/high mass higgs if(parent.mass()>1.8*children[0]->mass()) imode+=_wdecays.size()+_zdecays.size(); // generate the kinematics return generate(true,false,imode,parent); } double SMHiggsWWDecayer::me2(const int, const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half))); // check if Z or W decay bool Z0=decay[0]->id()==-decay[1]->id(); if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(_rho,const_ptr_cast(&inpart),incoming); _swave = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming); + // fix rho if no correlations + fixRho(_rho); } if(meopt==Terminate) { ScalarWaveFunction::constructSpinInfo(const_ptr_cast(&inpart), incoming,true); SpinorBarWaveFunction:: constructSpinInfo(_fwave1,decay[0],outgoing,true); SpinorWaveFunction :: constructSpinInfo(_awave1,decay[1],outgoing,true); SpinorBarWaveFunction:: constructSpinInfo(_fwave2,decay[2],outgoing,true); SpinorWaveFunction :: constructSpinInfo(_awave2,decay[3],outgoing,true); return 0.; } SpinorBarWaveFunction:: calculateWaveFunctions(_fwave1,decay[0],outgoing); SpinorWaveFunction :: calculateWaveFunctions(_awave1,decay[1],outgoing); SpinorBarWaveFunction:: calculateWaveFunctions(_fwave2,decay[2],outgoing); SpinorWaveFunction :: calculateWaveFunctions(_awave2,decay[3],outgoing); // get the intermediates and vertex tcPDPtr inter[2]; AbstractFFVVertexPtr vert; if(Z0) { inter[0]=getParticleData(ParticleID::Z0); inter[1]=inter[0]; vert=_theFFZVertex; } else { inter[0]=getParticleData(ParticleID::Wplus); inter[1]=getParticleData(ParticleID::Wminus); vert=_theFFWVertex; } // construct the spinors for the outgoing particles Energy2 scale0(sqr(inpart.mass())); Energy2 scale1((decay[0]->momentum()+decay[1]->momentum()).m2()); Energy2 scale2((decay[2]->momentum()+decay[3]->momentum()).m2()); // for decays to quarks ensure boson is massive enough to // put quarks on constituent mass-shell if(scale1dataPtr()->constituentMass()+ decay[1]->dataPtr()->constituentMass())) return 0.; if(scale2dataPtr()->constituentMass()+ decay[3]->dataPtr()->constituentMass())) return 0.; // compute the boson currents VectorWaveFunction curr1[2][2],curr2[2][2]; unsigned int ohel1,ohel2,ohel3,ohel4; for(ohel1=0;ohel1<2;++ohel1) { for(ohel2=0;ohel2<2;++ohel2) { curr1[ohel1][ohel2]=vert->evaluate(scale1,1,inter[0], _awave1[ohel2],_fwave1[ohel1]); curr2[ohel1][ohel2]=vert->evaluate(scale2,1,inter[1], _awave2[ohel2],_fwave2[ohel1]); } } // compute the matrix element for(ohel1=0;ohel1<2;++ohel1) { for(ohel2=0;ohel2<2;++ohel2) { for(ohel3=0;ohel3<2;++ohel3) { for(ohel4=0;ohel4<2;++ohel4) { (*ME())(0,ohel1,ohel2,ohel3,ohel4)= _theHVVVertex->evaluate(scale0,curr1[ohel1][ohel2], curr2[ohel3][ohel4],_swave); } } } } double output=(ME()->contract(_rho)).real()*scale0*UnitRemoval::InvE2; // set up the colour flows if(decay[0]->coloured()) { output*=3.; decay[0]->antiColourNeighbour(decay[1]); } if(decay[2]->coloured()) { output*=3.; decay[2]->antiColourNeighbour(decay[3]); } // divide out the gauge boson branching ratios output/=_ratio[imode()]; // if Z0 decays identical particle factor if(Z0) output*=0.5; // return the answer return output; } void SMHiggsWWDecayer::dataBaseOutput(ofstream & os,bool header) const { if(header) os << "update decayers set parameters=\""; for(unsigned int ix=0;ix<2;++ix) { os << "newdef " << name() << ":WMaximum " << ix << " " << _wmax[ix] << "\n"; os << "newdef " << name() << ":ZMaximum " << ix << " " << _zmax[ix] << "\n"; } PerturbativeDecayer::dataBaseOutput(os,false); if(header) os << "\n\" where BINARY ThePEGName=\"" << fullName() << "\";" << endl; } void SMHiggsWWDecayer::doinitrun() { PerturbativeDecayer::doinitrun(); for(unsigned int ix=0;ix<2;++ix) { _zmax[ix]=0.; _wmax[ix]=0.; } unsigned int ntest=_wdecays.size()+_zdecays.size(); if(initialize()) { for(unsigned int ix=0;ixexternalParticles(1)->iCharge()== -mode(ix)->externalParticles(2)->iCharge()) { _zmax[iloc]=max(mode(ix)->maxWeight(),_zmax[iloc]); } else { _wmax[iloc]=max(mode(ix)->maxWeight(),_wmax[iloc]); } } } } diff --git a/Decay/Perturbative/SMTopDecayer.cc b/Decay/Perturbative/SMTopDecayer.cc --- a/Decay/Perturbative/SMTopDecayer.cc +++ b/Decay/Perturbative/SMTopDecayer.cc @@ -1,764 +1,766 @@ // -*- C++ -*- // // SMTopDecayer.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 SMTopDecayer class. // #include "SMTopDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/ParVector.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "Herwig/Decay/DecayVertex.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "Herwig/PDT/ThreeBodyAllOn1IntegralCalculator.h" #include "Herwig/Shower/RealEmissionProcess.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; SMTopDecayer::SMTopDecayer() : _wquarkwgt(6,0.),_wleptonwgt(3,0.), _xg_sampling(1.5), _initialenhance(1.), _finalenhance(2.3) { _wleptonwgt[0] = 0.302583; _wleptonwgt[1] = 0.301024; _wleptonwgt[2] = 0.299548; _wquarkwgt[0] = 0.851719; _wquarkwgt[1] = 0.0450162; _wquarkwgt[2] = 0.0456962; _wquarkwgt[3] = 0.859839; _wquarkwgt[4] = 3.9704e-06; _wquarkwgt[5] = 0.000489657; generateIntermediates(true); } bool SMTopDecayer::accept(tcPDPtr parent, const tPDVector & children) const { if(abs(parent->id()) != ParticleID::t) return false; int id0(0),id1(0),id2(0); for(tPDVector::const_iterator it = children.begin(); it != children.end();++it) { int id=(**it).id(),absid(abs(id)); if(absid==ParticleID::b&&double(id)/double(parent->id())>0) { id0=id; } else { switch (absid) { case ParticleID::nu_e: case ParticleID::nu_mu: case ParticleID::nu_tau: id1 = id; break; case ParticleID::eminus: case ParticleID::muminus: case ParticleID::tauminus: id2 = id; break; case ParticleID::b: case ParticleID::d: case ParticleID::s: id1 = id; break; case ParticleID::u: case ParticleID::c: id2=id; break; default : break; } } } if(id0==0||id1==0||id2==0) return false; if(double(id1)/double(id2)>0) return false; return true; } ParticleVector SMTopDecayer::decay(const Particle & parent, const tPDVector & children) const { int id1(0),id2(0); for(tPDVector::const_iterator it = children.begin(); it != children.end();++it) { int id=(**it).id(),absid=abs(id); if(absid == ParticleID::b && double(id)/double(parent.id())>0) continue; //leptons if(absid > 10 && absid%2==0) id1=absid; if(absid > 10 && absid%2==1) id2=absid; //quarks if(absid < 10 && absid%2==0) id2=absid; if(absid < 10 && absid%2==1) id1=absid; } unsigned int imode(0); if(id2 >=11 && id2<=16) imode = (id1-12)/2; else imode = id1+1+id2/2; bool cc = parent.id() == ParticleID::tbar; ParticleVector out(generate(true,cc,imode,parent)); //arrange colour flow PPtr pparent=const_ptr_cast(&parent); out[1]->incomingColour(pparent,out[1]->id()<0); ParticleVector products = out[0]->children(); if(products[0]->hasColour()) products[0]->colourNeighbour(products[1],true); else if(products[0]->hasAntiColour()) products[0]->colourNeighbour(products[1],false); return out; } void SMTopDecayer::persistentOutput(PersistentOStream & os) const { os << FFWVertex_ << FFGVertex_ << FFPVertex_ << WWWVertex_ << _wquarkwgt << _wleptonwgt << _wplus << _initialenhance << _finalenhance << _xg_sampling; } void SMTopDecayer::persistentInput(PersistentIStream & is, int) { is >> FFWVertex_ >> FFGVertex_ >> FFPVertex_ >> WWWVertex_ >> _wquarkwgt >> _wleptonwgt >> _wplus >> _initialenhance >> _finalenhance >> _xg_sampling; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSMTopDecayer("Herwig::SMTopDecayer", "HwPerturbativeDecay.so"); void SMTopDecayer::Init() { static ClassDocumentation documentation ("This is the implementation of the SMTopDecayer which " "decays top quarks into bottom quarks and either leptons " "or quark-antiquark pairs including the matrix element for top decay", "The matrix element correction for top decay \\cite{Hamilton:2006ms}.", "%\\cite{Hamilton:2006ms}\n" "\\bibitem{Hamilton:2006ms}\n" " K.~Hamilton and P.~Richardson,\n" " ``A simulation of QCD radiation in top quark decays,''\n" " JHEP {\\bf 0702}, 069 (2007)\n" " [arXiv:hep-ph/0612236].\n" " %%CITATION = JHEPA,0702,069;%%\n"); static ParVector interfaceQuarkWeights ("QuarkWeights", "Maximum weights for the hadronic decays", &SMTopDecayer::_wquarkwgt, 6, 1.0, 0.0, 10.0, false, false, Interface::limited); static ParVector interfaceLeptonWeights ("LeptonWeights", "Maximum weights for the semi-leptonic decays", &SMTopDecayer::_wleptonwgt, 3, 1.0, 0.0, 10.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.", &SMTopDecayer::_initialenhance, 1.0, 1.0, 10000.0, false, false, Interface::limited); static Parameter interfaceFinalEnhancementFactor ("FinalEnhancementFactor", "The enhancement factor for final-state radiation in the shower to ensure" " the weight for the matrix element correction is less than one", &SMTopDecayer::_finalenhance, 1.6, 1.0, 1000.0, false, false, Interface::limited); static Parameter interfaceSamplingTopHardMEC ("SamplingTopHardMEC", "The importance sampling power for choosing an initial xg, " "to sample xg according to xg^-_xg_sampling", &SMTopDecayer::_xg_sampling, 1.5, 1.2, 2.0, false, false, Interface::limited); } double SMTopDecayer::me2(const int, const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half))); // spinors etc for the decaying particle if(meopt==Initialize) { // spinors and rho if(inpart.id()>0) SpinorWaveFunction ::calculateWaveFunctions(_inHalf,_rho, const_ptr_cast(&inpart), incoming); else SpinorBarWaveFunction::calculateWaveFunctions(_inHalfBar,_rho, const_ptr_cast(&inpart), incoming); + // fix rho if no correlations + fixRho(_rho); } // setup spin info when needed if(meopt==Terminate) { // for the decaying particle if(inpart.id()>0) { SpinorWaveFunction:: constructSpinInfo(_inHalf,const_ptr_cast(&inpart),incoming,true); SpinorBarWaveFunction::constructSpinInfo(_inHalfBar,decay[0],outgoing,true); SpinorWaveFunction ::constructSpinInfo(_outHalf ,decay[1],outgoing,true); SpinorBarWaveFunction::constructSpinInfo(_outHalfBar,decay[2],outgoing,true); } else { SpinorBarWaveFunction:: constructSpinInfo(_inHalfBar,const_ptr_cast(&inpart),incoming,true); SpinorWaveFunction::constructSpinInfo(_inHalf,decay[0],outgoing,true); SpinorBarWaveFunction::constructSpinInfo(_outHalfBar,decay[1],outgoing,true); SpinorWaveFunction ::constructSpinInfo(_outHalf ,decay[2],outgoing,true); } } if ( ( decay[1]->momentum() + decay[2]->momentum() ).m() < decay[1]->data().constituentMass() + decay[2]->data().constituentMass() ) return 0.0; // spinors for the decay product if(inpart.id()>0) { SpinorBarWaveFunction::calculateWaveFunctions(_inHalfBar ,decay[0],outgoing); SpinorWaveFunction ::calculateWaveFunctions(_outHalf ,decay[1],outgoing); SpinorBarWaveFunction::calculateWaveFunctions(_outHalfBar,decay[2],outgoing); } else { SpinorWaveFunction ::calculateWaveFunctions(_inHalf ,decay[0],outgoing); SpinorBarWaveFunction::calculateWaveFunctions(_outHalfBar,decay[1],outgoing); SpinorWaveFunction ::calculateWaveFunctions(_outHalf ,decay[2],outgoing); } Energy2 scale(sqr(inpart.mass())); if(inpart.id() == ParticleID::t) { //Define intermediate vector wave-function for Wplus tcPDPtr Wplus(getParticleData(ParticleID::Wplus)); VectorWaveFunction inter; unsigned int thel,bhel,fhel,afhel; for(thel = 0;thel<2;++thel){ for(bhel = 0;bhel<2;++bhel){ inter = FFWVertex_->evaluate(scale,1,Wplus,_inHalf[thel], _inHalfBar[bhel]); for(afhel=0;afhel<2;++afhel){ for(fhel=0;fhel<2;++fhel){ (*ME())(thel,bhel,afhel,fhel) = FFWVertex_->evaluate(scale,_outHalf[afhel], _outHalfBar[fhel],inter); } } } } } else if(inpart.id() == ParticleID::tbar) { VectorWaveFunction inter; tcPDPtr Wminus(getParticleData(ParticleID::Wminus)); unsigned int tbhel,bbhel,afhel,fhel; for(tbhel = 0;tbhel<2;++tbhel){ for(bbhel = 0;bbhel<2;++bbhel){ inter = FFWVertex_-> evaluate(scale,1,Wminus,_inHalf[bbhel],_inHalfBar[tbhel]); for(afhel=0;afhel<2;++afhel){ for(fhel=0;fhel<2;++fhel){ (*ME())(tbhel,bbhel,fhel,afhel) = FFWVertex_->evaluate(scale,_outHalf[afhel], _outHalfBar[fhel],inter); } } } } } double output = (ME()->contract(_rho)).real(); if(abs(decay[1]->id())<=6) output *=3.; return output; } void SMTopDecayer::doinit() { PerturbativeDecayer::doinit(); //get vertices from SM object tcHwSMPtr hwsm = dynamic_ptr_cast(standardModel()); if(!hwsm) throw InitException() << "Must have Herwig::StandardModel in " << "SMTopDecayer::doinit()"; FFWVertex_ = hwsm->vertexFFW(); FFGVertex_ = hwsm->vertexFFG(); FFPVertex_ = hwsm->vertexFFP(); WWWVertex_ = hwsm->vertexWWW(); //initialise FFWVertex_->init(); FFGVertex_->init(); FFPVertex_->init(); WWWVertex_->init(); //set up decay modes _wplus = getParticleData(ParticleID::Wplus); DecayPhaseSpaceModePtr mode; DecayPhaseSpaceChannelPtr Wchannel; tPDVector extpart(4); vector wgt(1,1.0); extpart[0] = getParticleData(ParticleID::t); extpart[1] = getParticleData(ParticleID::b); //lepton modes for(int i=11; i<17;i+=2) { extpart[2] = getParticleData(-i); extpart[3] = getParticleData(i+1); mode = new_ptr(DecayPhaseSpaceMode(extpart,this)); Wchannel = new_ptr(DecayPhaseSpaceChannel(mode)); Wchannel->addIntermediate(extpart[0],0,0.0,-1,1); Wchannel->addIntermediate(_wplus,0,0.0,2,3); Wchannel->init(); mode->addChannel(Wchannel); addMode(mode,_wleptonwgt[(i-11)/2],wgt); } //quark modes unsigned int iz=0; for(int ix=1;ix<6;ix+=2) { for(int iy=2;iy<6;iy+=2) { // check that the combination of particles is allowed if(FFWVertex_->allowed(-ix,iy,ParticleID::Wminus)) { extpart[2] = getParticleData(-ix); extpart[3] = getParticleData( iy); mode = new_ptr(DecayPhaseSpaceMode(extpart,this)); Wchannel = new_ptr(DecayPhaseSpaceChannel(mode)); Wchannel->addIntermediate(extpart[0],0,0.0,-1,1); Wchannel->addIntermediate(_wplus,0,0.0,2,3); Wchannel->init(); mode->addChannel(Wchannel); addMode(mode,_wquarkwgt[iz],wgt); ++iz; } else { throw InitException() << "SMTopDecayer::doinit() the W vertex" << "cannot handle all the quark modes" << Exception::abortnow; } } } } void SMTopDecayer::dataBaseOutput(ofstream & os,bool header) const { if(header) os << "update decayers set parameters=\""; // parameters for the PerturbativeDecayer base class for(unsigned int ix=0;ix<_wquarkwgt.size();++ix) { os << "newdef " << name() << ":QuarkWeights " << ix << " " << _wquarkwgt[ix] << "\n"; } for(unsigned int ix=0;ix<_wleptonwgt.size();++ix) { os << "newdef " << name() << ":LeptonWeights " << ix << " " << _wleptonwgt[ix] << "\n"; } PerturbativeDecayer::dataBaseOutput(os,false); if(header) os << "\n\" where BINARY ThePEGName=\"" << fullName() << "\";" << endl; } void SMTopDecayer::doinitrun() { PerturbativeDecayer::doinitrun(); if(initialize()) { for(unsigned int ix=0;ixmaxWeight(); else _wquarkwgt [ix-3] = mode(ix)->maxWeight(); } } } WidthCalculatorBasePtr SMTopDecayer::threeBodyMEIntegrator(const DecayMode & dm) const { // identify W decay products int sign = dm.parent()->id() > 0 ? 1 : -1; int iferm(0),ianti(0); for(ParticleMSet::const_iterator pit=dm.products().begin(); pit!=dm.products().end();++pit) { int id = (**pit).id(); if(id*sign != ParticleID::b) { if (id*sign > 0 ) iferm = id*sign; else ianti = id*sign; } } assert(iferm!=0&&ianti!=0); // work out which mode we are doing int imode(-1); for(unsigned int ix=0;ixexternalParticles(2)->id() == ianti && mode(ix)->externalParticles(3)->id() == iferm ) { imode = ix; break; } } assert(imode>=0); // get the masses we need Energy m[3] = {mode(imode)->externalParticles(1)->mass(), mode(imode)->externalParticles(3)->mass(), mode(imode)->externalParticles(2)->mass()}; return new_ptr(ThreeBodyAllOn1IntegralCalculator (3,_wplus->mass(),_wplus->width(),0.0,*this,imode,m[0],m[1],m[2])); } InvEnergy SMTopDecayer::threeBodydGammads(const int imode, const Energy2 mt2, const Energy2 mffb2, const Energy mb, const Energy mf, const Energy mfb) const { Energy mffb(sqrt(mffb2)); Energy mw(_wplus->mass()); Energy2 mw2(sqr(mw)),gw2(sqr(_wplus->width())); Energy mt(sqrt(mt2)); Energy Eb = 0.5*(mt2-mffb2-sqr(mb))/mffb; Energy Ef = 0.5*(mffb2-sqr(mfb)+sqr(mf))/mffb; Energy Ebm = sqrt(sqr(Eb)-sqr(mb)); Energy Efm = sqrt(sqr(Ef)-sqr(mf)); Energy2 upp = sqr(Eb+Ef)-sqr(Ebm-Efm); Energy2 low = sqr(Eb+Ef)-sqr(Ebm+Efm); InvEnergy width=(dGammaIntegrand(mffb2,upp,mt,mb,mf,mfb,mw)- dGammaIntegrand(mffb2,low,mt,mb,mf,mfb,mw)) /32./mt2/mt/8/pow(Constants::pi,3)/(sqr(mffb2-mw2)+mw2*gw2); // couplings width *= 0.25*sqr(4.*Constants::pi*generator()->standardModel()->alphaEM(mt2)/ generator()->standardModel()->sin2ThetaW()); width *= generator()->standardModel()->CKM(*mode(imode)->externalParticles(0), *mode(imode)->externalParticles(1)); if(abs(mode(imode)->externalParticles(2)->id())<=6) { width *=3.; if(abs(mode(imode)->externalParticles(2)->id())%2==0) width *=generator()->standardModel()->CKM(*mode(imode)->externalParticles(2), *mode(imode)->externalParticles(3)); else width *=generator()->standardModel()->CKM(*mode(imode)->externalParticles(3), *mode(imode)->externalParticles(2)); } // final spin average assert(!std::isnan(double(width*MeV))); return 0.5*width; } Energy6 SMTopDecayer::dGammaIntegrand(Energy2 mffb2, Energy2 mbf2, Energy mt, Energy mb, Energy mf, Energy mfb, Energy mw) const { Energy2 mt2(sqr(mt)) ,mb2(sqr(mb)) ,mf2(sqr(mf )),mfb2(sqr(mfb )),mw2(sqr(mw )); Energy4 mt4(sqr(mt2)),mb4(sqr(mb2)),mf4(sqr(mf2)),mfb4(sqr(mfb2)),mw4(sqr(mw2)); return -mbf2 * ( + 6 * mb2 * mf2 * mfb2 * mffb2 + 6 * mb2 * mt2 * mfb2 * mffb2 + 6 * mb2 * mt2 * mf2 * mffb2 + 12 * mb2 * mt2 * mf2 * mfb2 - 3 * mb2 * mfb4 * mffb2 + 3 * mb2 * mf2 * mffb2 * mffb2 - 3 * mb2 * mf4 * mffb2 - 6 * mb2 * mt2 * mfb4 - 6 * mb2 * mt2 * mf4 - 3 * mb4 * mfb2 * mffb2 - 3 * mb4 * mf2 * mffb2 - 6 * mb4 * mf2 * mfb2 + 3 * mt4 * mf4 + 3 * mb4 * mfb4 + 3 * mb4 * mf4 + 3 * mt4 * mfb4 + 3 * mb2 * mfb2 * mffb2 * mffb2 + 3 * mt2 * mfb2 * mffb2 * mffb2 - 3 * mt2 * mfb4 * mffb2 + 3 * mt2 * mf2 * mffb2 * mffb2 - 3 * mt2 * mf4 * mffb2 - 3 * mt4 * mfb2 * mffb2 - 3 * mt4 * mf2 * mffb2 - 6 * mt4 * mf2 * mfb2 + 6 * mt2 * mf2 * mfb2 * mffb2 + 12 * mt2 * mf2 * mw4 + 12 * mb2 * mfb2 * mw4 + 12 * mb2 * mt2 * mw4 + 6 * mw2 * mt2 * mfb2 * mbf2 - 12 * mw2 * mt2 * mf2 * mffb2 - 6 * mw2 * mt2 * mf2 * mbf2 - 12 * mw2 * mt2 * mf2 * mfb2 - 12 * mw2 * mb2 * mfb2 * mffb2 - 6 * mw2 * mb2 * mfb2 * mbf2 + 6 * mw2 * mb2 * mf2 * mbf2 - 12 * mw2 * mb2 * mf2 * mfb2 - 12 * mw2 * mb2 * mt2 * mfb2 - 12 * mw2 * mb2 * mt2 * mf2 + 12 * mf2 * mfb2 * mw4 + 4 * mbf2 * mbf2 * mw4 - 6 * mfb2 * mbf2 * mw4 - 6 * mf2 * mbf2 * mw4 - 6 * mt2 * mbf2 * mw4 - 6 * mb2 * mbf2 * mw4 + 12 * mw2 * mt2 * mf4 + 12 * mw2 * mt4 * mf2 + 12 * mw2 * mb2 * mfb4 + 12 * mw2 * mb4 * mfb2) /mw4 / 3.; } void SMTopDecayer::initializeMECorrection(RealEmissionProcessPtr born, double & initial, double & final) { // check the outgoing particles PPtr part[2]; for(unsigned int ix=0;ixbornOutgoing().size();++ix) { part[ix]= born->bornOutgoing()[ix]; } // check the final-state particles and get the masses if(abs(part[0]->id())==ParticleID::Wplus&&abs(part[1]->id())==ParticleID::b) { _ma=part[0]->mass(); _mc=part[1]->mass(); } else if(abs(part[1]->id())==ParticleID::Wplus&&abs(part[0]->id())==ParticleID::b) { _ma=part[1]->mass(); _mc=part[0]->mass(); } else { return; } // set the top mass _mt=born->bornIncoming()[0]->mass(); // set the gluon mass _mg=getParticleData(ParticleID::g)->constituentMass(); // set the radiation enhancement factors initial = _initialenhance; final = _finalenhance; // reduced mass parameters _a=sqr(_ma/_mt); _g=sqr(_mg/_mt); _c=sqr(_mc/_mt); double lambda = sqrt(1.+sqr(_a)+sqr(_c)-2.*_a-2.*_c-2.*_a*_c); _ktb = 0.5*(3.-_a+_c+lambda); _ktc = 0.5*(1.-_a+3.*_c+lambda); useMe(); } bool SMTopDecayer::softMatrixElementVeto(PPtr parent, PPtr progenitor, const bool & , const Energy & highestpT, const vector &, const double & z, const Energy & scale, const Energy & pt) { // check if we need to apply the full correction // the initial-state correction if(abs(progenitor->id())==ParticleID::t&&abs(parent->id())==ParticleID::t) { // check if hardest so far // if not just need to remove effect of enhancement bool veto(false); // if not hardest so far if(ptxgbcut(_ktb)) wgt = 0.; if(wgt>1.) { generator()->log() << "Violation of maximum for initial-state " << " soft veto in " << "SMTopDecayer::softMatrixElementVeto" << "xg = " << xg << " xa = " << xa << "weight = " << wgt << "\n"; wgt=1.; } // compute veto from weight veto = !UseRandom::rndbool(wgt); } } // return the veto return veto; } // final-state correction else if(abs(progenitor->id())==ParticleID::b&&abs(parent->id())==ParticleID::b) { // check if hardest so far // if not just need to remove effect of enhancement // if not hardest so far if(ptlog() << "Imaginary root for final-state veto in " << "SMTopDecayer::softMatrixElementVeto" << "\nz = " << z << "\nkappa = " << kappa << "\nxa = " << xa << "\nroot^2= " << root; return true; } root=sqrt(root); double xg((2.-xa)*(1.-r)-(z-r)*root); // xfact (below) is supposed to equal xg/(1-z). double xfact(z*kappa/2./(z*(1.-z)*kappa+_c)*(2.-xa-root)+root); // calculate the full result double f(me(xa,xg)); // jacobian double J(z*root); double wgt(f*J*2.*kappa/(1.+sqr(z)-2.*_c/kappa/z)/sqr(xfact)/_finalenhance); if(wgt>1.) { generator()->log() << "Violation of maximum for final-state soft veto in " << "SMTopDecayer::softMatrixElementVeto" << "xg = " << xg << " xa = " << xa << "weight = " << wgt << "\n"; wgt=1.; } // compute veto from weight and return return !UseRandom::rndbool(wgt); } // otherwise don't veto else return !UseRandom::rndbool(1./_finalenhance); } double SMTopDecayer::me(double xw,double xg) { double prop(1.+_a-_c-xw),xg2(sqr(xg)); double lambda=sqrt(1.+_a*_a+_c*_c-2.*_a-2.*_c-2.*_a*_c); double denom=(1.-2*_a*_a+_a+_c*_a+_c*_c-2.*_c); double wgt=-_c*xg2/prop+(1.-_a+_c)*xg-(prop*(1 - xg)+xg2) +(0.5*(1.+2.*_a+_c)*sqr(prop-xg)*xg+2.*_a*prop*xg2)/denom; return wgt/(lambda*prop); } // xgbcut is the point along the xg axis where the upper bound on the // top quark (i.e. b) emission phase space goes back on itself in the // xa vs xg plane i.e. roughly mid-way along the xg axis in // the xa vs xg Dalitz plot. double SMTopDecayer::xgbcut(double kt) { double lambda2 = 1.+_a*_a+_c*_c-2.*_a-2.*_c-2.*_a*_c; double num1 = kt*kt*(1.-_a-_c); double num2 = 2.*kt*sqrt(_a*(kt*kt*_c+lambda2*(kt-1.))); return (num1-num2)/(kt*kt-4.*_a*(kt-1.)); } double SMTopDecayer::loME(const Particle & inpart, const ParticleVector & decay) { // spinors vector swave; vector awave; vector vwave; tPPtr Wboson = abs(decay[0]->id())==ParticleID::Wplus ? decay[0] : decay[1]; tPPtr bquark = abs(decay[0]->id())==ParticleID::Wplus ? decay[1] : decay[0]; // spinors if(inpart.id()>0) { SpinorWaveFunction ::calculateWaveFunctions(swave,const_ptr_cast(&inpart), incoming); SpinorBarWaveFunction::calculateWaveFunctions(awave,bquark,outgoing); } else { SpinorBarWaveFunction::calculateWaveFunctions(awave,const_ptr_cast(&inpart), incoming); SpinorWaveFunction ::calculateWaveFunctions(swave,bquark,outgoing); } // polarization vectors VectorWaveFunction::calculateWaveFunctions(vwave,Wboson,outgoing,false); Energy2 scale(sqr(inpart.mass())); double me=0.; if(inpart.id() == ParticleID::t) { for(unsigned int thel = 0; thel < 2; ++thel) { for(unsigned int bhel = 0; bhel < 2; ++bhel) { for(unsigned int whel = 0; whel < 3; ++whel) { Complex diag = FFWVertex_->evaluate(scale,swave[thel],awave[bhel],vwave[whel]); me += norm(diag); } } } } else if(inpart.id() == ParticleID::tbar) { for(unsigned int thel = 0; thel < 2; ++thel) { for(unsigned int bhel = 0; bhel < 2; ++bhel){ for(unsigned int whel = 0; whel < 3; ++whel) { Complex diag = FFWVertex_->evaluate(scale,swave[bhel],awave[thel],vwave[whel]); me += norm(diag); } } } } return me; } double SMTopDecayer::realME(const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter) { // vertex for emission from fermions AbstractFFVVertexPtr vertex = inter==ShowerInteraction::QCD ? FFGVertex_ : FFPVertex_; // spinors vector swave; vector awave; vector vwave,gwave; tPPtr Wboson = abs(decay[0]->id())==ParticleID::Wplus ? decay[0] : decay[1]; tPPtr bquark = abs(decay[0]->id())==ParticleID::Wplus ? decay[1] : decay[0]; // spinors if(inpart.id()>0) { SpinorWaveFunction ::calculateWaveFunctions(swave,const_ptr_cast(&inpart), incoming); SpinorBarWaveFunction::calculateWaveFunctions(awave,bquark,outgoing); } else { SpinorBarWaveFunction::calculateWaveFunctions(awave,const_ptr_cast(&inpart), incoming); SpinorWaveFunction ::calculateWaveFunctions(swave,bquark,outgoing); } // polarization vectors VectorWaveFunction::calculateWaveFunctions(vwave,Wboson,outgoing,false); VectorWaveFunction::calculateWaveFunctions(gwave,decay[2],outgoing,true ); Energy2 scale(sqr(inpart.mass())); double me=0.; vector diag(3,0.); if(inpart.id() == ParticleID::t) { for(unsigned int thel = 0; thel < 2; ++thel) { for(unsigned int bhel = 0; bhel < 2; ++bhel) { for(unsigned int whel = 0; whel < 3; ++whel) { for(unsigned int ghel =0; ghel <3; ghel+=2) { // emission from top SpinorWaveFunction interF = vertex->evaluate(scale,3,inpart.dataPtr(),swave[thel],gwave[ghel]); diag[0] = FFWVertex_->evaluate(scale,interF,awave[bhel],vwave[whel]); // emission from bottom SpinorBarWaveFunction interB = vertex->evaluate(scale,3,bquark->dataPtr()->CC(),awave[bhel],gwave[ghel]); diag[1] = FFWVertex_->evaluate(scale,swave[thel],interB,vwave[whel]); // emission from W if(inter==ShowerInteraction::QED) { VectorWaveFunction interV = WWWVertex_->evaluate(scale,3,Wboson->dataPtr()->CC(),vwave[whel],gwave[ghel]); diag[1] = FFWVertex_->evaluate(scale,swave[thel],awave[bhel],interV); } Complex sum = std::accumulate(diag.begin(),diag.end(),Complex(0.)); me += norm(sum); } } } } } else if(inpart.id() == ParticleID::tbar) { for(unsigned int thel = 0; thel < 2; ++thel) { for(unsigned int bhel = 0; bhel < 2; ++bhel){ for(unsigned int whel = 0; whel < 3; ++whel) { for(unsigned int ghel =0; ghel <3; ghel+=2) { // emission from top SpinorBarWaveFunction interB = vertex->evaluate(scale,3,inpart.dataPtr(),awave[thel],gwave[ghel]); diag[1] = FFWVertex_->evaluate(scale,swave[bhel],interB,vwave[whel]); // emission from bottom SpinorWaveFunction interF = vertex->evaluate(scale,3,bquark->dataPtr()->CC(),swave[bhel],gwave[ghel]); diag[0] = FFWVertex_->evaluate(scale,interF,awave[thel],vwave[whel]); // emission from W if(inter==ShowerInteraction::QED) { VectorWaveFunction interV = WWWVertex_->evaluate(scale,3,Wboson->dataPtr()->CC(),vwave[whel],gwave[ghel]); diag[1] = FFWVertex_->evaluate(scale,swave[bhel],awave[thel],interV); } Complex sum = std::accumulate(diag.begin(),diag.end(),Complex(0.)); me += norm(sum); } } } } } // divide out the coupling me /= norm(vertex->norm()); // return the total return me; } double SMTopDecayer::matrixElementRatio(const Particle & inpart, const ParticleVector & decay2, const ParticleVector & decay3, MEOption , ShowerInteraction inter) { double Nc = standardModel()->Nc(); double Cf = (sqr(Nc) - 1.) / (2.*Nc); // if(inter==ShowerInteraction::QED) return 0.; // double f = (1. + sqr(e2()) - 2.*sqr(s2()) + s2() + s2()*e2() - 2.*e2()); // // // double B = f/s2(); // Energy2 PbPg = decay3[0]->momentum()*decay3[2]->momentum(); // Energy2 PtPg = inpart.momentum()*decay3[2]->momentum(); // Energy2 PtPb = inpart.momentum()*decay3[0]->momentum(); // double R = Cf *((-4.*sqr(mb())*f/s2()) * ((sqr(mb())*e2()/sqr(PbPg)) + // (sqr(mb())/sqr(PtPg)) - 2.*(PtPb/(PtPg*PbPg))) + // (16. + 8./s2() + 8.*e2()/s2()) * ((PtPg/PbPg) + (PbPg/PtPg)) - // (16./s2()) * (1. + e2())); // return R/B*Constants::pi; double Bnew = loME(inpart,decay2); double Rnew = realME(inpart,decay3,inter); double output = Rnew/Bnew*4.*Constants::pi*sqr(inpart.mass())*UnitRemoval::InvE2; if(inter==ShowerInteraction::QCD) output *= Cf; return output; } diff --git a/Decay/Perturbative/SMWDecayer.cc b/Decay/Perturbative/SMWDecayer.cc --- a/Decay/Perturbative/SMWDecayer.cc +++ b/Decay/Perturbative/SMWDecayer.cc @@ -1,740 +1,742 @@ // -*- C++ -*- // // SMWDecayer.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 SMWDecayer class. // #include "SMWDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/ParVector.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "Herwig/Decay/DecayVertex.h" #include "ThePEG/Helicity/VectorSpinInfo.h" #include "ThePEG/Helicity/FermionSpinInfo.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "Herwig/Shower/RealEmissionProcess.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include using namespace Herwig; using namespace ThePEG::Helicity; const double SMWDecayer::EPS_=0.00000001; SMWDecayer::SMWDecayer() : quarkWeight_(6,0.), leptonWeight_(3,0.), CF_(4./3.), NLO_(false) { quarkWeight_[0] = 1.01596; quarkWeight_[1] = 0.0537308; quarkWeight_[2] = 0.0538085; quarkWeight_[3] = 1.01377; quarkWeight_[4] = 1.45763e-05; quarkWeight_[5] = 0.0018143; leptonWeight_[0] = 0.356594; leptonWeight_[1] = 0.356593; leptonWeight_[2] = 0.356333; // intermediates generateIntermediates(false); } void SMWDecayer::doinit() { PerturbativeDecayer::doinit(); // get the vertices from the Standard Model object tcHwSMPtr hwsm=dynamic_ptr_cast(standardModel()); if(!hwsm) throw InitException() << "Must have Herwig StandardModel object in" << "SMWDecayer::doinit()" << Exception::runerror; FFWVertex_ = hwsm->vertexFFW(); FFGVertex_ = hwsm->vertexFFG(); WWWVertex_ = hwsm->vertexWWW(); FFPVertex_ = hwsm->vertexFFP(); // make sure they are initialized FFGVertex_->init(); FFWVertex_->init(); WWWVertex_->init(); FFPVertex_->init(); // now set up the decay modes DecayPhaseSpaceModePtr mode; tPDVector extpart(3); vector wgt(0); // W modes extpart[0]=getParticleData(ParticleID::Wplus); // loop for the quarks unsigned int iz=0; for(int ix=1;ix<6;ix+=2) { for(int iy=2;iy<6;iy+=2) { // check that the combination of particles is allowed if(!FFWVertex_->allowed(-ix,iy,ParticleID::Wminus)) throw InitException() << "SMWDecayer::doinit() the W vertex" << "cannot handle all the quark modes" << Exception::abortnow; extpart[1] = getParticleData(-ix); extpart[2] = getParticleData( iy); mode = new_ptr(DecayPhaseSpaceMode(extpart,this)); addMode(mode,quarkWeight_[iz],wgt); ++iz; } } // loop for the leptons for(int ix=11;ix<17;ix+=2) { // check that the combination of particles is allowed // if(!FFWVertex_->allowed(-ix,ix+1,ParticleID::Wminus)) // throw InitException() << "SMWDecayer::doinit() the W vertex" // << "cannot handle all the lepton modes" // << Exception::abortnow; extpart[1] = getParticleData(-ix); extpart[2] = getParticleData(ix+1); mode = new_ptr(DecayPhaseSpaceMode(extpart,this)); addMode(mode,leptonWeight_[(ix-11)/2],wgt); } gluon_ = getParticleData(ParticleID::g); } int SMWDecayer::modeNumber(bool & cc,tcPDPtr parent, const tPDVector & children) const { int imode(-1); if(children.size()!=2) return imode; int id0=parent->id(); tPDVector::const_iterator pit = children.begin(); int id1=(**pit).id(); ++pit; int id2=(**pit).id(); if(abs(id0)!=ParticleID::Wplus) return imode; int idd(0),idu(0); if(abs(id1)%2==1&&abs(id2)%2==0) { idd=abs(id1); idu=abs(id2); } else if(abs(id1)%2==0&&abs(id2)%2==1) { idd=abs(id2); idu=abs(id1); } if(idd==0&&idu==0) { return imode; } else if(idd<=5) { imode=idd+idu/2-2; } else { imode=(idd-1)/2+1; } cc= (id0==ParticleID::Wminus); return imode; } void SMWDecayer::persistentOutput(PersistentOStream & os) const { os << FFWVertex_ << quarkWeight_ << leptonWeight_ << FFGVertex_ << gluon_ << NLO_ << WWWVertex_ << FFPVertex_; } void SMWDecayer::persistentInput(PersistentIStream & is, int) { is >> FFWVertex_ >> quarkWeight_ >> leptonWeight_ >> FFGVertex_ >> gluon_ >> NLO_ >> WWWVertex_ >> FFPVertex_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSMWDecayer("Herwig::SMWDecayer", "HwPerturbativeDecay.so"); void SMWDecayer::Init() { static ClassDocumentation documentation ("The SMWDecayer class is the implementation of the decay" " of the W boson to the Standard Model fermions."); static ParVector interfaceWquarkMax ("QuarkMax", "The maximum weight for the decay of the W to quarks", &SMWDecayer::quarkWeight_, 0, 0, 0, -10000, 10000, false, false, true); static ParVector interfaceWleptonMax ("LeptonMax", "The maximum weight for the decay of the W to leptons", &SMWDecayer::leptonWeight_, 0, 0, 0, -10000, 10000, false, false, true); static Switch interfaceNLO ("NLO", "Whether to return the LO or NLO result", &SMWDecayer::NLO_, false, false, false); static SwitchOption interfaceNLOLO (interfaceNLO, "No", "Leading-order result", false); static SwitchOption interfaceNLONLO (interfaceNLO, "Yes", "NLO result", true); } // return the matrix element squared double SMWDecayer::me2(const int, const Particle & part, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1Half,PDT::Spin1Half))); int iferm(1),ianti(0); if(decay[0]->id()>0) swap(iferm,ianti); if(meopt==Initialize) { VectorWaveFunction::calculateWaveFunctions(vectors_,rho_, const_ptr_cast(&part), incoming,false); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { VectorWaveFunction::constructSpinInfo(vectors_,const_ptr_cast(&part), incoming,true,false); SpinorBarWaveFunction:: constructSpinInfo(wavebar_,decay[iferm],outgoing,true); SpinorWaveFunction:: constructSpinInfo(wave_ ,decay[ianti],outgoing,true); return 0.; } SpinorBarWaveFunction:: calculateWaveFunctions(wavebar_,decay[iferm],outgoing); SpinorWaveFunction:: calculateWaveFunctions(wave_ ,decay[ianti],outgoing); // compute the matrix element Energy2 scale(sqr(part.mass())); for(unsigned int ifm=0;ifm<2;++ifm) { for(unsigned int ia=0;ia<2;++ia) { for(unsigned int vhel=0;vhel<3;++vhel) { if(iferm>ianti) (*ME())(vhel,ia,ifm)= FFWVertex_->evaluate(scale,wave_[ia],wavebar_[ifm],vectors_[vhel]); else (*ME())(vhel,ifm,ia)= FFWVertex_->evaluate(scale,wave_[ia],wavebar_[ifm],vectors_[vhel]); } } } double output=(ME()->contract(rho_)).real()*UnitRemoval::E2/scale; if(abs(decay[0]->id())<=6) output*=3.; if(decay[0]->hasColour()) decay[0]->antiColourNeighbour(decay[1]); else if(decay[1]->hasColour()) decay[1]->antiColourNeighbour(decay[0]); // leading-order result if(!NLO_) return output; // check decay products coloured, otherwise return if(!decay[0]->dataPtr()->coloured()) return output; // inital masses, couplings etc // W mass mW_ = part.mass(); // strong coupling aS_ = SM().alphaS(sqr(mW_)); // reduced mass double mu1 = (decay[0]->dataPtr()->mass())/mW_; double mu2 = (decay[1]->dataPtr()->mass())/mW_; // scale scale_ = sqr(mW_); // now for the nlo loop correction double virt = CF_*aS_/Constants::pi; // now for the real correction double realFact=0.; for(int iemit=0;iemit<2;++iemit) { double phi = UseRandom::rnd()*Constants::twopi; // set the emitter and the spectator double muj = iemit==0 ? mu1 : mu2; double muk = iemit==0 ? mu2 : mu1; double muj2 = sqr(muj); double muk2 = sqr(muk); // calculate y double yminus = 0.; double yplus = 1.-2.*muk*(1.-muk)/(1.-muj2-muk2); double y = yminus + UseRandom::rnd()*(yplus-yminus); double v = sqrt(sqr(2.*muk2 + (1.-muj2-muk2)*(1.-y))-4.*muk2) /(1.-muj2-muk2)/(1.-y); double zplus = (1.+v)*(1.-muj2-muk2)*y/2./(muj2+(1.-muj2-muk2)*y); double zminus = (1.-v)*(1.-muj2-muk2)*y/2./(muj2+(1.-muj2-muk2)*y); double z = zminus + UseRandom::rnd()*(zplus-zminus); double jac = (1.-y)*(yplus-yminus)*(zplus-zminus); // calculate x1,x2,x3,xT double x2 = 1.-y*(1.-muj2-muk2)-muj2+muk2; double x1 = 1.+muj2-muk2-z*(x2-2.*muk2); // copy the particle objects over for calculateRealEmission vector hardProcess(3); hardProcess[0] = const_ptr_cast(&part); hardProcess[1] = decay[0]; hardProcess[2] = decay[1]; realFact += 0.25*jac*sqr(1.-muj2-muk2)/ sqrt((1.-sqr(muj-muk))*(1.-sqr(muj+muk)))/Constants::twopi *2.*CF_*aS_*calculateRealEmission(x1, x2, hardProcess, phi, muj, muk, iemit, true); } // the born + virtual + real output *= (1. + virt + realFact); return output; } void SMWDecayer::doinitrun() { PerturbativeDecayer::doinitrun(); if(initialize()) { for(unsigned int ix=0;ixmaxWeight(); else leptonWeight_[ix-6]=mode(ix)->maxWeight(); } } } void SMWDecayer::dataBaseOutput(ofstream & output, bool header) const { if(header) output << "update decayers set parameters=\""; for(unsigned int ix=0;ixbornOutgoing().size();++ix) qq.push_back(born->bornOutgoing()[ix]); // ensure quark first if(qq[0]->id()<0) swap(qq[0],qq[1]); // centre of mass energy d_Q_ = (qq[0]->momentum() + qq[1]->momentum()).m(); // quark mass d_m_ = 0.5*(qq[0]->momentum().m()+qq[1]->momentum().m()); // set the other parameters setRho(sqr(d_m_/d_Q_)); setKtildeSymm(); // otherwise can do it initial=1.; final =1.; } bool SMWDecayer::softMatrixElementVeto(PPtr parent, PPtr progenitor, const bool & , const Energy & highestpT, const vector & ids, const double & d_z, const Energy & d_qt, const Energy & ) { // check we should be applying the veto if(parent->id()!=progenitor->id()|| ids[0]!=ids[1]|| ids[2]->id()!=ParticleID::g) return false; // calculate pt Energy2 d_m2 = parent->momentum().m2(); Energy2 pPerp2 = sqr(d_z*d_qt) - d_m2; if(pPerp2id()>0) weight = qWeightX(d_qt, d_z); else weight = qbarWeightX(d_qt, d_z); // compute veto from weight and return return !UseRandom::rndbool(weight); } void SMWDecayer::setRho(double r) { d_rho_ = r; d_v_ = sqrt(1.-4.*d_rho_); } void SMWDecayer::setKtildeSymm() { d_kt1_ = (1. + sqrt(1. - 4.*d_rho_))/2.; setKtilde2(); } void SMWDecayer::setKtilde2() { double num = d_rho_ * d_kt1_ + 0.25 * d_v_ *(1.+d_v_)*(1.+d_v_); double den = d_kt1_ - d_rho_; d_kt2_ = num/den; } double SMWDecayer::getZfromX(double x1, double x2) { double uval = u(x2); double num = x1 - (2. - x2)*uval; double den = sqrt(x2*x2 - 4.*d_rho_); return uval + num/den; } double SMWDecayer::getKfromX(double x1, double x2) { double zval = getZfromX(x1, x2); return (1.-x2)/(zval*(1.-zval)); } double SMWDecayer::MEV(double x1, double x2) { // Vector part double num = (x1+2.*d_rho_)*(x1+2.*d_rho_) + (x2+2.*d_rho_)*(x2+2.*d_rho_) - 8.*d_rho_*(1.+2.*d_rho_); double den = (1.+2.*d_rho_)*(1.-x1)*(1.-x2); return (num/den - 2.*d_rho_/((1.-x1)*(1.-x1)) - 2*d_rho_/((1.-x2)*(1.-x2)))/d_v_; } double SMWDecayer::MEA(double x1, double x2) { // Axial part double num = (x1+2.*d_rho_)*(x1+2.*d_rho_) + (x2+2.*d_rho_)*(x2+2.*d_rho_) + 2.*d_rho_*((5.-x1-x2)*(5.-x1-x2) - 19.0 + 4*d_rho_); double den = d_v_*d_v_*(1.-x1)*(1.-x2); return (num/den - 2.*d_rho_/((1.-x1)*(1.-x1)) - 2*d_rho_/((1.-x2)*(1.-x2)))/d_v_; } double SMWDecayer::u(double x2) { return 0.5*(1. + d_rho_/(1.-x2+d_rho_)); } void SMWDecayer:: getXXbar(double kti, double z, double &x, double &xbar) { double w = sqr(d_v_) + kti*(-1. + z)*z*(2. + kti*(-1. + z)*z); if (w < 0) { x = -1.; xbar = -1; } else { x = (1. + sqr(d_v_)*(-1. + z) + sqr(kti*(-1. + z))*z*z*z + z*sqrt(w) - kti*(-1. + z)*z*(2. + z*(-2 + sqrt(w))))/ (1. - kti*(-1. + z)*z + sqrt(w)); xbar = 1. + kti*(-1. + z)*z; } } double SMWDecayer::qWeight(double x, double xbar) { double rval; double xg = 2. - xbar - x; // always return one in the soft gluon region if(xg < EPS_) return 1.0; // check it is in the phase space if((1.-x)*(1.-xbar)*(1.-xg) < d_rho_*xg*xg) return 0.0; double k1 = getKfromX(x, xbar); double k2 = getKfromX(xbar, x); // Is it in the quark emission zone? if(k1 < d_kt1_) { rval = MEV(x, xbar)/PS(x, xbar); // is it also in the anti-quark emission zone? if(k2 < d_kt2_) rval *= 0.5; return rval; } return 1.0; } double SMWDecayer::qbarWeight(double x, double xbar) { double rval; double xg = 2. - xbar - x; // always return one in the soft gluon region if(xg < EPS_) return 1.0; // check it is in the phase space if((1.-x)*(1.-xbar)*(1.-xg) < d_rho_*xg*xg) return 0.0; double k1 = getKfromX(x, xbar); double k2 = getKfromX(xbar, x); // Is it in the antiquark emission zone? if(k2 < d_kt2_) { rval = MEV(x, xbar)/PS(xbar, x); // is it also in the quark emission zone? if(k1 < d_kt1_) rval *= 0.5; return rval; } return 1.0; } double SMWDecayer::qWeightX(Energy qtilde, double z) { double x, xb; getXXbar(sqr(qtilde/d_Q_), z, x, xb); // if exceptionally out of phase space, leave this emission, as there // is no good interpretation for the soft ME correction. if (x < 0 || xb < 0) return 1.0; return qWeight(x, xb); } double SMWDecayer::qbarWeightX(Energy qtilde, double z) { double x, xb; getXXbar(sqr(qtilde/d_Q_), z, xb, x); // see above in qWeightX. if (x < 0 || xb < 0) return 1.0; return qbarWeight(x, xb); } double SMWDecayer::PS(double x, double xbar) { double u = 0.5*(1. + d_rho_ / (1.-xbar+d_rho_)); double z = u + (x - (2.-xbar)*u)/sqrt(xbar*xbar - 4.*d_rho_); double brack = (1.+z*z)/(1.-z)- 2.*d_rho_/(1-xbar); // interesting: the splitting function without the subtraction // term. Actually gives a much worse approximation in the collinear // limit. double brack = (1.+z*z)/(1.-z); double den = (1.-xbar)*sqrt(xbar*xbar - 4.*d_rho_); return brack/den; } double SMWDecayer::matrixElementRatio(const Particle & inpart, const ParticleVector & decay2, const ParticleVector & decay3, MEOption, ShowerInteraction inter) { // extract partons and LO momentas vector partons(1,inpart.dataPtr()); vector lomom(1,inpart.momentum()); for(unsigned int ix=0;ix<2;++ix) { partons.push_back(decay2[ix]->dataPtr()); lomom.push_back(decay2[ix]->momentum()); } vector realmom(1,inpart.momentum()); for(unsigned int ix=0;ix<3;++ix) { if(ix==2) partons.push_back(decay3[ix]->dataPtr()); realmom.push_back(decay3[ix]->momentum()); } if(partons[0]->id()<0) { swap(partons[1],partons[2]); swap(lomom[1],lomom[2]); swap(realmom[1],realmom[2]); } scale_ = sqr(inpart.mass()); double lome = loME(partons,lomom); InvEnergy2 reme = realME(partons,realmom,inter); double ratio = reme/lome*sqr(inpart.mass())*4.*Constants::pi; if(inter==ShowerInteraction::QCD) ratio *= CF_; return ratio; } double SMWDecayer::meRatio(vector partons, vector momenta, unsigned int iemitter, bool subtract) const { Lorentz5Momentum q = momenta[1]+momenta[2]+momenta[3]; Energy2 Q2=q.m2(); Energy2 lambda = sqrt((Q2-sqr(momenta[1].mass()+momenta[2].mass()))* (Q2-sqr(momenta[1].mass()-momenta[2].mass()))); InvEnergy2 D[2]; double lome(0.); for(unsigned int iemit=0;iemit<2;++iemit) { unsigned int ispect = iemit==0 ? 1 : 0; Energy2 pipj = momenta[3 ] * momenta[1+iemit ]; Energy2 pipk = momenta[3 ] * momenta[1+ispect]; Energy2 pjpk = momenta[1+iemit] * momenta[1+ispect]; double y = pipj/(pipj+pipk+pjpk); double z = pipk/( pipk+pjpk); Energy mij = sqrt(2.*pipj+sqr(momenta[1+iemit].mass())); Energy2 lamB = sqrt((Q2-sqr(mij+momenta[1+ispect].mass()))* (Q2-sqr(mij-momenta[1+ispect].mass()))); Energy2 Qpk = q*momenta[1+ispect]; Lorentz5Momentum pkt = lambda/lamB*(momenta[1+ispect]-Qpk/Q2*q) +0.5/Q2*(Q2+sqr(momenta[1+ispect].mass())-sqr(momenta[1+ispect].mass()))*q; Lorentz5Momentum pijt = q-pkt; double muj = momenta[1+iemit ].mass()/sqrt(Q2); double muk = momenta[1+ispect].mass()/sqrt(Q2); double vt = sqrt((1.-sqr(muj+muk))*(1.-sqr(muj-muk)))/(1.-sqr(muj)-sqr(muk)); double v = sqrt(sqr(2.*sqr(muk)+(1.-sqr(muj)-sqr(muk))*(1.-y))-4.*sqr(muk)) /(1.-y)/(1.-sqr(muj)-sqr(muk)); // dipole term D[iemit] = 0.5/pipj*(2./(1.-(1.-z)*(1.-y)) -vt/v*(2.-z+sqr(momenta[1+iemit].mass())/pipj)); // matrix element vector lomom(3); lomom[0] = momenta[0]; if(iemit==0) { lomom[1] = pijt; lomom[2] = pkt ; } else { lomom[2] = pijt; lomom[1] = pkt ; } if(iemit==0) lome = loME(partons,lomom); } InvEnergy2 ratio = realME(partons,momenta,ShowerInteraction::QCD)/lome*abs(D[iemitter]) /(abs(D[0])+abs(D[1])); if(subtract) return Q2*(ratio-2.*D[iemitter]); else return Q2*ratio; } double SMWDecayer::loME(const vector & partons, const vector & momenta) const { // compute the spinors vector vin; vector aout; vector fout; VectorWaveFunction win (momenta[0],partons[0],incoming); SpinorBarWaveFunction qkout(momenta[1],partons[1],outgoing); SpinorWaveFunction qbout(momenta[2],partons[2],outgoing); for(unsigned int ix=0;ix<2;++ix){ qkout.reset(ix); fout.push_back(qkout); qbout.reset(ix); aout.push_back(qbout); } for(unsigned int ix=0;ix<3;++ix){ win.reset(ix); vin.push_back(win); } // temporary storage of the different diagrams // sum over helicities to get the matrix element double total(0.); for(unsigned int inhel=0;inhel<3;++inhel) { for(unsigned int outhel1=0;outhel1<2;++outhel1) { for(unsigned int outhel2=0;outhel2<2;++outhel2) { Complex diag1 = FFWVertex_->evaluate(scale_,aout[outhel2],fout[outhel1],vin[inhel]); total += norm(diag1); } } } // return the answer return total; } InvEnergy2 SMWDecayer::realME(const vector & partons, const vector & momenta, ShowerInteraction inter) const { // compute the spinors vector vin; vector aout; vector fout; vector gout; VectorWaveFunction win (momenta[0],partons[0],incoming); SpinorBarWaveFunction qkout(momenta[1],partons[1],outgoing); SpinorWaveFunction qbout(momenta[2],partons[2],outgoing); VectorWaveFunction gluon(momenta[3],partons[3],outgoing); for(unsigned int ix=0;ix<2;++ix){ qkout.reset(ix); fout.push_back(qkout); qbout.reset(ix); aout.push_back(qbout); gluon.reset(2*ix); gout.push_back(gluon); } for(unsigned int ix=0;ix<3;++ix){ win.reset(ix); vin.push_back(win); } vector diag(3,0.); double total(0.); AbstractFFVVertexPtr vertex = inter==ShowerInteraction::QCD ? FFGVertex_ : FFPVertex_; for(unsigned int inhel1=0;inhel1<3;++inhel1) { for(unsigned int outhel1=0;outhel1<2;++outhel1) { for(unsigned int outhel2=0;outhel2<2;++outhel2) { for(unsigned int outhel3=0;outhel3<2;++outhel3) { SpinorBarWaveFunction off1 = vertex->evaluate(scale_,3,partons[1]->CC(),fout[outhel1],gout[outhel3]); diag[0] = FFWVertex_->evaluate(scale_,aout[outhel2],off1,vin[inhel1]); SpinorWaveFunction off2 = vertex->evaluate(scale_,3,partons[2]->CC(),aout[outhel2],gout[outhel3]); diag[1] = FFWVertex_->evaluate(scale_,off2,fout[outhel1],vin[inhel1]); if(inter==ShowerInteraction::QED) { VectorWaveFunction off3 = WWWVertex_->evaluate(scale_,3,partons[0],vin[inhel1],gout[outhel3]); diag[2] = FFWVertex_->evaluate(scale_,aout[outhel2],fout[outhel1],off3); } // sum of diagrams Complex sum = std::accumulate(diag.begin(),diag.end(),Complex(0.)); // me2 total += norm(sum); } } } } // divide out the coupling total /= norm(vertex->norm()); // double g = sqrt(2.)*abs(FFWVertex_->norm()); // double xg = 2.*momenta[3].t()/momenta[0].mass(); // double xe,mue2; // if(abs(partons[1]->id())==ParticleID::eminus) { // xe = 2.*momenta[1].t()/momenta[0].mass(); // mue2 = sqr(momenta[1].mass()/momenta[0].mass()); // } // else { // xe = 2.*momenta[2].t()/momenta[0].mass(); // mue2 = sqr(momenta[2].mass()/momenta[0].mass()); // } // double cg = -4. * g * g * (-pow(mue2, 3.) / 2. + (xg * xg / 4. + (xe / 2. + 1.) * xg + 5. / 2. * xe - 2.) * mue2 * mue2 // + (pow(xg, 3.) / 4. + (xe / 4. - 5. / 4.) * xg * xg + (-7. / 2. * xe + 3.) * xg - 3. * xe * xe // + 11. / 2. * xe - 7. / 2.) * mue2 + (xg * xg / 2. + (xe - 2.) * xg + xe * xe - 2. * xe + 2.) * (-1. + xg + xe)) * (xe - mue2 - 1.) * // pow(xg, -2.) * pow(-1. + xg + xe - mue2, -2.); // cerr << "real " << cg/total << "\n"; // return the total return total*UnitRemoval::InvE2; } double SMWDecayer::calculateRealEmission(double x1, double x2, vector hardProcess, double phi, double muj, double muk, int iemit, bool subtract) const { // make partons data object for meRatio vector partons (3); for(int ix=0; ix<3; ++ix) partons[ix] = hardProcess[ix]->dataPtr(); partons.push_back(gluon_); // calculate x3 double x3 = 2.-x1-x2; double xT = sqrt(max(0.,sqr(x3)-0.25*sqr(sqr(x2)+sqr(x3)-sqr(x1)-4.*sqr(muk)+4.*sqr(muj)) /(sqr(x2)-4.*sqr(muk)))); // calculate the momenta Energy M = mW_; Lorentz5Momentum pspect(ZERO,ZERO,-0.5*M*sqrt(max(sqr(x2)-4.*sqr(muk),0.)), 0.5*M*x2,M*muk); Lorentz5Momentum pemit (-0.5*M*xT*cos(phi),-0.5*M*xT*sin(phi), 0.5*M*sqrt(max(sqr(x1)-sqr(xT)-4.*sqr(muj),0.)), 0.5*M*x1,M*muj); Lorentz5Momentum pgluon(0.5*M*xT*cos(phi), 0.5*M*xT*sin(phi), 0.5*M*sqrt(max(sqr(x3)-sqr(xT),0.)),0.5*M*x3,ZERO); if(abs(pspect.z()+pemit.z()-pgluon.z())/M<1e-6) pgluon.setZ(-pgluon.z()); else if(abs(pspect.z()-pemit.z()+pgluon.z())/M<1e-6) pemit .setZ(- pemit.z()); // boost and rotate momenta LorentzRotation eventFrame( ( hardProcess[1]->momentum() + hardProcess[2]->momentum() ).findBoostToCM() ); Lorentz5Momentum spectator = eventFrame*hardProcess[iemit+1]->momentum(); eventFrame.rotateZ( -spectator.phi() ); eventFrame.rotateY( -spectator.theta() ); eventFrame.invert(); vector momenta(3); momenta[0] = hardProcess[0]->momentum(); if(iemit==0) { momenta[2] = eventFrame*pspect; momenta[1] = eventFrame*pemit ; } else { momenta[1] = eventFrame*pspect; momenta[2] = eventFrame*pemit ; } momenta.push_back(eventFrame*pgluon); // calculate the weight double realwgt(0.); if(1.-x1>1e-5 && 1.-x2>1e-5) realwgt = meRatio(partons,momenta,iemit,subtract); return realwgt; } diff --git a/Decay/Perturbative/SMZDecayer.cc b/Decay/Perturbative/SMZDecayer.cc --- a/Decay/Perturbative/SMZDecayer.cc +++ b/Decay/Perturbative/SMZDecayer.cc @@ -1,1119 +1,1121 @@ // -*- C++ -*- // // SMZDecayer.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 SMZDecayer class. // #include "SMZDecayer.h" #include "Herwig/Utilities/Maths.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/ParVector.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "Herwig/Decay/DecayVertex.h" #include "ThePEG/Helicity/VectorSpinInfo.h" #include "ThePEG/Helicity/FermionSpinInfo.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "Herwig/Shower/RealEmissionProcess.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include using namespace Herwig; using namespace ThePEG::Helicity; const double SMZDecayer::EPS_=0.00000001; SMZDecayer::SMZDecayer() : quarkWeight_(5,0.), leptonWeight_(6,0.), CF_(4./3.), NLO_(false) { quarkWeight_[0] = 0.488029; quarkWeight_[1] = 0.378461; quarkWeight_[2] = 0.488019; quarkWeight_[3] = 0.378027; quarkWeight_[4] = 0.483207; leptonWeight_[0] = 0.110709; leptonWeight_[1] = 0.220276; leptonWeight_[2] = 0.110708; leptonWeight_[3] = 0.220276; leptonWeight_[4] = 0.110458; leptonWeight_[5] = 0.220276; // intermediates generateIntermediates(false); // QED corrections hasRealEmissionME(true); hasOneLoopME(true); } void SMZDecayer::doinit() { PerturbativeDecayer::doinit(); // get the vertices from the Standard Model object tcHwSMPtr hwsm=dynamic_ptr_cast(standardModel()); if(!hwsm) throw InitException() << "Must have Herwig StandardModel object in" << "SMZDecayer::doinit()" << Exception::runerror; // cast the vertices FFZVertex_ = dynamic_ptr_cast(hwsm->vertexFFZ()); FFZVertex_->init(); FFGVertex_ = hwsm->vertexFFG(); FFGVertex_->init(); FFPVertex_ = hwsm->vertexFFP(); FFPVertex_->init(); gluon_ = getParticleData(ParticleID::g); // now set up the decay modes DecayPhaseSpaceModePtr mode; tPDVector extpart(3); vector wgt(0); // the Z decay modes extpart[0]=getParticleData(ParticleID::Z0); // loop over the quarks and the leptons for(int istep=0;istep<11;istep+=10) { for(int ix=1;ix<7;++ix) { int iy=istep+ix; if(iy==6) continue; extpart[1] = getParticleData(-iy); extpart[2] = getParticleData( iy); mode = new_ptr(DecayPhaseSpaceMode(extpart,this)); if(iy<=6) addMode(mode, quarkWeight_.at(ix-1),wgt); else addMode(mode,leptonWeight_.at(iy-11),wgt); } } } int SMZDecayer::modeNumber(bool & cc,tcPDPtr parent, const tPDVector & children) const { int imode(-1); if(children.size()!=2) return imode; int id0=parent->id(); tPDVector::const_iterator pit = children.begin(); int id1=(**pit).id(); ++pit; int id2=(**pit).id(); // Z to quarks or leptons cc =false; if(id0!=ParticleID::Z0) return imode; if(abs(id1)<6&&id1==-id2) { imode=abs(id1)-1; } else if(abs(id1)>=11&&abs(id1)<=16&&id1==-id2) { imode=abs(id1)-6; } cc = false; return imode; } void SMZDecayer::persistentOutput(PersistentOStream & os) const { os << FFZVertex_ << FFPVertex_ << FFGVertex_ << quarkWeight_ << leptonWeight_ << NLO_ << gluon_; } void SMZDecayer::persistentInput(PersistentIStream & is, int) { is >> FFZVertex_ >> FFPVertex_ >> FFGVertex_ >> quarkWeight_ >> leptonWeight_ >> NLO_ >> gluon_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSMZDecayer("Herwig::SMZDecayer", "HwPerturbativeDecay.so"); void SMZDecayer::Init() { static ClassDocumentation documentation ("The SMZDecayer class is the implementation of the decay" " Z boson to the Standard Model fermions."); static ParVector interfaceZquarkMax ("QuarkMax", "The maximum weight for the decay of the Z to quarks", &SMZDecayer::quarkWeight_, 0, 0, 0, -10000, 10000, false, false, true); static ParVector interfaceZleptonMax ("LeptonMax", "The maximum weight for the decay of the Z to leptons", &SMZDecayer::leptonWeight_, 0, 0, 0, -10000, 10000, false, false, true); static Switch interfaceNLO ("NLO", "Whether to return the LO or NLO result", &SMZDecayer::NLO_, false, false, false); static SwitchOption interfaceNLOLO (interfaceNLO, "No", "Leading-order result", false); static SwitchOption interfaceNLONLO (interfaceNLO, "Yes", "NLO result", true); } // return the matrix element squared double SMZDecayer::me2(const int, const Particle & part, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1Half,PDT::Spin1Half))); int iferm(1),ianti(0); if(decay[0]->id()>0) swap(iferm,ianti); if(meopt==Initialize) { VectorWaveFunction::calculateWaveFunctions(_vectors,_rho, const_ptr_cast(&part), incoming,false); + // fix rho if no correlations + fixRho(_rho); } if(meopt==Terminate) { VectorWaveFunction::constructSpinInfo(_vectors,const_ptr_cast(&part), incoming,true,false); SpinorBarWaveFunction:: constructSpinInfo(_wavebar,decay[iferm],outgoing,true); SpinorWaveFunction:: constructSpinInfo(_wave ,decay[ianti],outgoing,true); return 0.; } SpinorBarWaveFunction:: calculateWaveFunctions(_wavebar,decay[iferm],outgoing); SpinorWaveFunction:: calculateWaveFunctions(_wave ,decay[ianti],outgoing); // compute the matrix element Energy2 scale(sqr(part.mass())); unsigned int ifm,ia,vhel; for(ifm=0;ifm<2;++ifm) { for(ia=0;ia<2;++ia) { for(vhel=0;vhel<3;++vhel) { if(iferm>ianti) (*ME())(vhel,ia,ifm)= FFZVertex_->evaluate(scale,_wave[ia],_wavebar[ifm],_vectors[vhel]); else (*ME())(vhel,ifm,ia)= FFZVertex_->evaluate(scale,_wave[ia],_wavebar[ifm],_vectors[vhel]); } } } double output=(ME()->contract(_rho)).real()*UnitRemoval::E2/scale; if(abs(decay[0]->id())<=6) output*=3.; if(decay[0]->hasColour()) decay[0]->antiColourNeighbour(decay[1]); else if(decay[1]->hasColour()) decay[1]->antiColourNeighbour(decay[0]); // if LO return if(!NLO_) return output; // check decay products coloured, otherwise return if(!decay[0]->dataPtr()->coloured()) return output; // inital masses, couplings etc // fermion mass Energy particleMass = decay[0]->dataPtr()->mass(); // Z mass mZ_ = part.mass(); // strong coupling aS_ = SM().alphaS(sqr(mZ_)); // reduced mass mu_ = particleMass/mZ_; mu2_ = sqr(mu_); // scale scale_ = sqr(mZ_); // compute the spinors vector aout; vector fout; vector vin; SpinorBarWaveFunction qkout(decay[0]->momentum(),decay[0]->dataPtr(),outgoing); SpinorWaveFunction qbout(decay[1]->momentum(),decay[1]->dataPtr(),outgoing); VectorWaveFunction zin (part.momentum() ,part.dataPtr() ,incoming); for(unsigned int ix=0;ix<2;++ix){ qkout.reset(ix); fout.push_back(qkout); qbout.reset(ix); aout.push_back(qbout); } for(unsigned int ix=0;ix<3;++ix){ zin.reset(ix); vin.push_back(zin); } // temporary storage of the different diagrams // sum over helicities to get the matrix element double total=0.; if(mu_!=0.) { LorentzPolarizationVector momDiff = (decay[0]->momentum()-decay[1]->momentum())/2./ (decay[0]->momentum().mass()+decay[1]->momentum().mass()); // scalars Complex scalar1 = zin.wave().dot(momDiff); for(unsigned int outhel1=0;outhel1<2;++outhel1) { for(unsigned int outhel2=0;outhel2<2;++outhel2) { for(unsigned int inhel=0;inhel<3;++inhel) { // first the LO bit Complex diag1 = FFZVertex_->evaluate(scale_,aout[outhel2], fout[outhel1],vin[inhel]); // extra stuff for NLO LorentzPolarizationVector left = aout[outhel2].wave().leftCurrent(fout[outhel1].wave()); LorentzPolarizationVector right = aout[outhel2].wave().rightCurrent(fout[outhel1].wave()); Complex scalar = aout[outhel2].wave().scalar(fout[outhel1].wave()); // nlo specific pieces Complex diag3 = Complex(0.,1.)*FFZVertex_->norm()* (FFZVertex_->right()*( left.dot(zin.wave())) + FFZVertex_-> left()*(right.dot(zin.wave())) - ( FFZVertex_-> left()+FFZVertex_->right())*scalar1*scalar); // nlo piece total += real(diag1*conj(diag3) + diag3*conj(diag1)); } } } // rescale total *= UnitRemoval::E2/scale_; } else { total = ZERO; } // now for the NLO bit double mu4 = sqr(mu2_); double lmu = mu_!=0. ? log(mu_) : 0.; double v = sqrt(1.-4.*mu2_),v2(sqr(v)); double omv = 4.*mu2_/(1.+v); double f1,f2,fNS,VNS; double r = omv/(1.+v); double lr = mu_!=0. ? log(r) : 0.; // normal form if(mu_>1e-4) { f1 = CF_*aS_/Constants::pi* ( +1. + 3.*log(0.5*(1.+v)) - 1.5*log(0.5*(1.+v2)) + sqr(Constants::pi)/6. - 0.5*sqr(lr) - (1.+v2)/v*(lr*log(1.+v2) + sqr(Constants::pi)/12. -0.5*log(4.*mu2_)*lr + 0.25*sqr(lr))); fNS = -0.5*(1.+2.*v2)*lr/v + 1.5*lr - 2./3.*sqr(Constants::pi) + 0.5*sqr(lr) + (1.+v2)/v*(Herwig::Math::ReLi2(r) + sqr(Constants::pi)/3. - 0.25*sqr(lr) + lr*log((2.*v/ (1.+v)))); VNS = 1.5*log(0.5*(1.+v2)) + 0.5*(1.+v2)/v*( 2.*lr*log(2.*(1.+v2)/sqr(1.+v)) + 2.*Herwig::Math::ReLi2(sqr(r)) - 2.*Herwig::Math::ReLi2(2.*v/(1.+v)) - sqr(Constants::pi)/6.) + log(1.-mu_) - 2.*log(1.-2.*mu_) - 4.*mu2_/(1.+v2)*log(mu_/(1.-mu_)) - mu_/(1.-mu_) + 4.*(2.*mu2_-mu_)/(1.+v2) + 0.5*sqr(Constants::pi); f2 = CF_*aS_/Constants::pi*mu2_*lr/v; } // small mass limit else { f1 = -CF_*aS_/Constants::pi/6.* ( - 6. - 24.*lmu*mu2_ - 15.*mu4 - 12.*mu4*lmu - 24.*mu4*sqr(lmu) + 2.*mu4*sqr(Constants::pi) - 12.*mu2_*mu4 - 96.*mu2_*mu4*sqr(lmu) + 8.*mu2_*mu4*sqr(Constants::pi) - 80.*mu2_*mu4*lmu); fNS = - mu2_/18.*( + 36.*lmu - 36. - 45.*mu2_ + 216.*lmu*mu2_ - 24.*mu2_*sqr(Constants::pi) + 72.*mu2_*sqr(lmu) - 22.*mu4 + 1032.*mu4 * lmu - 96.*mu4*sqr(Constants::pi) + 288.*mu4*sqr(lmu)); VNS = - mu2_/1260.*(-6930. + 7560.*lmu + 2520.*mu_ - 16695.*mu2_ + 1260.*mu2_*sqr(Constants::pi) + 12600.*lmu*mu2_ + 1344.*mu_*mu2_ - 52780.*mu4 + 36960.*mu4*lmu + 5040.*mu4*sqr(Constants::pi) - 12216.*mu_*mu4); f2 = CF_*aS_*mu2_/Constants::pi*( 2.*lmu + 4.*mu2_*lmu + 2.*mu2_ + 12.*mu4*lmu + 7.*mu4); } // add up bits for f1 f1 += CF_*aS_/Constants::pi*(fNS+VNS); double realFact(0.); for(int iemit=0;iemit<2;++iemit) { // now for the real correction double phi = UseRandom::rnd()*Constants::twopi; // calculate y double yminus = 0.; double yplus = 1.-2.*mu_*(1.-mu_)/(1.-2*mu2_); double y = yminus + UseRandom::rnd()*(yplus-yminus); // calculate z double v1 = sqrt(sqr(2.*mu2_+(1.-2.*mu2_)*(1.-y))-4.*mu2_)/(1.-2.*mu2_)/(1.-y); double zplus = (1.+v1)*(1.-2.*mu2_)*y/2./(mu2_ +(1.-2.*mu2_)*y); double zminus = (1.-v1)*(1.-2.*mu2_)*y/2./(mu2_ +(1.-2.*mu2_)*y); double z = zminus + UseRandom::rnd()*(zplus-zminus); double jac = (1.-y)*(yplus-yminus)*(zplus-zminus); // calculate x1,x2 double x2 = 1. - y*(1.-2.*mu2_); double x1 = 1. - z*(x2-2.*mu2_); // copy the particle objects over for calculateRealEmission vector hardProcess(3); hardProcess[0] = const_ptr_cast(&part); hardProcess[1] = decay[0]; hardProcess[2] = decay[1]; // total real emission contribution realFact += 0.25*jac*sqr(1.-2.*mu2_)/ sqrt(1.-4.*mu2_)/Constants::twopi *2.*CF_*aS_*calculateRealEmission(x1, x2, hardProcess, phi, iemit, true); } // the born + virtual + real output = output*(1. + f1 + realFact) + f2*total; return output; } void SMZDecayer::doinitrun() { PerturbativeDecayer::doinitrun(); if(initialize()) { for(unsigned int ix=0;ixmaxWeight(); else if(ix<11) leptonWeight_[ix-5 ]=mode(ix)->maxWeight(); } } } void SMZDecayer::dataBaseOutput(ofstream & output, bool header) const { if(header) output << "update decayers set parameters=\""; for(unsigned int ix=0;ixmomentum().phi(); // wavefunctions for the decaying particle in the rotated dipole frame vector vec1 = _vectors; for(unsigned int ix=0;ix vec2 = _vectors; for(unsigned int ix=0;ixid()<0) swap(iferm,ianti); // wavefunctions for the particles before the radiation // wavefunctions for the outgoing fermion SpinorBarWaveFunction wavebartemp; Lorentz5Momentum ptemp = - _wavebar[0].momentum(); ptemp *= rot2; if(ptemp.perp()/ptemp.e()<1e-10) { ptemp.setX(ZERO); ptemp.setY(ZERO); } wavebartemp = SpinorBarWaveFunction(ptemp,_wavebar[0].particle(),outgoing); // wavefunctions for the outgoing antifermion SpinorWaveFunction wavetemp; ptemp = - _wave[0].momentum(); ptemp *= rot2; if(ptemp.perp()/ptemp.e()<1e-10) { ptemp.setX(ZERO); ptemp.setY(ZERO); } wavetemp = SpinorWaveFunction(ptemp,_wave[0].particle(),outgoing); // loop over helicities vector wf_old; vector wfb_old; for(unsigned int ihel=0;ihel<2;++ihel) { wavetemp.reset(ihel); wf_old.push_back(wavetemp); wavebartemp.reset(ihel); wfb_old.push_back(wavebartemp); } // calculate the wave functions for the new fermions // ensure the momenta have pT=0 for(unsigned int ix=0;ix<2;++ix) { Lorentz5Momentum ptemp = children[ix]->momentum(); if(ptemp.perp()/ptemp.e()<1e-10) { ptemp.setX(ZERO); ptemp.setY(ZERO); children[ix]->set5Momentum(ptemp); } } // calculate the wavefunctions vector wfb; SpinorBarWaveFunction::calculateWaveFunctions(wfb,children[iferm],outgoing); vector wf; SpinorWaveFunction::calculateWaveFunctions (wf ,children[ianti],outgoing); // wave functions for the photons vector photon; VectorWaveFunction::calculateWaveFunctions(photon,children[2],outgoing,true); // loop to calculate the matrix elements Complex lome[3][2][2],diffme[3][2][2][2],summe[3][2][2][2]; Energy2 scale(sqr(parent.mass())); Complex diff[2]={0.,0.}; Complex sum [2]={0.,0.}; for(unsigned int ifm=0;ifm<2;++ifm) { for(unsigned int ia=0;ia<2;++ia) { for(unsigned int vhel=0;vhel<3;++vhel) { // calculation of the leading-order matrix element Complex loamp = FFZVertex_->evaluate(scale,wf_old[ia], wfb_old[ifm],vec2[vhel]); Complex lotemp = FFZVertex_->evaluate(scale,wf[ia], wfb[ifm],vec1[vhel]); if(iferm>ianti) lome[vhel][ia][ifm] = loamp; else lome[vhel][ifm][ia] = loamp; // photon loop for the real emmision terms for(unsigned int phel=0;phel<2;++phel) { // radiation from the antifermion // normal case with small angle treatment if(children[2 ]->momentum().z()/ children[iferm]->momentum().z()>=ZERO && iemitter == iferm ) { Complex dipole = e*double(children[iferm]->dataPtr()->iCharge())/3.* UnitRemoval::E*loamp* (children[iferm]->momentum()*photon[2*phel].wave())/ (children[iferm]->momentum()*children[2]->momentum()); // sum and difference SpinorBarWaveFunction foff = FFPVertex_->evaluateSmall(ZERO,3,children[iferm]->dataPtr()->CC(), wfb[ifm],photon[2*phel], ifm,2*phel,ctheta,phi,stheta,false); diff[0] = FFZVertex_->evaluate(scale,wf[ia],foff,vec1[vhel]) + e*double(children[iferm]->dataPtr()->iCharge())/3.* UnitRemoval::E*(lotemp-loamp)* (children[iferm]->momentum()*photon[2*phel].wave())/ (children[iferm]->momentum()*children[2]->momentum()); sum [0] = diff[0]+2.*dipole; } // special if fermion backwards else { SpinorBarWaveFunction foff = FFPVertex_->evaluate(ZERO,3,children[iferm]->dataPtr()->CC(), wfb[ifm],photon[2*phel]); Complex diag = FFZVertex_->evaluate(scale,wf[ia],foff,vec1[vhel]); Complex dipole = e*double(children[iferm]->dataPtr()->iCharge())/3.* UnitRemoval::E*loamp* (children[iferm]->momentum()*photon[2*phel].wave())/ (children[iferm]->momentum()*children[2]->momentum()); diff[0] = diag-dipole; sum [0] = diag+dipole; } // radiation from the anti fermion // small angle case in general if(children[2 ]->momentum().z()/ children[ianti]->momentum().z()>=ZERO && iemitter == ianti ) { Complex dipole = e*double(children[ianti]->dataPtr()->iCharge())/3.* UnitRemoval::E*loamp* (children[ianti]->momentum()*photon[2*phel].wave())/ (children[ianti]->momentum()*children[2]->momentum()); // sum and difference SpinorWaveFunction foff = FFPVertex_->evaluateSmall(ZERO,3,children[ianti]->dataPtr()->CC(), wf[ia],photon[2*phel], ia,2*phel,ctheta,phi,stheta,false); diff[1] = FFZVertex_->evaluate(scale,foff ,wfb[ifm],vec1[vhel]) + e*double(children[ianti]->dataPtr()->iCharge())/3.* UnitRemoval::E*(lotemp-loamp)* (children[ianti]->momentum()*photon[2*phel].wave())/ (children[ianti]->momentum()*children[2]->momentum()); sum [1] = diff[1]+2.*dipole; } // special if fermion backwards after radiation else { SpinorWaveFunction foff = FFPVertex_->evaluate(ZERO,3,children[ianti]->dataPtr()->CC(), wf[ia],photon[2*phel]); Complex diag = FFZVertex_->evaluate(scale,foff ,wfb[ifm],vec1[vhel]); Complex dipole = e*double(children[ianti]->dataPtr()->iCharge())/3.* UnitRemoval::E*loamp* (children[ianti]->momentum()*photon[2*phel].wave())/ (children[ianti]->momentum()*children[2]->momentum()); // sum and difference diff[1] = diag - dipole; sum [1] = diag + dipole; } // add to me if(iferm>ianti) { diffme[vhel][ia][ifm][phel] = diff[0] + diff[1]; summe [vhel][ia][ifm][phel] = sum[0] + sum[1] ; } else { diffme [vhel][ifm][ia][phel] = diff[0] + diff[1]; summe [vhel][ifm][ia][phel] = sum[0] + sum[1] ; } } } } } // cerr << parent << "\n"; // for(unsigned int ix=0;ixdataPtr()->iCharge()* // children[1]->dataPtr()->iCharge()/9.; // Energy2 ubar = 2.*children[0]->momentum()*children[2]->momentum(); // Energy2 tbar = 2.*children[1]->momentum()*children[2]->momentum(); // double mu2 = sqr(children[1]->mass()/parent.mass()); // double gL = (FFZVertex_->left() *FFZVertex_->norm()).real(); // double gR = (FFZVertex_->right()*FFZVertex_->norm()).real(); // Energy2 den = sqr(parent.mass())*(((sqr(gL)+sqr(gR))*(1-mu2)+6.*mu2*gL*gR)); // InvEnergy2 anal = -iCharge*( 2.*(ubar/tbar+tbar/ubar)/sqr(parent.mass())+ // 4.*mu2/den*((sqr(gL)+sqr(gR))*(1+ubar/tbar+tbar/ubar) // -2.*gL*gR*(1.+2.*(ubar/tbar+tbar/ubar)))); // cerr << "testing ratio " << parent.PDGName() // << " " << difference.real()/sqr(e)/lo.real()*UnitRemoval::InvE2/(anal) << "\n" // << stheta << " " << ctheta << "\n"; return difference.real()/sqr(e)/lo.real()*UnitRemoval::InvE2; } double SMZDecayer::oneLoopVirtualME(unsigned int, const Particle & parent, const ParticleVector & children) { assert(children.size()==2); // velocities of the particles double beta = sqrt(1.-4.*sqr(children[0]->mass()/parent.mass())); double opb = 1.+beta; double omb = 4.*sqr(children[0]->mass()/parent.mass())/opb; // couplings double gL = (FFZVertex_->left() *FFZVertex_->norm()).real(); double gR = (FFZVertex_->right()*FFZVertex_->norm()).real(); double gA = 0.5*(gL-gR); double gV = 0.5*(gL+gR); // correction terms double ln = log(omb/opb); double f1 = 1. + ln*beta; double fA = 1. + ln/beta; InvEnergy f2 = 0.5*sqrt(omb*opb)/parent.mass()/beta*ln; // momentum difference for the loop Lorentz5Momentum q = children[0]->momentum()-children[1]->momentum(); if(children[0]->id()<0) q *= -1.; // spinors vector > sp; vector > sbar; for(unsigned int ix=0;ix<2;++ix) { sp .push_back( _wave[ix].dimensionedWave()); sbar.push_back(_wavebar[ix].dimensionedWave()); } // polarization vectors vector pol; for(unsigned int ix=0;ix<3;++ix) pol.push_back(_vectors[ix].wave()); // matrix elements complex lome[3][2][2],loopme[3][2][2]; for(unsigned int vhel=0;vhel<3;++vhel) { for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { complex vector = sp[ihel1].generalCurrent(sbar[ihel2], 1.,1.).dot(pol[vhel]); complex axial = sp[ihel1].generalCurrent(sbar[ihel2],-1.,1.).dot(pol[vhel]); complex scalar = sp[ihel1].scalar(sbar[ihel2])*(q*pol[vhel]); lome [vhel][ihel1][ihel2] = gV* vector-gA* axial; loopme[vhel][ihel1][ihel2] = gV*f1*vector-gA*fA*axial+scalar*f2*gV; } } } // sum sums complex den(ZERO),num(ZERO); for(unsigned int vhel1=0;vhel1<3;++vhel1) { for(unsigned int vhel2=0;vhel2<3;++vhel2) { for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { num += _rho(vhel1,vhel2)* ( lome[vhel1][ihel1][ihel2]*conj(loopme[vhel2][ihel1][ihel2])+ loopme[vhel1][ihel1][ihel2]*conj( lome[vhel2][ihel1][ihel2])); den += _rho(vhel1,vhel2)* lome[vhel1][ihel1][ihel2]*conj(lome[vhel2][ihel1][ihel2]); } } } } // prefactor double iCharge = children[0]->dataPtr()->iCharge()* children[1]->dataPtr()->iCharge()/9.; double pre = 0.5*SM().alphaEM()*iCharge/Constants::pi; // output return pre*num.real()/den.real(); } void SMZDecayer:: initializeMECorrection(RealEmissionProcessPtr born, double & initial, double & final) { // get the quark and antiquark ParticleVector qq; for(unsigned int ix=0;ixbornOutgoing().size();++ix) qq.push_back(born->bornOutgoing()[ix]); // ensure quark first if(qq[0]->id()<0) swap(qq[0],qq[1]); // centre of mass energy d_Q_ = (qq[0]->momentum() + qq[1]->momentum()).m(); // quark mass d_m_ = 0.5*(qq[0]->momentum().m()+qq[1]->momentum().m()); // set the other parameters setRho(sqr(d_m_/d_Q_)); setKtildeSymm(); // otherwise can do it initial=1.; final =1.; } bool SMZDecayer::softMatrixElementVeto(PPtr parent, PPtr progenitor, const bool & , const Energy & highestpT, const vector & ids, const double & d_z, const Energy & d_qt, const Energy &) { // check we should be applying the veto if(parent->id()!=progenitor->id()|| ids[0]->id()!=ids[1]->id()|| ids[2]->id()!=ParticleID::g) return false; // calculate pt Energy2 d_m2 = parent->momentum().m2(); Energy pPerp = (1.-d_z)*sqrt( sqr(d_z*d_qt) - d_m2); // if not hardest so far don't apply veto if(pPerpid()>0) weight = qWeightX(d_qt, d_z); else weight = qbarWeightX(d_qt, d_z); // compute veto from weight and return return !UseRandom::rndbool(weight); } void SMZDecayer::setRho(double r) { d_rho_ = r; d_v_ = sqrt(1.-4.*d_rho_); } void SMZDecayer::setKtildeSymm() { d_kt1_ = (1. + sqrt(1. - 4.*d_rho_))/2.; setKtilde2(); } void SMZDecayer::setKtilde2() { double num = d_rho_ * d_kt1_ + 0.25 * d_v_ *(1.+d_v_)*(1.+d_v_); double den = d_kt1_ - d_rho_; d_kt2_ = num/den; } double SMZDecayer::getZfromX(double x1, double x2) { double uval = u(x2); double num = x1 - (2. - x2)*uval; double den = sqrt(x2*x2 - 4.*d_rho_); return uval + num/den; } double SMZDecayer::getKfromX(double x1, double x2) { double zval = getZfromX(x1, x2); return (1.-x2)/(zval*(1.-zval)); } double SMZDecayer::MEV(double x1, double x2) { // Vector part double num = (x1+2.*d_rho_)*(x1+2.*d_rho_) + (x2+2.*d_rho_)*(x2+2.*d_rho_) - 8.*d_rho_*(1.+2.*d_rho_); double den = (1.+2.*d_rho_)*(1.-x1)*(1.-x2); return (num/den - 2.*d_rho_/((1.-x1)*(1.-x1)) - 2*d_rho_/((1.-x2)*(1.-x2)))/d_v_; } double SMZDecayer::MEA(double x1, double x2) { // Axial part double num = (x1+2.*d_rho_)*(x1+2.*d_rho_) + (x2+2.*d_rho_)*(x2+2.*d_rho_) + 2.*d_rho_*((5.-x1-x2)*(5.-x1-x2) - 19.0 + 4*d_rho_); double den = d_v_*d_v_*(1.-x1)*(1.-x2); return (num/den - 2.*d_rho_/((1.-x1)*(1.-x1)) - 2*d_rho_/((1.-x2)*(1.-x2)))/d_v_; } double SMZDecayer::u(double x2) { return 0.5*(1. + d_rho_/(1.-x2+d_rho_)); } void SMZDecayer:: getXXbar(double kti, double z, double &x, double &xbar) { double w = sqr(d_v_) + kti*(-1. + z)*z*(2. + kti*(-1. + z)*z); if (w < 0) { x = -1.; xbar = -1; } else { x = (1. + sqr(d_v_)*(-1. + z) + sqr(kti*(-1. + z))*z*z*z + z*sqrt(w) - kti*(-1. + z)*z*(2. + z*(-2 + sqrt(w))))/ (1. - kti*(-1. + z)*z + sqrt(w)); xbar = 1. + kti*(-1. + z)*z; } } double SMZDecayer::qWeight(double x, double xbar) { double rval; double xg = 2. - xbar - x; // always return one in the soft gluon region if(xg < EPS_) return 1.0; // check it is in the phase space if((1.-x)*(1.-xbar)*(1.-xg) < d_rho_*xg*xg) return 0.0; double k1 = getKfromX(x, xbar); double k2 = getKfromX(xbar, x); // Is it in the quark emission zone? if(k1 < d_kt1_) { rval = MEV(x, xbar)/PS(x, xbar); // is it also in the anti-quark emission zone? if(k2 < d_kt2_) rval *= 0.5; return rval; } return 1.0; } double SMZDecayer::qbarWeight(double x, double xbar) { double rval; double xg = 2. - xbar - x; // always return one in the soft gluon region if(xg < EPS_) return 1.0; // check it is in the phase space if((1.-x)*(1.-xbar)*(1.-xg) < d_rho_*xg*xg) return 0.0; double k1 = getKfromX(x, xbar); double k2 = getKfromX(xbar, x); // Is it in the antiquark emission zone? if(k2 < d_kt2_) { rval = MEV(x, xbar)/PS(xbar, x); // is it also in the quark emission zone? if(k1 < d_kt1_) rval *= 0.5; return rval; } return 1.0; } double SMZDecayer::qWeightX(Energy qtilde, double z) { double x, xb; getXXbar(sqr(qtilde/d_Q_), z, x, xb); // if exceptionally out of phase space, leave this emission, as there // is no good interpretation for the soft ME correction. if (x < 0 || xb < 0) return 1.0; return qWeight(x, xb); } double SMZDecayer::qbarWeightX(Energy qtilde, double z) { double x, xb; getXXbar(sqr(qtilde/d_Q_), z, xb, x); // see above in qWeightX. if (x < 0 || xb < 0) return 1.0; return qbarWeight(x, xb); } double SMZDecayer::PS(double x, double xbar) { double u = 0.5*(1. + d_rho_ / (1.-xbar+d_rho_)); double z = u + (x - (2.-xbar)*u)/sqrt(xbar*xbar - 4.*d_rho_); double brack = (1.+z*z)/(1.-z)- 2.*d_rho_/(1-xbar); // interesting: the splitting function without the subtraction // term. Actually gives a much worse approximation in the collinear // limit. double brack = (1.+z*z)/(1.-z); double den = (1.-xbar)*sqrt(xbar*xbar - 4.*d_rho_); return brack/den; } double SMZDecayer::matrixElementRatio(const Particle & inpart, const ParticleVector & decay2, const ParticleVector & decay3, MEOption, ShowerInteraction inter) { // extract partons and LO momentas vector partons(1,inpart.dataPtr()); vector lomom(1,inpart.momentum()); for(unsigned int ix=0;ix<2;++ix) { partons.push_back(decay2[ix]->dataPtr()); lomom.push_back(decay2[ix]->momentum()); } vector realmom(1,inpart.momentum()); for(unsigned int ix=0;ix<3;++ix) { if(ix==2) partons.push_back(decay3[ix]->dataPtr()); realmom.push_back(decay3[ix]->momentum()); } if(partons[0]->id()<0) { swap(partons[1],partons[2]); swap(lomom[1],lomom[2]); swap(realmom[1],realmom[2]); } scale_ = sqr(inpart.mass()); double lome = loME(partons,lomom); InvEnergy2 reme = realME(partons,realmom,inter); double ratio = reme/lome*sqr(inpart.mass())*4.*Constants::pi; if(inter==ShowerInteraction::QCD) ratio *= CF_; return ratio; } double SMZDecayer::meRatio(vector partons, vector momenta, unsigned int iemitter, bool subtract) const { Lorentz5Momentum q = momenta[1]+momenta[2]+momenta[3]; Energy2 Q2=q.m2(); Energy2 lambda = sqrt((Q2-sqr(momenta[1].mass()+momenta[2].mass()))* (Q2-sqr(momenta[1].mass()-momenta[2].mass()))); InvEnergy2 D[2]; double lome[2]; for(unsigned int iemit=0;iemit<2;++iemit) { unsigned int ispect = iemit==0 ? 1 : 0; Energy2 pipj = momenta[3 ] * momenta[1+iemit ]; Energy2 pipk = momenta[3 ] * momenta[1+ispect]; Energy2 pjpk = momenta[1+iemit] * momenta[1+ispect]; double y = pipj/(pipj+pipk+pjpk); double z = pipk/( pipk+pjpk); Energy mij = sqrt(2.*pipj+sqr(momenta[1+iemit].mass())); Energy2 lamB = sqrt((Q2-sqr(mij+momenta[1+ispect].mass()))* (Q2-sqr(mij-momenta[1+ispect].mass()))); Energy2 Qpk = q*momenta[1+ispect]; Lorentz5Momentum pkt = lambda/lamB*(momenta[1+ispect]-Qpk/Q2*q) +0.5/Q2*(Q2+sqr(momenta[1+ispect].mass())-sqr(momenta[1+ispect].mass()))*q; Lorentz5Momentum pijt = q-pkt; double muj = momenta[1+iemit ].mass()/sqrt(Q2); double muk = momenta[1+ispect].mass()/sqrt(Q2); double vt = sqrt((1.-sqr(muj+muk))*(1.-sqr(muj-muk)))/(1.-sqr(muj)-sqr(muk)); double v = sqrt(sqr(2.*sqr(muk)+(1.-sqr(muj)-sqr(muk))*(1.-y))-4.*sqr(muk)) /(1.-y)/(1.-sqr(muj)-sqr(muk)); // dipole term D[iemit] = 0.5/pipj*(2./(1.-(1.-z)*(1.-y)) -vt/v*(2.-z+sqr(momenta[1+iemit].mass())/pipj)); // matrix element vector lomom(3); lomom[0] = momenta[0]; if(iemit==0) { lomom[1] = pijt; lomom[2] = pkt ; } else { lomom[2] = pijt; lomom[1] = pkt ; } lome[iemit] = loME(partons,lomom); } InvEnergy2 ratio = realME(partons,momenta,ShowerInteraction::QCD)*abs(D[iemitter]) /(abs(D[0]*lome[0])+abs(D[1]*lome[1])); if(subtract) return Q2*(ratio-2.*D[iemitter]); else return Q2*ratio; } double SMZDecayer::loME(const vector & partons, const vector & momenta) const { // compute the spinors vector vin; vector aout; vector fout; VectorWaveFunction zin (momenta[0],partons[0],incoming); SpinorBarWaveFunction qkout(momenta[1],partons[1],outgoing); SpinorWaveFunction qbout(momenta[2],partons[2],outgoing); for(unsigned int ix=0;ix<2;++ix){ qkout.reset(ix); fout.push_back(qkout); qbout.reset(ix); aout.push_back(qbout); } for(unsigned int ix=0;ix<3;++ix){ zin.reset(ix); vin.push_back(zin); } // temporary storage of the different diagrams // sum over helicities to get the matrix element double total(0.); for(unsigned int inhel=0;inhel<3;++inhel) { for(unsigned int outhel1=0;outhel1<2;++outhel1) { for(unsigned int outhel2=0;outhel2<2;++outhel2) { Complex diag1 = FFZVertex_->evaluate(scale_,aout[outhel2],fout[outhel1],vin[inhel]); total += norm(diag1); } } } // return the answer return total; } InvEnergy2 SMZDecayer::realME(const vector & partons, const vector & momenta, ShowerInteraction inter) const { AbstractFFVVertexPtr vertex = inter==ShowerInteraction::QCD ? FFGVertex_ : FFPVertex_; // compute the spinors vector vin; vector aout; vector fout; vector gout; VectorWaveFunction zin (momenta[0],partons[0],incoming); SpinorBarWaveFunction qkout(momenta[1],partons[1],outgoing); SpinorWaveFunction qbout(momenta[2],partons[2],outgoing); VectorWaveFunction gluon(momenta[3],partons[3],outgoing); for(unsigned int ix=0;ix<2;++ix){ qkout.reset(ix); fout.push_back(qkout); qbout.reset(ix); aout.push_back(qbout); gluon.reset(2*ix); gout.push_back(gluon); } for(unsigned int ix=0;ix<3;++ix){ zin.reset(ix); vin.push_back(zin); } vector diag(2,0.); double total(0.); for(unsigned int inhel1=0;inhel1<3;++inhel1) { for(unsigned int outhel1=0;outhel1<2;++outhel1) { for(unsigned int outhel2=0;outhel2<2;++outhel2) { for(unsigned int outhel3=0;outhel3<2;++outhel3) { SpinorBarWaveFunction off1 = vertex->evaluate(scale_,3,partons[1]->CC(),fout[outhel1],gout[outhel3]); diag[0] = FFZVertex_->evaluate(scale_,aout[outhel2],off1,vin[inhel1]); SpinorWaveFunction off2 = vertex->evaluate(scale_,3,partons[2]->CC(),aout[outhel2],gout[outhel3]); diag[1] = FFZVertex_->evaluate(scale_,off2,fout[outhel1],vin[inhel1]); // sum of diagrams Complex sum = std::accumulate(diag.begin(),diag.end(),Complex(0.)); // me2 total += norm(sum); } } } } // divide out the coupling total /= norm(vertex->norm()); // return the total return total*UnitRemoval::InvE2; } double SMZDecayer::calculateRealEmission(double x1, double x2, vector hardProcess, double phi, bool subtract) const { // make partons data object for meRatio vector partons (3); for(int ix=0; ix<3; ++ix) partons[ix] = hardProcess[ix]->dataPtr(); partons.push_back(gluon_); // calculate x3 double x3 = 2.-x1-x2; double xT = sqrt(max(0.,sqr(x3) -0.25*sqr(sqr(x2)+sqr(x3)-sqr(x1))/(sqr(x2)-4.*mu2_))); // calculate the momenta Energy M = mZ_; Lorentz5Momentum pspect(ZERO,ZERO,-0.5*M*sqrt(max(sqr(x2)-4.*mu2_,0.)),0.5*M*x2,M*mu_); Lorentz5Momentum pemit (-0.5*M*xT*cos(phi),-0.5*M*xT*sin(phi), 0.5*M*sqrt(max(sqr(x1)-sqr(xT)-4.*mu2_,0.)),0.5*M*x1,M*mu_); Lorentz5Momentum pgluon(0.5*M*xT*cos(phi), 0.5*M*xT*sin(phi), 0.5*M*sqrt(max(sqr(x3)-sqr(xT),0.)),0.5*M*x3,ZERO); if(abs(pspect.z()+pemit.z()-pgluon.z())/M<1e-6) pgluon.setZ(-pgluon.z()); else if(abs(pspect.z()-pemit.z()+pgluon.z())/M<1e-6) pemit .setZ(- pemit.z()); // loop over the possible emitting partons double realwgt(0.); for(unsigned int iemit=0;iemit<2;++iemit) { // boost and rotate momenta LorentzRotation eventFrame( ( hardProcess[1]->momentum() + hardProcess[2]->momentum() ).findBoostToCM() ); Lorentz5Momentum spectator = eventFrame*hardProcess[iemit+1]->momentum(); eventFrame.rotateZ( -spectator.phi() ); eventFrame.rotateY( -spectator.theta() ); eventFrame.invert(); vector momenta(3); momenta[0] = hardProcess[0]->momentum(); if(iemit==0) { momenta[2] = eventFrame*pspect; momenta[1] = eventFrame*pemit ; } else { momenta[1] = eventFrame*pspect; momenta[2] = eventFrame*pemit ; } momenta.push_back(eventFrame*pgluon); // calculate the weight if(1.-x1>1e-5 && 1.-x2>1e-5) realwgt += meRatio(partons,momenta,iemit,subtract); } // total real emission contribution return realwgt; } double SMZDecayer::calculateRealEmission(double x1, double x2, vector hardProcess, double phi, bool subtract, int emitter) const { // make partons data object for meRatio vector partons (3); for(int ix=0; ix<3; ++ix) partons[ix] = hardProcess[ix]->dataPtr(); partons.push_back(gluon_); // calculate x3 double x3 = 2.-x1-x2; double xT = sqrt(max(0.,sqr(x3) -0.25*sqr(sqr(x2)+sqr(x3)-sqr(x1))/(sqr(x2)-4.*mu2_))); // calculate the momenta Energy M = mZ_; Lorentz5Momentum pspect(ZERO,ZERO,-0.5*M*sqrt(max(sqr(x2)-4.*mu2_,0.)),0.5*M*x2,M*mu_); Lorentz5Momentum pemit (-0.5*M*xT*cos(phi),-0.5*M*xT*sin(phi), 0.5*M*sqrt(max(sqr(x1)-sqr(xT)-4.*mu2_,0.)),0.5*M*x1,M*mu_); Lorentz5Momentum pgluon( 0.5*M*xT*cos(phi), 0.5*M*xT*sin(phi), 0.5*M*sqrt(max(sqr(x3)-sqr(xT),0.)),0.5*M*x3,ZERO); if(abs(pspect.z()+pemit.z()-pgluon.z())/M<1e-6) pgluon.setZ(-pgluon.z()); else if(abs(pspect.z()-pemit.z()+pgluon.z())/M<1e-6) pemit .setZ(- pemit.z()); // boost and rotate momenta LorentzRotation eventFrame( ( hardProcess[1]->momentum() + hardProcess[2]->momentum() ).findBoostToCM() ); Lorentz5Momentum spectator = eventFrame*hardProcess[emitter+1]->momentum(); eventFrame.rotateZ( -spectator.phi() ); eventFrame.rotateY( -spectator.theta() ); eventFrame.invert(); vector momenta(3); momenta[0] = hardProcess[0]->momentum(); if(emitter==0) { momenta[2] = eventFrame*pspect; momenta[1] = eventFrame*pemit ; } else { momenta[1] = eventFrame*pspect; momenta[2] = eventFrame*pemit ; } momenta.push_back(eventFrame*pgluon); // calculate the weight double realwgt(0.); if(1.-x1>1e-5 && 1.-x2>1e-5) realwgt = meRatio(partons,momenta,emitter,subtract); // total real emission contribution return realwgt; } diff --git a/Decay/Tau/TauDecayer.cc b/Decay/Tau/TauDecayer.cc --- a/Decay/Tau/TauDecayer.cc +++ b/Decay/Tau/TauDecayer.cc @@ -1,359 +1,361 @@ // -*- C++ -*- // // TauDecayer.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 TauDecayer class. // // Author: Peter Richardson // #include "TauDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/ParVector.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Helicity/VectorSpinInfo.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "Herwig/Decay/DecayVertex.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include "ThePEG/Helicity/FermionSpinInfo.h" #include "ThePEG/StandardModel/StandardModelBase.h" using namespace Herwig; using namespace ThePEG::Helicity; void TauDecayer::doinit() { DecayIntegrator::doinit(); // make sure the current got initialised _current->init(); // set up the phase-space channels DecayPhaseSpaceModePtr mode; DecayPhaseSpaceChannelPtr channel; tPDVector extpart,ptemp; extpart.push_back(getParticleData(ParticleID::tauminus)); extpart.push_back(getParticleData(ParticleID::nu_tau)); Energy mtau(extpart[0]->mass()); double maxweight; vector channelwgts; int iq(0),ia(0); _modemap.clear(); unsigned int ix,iy; bool done; vector::iterator start,end; for(ix=0;ix<_current->numberOfModes();++ix) { // get the external particles for this mode extpart.resize(2); ptemp=_current->particles(-3,ix,iq,ia); for(iy=0;iyaddIntermediate(extpart[0],0,0.0,-1,1); done=_current->createMode(-3,ix,mode,2,1,channel,mtau); if(done) { // the maximum weight and the channel weights // the maximum maxweight = _wgtmax.size()>numberModes() ? _wgtmax[numberModes()] : 0; // the weights for the channel if(_wgtloc.size()>numberModes()&& _wgtloc[numberModes()]+mode->numberChannels()<=_weights.size()) { start=_weights.begin()+_wgtloc[numberModes()]; end = start+mode->numberChannels(); channelwgts=vector(start,end); } else { channelwgts.resize(mode->numberChannels(),1./(mode->numberChannels())); } _modemap.push_back(ix); // special for the two body modes if(extpart.size()==3) { channelwgts.clear(); mode=new_ptr(DecayPhaseSpaceMode(extpart,this)); } addMode(mode,maxweight,channelwgts); } } _current->reset(); _current->touch(); _current->update(); } void TauDecayer::doinitrun() { _current->initrun(); DecayIntegrator::doinitrun(); if(initialize()) { _weights.clear();_wgtloc.clear();_wgtmax.clear(); unsigned int ix,iy; for(ix=0;ixmaxWeight()); _wgtloc.push_back(_weights.size()); for(iy=0;iynumberChannels();++iy) { _weights.push_back(mode(ix)->channelWeight(iy)); } } } } bool TauDecayer::accept(tcPDPtr parent, const tPDVector & children) const { bool allowed(false); // find the neutrino int idnu(0),idtemp,idin(parent->id()); vector idother; tPDVector::const_iterator pit = children.begin(); tPDVector::const_iterator pend = children.end(); for( ; pit!=pend;++pit) { idtemp=(**pit).id(); if(abs(idtemp)==16) idnu=idtemp; else idother.push_back(idtemp); } if((idnu==ParticleID::nu_tau && idin==ParticleID::tauminus)|| (idnu==ParticleID::nu_taubar && idin==ParticleID::tauplus )) { allowed=_current->accept(idother); } return allowed; } int TauDecayer::modeNumber(bool & cc,tcPDPtr parent, const tPDVector & children) const { int imode(-1); tPDVector::const_iterator pit = children.begin(); tPDVector::const_iterator pend = children.end(); int idtemp;vector idother; for( ; pit!=pend;++pit) { idtemp=(**pit).id(); if(abs(idtemp)!=16) idother.push_back(idtemp); } unsigned int itemp=_current->decayMode(idother); for(unsigned int ix=0;ix<_modemap.size();++ix) { if(_modemap[ix]==itemp) imode=ix; } // perform the decay cc=parent->id()==ParticleID::tauplus; return imode; } void TauDecayer::persistentOutput(PersistentOStream & os) const { os << _modemap << _current << _wgtloc << _wgtmax << _weights << _polOpt << _tauMpol << _tauPpol; } void TauDecayer::persistentInput(PersistentIStream & is, int) { is >> _modemap >> _current >> _wgtloc >> _wgtmax >> _weights >> _polOpt >> _tauMpol >> _tauPpol; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigTauDecayer("Herwig::TauDecayer", "HwTauDecay.so"); void TauDecayer::Init() { static ClassDocumentation documentation ("The TauDecayer class is designed to use a weak current" " to perform the decay of the tau."); static Reference interfaceWeakCurrent ("WeakCurrent", "The reference for the decay current to be used.", &TauDecayer::_current, false, false, true, false, false); static ParVector interfaceWeightLocation ("WeightLocation", "The locations of the weights for a given channel in the vector", &TauDecayer::_wgtloc, 0, 0, 0, 0, 10000, false, false, true); static ParVector interfaceWeightMax ("MaximumWeight", "The maximum weight for a given channel.", &TauDecayer::_wgtmax, 0, 0, 0, 0., 100., false, false, true); static ParVector interfaceWeights ("Weights", "The weights for the integration.", &TauDecayer::_weights, 0, 0, 0, 0., 1., false, false, true); static Switch interfacePolarizationOption ("PolarizationOption", "Option of forcing the polarization of the tau leptons, N.B. you" " should only use this option for making distributions for" " comparision if you really know what you are doing.", &TauDecayer::_polOpt, false, false, false); static SwitchOption interfacePolarizationOptionDefault (interfacePolarizationOption, "Default", "Don't force the polarization use the full spin density matrices" " to get the right answer", false); static SwitchOption interfacePolarizationOptionForce (interfacePolarizationOption, "Force", "Force the polarizations", true); static Parameter interfaceTauMinusPolarization ("TauMinusPolarization", "The polarization of the tau-, left=-1, right=+1 if this is forced.", &TauDecayer::_tauMpol, 0.0, -1.0, 1.0, false, false, Interface::limited); static Parameter interfaceTauPlusPolarization ("TauPlusPolarization", "The polarization of the tau+, left=-1, right=+1 if this is forced.", &TauDecayer::_tauPpol, 0.0, -1.0, 1.0, false, false, Interface::limited); } // combine the currents to give the matrix element double TauDecayer::me2(const int ichan,const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { // map the mode to those in the current int mode(_modemap[imode()]); // get the particles for the hadronic current ParticleVector hadpart(decay.begin()+1,decay.end()); Energy q; // extract info on the decaying particle if(meopt==Initialize) { // spin density matrix for the decaying particle _rho = RhoDMatrix(PDT::Spin1Half); if(inpart.id()==ParticleID::tauminus) SpinorWaveFunction ::calculateWaveFunctions(_inspin,_rho, const_ptr_cast(&inpart), incoming); else SpinorBarWaveFunction::calculateWaveFunctions(_inbar ,_rho, const_ptr_cast(&inpart), incoming); + // fix rho if no correlations + fixRho(_rho); if(_polOpt) { _rho(0,1) = _rho(1,0) = 0.; if(inpart.id()==ParticleID::tauminus) { _rho(0,0) = 0.5*(1.-_tauMpol); _rho(1,1) = 0.5*(1.+_tauMpol); } else { _rho(0,0) = 0.5*(1.+_tauPpol); _rho(1,1) = 0.5*(1.-_tauPpol); } } // work out the mapping for the hadron vector _constants = vector(decay.size()+1); _ispin = vector(decay.size()); int itemp(1); unsigned int ix(decay.size()); do { --ix; _ispin[ix] = decay[ix]->data().iSpin(); itemp *= _ispin[ix]; _constants[ix] = itemp; } while(ix>0); _constants[decay.size()] = 1; _constants[0 ] = _constants[1]; } if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,_ispin))); // connect the spininfo up if needed if(meopt==Terminate) { if(inpart.id()==ParticleID::tauminus) { SpinorWaveFunction :: constructSpinInfo(_inspin,const_ptr_cast(&inpart),incoming,true); SpinorBarWaveFunction:: constructSpinInfo(_inbar,decay[0],outgoing,true); } else { SpinorBarWaveFunction:: constructSpinInfo(_inbar ,const_ptr_cast(&inpart),incoming,true); SpinorWaveFunction:: constructSpinInfo(_inspin,decay[0],outgoing,true); } _current->current(mode,ichan,q,hadpart,meopt); return 0.; } // calculate the spinors for the decay products if(inpart.id()==ParticleID::tauminus) SpinorBarWaveFunction::calculateWaveFunctions(_inbar ,decay[0],outgoing); else SpinorWaveFunction ::calculateWaveFunctions(_inspin,decay[0],outgoing); // calculate the hadron current vector hadron(_current->current(mode,ichan,q,hadpart,meopt)); // prefactor double pre = sqr(pow(inpart.mass()/q,int(hadpart.size()-2))); // calculate the lepton current LorentzPolarizationVectorE lepton[2][2]; for(unsigned ix=0;ix<2;++ix) { for(unsigned iy=0;iy<2;++iy) { if(inpart.id()==15) lepton[ix][iy]=2.*_inspin[ix].leftCurrent(_inbar[iy]); else lepton[iy][ix]=2.*_inspin[ix].leftCurrent(_inbar[iy]); } } // compute the matrix element vector ihel(decay.size()+1); for(unsigned int hhel=0;hhel1;--ix) { ihel[ix]=(hhel%_constants[ix-1])/_constants[ix]; } // loop over the helicities of the tau and neutrino and set up the matrix // element for(ihel[1]=0;ihel[1]<2;++ihel[1]){ for(ihel[0]=0;ihel[0]<2;++ihel[0]) { (*ME())(ihel)= lepton[ihel[0]][ihel[1]].dot(hadron[hhel])* SM().fermiConstant(); } } } // multiply by the CKM element int iq,ia; _current->decayModeInfo(mode,iq,ia); double ckm(1.); if(iq<=6) { if(iq%2==0) ckm = SM().CKM(iq/2-1,(abs(ia)-1)/2); else ckm = SM().CKM(abs(ia)/2-1,(iq-1)/2); } return 0.5*pre*ckm*(ME()->contract(_rho)).real(); } // output the setup information for the particle database void TauDecayer::dataBaseOutput(ofstream & output,bool header) const { unsigned int ix; if(header) output << "update decayers set parameters=\""; DecayIntegrator::dataBaseOutput(output,false); for(ix=0;ix<_wgtloc.size();++ix) { output << "insert " << name() << ":WeightLocation " << ix << " " << _wgtloc[ix] << "\n"; } for(ix=0;ix<_wgtmax.size();++ix) { output << "insert " << name() << ":MaximumWeight " << ix << " " << _wgtmax[ix] << "\n"; } for(ix=0;ix<_weights.size();++ix) { output << "insert " << name() << ":Weights " << ix << " " << _weights[ix] << "\n"; } _current->dataBaseOutput(output,false,true); output << "newdef " << name() << ":WeakCurrent " << _current->name() << " \n"; output << "\n\" where BINARY ThePEGName=\"" << fullName() << "\";\n"; } 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 ) { 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 ) { 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], + 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/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 ) { 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(), + 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(), + 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], + 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], + 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(),qin[ihel1],pout[phel]); + FFPvertex_->evaluate(ZERO,5,qin[ihel1].particle()->CC(),qin[ihel1],pout[phel]); SpinorBarWaveFunction inters2 = - FFPvertex_->evaluate(ZERO,5,qin[ihel1].particle()->CC(), + 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(),qin[ihel1],gout[ghel]); + FFGvertex_->evaluate(mu2,5,qin[ihel1].particle()->CC(),qin[ihel1],gout[ghel]); SpinorBarWaveFunction inters4 = - FFPvertex_->evaluate(ZERO,5,qbarin[ihel2].particle(), + 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(), + 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()->CC(), - qin[ihel1],wout[whel]); + 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/MatrixElement/Powheg/MEPP2VVPowheg.cc b/MatrixElement/Powheg/MEPP2VVPowheg.cc --- a/MatrixElement/Powheg/MEPP2VVPowheg.cc +++ b/MatrixElement/Powheg/MEPP2VVPowheg.cc @@ -1,5279 +1,5279 @@ // -*- C++ -*- // // MEPP2VVPowheg.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 MEPP2VVPowheg class. // #include "MEPP2VVPowheg.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/MatrixElement/Tree2toNDiagram.h" #include "ThePEG/Handlers/StandardXComb.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "Herwig/MatrixElement/HardVertex.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include "Herwig/Shower/RealEmissionProcess.h" using namespace Herwig; MEPP2VVPowheg::MEPP2VVPowheg() : tiny(1.e-10), CF_(4./3.), TR_(0.5), NC_(3.), contrib_(1), channels_(0), nlo_alphaS_opt_(0) , fixed_alphaS_(0.1180346226), removebr_(1), scaleopt_(1), mu_F_(100.*GeV), mu_UV_(100.*GeV), ckm_(3,vector(3,0.0)), helicityConservation_(true), realMESpinCorrelations_(true), power_(2.0), preqqbar_(3.7),preqg_(16.0),pregqbar_(11.0), b0_((11.-2./3.*5.)/4./Constants::pi), LambdaQCD_(91.118*GeV*exp(-1./2./((11.-2./3.*5.)/4./Constants::pi)/0.118)), min_pT_(2.*GeV){ massOption(vector(2,1)); } void MEPP2VVPowheg::persistentOutput(PersistentOStream & os) const { os << contrib_ << channels_ << nlo_alphaS_opt_ << fixed_alphaS_ << removebr_ << scaleopt_ << ounit(mu_F_,GeV) << ounit(mu_UV_,GeV) << ckm_ << helicityConservation_ << FFPvertex_ << FFWvertex_ << FFZvertex_ << WWWvertex_ << FFGvertex_ << realMESpinCorrelations_ << showerAlphaS_ << power_ << preqqbar_ << preqg_ << pregqbar_ << prefactor_ << b0_ << ounit(LambdaQCD_,GeV) << ounit( min_pT_,GeV ); } void MEPP2VVPowheg::persistentInput(PersistentIStream & is, int) { is >> contrib_ >> channels_ >> nlo_alphaS_opt_ >> fixed_alphaS_ >> removebr_ >> scaleopt_ >> iunit(mu_F_,GeV) >> iunit(mu_UV_,GeV) >> ckm_ >> helicityConservation_ >> FFPvertex_ >> FFWvertex_ >> FFZvertex_ >> WWWvertex_ >> FFGvertex_ >> realMESpinCorrelations_ >> showerAlphaS_ >> power_ >> preqqbar_ >> preqg_ >> pregqbar_ >> prefactor_ >> b0_ >> iunit(LambdaQCD_,GeV) >> iunit( min_pT_, GeV ); } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigMEPP2VVPowheg("Herwig::MEPP2VVPowheg", "HwMEHadron.so HwPowhegMEHadron.so"); void MEPP2VVPowheg::Init() { static ClassDocumentation documentation ("The MEPP2VVPowheg class implements the NLO matrix elements for the production of" "pairs of electroweak vector bosons.", "The calcultaion of $W^+W^-$, $W^\\pm Z^0$ and $Z^0Z^0$ production" " in hadron collisions at next-to-leading order in the POWHEG scheme" " is described in \\cite{Hamilton:2010mb}.", "\\bibitem{Hamilton:2010mb}\n" " K.~Hamilton,\n" "%``A positive-weight next-to-leading order simulation of weak boson pair\n" "%production,''\n" "JHEP {\bf 1101} (2011) 009\n" "[arXiv:1009.5391 [hep-ph]].\n" "%%CITATION = JHEPA,1101,009;%%\n"); static Switch interfaceContribution ("Contribution", "Which contributions to the cross section to include", &MEPP2VVPowheg::contrib_, 1, false, false); static SwitchOption interfaceContributionLeadingOrder (interfaceContribution, "LeadingOrder", "Just generate the leading order cross section", 0); static SwitchOption interfaceContributionPositiveNLO (interfaceContribution, "PositiveNLO", "Generate the positive contribution to the full NLO cross section", 1); static SwitchOption interfaceContributionNegativeNLO (interfaceContribution, "NegativeNLO", "Generate the negative contribution to the full NLO cross section", 2); static Switch interfaceChannels ("Channels", "Which channels to include in the cross section", &MEPP2VVPowheg::channels_, 0, false, false); static SwitchOption interfaceChannelsAll (interfaceChannels, "All", "All channels required for the full NLO cross section: qqb, qg, gqb", 0); static SwitchOption interfaceChannelsAnnihilation (interfaceChannels, "Annihilation", "Only include the qqb annihilation channel, omitting qg and gqb channels", 1); static SwitchOption interfaceChannelsCompton (interfaceChannels, "Compton", "Only include the qg and gqb compton channels, omitting all qqb processes", 2); static Switch interfaceNLOalphaSopt ("NLOalphaSopt", "An option allowing you to supply a fixed value of alpha_S " "through the FixedNLOAlphaS interface.", &MEPP2VVPowheg::nlo_alphaS_opt_, 0, false, false); static SwitchOption interfaceNLOalphaSoptRunningAlphaS (interfaceNLOalphaSopt, "RunningAlphaS", "Use the usual running QCD coupling evaluated at scale mu_UV2()", 0); static SwitchOption interfaceNLOalphaSoptFixedAlphaS (interfaceNLOalphaSopt, "FixedAlphaS", "Use a constant QCD coupling for comparison/debugging purposes", 1); static Parameter interfaceFixedNLOalphaS ("FixedNLOalphaS", "The value of alphaS to use for the nlo weight if nlo_alphaS_opt_=1", &MEPP2VVPowheg::fixed_alphaS_, 0.1180346226, 0., 1.0, false, false, Interface::limited); static Switch interfaceremovebr ("removebr", "Whether to multiply the event weights by the MCFM branching ratios", &MEPP2VVPowheg::removebr_, 1, false, false); static SwitchOption interfaceProductionCrossSection (interfaceremovebr, "Yes", "Do not multiply in the branching ratios (default running)", 1); static SwitchOption interfaceIncludeBRs (interfaceremovebr, "No", "Multiply by MCFM branching ratios for comparison/debugging purposes", 0); static Switch interfaceScaleOption ("ScaleOption", "Option for running / fixing EW and QCD factorization & renormalization scales", &MEPP2VVPowheg::scaleopt_, 1, false, false); static SwitchOption interfaceDynamic (interfaceScaleOption, "Dynamic", "QCD factorization & renormalization scales are sqr(pV1+pV2). " "EW scale is (mV1^2+mV2^2)/2 (similar to MCatNLO)", 1); static SwitchOption interfaceFixed (interfaceScaleOption, "Fixed", "QCD factorization fixed to value by FactorizationScaleValue." "EW and QCD renormalization scales fixed by RenormalizationScaleValue.", 2); static Parameter interfaceFactorizationScaleValue ("FactorizationScaleValue", "Value to use for the QCD factorization scale if fixed scales" "have been requested with the ScaleOption interface.", &MEPP2VVPowheg::mu_F_, GeV, 100.0*GeV, 50.0*GeV, 500.0*GeV, true, false, Interface::limited); static Parameter interfaceRenormalizationScaleValue ("RenormalizationScaleValue", "Value to use for the EW and QCD renormalization scales if fixed " "scales have been requested with the ScaleOption interface.", &MEPP2VVPowheg::mu_UV_, GeV, 100.0*GeV, 50.0*GeV, 500.0*GeV, true, false, Interface::limited); static Switch interfaceSpinCorrelations ("SpinCorrelations", "Flag to select leading order spin correlations or a " "calculation taking into account the real NLO effects", &MEPP2VVPowheg::realMESpinCorrelations_, 1, false, false); static SwitchOption interfaceSpinCorrelationsLeadingOrder (interfaceSpinCorrelations, "LeadingOrder", "Decay bosons using a leading order 2->2 calculation of the " "production spin density matrix", 0); static SwitchOption interfaceSpinCorrelationsRealNLO (interfaceSpinCorrelations, "RealNLO", "Decay bosons using a production spin density matrix which " "takes into account the effects of real radiation", 1); static Reference interfaceCoupling ("Coupling", "The object calculating the strong coupling constant", &MEPP2VVPowheg::showerAlphaS_, false, false, true, false, false); static Parameter interfacePower ("Power", "The power for the sampling of the matrix elements", &MEPP2VVPowheg::power_, 2.0, 1.0, 10.0, false, false, Interface::limited); static Parameter interfacePrefactorqqbar ("Prefactorqqbar", "The prefactor for the sampling of the q qbar channel", &MEPP2VVPowheg::preqqbar_, 5.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacePrefactorqg ("Prefactorqg", "The prefactor for the sampling of the q g channel", &MEPP2VVPowheg::preqg_, 3.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacePrefactorgqbar ("Prefactorgqbar", "The prefactor for the sampling of the g qbar channel", &MEPP2VVPowheg::pregqbar_, 3.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacepTMin ("minPt", "The pT cut on hardest emision generation" "2*(1-Beta)*exp(-sqr(intrinsicpT/RMS))/sqr(RMS)", &MEPP2VVPowheg::min_pT_, GeV, 2.*GeV, ZERO, 100000.0*GeV, false, false, Interface::limited); } Energy2 MEPP2VVPowheg::scale() const { // N.B. This scale is the electroweak scale! // It is used in the evaluation of the LO code // in the MEPP2VV base class. This means it // should appear in the denominator of the // NLOweight here and all other LO parts like // the function for the lumi ratio (Lhat). It // should also be used for evaluating any EW // parameters / vertices in the numerator. // The scaleopt_ == 1 "running" option is // chosen to be like the MC@NLO one (it ought // to be more like sHat instead?). return scaleopt_ == 1 ? // 0.5*(meMomenta()[2].m2()+meMomenta()[3].m2()) : sqr(mu_UV_); sHat() : sqr(mu_UV_); } Energy2 MEPP2VVPowheg::mu_F2() const { return scaleopt_ == 1 ? // ((H_.k1r()).m2()+k1r_perp2_lab_+(H_.k2r()).m2()+k2r_perp2_lab_)/2. : sqr(mu_F_); sHat() : sqr(mu_F_); } Energy2 MEPP2VVPowheg::mu_UV2() const { return scaleopt_ == 1 ? // ((H_.k1r()).m2()+k1r_perp2_lab_+(H_.k2r()).m2()+k2r_perp2_lab_)/2. : sqr(mu_UV_); sHat() : sqr(mu_UV_); } void MEPP2VVPowheg::doinit() { MEPP2VV::doinit(); // get the vertices we need // get a pointer to the standard model object in the run static const tcHwSMPtr hwsm = dynamic_ptr_cast(standardModel()); if (!hwsm) throw InitException() << "missing hwsm pointer in MEPP2VVPowheg::doinit()" << Exception::abortnow; // get pointers to all required Vertex objects FFPvertex_ = hwsm->vertexFFP(); FFZvertex_ = hwsm->vertexFFZ(); WWWvertex_ = hwsm->vertexWWW(); FFWvertex_ = hwsm->vertexFFW(); FFGvertex_ = hwsm->vertexFFG(); // get the ckm object Ptr::pointer theCKM=dynamic_ptr_cast::pointer>(SM().CKM()); if(!theCKM) throw InitException() << "MEPP2VVPowheg::doinit() " << "the CKM object must be the Herwig one" << Exception::runerror; unsigned int ix,iy; // get the CKM matrix (unsquared for interference) vector< vector > CKM(theCKM->getUnsquaredMatrix(SM().families())); for(ix=0;ix<3;++ix){for(iy=0;iy<3;++iy){ckm_[ix][iy]=CKM[ix][iy];}} // insert the different prefactors in the vector for easy look up prefactor_.push_back(preqqbar_); prefactor_.push_back(preqg_); prefactor_.push_back(pregqbar_); } int MEPP2VVPowheg::nDim() const { int output = MEPP2VV::nDim(); // See related comment in MEPP2VVPowheg::generateKinematics! if(contrib_>0) output += 2; return output; } bool MEPP2VVPowheg::generateKinematics(const double * r) { // N.B. A fix was made to make theta2 a radiative // variable in r4532. Originally theta2 was take to // be the azimuthal angle coming from the generation // of the Born kinematics inherited from MEPP2VV i.e. // before the change theta2 was a random number between // 0 and 2pi. On changing theta2 was set to be // theta2 = (*(r+3)) * 2.*Constants::pi; // and nDim returned if(contrib_>0) output += 3; // In the months following it was noticed that agreement // with MCFM was per mille at Tevatron energies but got // close to 1 percent for LHC energies (for all VV // processes). After searching back up the svn branch // running 2M events each time, the change was spotted // to occur on r4532. Changing: // if(contrib_>0) output += 3; // in ::nDim() and also, // xt = (*(r +nDim() -3)); // y = (*(r +nDim() -2)) * 2. - 1.; // theta2 = (*(r +nDim() -1)) * 2.*Constants::pi; // did not fix the problem. The following code gives the // same good level of agreement at LHC and TVT: double xt( -999.); double y( -999.); double theta2( -999.); if(contrib_>0) { // Generate the radiative integration variables: xt = (*(r +nDim() -2)); y = (*(r +nDim() -1)) * 2. - 1.; // KH 19th August - next line changed for phi in 0->pi not 0->2pi // theta2 = UseRandom::rnd() * 2.*Constants::pi; theta2 = UseRandom::rnd() *Constants::pi; } // Continue with lo matrix element code: bool output(MEPP2VV::generateKinematics(r)); // Work out the kinematics for the leading order / virtual process // and also get the leading order luminosity function: getKinematics(xt,y,theta2); return output; } double MEPP2VVPowheg::me2() const { double output(0.0); useMe(); output = MEPP2VV::me2(); double mcfm_brs(1.); if(!removebr_) { switch(MEPP2VV::process()) { case 1: // W+(->e+,nu_e) W-(->e-,nu_ebar) (MCFM: 61 [nproc]) mcfm_brs *= 0.109338816; mcfm_brs *= 0.109338816; break; case 2: // W+/-(mu+,nu_mu / mu-,nu_mubar) Z(nu_e,nu_ebar) // (MCFM: 72+77 [nproc]) mcfm_brs *= 0.109338816; mcfm_brs *= 0.06839002; break; case 3: // Z(mu-,mu+) Z(e-,e+) (MCFM: 86 [nproc]) mcfm_brs *= 0.034616433; mcfm_brs *= 0.034616433; mcfm_brs *= 2.; // as identical particle factor 1/2 is now obsolete. break; case 4: // W+(mu+,nu_mu) Z(nu_e,nu_ebar) (MCFM: 72 [nproc]) mcfm_brs *= 0.109338816; mcfm_brs *= 0.06839002; break; case 5: // W-(mu-,nu_mubar) Z(nu_e,nu_ebar) (MCFM: 77 [nproc]) mcfm_brs *= 0.109338816; mcfm_brs *= 0.06839002; break; } } // Store the value of the leading order squared matrix element: lo_me2_ = output; output *= NLOweight(); output *= mcfm_brs; return output; } void MEPP2VVPowheg::getKinematics(double xt, double y, double theta2) { // In this member we want to get the lo_lumi_ as this is a // common denominator in the NLO weight. We want also the // bornVVKinematics object and all of the realVVKinematics // objects needed for the NLO weight. // Check if the W- is first in W+W- production. Already confirmed // mePartonData()[0] is a quark, and mePartonData()[1] is an antiquark. // We assume mePartonData[2] and mePartonData[3] are, respectively, // W+/- Z, W+/- W-/+, or Z Z. bool wminus_first(false); if((mePartonData()[2]->id()==-24)&&(mePartonData()[3]->id()==24)) wminus_first=true; // Now get all data on the LO process needed for the NLO computation: // The +z hadron in the lab: hadron_A_=dynamic_ptr_cast::transient_const_pointer> (lastParticles().first->dataPtr()); // The -z hadron in the lab: hadron_B_=dynamic_ptr_cast::transient_const_pointer> (lastParticles().second->dataPtr()); // Leading order momentum fractions: double xa(lastX1()); // The +z momentum fraction in the lab. double xb(lastX2()); // The -z momentum fraction in the lab. // Particle data for incoming +z & -z QCD particles respectively: ab_ = lastPartons().first ->dataPtr(); // The +z momentum parton in the lab. bb_ = lastPartons().second->dataPtr(); // The -z momentum parton in the lab. // We checked TVT & LHC for all VV channels with 10K events: // lastParticles().first ->momentum().z() is always positive // lastParticles().second->momentum().z() is always negative // lastParticles().first ->momentum().z()*xa=lastPartons().first ->momentum().z() 1 in 10^6 // lastParticles().second->momentum().z()*xb=lastPartons().second->momentum().z() 1 in 10^6 // Set the quark and antiquark data pointers. quark_ = mePartonData()[0]; antiquark_ = mePartonData()[1]; if(quark_->id()<0) swap(quark_,antiquark_); // Now in _our_ calculation we basically define the +z axis as being // given by the direction of the incoming quark for q+qb & q+g processes // and the incoming gluon for g+qbar processes. So now we might need to // flip the values of hadron_A_, hadron_B_, ab_, bb_, xa, xb accordingly: if(ab_->id()!=quark_->id()) { swap(hadron_A_,hadron_B_); swap(ab_,bb_); swap(xa,xb); } // So hadron_A_ is the thing containing a quark (ab_) with momentum frac xa, // hadron_B_ is the thing containing an antiquark (bb_) with momentum frac xb. // Now get the partonic flux for the Born process: lo_lumi_ = hadron_A_->pdf()->xfx(hadron_A_,ab_,scale(),xa)/xa * hadron_B_->pdf()->xfx(hadron_B_,bb_,scale(),xb)/xb; // For W+W- events make sure k1 corresponds to the W+ momentum: if(MEPP2VV::process()==1&&wminus_first) swap(meMomenta()[2],meMomenta()[3]); // Create the object containing all 2->2 __kinematic__ information: B_ = bornVVKinematics(meMomenta(),xa,xb); // We checked that meMomenta()[0] (quark) is in the +z direction and meMomenta()[1] // is in the -z direction (antiquark). // Revert momentum swap in case meMomenta and mePartonData correlation // needs preserving for other things. if(MEPP2VV::process()==1&&wminus_first) swap(meMomenta()[2],meMomenta()[3]); // Check the Born kinematics objects is internally consistent: // B_.sanityCheck(); // If we are going beyond leading order then lets calculate all of // the necessary real emission kinematics. if(contrib_>0) { // Soft limit of the 2->3 real emission kinematics: S_ = realVVKinematics(B_, 1., y, theta2); // Soft-collinear limit of the 2->3 kinematics (emission in +z direction): SCp_ = realVVKinematics(B_, 1., 1., theta2); // Soft-collinear limit of the 2->3 kinematics (emission in -z direction): SCm_ = realVVKinematics(B_, 1.,-1., theta2); // Collinear limit of the 2->3 kinematics (emission in +z direction): Cp_ = realVVKinematics(B_, xt, 1., theta2); // Collinear limit of the 2->3 kinematics (emission in -z direction): Cm_ = realVVKinematics(B_, xt,-1., theta2); // The resolved 2->3 real emission kinematics: H_ = realVVKinematics(B_, xt, y, theta2); // Borrowed from VVhardGenerator (lab momenta of k1,k2): Energy pT(sqrt(H_.pT2_in_lab())); LorentzRotation yzRotation; yzRotation.setRotateX(-atan2(pT/GeV,sqrt(B_.sb())/GeV)); LorentzRotation boostFrompTisZero; boostFrompTisZero.setBoostY(-pT/sqrt(B_.sb()+pT*pT)); LorentzRotation boostFromYisZero; boostFromYisZero.setBoostZ(tanh(B_.Yb())); k1r_perp2_lab_ = (boostFromYisZero*boostFrompTisZero*yzRotation*(H_.k1r())).perp2(); k2r_perp2_lab_ = (boostFromYisZero*boostFrompTisZero*yzRotation*(H_.k2r())).perp2(); // Check all the real kinematics objects are internally consistent: // S_.sanityCheck(); // SCp_.sanityCheck(); // SCm_.sanityCheck(); // Cp_.sanityCheck(); // Cm_.sanityCheck(); // H_.sanityCheck(); } return; } double MEPP2VVPowheg::NLOweight() const { // If only leading order is required return 1: if(contrib_==0) return lo_me()/lo_me2_; // Calculate alpha_S and alpha_S/(2*pi). alphaS_ = nlo_alphaS_opt_==1 ? fixed_alphaS_ : SM().alphaS(mu_UV2()); double alsOn2pi(alphaS_/2./pi); // Particle data objects for the new plus and minus colliding partons. tcPDPtr gluon; gluon = getParticleData(ParticleID::g); // Get the all couplings. gW_ = sqrt(4.0*pi*SM().alphaEM(scale())/SM().sin2ThetaW()); sin2ThetaW_ = SM().sin2ThetaW(); double cosThetaW(sqrt(1.-sin2ThetaW_)); guL_ = gW_/2./cosThetaW*( 1.-4./3.*sin2ThetaW_); gdL_ = gW_/2./cosThetaW*(-1.+2./3.*sin2ThetaW_); guR_ = gW_/2./cosThetaW*( -4./3.*sin2ThetaW_); gdR_ = gW_/2./cosThetaW*( +2./3.*sin2ThetaW_); eZ_ = gW_*cosThetaW; eZ2_ = sqr(eZ_); // MCFM has gwsq = 0.4389585130009 -> gw = 0.662539442600115 // Here we have gW_ = 0.662888 // MCFM has xw = 0.22224653300000 -> sqrt(xw) = 0.471430306 // Here we have 0.222247 // MCFM has esq = 0.097557007645279 -> e = 0.31234117187024679 // Here we have 4.0*pi*SM().alphaEM(sqr(100.*GeV)) = 0.0976596 // If the process is W-Z instead of W+Z we must transform these // couplings as follows, according to NPB 383(1992)3-44 Eq.3.23 if(mePartonData()[2]->id()==-24&&mePartonData()[3]->id()==23) { swap(guL_,gdL_); eZ_ *= -1.; } // Get the CKM entry. Note that this code was debugged // considerably; the call to CKM(particle,particle) // did not appear to work, so we extract the elements // as follows below. The right numbers now appear to // to be associated with the right quarks. double Kij(-999.); // W+Z / W-Z if(abs(mePartonData()[2]->id())==24&&mePartonData()[3]->id()==23) { int up_id(-999),dn_id(-999); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==1) { up_id = abs(quark_->id()); dn_id = abs(antiquark_->id()); } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==0) { up_id = abs(antiquark_->id()); dn_id = abs(quark_->id()); } else { cout << "MEPP2VVPowheg:" << endl; cout << "WZ needs an up and a down type quark as incoming!" << endl; } up_id /= 2; up_id -= 1; dn_id -= 1; dn_id /= 2; Kij = sqrt(SM().CKM(up_id,dn_id)); } // W+W- else if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { int up_ida(abs(quark_->id())/2-1); int up_idb(abs(antiquark_->id())/2-1); Kij = sqrt(std::norm( CKM(up_ida,0)*CKM(up_idb,0) + CKM(up_ida,1)*CKM(up_idb,1) + CKM(up_ida,2)*CKM(up_idb,2))); } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { int dn_ida((abs(quark_->id())-1)/2); int dn_idb((abs(antiquark_->id())-1)/2); Kij = sqrt(std::norm( CKM(0,dn_ida)*CKM(0,dn_idb) + CKM(1,dn_ida)*CKM(1,dn_idb) + CKM(2,dn_ida)*CKM(2,dn_idb))); } else { cout << "MEPP2VVPowheg:" << endl; cout << "WW needs 2 down-type / 2 up-type!" << endl; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { Kij = 2.*sqrt(2.)/gW_; } else { cout << "MEPP2VVPowheg: incompatible final state particles!" << endl; } Fij2_ = sqr(gW_/2./sqrt(2.)*Kij); // Get the leading order matrix element (this is necessary!) M_Born_ = M_Born_WZ(B_); // // Get the regular part of the virtual correction (only needed for sanityCheck()!) // M_V_regular_ = M_V_regular(S_); // // Get the q + qbar real emission matrix element (only needed for sanityCheck()!) // t_u_M_R_qqb_ = t_u_M_R_qqb(H_); // Calculate the integrand double wgt(0.); double wqqb(0.); double wgqb(0.); double wqg(0.); double wqqbvirt(0.); double wqqbcollin(0.); double wqqbreal(0.); double wqgcollin(0.); double wqgreal(0.); double wgqbcollin(0.); double wgqbreal(0.); if(channels_==0||channels_==1) { // q+qb wqqbvirt = Vtilde_universal(S_) + M_V_regular(S_)/lo_me2_; wqqbcollin = alsOn2pi*( Ctilde_Ltilde_qq_on_x(quark_,antiquark_,Cp_) + Ctilde_Ltilde_qq_on_x(quark_,antiquark_,Cm_) ); wqqbreal = alsOn2pi*Rtilde_Ltilde_qqb_on_x(quark_,antiquark_); wqqb = wqqbvirt + wqqbcollin + wqqbreal; } if(channels_==0||channels_==2) { // q+g wqgcollin = alsOn2pi*Ctilde_Ltilde_gq_on_x(quark_,gluon,Cm_); wqgreal = alsOn2pi*Rtilde_Ltilde_qg_on_x(quark_,gluon); wqg = wqgreal + wqgcollin; // g+qb wgqbcollin = alsOn2pi*Ctilde_Ltilde_gq_on_x(gluon,antiquark_,Cp_); wgqbreal = alsOn2pi*Rtilde_Ltilde_gqb_on_x(gluon,antiquark_); wgqb = wgqbreal+wgqbcollin; } // total contribution wgt = 1.+(wqqb+wgqb+wqg); // If restricting to qg, gqb channels then subtract the LO contribution: if(channels_==2) wgt -= 1.; if(!isfinite(wgt)) { cout << "MEPP2VVPowheg:: NLO weight " << "is bad: wgt = " << wgt << endl; cout << "MEPP2VVPowheg sanityCheck invoked!" << endl; cout << ab_->PDGName() << ", " << bb_->PDGName() << ", " << mePartonData()[2]->PDGName() << ", " << mePartonData()[3]->PDGName() << endl; cout << "lo_me2_ - M_Born_ (rel) = " << lo_me2_-M_Born_ << " (" << (lo_me2_-M_Born_)/M_Born_ << ")\n"; cout << "lo_me2_, M_Born_ " << lo_me2_ << ", " << M_Born_ << endl; cout << "xr = " << H_.xr() << " 1-xr = " << 1.-H_.xr() << " y = " << H_.y() << endl; cout << "tkr = " << H_.tkr()/GeV2 << " ukr = " << H_.ukr()/GeV2 << endl; cout << "root(sb) = " << sqrt(B_.sb())/GeV << endl; cout << "sb+tb+ub = " << B_.sb()/GeV2 << " + " << B_.tb()/GeV2 << " + " << B_.ub()/GeV2 << endl; cout << "sqrt(k12) " << sqrt(H_.k12r())/GeV << endl; cout << "sqrt(k22) " << sqrt(H_.k22r())/GeV << endl; cout << "sqr(Kij) " << Kij*Kij << endl; cout << "wqqbvirt " << wqqbvirt << endl; cout << "wqqbcollin " << wqqbcollin << endl; cout << "wqqbreal " << wqqbreal << endl; cout << "wqqb " << wqqb << endl; cout << "wqgcollin " << wqgcollin << endl; cout << "wqgreal " << wqgreal << endl; cout << "wqg " << wqg << endl; cout << "wgqbcollin " << wgqbcollin << endl; cout << "wgqbreal " << wgqbreal << endl; cout << "wgqb " << wgqb << endl; cout << "wgt " << wgt << endl; throw Exception() << "MEPP2VVPowheg:: NLO weight " << "is bad: " << wgt << Exception::eventerror; } return contrib_==1 ? max(0.,wgt) : max(0.,-wgt); } double MEPP2VVPowheg::Lhat_ab(tcPDPtr a, tcPDPtr b, realVVKinematics Kinematics) const { if(!(abs(a->id())<=6||a->id()==21)||!(abs(b->id())<=6||b->id()==21)) cout << "MEPP2VVPowheg::Lhat_ab: Error," << "particle a = " << a->PDGName() << ", " << "particle b = " << b->PDGName() << endl; double nlo_lumi(-999.); double x1(Kinematics.x1r()),x2(Kinematics.x2r()); nlo_lumi = (hadron_A_->pdf()->xfx(hadron_A_,a,mu_F2(),x1)/x1) * (hadron_B_->pdf()->xfx(hadron_B_,b,mu_F2(),x2)/x2); return nlo_lumi / lo_lumi_; } double MEPP2VVPowheg::Vtilde_universal(realVVKinematics S) const { double xbar_y = S.xbar(); double y = S.y(); double eta1b(S.bornVariables().eta1b()); double eta2b(S.bornVariables().eta2b()); Energy2 sb(S.s2r()); return alphaS_/2./pi*CF_ * ( log(sb/mu_F2()) * (3. + 4.*log(eta1b)+4.*log(eta2b)) + 8.*sqr(log(eta1b)) +8.*sqr(log(eta2b)) - 2.*sqr(pi)/3. ) + alphaS_/2./pi*CF_ * ( 8./(1.+y)*log(sqrt(1.-xbar_y)/eta2b) + 8./(1.-y)*log(sqrt(1.-xbar_y)/eta1b) ); } double MEPP2VVPowheg::Ctilde_Ltilde_qq_on_x(tcPDPtr a, tcPDPtr b, realVVKinematics C) const { if(C.y()!= 1.&&C.y()!=-1.) cout << "\nCtilde_qq::y value not allowed."; if(C.y()== 1.&&!(abs(a->id())>0&&abs(a->id())<7)) cout << "\nCtilde_qq::for Cqq^plus a must be a quark! id = " << a->id() << "\n"; if(C.y()==-1.&&!(abs(b->id())>0&&abs(b->id())<7)) cout << "\nCtilde_qq::for Cqq^minus b must be a quark! id = " << b->id() << "\n"; double xt = C.xt(); double x = C.xr(); double etab = C.y() == 1. ? C.bornVariables().eta1b() : C.bornVariables().eta2b() ; Energy2 sb(C.s2r()); if(fabs(1.-xt)<=tiny||fabs(1.-H_.xr())<=tiny) return 0.; return ( ( (1./(1.-xt))*log(sb/mu_F2()/x)+4.*log(etab)/(1.-xt) + 2.*log(1.-xt)/(1.-xt) )*CF_*(1.+sqr(x)) + sqr(etab)*CF_*(1.-x) )*Lhat_ab(a,b,C) / x - ( ( (1./(1.-xt))*log(sb/mu_F2() )+4.*log(etab)/(1.-xt) + 2.*log(1.-xt)/(1.-xt) )*CF_*2. )*Lhat_ab(a,b,S_); } double MEPP2VVPowheg::Ctilde_Ltilde_gq_on_x(tcPDPtr a, tcPDPtr b, realVVKinematics C) const { if(C.y()!= 1.&&C.y()!=-1.) cout << "\nCtilde_gq::y value not allowed."; if(C.y()== 1.&&a->id()!=21) cout << "\nCtilde_gq::for Cgq^plus a must be a gluon! id = " << a->id() << "\n"; if(C.y()==-1.&&b->id()!=21) cout << "\nCtilde_gq::for Cgq^minus b must be a gluon! id = " << b->id() << "\n"; double xt = C.xt(); double x = C.xr(); double etab = C.y() == 1. ? C.bornVariables().eta1b() : C.bornVariables().eta2b() ; Energy2 sb(C.s2r()); return ( ( (1./(1.-xt))*log(sb/mu_F2()/x)+4.*log(etab)/(1.-xt) + 2.*log(1.-xt)/(1.-xt) )*(1.-x)*TR_*(sqr(x)+sqr(1.-x)) + sqr(etab)*TR_*2.*x*(1.-x) )*Lhat_ab(a,b,C) / x; } double MEPP2VVPowheg::Rtilde_Ltilde_qqb_on_x(tcPDPtr a , tcPDPtr b) const { if(!(abs(a->id())<=6||a->id()==21)||!(abs(b->id())<=6||b->id()==21)) cout << "MEPP2VVPowheg::Rtilde_Ltilde_qqb_on_x: Error," << "particle a = " << a->PDGName() << ", " << "particle b = " << b->PDGName() << endl; double xt(H_.xt()); double y(H_.y()); Energy2 s(H_.sr()); Energy2 sCp(Cp_.sr()); Energy2 sCm(Cm_.sr()); Energy2 t_u_M_R_qqb_H (t_u_M_R_qqb(H_ )); Energy2 t_u_M_R_qqb_Cp(t_u_M_R_qqb(Cp_)); Energy2 t_u_M_R_qqb_Cm(t_u_M_R_qqb(Cm_)); // Energy2 t_u_M_R_qqb_H (t_u_M_R_qqb_hel_amp(H_)); // Energy2 t_u_M_R_qqb_Cp(8.*pi*alphaS_*Cp_.sr()/Cp_.xr() // *CF_*(1.+sqr(Cp_.xr()))*lo_me2_); // Energy2 t_u_M_R_qqb_Cm(8.*pi*alphaS_*Cm_.sr()/Cm_.xr() // *CF_*(1.+sqr(Cm_.xr()))*lo_me2_); int config(0); if(fabs(1.-xt)<=tiny||fabs(1.-H_.xr())<=tiny) return 0.; if(fabs(1.-y )<=tiny) { t_u_M_R_qqb_H = t_u_M_R_qqb_Cp ; config = 1; } if(fabs(1.+y )<=tiny) { t_u_M_R_qqb_H = t_u_M_R_qqb_Cm ; config = -1; } if(fabs(H_.tkr()/s)<=tiny) { t_u_M_R_qqb_H = t_u_M_R_qqb_Cp ; config = 1; } if(fabs(H_.ukr()/s)<=tiny) { t_u_M_R_qqb_H = t_u_M_R_qqb_Cm ; config = -1; } if(config== 0) return ( ( (t_u_M_R_qqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qqb_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) + ( (t_u_M_R_qqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qqb_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) ) / lo_me2_ / 8. / pi / alphaS_; else if(config== 1) return ( (t_u_M_R_qqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qqb_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else if(config==-1) return ( (t_u_M_R_qqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qqb_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else throw Exception() << "MEPP2VVPowheg::Rtilde_Ltilde_qqb_on_x\n" << "The configuration is not identified as hard / soft / fwd collinear or bwd collinear." << "config = " << config << "\n" << "xt = " << xt << " 1.-xt = " << 1.-xt << "\n" << "y = " << y << " 1.-y = " << 1.-y << "\n" << Exception::eventerror; } double MEPP2VVPowheg::Rtilde_Ltilde_gqb_on_x(tcPDPtr a , tcPDPtr b) const { if(!(abs(a->id())<=6||a->id()==21)||!(abs(b->id())<=6||b->id()==21)) cout << "MEPP2VVPowheg::Rtilde_Ltilde_gqb_on_x: Error," << "particle a = " << a->PDGName() << ", " << "particle b = " << b->PDGName() << endl; double xt(H_.xt()); double y(H_.y()); Energy2 s(H_.sr()); Energy2 sCp(Cp_.sr()); Energy2 sCm(Cm_.sr()); Energy2 t_u_M_R_gqb_H (t_u_M_R_gqb(H_ )); Energy2 t_u_M_R_gqb_Cp(t_u_M_R_gqb(Cp_)); Energy2 t_u_M_R_gqb_Cm(t_u_M_R_gqb(Cm_)); // Energy2 t_u_M_R_gqb_H (t_u_M_R_gqb_hel_amp(H_)); // Energy2 t_u_M_R_gqb_Cp(8.*pi*alphaS_*Cp_.sr()/Cp_.xr()*(1.-Cp_.xr()) // *TR_*(sqr(Cp_.xr())+sqr(1.-Cp_.xr()))*lo_me2_); // Energy2 t_u_M_R_gqb_Cm(t_u_M_R_gqb(Cm_)); // // Energy2 t_u_M_R_gqb_Cm(t_u_M_R_gqb_hel_amp(Cm_)); int config(0); if(fabs(1.-xt)<=tiny||fabs(1.-H_.xr())<=tiny) return 0.; if(fabs(1.-y )<=tiny) { t_u_M_R_gqb_H = t_u_M_R_gqb_Cp ; config = 1; } if(fabs(1.+y )<=tiny) { t_u_M_R_gqb_H = t_u_M_R_gqb_Cm ; config = -1; } if(fabs(H_.tkr()/s)<=tiny) { t_u_M_R_gqb_H = t_u_M_R_gqb_Cp ; config = 1; } if(fabs(H_.ukr()/s)<=tiny) { t_u_M_R_gqb_H = t_u_M_R_gqb_Cm ; config = -1; } if(config== 0) return ( ( (t_u_M_R_gqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_gqb_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) + ( (t_u_M_R_gqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_gqb_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) ) / lo_me2_ / 8. / pi / alphaS_; else if(config== 1) return ( (t_u_M_R_gqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_gqb_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else if(config==-1) return ( (t_u_M_R_gqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_gqb_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else throw Exception() << "MEPP2VVPowheg::Rtilde_Ltilde_gqb_on_x\n" << "The configuration is not identified as hard / soft / fwd collinear or bwd collinear." << "config = " << config << "\n" << "xt = " << xt << " 1.-xt = " << 1.-xt << "\n" << "y = " << y << " 1.-y = " << 1.-y << "\n" << Exception::eventerror; } double MEPP2VVPowheg::Rtilde_Ltilde_qg_on_x(tcPDPtr a , tcPDPtr b) const { if(!(abs(a->id())<=6||a->id()==21)||!(abs(b->id())<=6||b->id()==21)) cout << "MEPP2VVPowheg::Rtilde_Ltilde_qg_on_x: Error," << "particle a = " << a->PDGName() << ", " << "particle b = " << b->PDGName() << endl; double xt(H_.xt()); double y(H_.y()); Energy2 s(H_.sr()); Energy2 sCp(Cp_.sr()); Energy2 sCm(Cm_.sr()); Energy2 t_u_M_R_qg_H (t_u_M_R_qg(H_ )); Energy2 t_u_M_R_qg_Cp(t_u_M_R_qg(Cp_)); Energy2 t_u_M_R_qg_Cm(t_u_M_R_qg(Cm_)); // Energy2 t_u_M_R_qg_H (t_u_M_R_qg_hel_amp(H_)); // Energy2 t_u_M_R_qg_Cp(t_u_M_R_qg(Cp_)); // // Energy2 t_u_M_R_qg_Cp(t_u_M_R_qg_hel_amp(Cp_)); // Energy2 t_u_M_R_qg_Cm(8.*pi*alphaS_*Cm_.sr()/Cm_.xr()*(1.-Cm_.xr()) // *TR_*(sqr(Cm_.xr())+sqr(1.-Cm_.xr()))*lo_me2_); int config(0); if(fabs(1.-xt)<=tiny||fabs(1.-H_.xr())<=tiny) return 0.; if(fabs(1.-y )<=tiny) { t_u_M_R_qg_H = t_u_M_R_qg_Cp ; config = 1; } if(fabs(1.+y )<=tiny) { t_u_M_R_qg_H = t_u_M_R_qg_Cm ; config = -1; } if(fabs(H_.tkr()/s)<=tiny) { t_u_M_R_qg_H = t_u_M_R_qg_Cp ; config = 1; } if(fabs(H_.ukr()/s)<=tiny) { t_u_M_R_qg_H = t_u_M_R_qg_Cm ; config = -1; } if(config== 0) return ( ( (t_u_M_R_qg_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qg_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) + ( (t_u_M_R_qg_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qg_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) ) / lo_me2_ / 8. / pi / alphaS_; else if(config== 1) return ( (t_u_M_R_qg_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qg_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else if(config==-1) return ( (t_u_M_R_qg_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qg_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else throw Exception() << "MEPP2VVPowheg::Rtilde_Ltilde_qg_on_x\n" << "The configuration is not identified as hard / soft / fwd collinear or bwd collinear." << "config = " << config << "\n" << "xt = " << xt << " 1.-xt = " << 1.-xt << "\n" << "y = " << y << " 1.-y = " << 1.-y << "\n" << Exception::eventerror; } /***************************************************************************/ // The following three functions are identically \tilde{I}_{4,t}, // \tilde{I}_{3,WZ} and \tilde{I}_{3,W} given in Eqs. B.8,B.9,B.10 // of NPB 383(1992)3-44, respectively. They are related to / derived // from the loop integrals in Eqs. A.3, A.5 and A.8 of the same paper. InvEnergy4 TildeI4t(Energy2 s, Energy2 t, Energy2 mW2, Energy2 mZ2); InvEnergy2 TildeI3WZ(Energy2 s, Energy2 mW2, Energy2 mZ2, double beta); InvEnergy2 TildeI3W(Energy2 s, Energy2 t, Energy2 mW2); /***************************************************************************/ // The following six functions are identically I_{dd}^{(1)}, I_{ud}^{(1)}, // I_{uu}^{(1)}, F_{u}^{(1)}, F_{d}^{(1)}, H^{(1)} from Eqs. B.4, B.5, B.3, // B.3, B.6, B.7 of NPB 383(1992)3-44, respectively. They make up the // one-loop matrix element. Ixx functions correspond to the graphs // with no TGC, Fx functions are due to non-TGC graphs interfering // with TGC graphs, while the H function is due purely to TGC graphs. double Idd1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta); double Iud1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta); double Iuu1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta); Energy2 Fu1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta); Energy2 Fd1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta); Energy4 H1 (Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); /***************************************************************************/ // M_V_Regular is the regular part of the one-loop matrix element // exactly as defined in Eqs. B.1 and B.2 of of NPB 383(1992)3-44. double MEPP2VVPowheg::M_V_regular(realVVKinematics S) const { Energy2 s(S.bornVariables().sb()); Energy2 t(S.bornVariables().tb()); Energy2 u(S.bornVariables().ub()); Energy2 mW2(S.k12r()); // N.B. the diboson masses are preserved in getting Energy2 mZ2(S.k22r()); // the 2->2 from the 2->3 kinematics. double beta(S.betaxr()); // N.B. for x=1 \beta_x=\beta in NPB 383(1992)3-44. double cosThetaW(sqrt(1.-sin2ThetaW_)); double eZ2(eZ2_); double eZ(eZ_); double gdL(gdL_); double guL(guL_); double gdR(gdR_); double guR(guR_); // W+W- if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { double e2(sqr(gW_)*sin2ThetaW_); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s-mW2)/Fij2_ * (e2*e2/s/s*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s/(s-mW2/sqr(cosThetaW))) +sqr( eZ*(guL-guR)/2./e2*s/(s-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s-mW2) * (gW_*gW_*e2/4./s *( 2./3.+2.*eZ*guL/2./e2*s/(s-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } gdL = gW_/sqrt(2.); guL = 0.; } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s-mW2)/Fij2_ * (e2*e2/s/s*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s/(s-mW2/sqr(cosThetaW))) +sqr( eZ*(gdL-gdR)/2./e2*s/(s-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s-mW2) * (gW_*gW_*e2/4./s *(-1./3.+2.*eZ*gdL/2./e2*s/(s-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } guL = gW_/sqrt(2.); gdL = 0.; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { eZ = 0.; eZ2 = 0.; double gV2,gA2; gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL; else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL; else { cout << "MEPP2VVPowheg:" << endl; cout << "ZZ needs 2 down-type / 2 up-type!" << endl; } } return 4.*pi*alphaS_*Fij2_*CF_*(1./sqr(4.*pi))/NC_ * ( gdL*gdL*Idd1(s,t,u,mW2,mZ2,beta) + gdL*guL*Iud1(s,t,u,mW2,mZ2,beta) + guL*guL*Iuu1(s,t,u,mW2,mZ2,beta) - eZ/(s-mW2) * ( gdL*Fd1(s,t,u,mW2,mZ2,beta) - guL*Fu1(s,t,u,mW2,mZ2,beta) ) + eZ2/sqr(s-mW2) * H1(s,t,u,mW2,mZ2) ); } /***************************************************************************/ InvEnergy4 TildeI4t(Energy2 s, Energy2 t, Energy2 mW2, Energy2 mZ2) { double sqrBrackets; sqrBrackets = ( sqr(log(-t/mW2))/2.+log(-t/mW2)*log(-t/mZ2)/2. - 2.*log(-t/mW2)*log((mW2-t)/mW2)-2.*ReLi2(t/mW2) ); swap(mW2,mZ2); sqrBrackets+= ( sqr(log(-t/mW2))/2.+log(-t/mW2)*log(-t/mZ2)/2. - 2.*log(-t/mW2)*log((mW2-t)/mW2)-2.*ReLi2(t/mW2) ); swap(mW2,mZ2); return sqrBrackets/s/t; } InvEnergy2 TildeI3WZ(Energy2 s, Energy2 mW2, Energy2 mZ2, double beta) { Energy2 sig(mZ2+mW2); Energy2 del(mZ2-mW2); double sqrBrackets ; sqrBrackets = ( ReLi2(2.*mW2/(sig-del*(del/s+beta))) + ReLi2((1.-del/s+beta)/2.) + sqr(log((1.-del/s+beta)/2.))/2. + log((1.-del/s-beta)/2.)*log((1.+del/s-beta)/2.) ); beta *= -1; sqrBrackets -= ( ReLi2(2.*mW2/(sig-del*(del/s+beta))) + ReLi2((1.-del/s+beta)/2.) + sqr(log((1.-del/s+beta)/2.))/2. + log((1.-del/s-beta)/2.)*log((1.+del/s-beta)/2.) ); beta *= -1; swap(mW2,mZ2); del *= -1.; sqrBrackets += ( ReLi2(2.*mW2/(sig-del*(del/s+beta))) + ReLi2((1.-del/s+beta)/2.) + sqr(log((1.-del/s+beta)/2.))/2. + log((1.-del/s-beta)/2.)*log((1.+del/s-beta)/2.) ); swap(mW2,mZ2); del *= -1.; beta *= -1; swap(mW2,mZ2); del *= -1.; sqrBrackets -= ( ReLi2(2.*mW2/(sig-del*(del/s+beta))) + ReLi2((1.-del/s+beta)/2.) + sqr(log((1.-del/s+beta)/2.))/2. + log((1.-del/s-beta)/2.)*log((1.+del/s-beta)/2.) ); beta *= -1; swap(mW2,mZ2); del *= -1.; return sqrBrackets/s/beta; } InvEnergy2 TildeI3W(Energy2 s, Energy2 t, Energy2 mW2) { return 1./(mW2-t)*(sqr(log(mW2/s))/2.-sqr(log(-t/s))/2.-sqr(pi)/2.); } /***************************************************************************/ double Idd1(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) { Energy2 sig(mZ2+mW2); Energy2 del(mZ2-mW2); double Val(0.); Val += 2.*(22.*t*t+t*(19.*s-18.*sig)+18.*mW2*mZ2)/t/t - 8.*(u*t+2*s*sig)/mW2/mZ2 - 2.*sqr(t-u)/t/s/sqr(beta); Val += +( 2.*(8.*t*t+4.*t*(s-3.*sig)+4*sqr(sig)-5.*s*sig+s*s)/t/s/sqr(beta) + 4.*(t*(3.*u+s)-3.*mW2*mZ2)/t/t + 6.*(t+u)*sqr(t-u)/t/s/s/sqr(sqr(beta)) )*log(-t/s); Val += +( ( 8.*t*t*(-2.*s+del)+8.*t*(-s*s+3.*s*sig-2.*del*sig) - 2.*(s-sig)*(s*s-4.*s*sig+3.*del*sig) )/t/s/s/beta/beta + 16.*s*(t-mZ2)/(t*(u+s)-mW2*mZ2) + 2.*(4.*t*t+t*(10.*s-3.*mZ2-9.*mW2)+12.*mW2*mZ2)/t/t -6.*(s-del)*(t+u)*sqr(t-u)/t/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( - ( 4.*t*t*(2.*sig-3.*s) - 4.*t*(s-sig)*(2.*s-3.*sig) - 2.*(s-2.*sig)*sqr(s-sig) )/t/s/beta/beta + ( 4.*sig*t-3.*s*s+4.*s*sig - 4.*(mW2*mW2+mZ2*mZ2) )/t - 3.*sqr(t*t-u*u)/t/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += +( 4.*(t*u+2.*s*sig)/3./mW2/mZ2 - 4.*(t-2.*u)/3./t )*pi*pi; Val += -( 4.*s*(t*u-2.*mW2*mZ2)/t )*TildeI4t(s,t,mW2,mZ2); Val += ( 8.*(t-mW2)*(u*t-2.*mW2*mZ2)/t/t )*TildeI3W(s,t,mW2); swap(mW2,mZ2); del *= -1; Val += 2.*(22.*t*t+t*(19.*s-18.*sig)+18.*mW2*mZ2)/t/t - 8.*(u*t+2*s*sig)/mW2/mZ2 - 2.*sqr(t-u)/t/s/sqr(beta); Val += +( 2.*(8.*t*t+4.*t*(s-3.*sig)+4*sqr(sig)-5.*s*sig+s*s)/t/s/sqr(beta) + 4.*(t*(3.*u+s)-3.*mW2*mZ2)/t/t + 6.*(t+u)*sqr(t-u)/t/s/s/sqr(sqr(beta)) )*log(-t/s); Val += +( ( 8.*t*t*(-2.*s+del)+8.*t*(-s*s+3.*s*sig-2.*del*sig) - 2.*(s-sig)*(s*s-4.*s*sig+3.*del*sig) )/t/s/s/beta/beta + 16.*s*(t-mZ2)/(t*(u+s)-mW2*mZ2) + 2.*(4.*t*t+t*(10.*s-3.*mZ2-9.*mW2)+12.*mW2*mZ2)/t/t -6.*(s-del)*(t+u)*sqr(t-u)/t/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( - ( 4.*t*t*(2.*sig-3.*s) - 4.*t*(s-sig)*(2.*s-3.*sig) - 2.*(s-2.*sig)*sqr(s-sig) )/t/s/beta/beta + ( 4.*sig*t-3.*s*s+4.*s*sig - 4.*(mW2*mW2+mZ2*mZ2) )/t - 3.*sqr(t*t-u*u)/t/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += +( 4.*(t*u+2.*s*sig)/3./mW2/mZ2 - 4.*(t-2.*u)/3./t )*pi*pi; Val += -( 4.*s*(t*u-2.*mW2*mZ2)/t )*TildeI4t(s,t,mW2,mZ2); Val += ( 8.*(t-mW2)*(u*t-2.*mW2*mZ2)/t/t )*TildeI3W(s,t,mW2); swap(mW2,mZ2); del *= -1; return Val; } /***************************************************************************/ double Iud1(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) { Energy2 sig(mZ2+mW2); Energy2 del(mZ2-mW2); double Val(0.); Val += 2.*(4.*t*t+t*(9.*s-4.*sig)-18.*s*sig)/t/u + 8.*(t*u+2.*s*sig)/mW2/mZ2 + 4.*s*s*(2.*t-sig)/u/(mW2*mZ2-t*(u+s)) - 2.*sqr(t-u)/u/s/sqr(beta); Val += ( 2.*(8.*t*t-4.*t*(s+3.*sig)-(s-sig)*(3.*s+4.*sig))/u/s/sqr(beta) + 6.*(t+u)*sqr(t-u)/u/s/s/sqr(sqr(beta)) - 12.*s*(t-sig)/t/u )*log(-t/s); Val += ( (2./u/s/s/sqr(beta))*( 4.*t*t*(-2.*s+del) + 4.*t*(s*s+s*(mZ2+5.*mW2)-2.*sig*del) + (s-sig)*(3.*s*s+8.*mW2*s-3.*sig*del) ) + (2.*t*(18.*s+3.*mW2+mZ2)-24.*s*sig)/t/u - 8.*s*(2.*t*t-t*(3.*s+4.*mZ2+2.*mW2)+2.*mZ2*(s+sig)) /u/(mW2*mZ2-t*(u+s)) - 8.*s*s*t*(2.*t-sig)*(t-mZ2)/u/sqr(mW2*mZ2-t*(u+s)) + 6.*(s-del)*(s-sig)*sqr(t-u)/u/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( -2.*(2.*t*t*(2.*sig-3.*s)+6.*sig*t*(s-sig)+sqr(s-sig)*(s+2.*sig)) /u/s/sqr(beta) +3.*s*(4.*t-4.*sig-s)/u -3.*sqr(s-sig)*sqr(t-u)/u/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += ( 4.*(u+4.*s)/3./u - 4.*(u*t+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += -( 16.*s*(t-sig)*(t-mW2)/t/u )*TildeI3W(s,t,mW2); Val += ( 8.*s*s*(t-sig)/u )*TildeI4t(s,t,mW2,mZ2); swap(t,u); Val += 2.*(4.*t*t+t*(9.*s-4.*sig)-18.*s*sig)/t/u + 8.*(t*u+2.*s*sig)/mW2/mZ2 + 4.*s*s*(2.*t-sig)/u/(mW2*mZ2-t*(u+s)) - 2.*sqr(t-u)/u/s/sqr(beta); Val += ( 2.*(8.*t*t-4.*t*(s+3.*sig)-(s-sig)*(3.*s+4.*sig))/u/s/sqr(beta) + 6.*(t+u)*sqr(t-u)/u/s/s/sqr(sqr(beta)) - 12.*s*(t-sig)/t/u )*log(-t/s); Val += ( (2./u/s/s/sqr(beta))*( 4.*t*t*(-2.*s+del) + 4.*t*(s*s+s*(mZ2+5.*mW2)-2.*sig*del) + (s-sig)*(3.*s*s+8.*mW2*s-3.*sig*del) ) + (2.*t*(18.*s+3.*mW2+mZ2)-24.*s*sig)/t/u - 8.*s*(2.*t*t-t*(3.*s+4.*mZ2+2.*mW2)+2.*mZ2*(s+sig)) /u/(mW2*mZ2-t*(u+s)) - 8.*s*s*t*(2.*t-sig)*(t-mZ2)/u/sqr(mW2*mZ2-t*(u+s)) + 6.*(s-del)*(s-sig)*sqr(t-u)/u/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( -2.*(2.*t*t*(2.*sig-3.*s)+6.*sig*t*(s-sig)+sqr(s-sig)*(s+2.*sig)) /u/s/sqr(beta) +3.*s*(4.*t-4.*sig-s)/u -3.*sqr(s-sig)*sqr(t-u)/u/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += ( 4.*(u+4.*s)/3./u - 4.*(u*t+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += -( 16.*s*(t-sig)*(t-mW2)/t/u )*TildeI3W(s,t,mW2); Val += ( 8.*s*s*(t-sig)/u )*TildeI4t(s,t,mW2,mZ2); swap(t,u); swap(mW2,mZ2); del *= -1; Val += 2.*(4.*t*t+t*(9.*s-4.*sig)-18.*s*sig)/t/u + 8.*(t*u+2.*s*sig)/mW2/mZ2 + 4.*s*s*(2.*t-sig)/u/(mW2*mZ2-t*(u+s)) - 2.*sqr(t-u)/u/s/sqr(beta); Val += ( 2.*(8.*t*t-4.*t*(s+3.*sig)-(s-sig)*(3.*s+4.*sig))/u/s/sqr(beta) + 6.*(t+u)*sqr(t-u)/u/s/s/sqr(sqr(beta)) - 12.*s*(t-sig)/t/u )*log(-t/s); Val += ( (2./u/s/s/sqr(beta))*( 4.*t*t*(-2.*s+del) + 4.*t*(s*s+s*(mZ2+5.*mW2)-2.*sig*del) + (s-sig)*(3.*s*s+8.*mW2*s-3.*sig*del) ) + (2.*t*(18.*s+3.*mW2+mZ2)-24.*s*sig)/t/u - 8.*s*(2.*t*t-t*(3.*s+4.*mZ2+2.*mW2)+2.*mZ2*(s+sig)) /u/(mW2*mZ2-t*(u+s)) - 8.*s*s*t*(2.*t-sig)*(t-mZ2)/u/sqr(mW2*mZ2-t*(u+s)) + 6.*(s-del)*(s-sig)*sqr(t-u)/u/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( -2.*(2.*t*t*(2.*sig-3.*s)+6.*sig*t*(s-sig)+sqr(s-sig)*(s+2.*sig)) /u/s/sqr(beta) +3.*s*(4.*t-4.*sig-s)/u -3.*sqr(s-sig)*sqr(t-u)/u/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += ( 4.*(u+4.*s)/3./u - 4.*(u*t+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += -( 16.*s*(t-sig)*(t-mW2)/t/u )*TildeI3W(s,t,mW2); Val += ( 8.*s*s*(t-sig)/u )*TildeI4t(s,t,mW2,mZ2); swap(mW2,mZ2); del *= -1; swap(t,u); swap(mW2,mZ2); del *= -1; Val += 2.*(4.*t*t+t*(9.*s-4.*sig)-18.*s*sig)/t/u + 8.*(t*u+2.*s*sig)/mW2/mZ2 + 4.*s*s*(2.*t-sig)/u/(mW2*mZ2-t*(u+s)) - 2.*sqr(t-u)/u/s/sqr(beta); Val += ( 2.*(8.*t*t-4.*t*(s+3.*sig)-(s-sig)*(3.*s+4.*sig))/u/s/sqr(beta) + 6.*(t+u)*sqr(t-u)/u/s/s/sqr(sqr(beta)) - 12.*s*(t-sig)/t/u )*log(-t/s); Val += ( (2./u/s/s/sqr(beta))*( 4.*t*t*(-2.*s+del) + 4.*t*(s*s+s*(mZ2+5.*mW2)-2.*sig*del) + (s-sig)*(3.*s*s+8.*mW2*s-3.*sig*del) ) + (2.*t*(18.*s+3.*mW2+mZ2)-24.*s*sig)/t/u - 8.*s*(2.*t*t-t*(3.*s+4.*mZ2+2.*mW2)+2.*mZ2*(s+sig)) /u/(mW2*mZ2-t*(u+s)) - 8.*s*s*t*(2.*t-sig)*(t-mZ2)/u/sqr(mW2*mZ2-t*(u+s)) + 6.*(s-del)*(s-sig)*sqr(t-u)/u/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( -2.*(2.*t*t*(2.*sig-3.*s)+6.*sig*t*(s-sig)+sqr(s-sig)*(s+2.*sig)) /u/s/sqr(beta) +3.*s*(4.*t-4.*sig-s)/u -3.*sqr(s-sig)*sqr(t-u)/u/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += ( 4.*(u+4.*s)/3./u - 4.*(u*t+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += -( 16.*s*(t-sig)*(t-mW2)/t/u )*TildeI3W(s,t,mW2); Val += ( 8.*s*s*(t-sig)/u )*TildeI4t(s,t,mW2,mZ2); swap(t,u); swap(mW2,mZ2); del *= -1; return Val; } /***************************************************************************/ double Iuu1(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) { double Val(Idd1(s,u,t,mW2,mZ2,beta)); return Val; } /***************************************************************************/ Energy2 Fd1 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) { Energy2 sig(mZ2+mW2); Energy2 del(mZ2-mW2); Energy2 Val(0.*GeV2); Val += 4.*(17.*t*t+t*(11.*s-13.*sig)+17.*(s*sig+mW2*mZ2))/t + 16.*(s-sig)*(t*u+2.*s*sig)/mW2/mZ2 + 4*s*s*(2.*t-sig)/(t*(u+s)-mW2*mZ2); Val += ( 8.*(t-u)/sqr(beta) - 4.*(3.*t*t-t*(s+3.*sig)+3.*(s*sig+mW2*mZ2))/t )*log(-t/s); Val += ( 8.*(t*t-t*(2.*s+3.*mW2+mZ2)+3.*(s*sig+mW2*mZ2))/t + 8.*s*(t*(3.*s+2.*sig)-2.*mZ2*(s+sig))/(t*(u+s)-mW2*mZ2) + 8.*s*s*t*(2.*t-sig)*(t-mZ2)/sqr(t*(u+s)-mW2*mZ2) - 8.*(s-del)*(t-u)/s/sqr(beta) )*log(-t/mW2); Val += ( 4.*(s-sig)*(t-u)/sqr(beta) + 4.*(sig-3.*s)*t + 4.*(4.*s*sig-mZ2*mZ2-mW2*mW2) )*TildeI3WZ(s,mW2,mZ2,beta); Val += -( 8.*(3.*t*t+2.*t*(2.*s-sig)+2.*(s*sig+mW2*mZ2))/3./t + 8.*(s-sig)*(t*u+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += ( 4.*(s*t*t-s*(s+sig)*t+2.*s*(s*sig+mW2*mZ2)) )*TildeI4t(s,t,mW2,mZ2); Val += -( 8.*(t-mW2)*(t*t-t*(s+sig)+2.*(s*sig+mW2*mZ2))/t )*TildeI3W(s,t,mW2); swap(mW2,mZ2); del *= -1; Val += 4.*(17.*t*t+t*(11.*s-13.*sig)+17.*(s*sig+mW2*mZ2))/t + 16.*(s-sig)*(t*u+2.*s*sig)/mW2/mZ2 + 4*s*s*(2.*t-sig)/(t*(u+s)-mW2*mZ2); Val += ( 8.*(t-u)/sqr(beta) - 4.*(3.*t*t-t*(s+3.*sig)+3.*(s*sig+mW2*mZ2))/t )*log(-t/s); Val += ( 8.*(t*t-t*(2.*s+3.*mW2+mZ2)+3.*(s*sig+mW2*mZ2))/t + 8.*s*(t*(3.*s+2.*sig)-2.*mZ2*(s+sig))/(t*(u+s)-mW2*mZ2) + 8.*s*s*t*(2.*t-sig)*(t-mZ2)/sqr(t*(u+s)-mW2*mZ2) - 8.*(s-del)*(t-u)/s/sqr(beta) )*log(-t/mW2); Val += ( 4.*(s-sig)*(t-u)/sqr(beta) + 4.*(sig-3.*s)*t + 4.*(4.*s*sig-mZ2*mZ2-mW2*mW2) )*TildeI3WZ(s,mW2,mZ2,beta); Val += -( 8.*(3.*t*t+2.*t*(2.*s-sig)+2.*(s*sig+mW2*mZ2))/3./t + 8.*(s-sig)*(t*u+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += ( 4.*(s*t*t-s*(s+sig)*t+2.*s*(s*sig+mW2*mZ2)) )*TildeI4t(s,t,mW2,mZ2); Val += -( 8.*(t-mW2)*(t*t-t*(s+sig)+2.*(s*sig+mW2*mZ2))/t )*TildeI3W(s,t,mW2); swap(mW2,mZ2); del *= -1; return Val; } /***************************************************************************/ Energy2 Fu1 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) { Energy2 Val(Fd1(s,u,t,mW2,mZ2,beta)); return Val; } /***************************************************************************/ Energy4 H1 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { Energy2 sig(mZ2+mW2); Energy4 Val(0.*GeV2*GeV2); Val = 8.*t*t+8.*t*(s-sig)+s*s+6.*s*sig+mZ2*mZ2+10.*mW2*mZ2+mW2*mW2 - sqr(s-sig)*(t*u+2.*s*sig)/mW2/mZ2; Val *= ( 16.-8.*pi*pi/3.); return Val; } Energy2 t_u_Rdd(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1 , Energy2 q2, Energy2 mW2, Energy2 mZ2); Energy2 t_u_Rud(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1 , Energy2 q2, Energy2 q1h, Energy2 q2h, Energy2 mW2, Energy2 mZ2); Energy2 t_u_Ruu(Energy2 s , Energy2 tk , Energy2 uk, Energy2 q1h, Energy2 q2h, Energy2 mW2, Energy2 mZ2); Energy4 t_u_RZds(Energy2 s ,Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2,Energy2 mW2, Energy2 mZ2); Energy4 t_u_RZda(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2); Energy4 t_u_RZd(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1 , Energy2 q2 , Energy2 s2 , Energy2 mW2, Energy2 mZ2); Energy4 t_u_RZu(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1h, Energy2 q2h, Energy2 s2 , Energy2 mW2, Energy2 mZ2); Energy6 t_u_RZs(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2); Energy6 t_u_RZa(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2); Energy6 t_u_RZ(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2 , Energy2 mW2, Energy2 mZ2); /***************************************************************************/ // t_u_M_R_qqb is the real emission q + qb -> n + g matrix element // exactly as defined in Eqs. C.1 of NPB 383(1992)3-44, multiplied by // tk * uk! Energy2 MEPP2VVPowheg::t_u_M_R_qqb(realVVKinematics R) const { // First the Born variables: Energy2 s2(R.s2r()); Energy2 mW2(R.k12r()); Energy2 mZ2(R.k22r()); // Then the rest: Energy2 s(R.sr()); Energy2 tk(R.tkr()); Energy2 uk(R.ukr()); Energy2 q1(R.q1r()); Energy2 q2(R.q2r()); Energy2 q1h(R.q1hatr()); Energy2 q2h(R.q2hatr()); double cosThetaW(sqrt(1.-sin2ThetaW_)); double eZ2(eZ2_); double eZ(eZ_); double gdL(gdL_); double guL(guL_); double gdR(gdR_); double guR(guR_); // W+W- if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { double e2(sqr(gW_)*sin2ThetaW_); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(guL-guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *( 2./3.+2.*eZ*guL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } gdL = gW_/sqrt(2.); guL = 0.; } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(gdL-gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *(-1./3.+2.*eZ*gdL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } guL = gW_/sqrt(2.); gdL = 0.; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { eZ = 0.; eZ2 = 0.; double gV2,gA2; gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL; else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL; else { cout << "MEPP2VVPowheg:" << endl; cout << "ZZ needs 2 down-type / 2 up-type!" << endl; } } return -2.*pi*alphaS_*Fij2_*CF_/NC_ * ( gdL*gdL*t_u_Rdd(s,tk,uk,q1,q2,mW2,mZ2) + 2.*gdL*guL*t_u_Rud(s,tk,uk,q1,q2,q1h,q2h,mW2,mZ2) + guL*guL*t_u_Ruu(s,tk,uk,q1h,q2h,mW2,mZ2) - 2.*eZ/(s2-mW2) * ( gdL * t_u_RZd(s,tk,uk,q1 ,q2 ,s2,mW2,mZ2) - guL * t_u_RZu(s,tk,uk,q1h,q2h,s2,mW2,mZ2) ) + eZ2/sqr(s2-mW2) *t_u_RZ(s,tk,uk,q1,q2,s2,mW2,mZ2) ); } Energy2 t_u_Rdd(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1,Energy2 q2, Energy2 mW2, Energy2 mZ2) { Energy2 Val(0.*GeV2); Val += 4.*(q2*(uk+2.*s+q2)+q1*(s+q1))/mW2/mZ2*uk + 16.*(uk+s)/q2*uk - 4.*(2.*uk+4.*s+q2)/mW2*uk - 4.*(2.*uk+5.*s+q2+2.*q1-mW2)/mZ2*uk + 4.*q1*s*(s+q1)/mW2/mZ2 + 16.*s*(s+q2-mZ2-mW2)/q1 - 4.*s*(4.*s+q2+q1)/mW2 + 16.*mW2*mZ2*s/q1/q2 + 4.*s + 16.*mZ2*(tk-2.*mW2)/q1/q2/q2*tk*uk + 16.*(2.*mZ2+mW2-tk)/q1/q2*tk*uk + 16.*mW2*(s-mZ2-mW2)/q1/q2*uk + 16.*mZ2*(q1-2.*mW2)/q2/q2*uk + 32.*mW2*mW2*mZ2/q1/q2/q2*uk + 16.*mW2/q1*uk + 4.*uk + 8./q2*tk*uk + 4.*q1/mW2/mZ2*tk*uk - 24./q1*tk*uk - 4./mW2*tk*uk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); Val += 4.*(q2*(uk+2.*s+q2)+q1*(s+q1))/mW2/mZ2*uk + 16.*(uk+s)/q2*uk - 4.*(2.*uk+4.*s+q2)/mW2*uk - 4.*(2.*uk+5.*s+q2+2.*q1-mW2)/mZ2*uk + 4.*q1*s*(s+q1)/mW2/mZ2 + 16.*s*(s+q2-mZ2-mW2)/q1 - 4.*s*(4.*s+q2+q1)/mW2 + 16.*mW2*mZ2*s/q1/q2 + 4.*s + 16.*mZ2*(tk-2.*mW2)/q1/q2/q2*tk*uk + 16.*(2.*mZ2+mW2-tk)/q1/q2*tk*uk + 16.*mW2*(s-mZ2-mW2)/q1/q2*uk + 16.*mZ2*(q1-2.*mW2)/q2/q2*uk + 32.*mW2*mW2*mZ2/q1/q2/q2*uk + 16.*mW2/q1*uk + 4.*uk + 8./q2*tk*uk + 4.*q1/mW2/mZ2*tk*uk - 24./q1*tk*uk - 4./mW2*tk*uk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); return Val; } Energy2 t_u_Rud(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1,Energy2 q2, Energy2 q1h,Energy2 q2h,Energy2 mW2, Energy2 mZ2) { Energy2 Val(0.*GeV2); Val += (uk*s*(uk+3.*s+q1h)+s*s*(s+mZ2)-(s+uk)*(2.*mZ2*s+3.*mW2*s+mW2*q1h) ) * 8./q1/q2h/q2*uk - (uk*(uk+3.*s+q1h-mW2)-(q2+s)*(q2-s)+s*(q2-mW2)+q1h*(q2-mW2)+mW2*q2 ) * 4.*s/mZ2/q1/q2h*uk - 4.*((s+uk+q2h-2.*mZ2)*(s+q1h-mZ2)-mZ2*q1)/mW2/q2*uk + 4.*(2.*s*uk+2.*mW2*uk+5.*s*s+2.*q1h*s-2.*mZ2*s)/q1/q2h*uk + 4.*(2.*s*uk-s*s-2.*q1h*s+2.*mW2*s+2.*mW2*q1h)/q1/q2h/q2*tk*uk + ((2.*uk+s)*(s+q1h)+s*(q2+q2h)+2.*q2*(s+q2h)-q1*s+q1*q2+q1h*q2h ) /mW2/mZ2*uk + 8.*s*(uk-q1h+mZ2)/q1/q2*uk + 4.*s*(-uk+s-q2+q1+q1h)/mZ2/q2h*uk + 4.*s*(-uk-q2+q1h)/mZ2/q1*uk + 8.*(mZ2*uk-s*s+mW2*s-2.*mZ2*q1-2.*mZ2*q1h)/q2h/q2*uk + 2.*(-uk-9.*s-4.*q2-5.*q2h-3.*q1-4.*q1h+8.*mZ2)/mW2*uk + 2.*(-4.*uk+3.*s+5.*q1+4.*q1h)/q2h*uk + 2.*(s*tk+q2*tk+s*s-q2*q2+q1h*q2)/mW2/mZ2*tk - 8.*s*(tk+s+q1h)/mW2/q2*tk + 2.*(-tk+3.*s+q2-q1h)/mW2*tk - 8.*s*s*s/q1h/q2 - 2.*s*q2*(s+q2)/mW2/mZ2 + 2.*s*(2.*s+q2)/mZ2 + 2.*s*(2.*s+q2)/mW2 - 16.*s*s/q1h - 2.*s - 16.*s*s/q1h/q2*tk - 8.*s/q2*tk - 16.*s/q1h*tk + 6.*s/mZ2*tk + 4.*s/q1*uk + 4.*s/mZ2*uk + 12.*uk + 4.*s*(tk+q1h-mW2)/mZ2/q1/q2h*tk*uk + 2.*(s+4.*q1+5.*q1h-4.*mZ2)/q2*uk - 4.*s*s*s/q1h/q1/q2h/q2*tk*uk - 4.*s*s/q1h/q2h/q2*tk*uk - 4.*s*s/q1h/q1/q2*tk*uk + 8.*s*s/mW2/q1h/q2*tk*uk - 4.*s*s/q1h/q1/q2h*tk*uk + 4.*(s+mZ2)/mW2/q2*tk*uk - 4.*s/q1h/q2h*tk*uk - 4.*s/q1h/q1*tk*uk + 12.*s/mW2/q1h*tk*uk - (s+4.*q2)/mW2/mZ2*tk*uk - 4.*(s+2.*mZ2)/q2h/q2*tk*uk - 4.*(3.*s+2.*q1h)/q1/q2*tk*uk - 8.*mW2/q1/q2h*tk*uk + 8./q2h*tk*uk + 8./q1*tk*uk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); swap(q1h,q2h); // Note this swap is done in accordance with MC@NLO. // It is not in NPB 383(1992)3-44 Eq.C.4! Val += (uk*s*(uk+3.*s+q1h)+s*s*(s+mZ2)-(s+uk)*(2.*mZ2*s+3.*mW2*s+mW2*q1h) ) * 8./q1/q2h/q2*uk - (uk*(uk+3.*s+q1h-mW2)-(q2+s)*(q2-s)+s*(q2-mW2)+q1h*(q2-mW2)+mW2*q2 ) * 4.*s/mZ2/q1/q2h*uk - 4.*((s+uk+q2h-2.*mZ2)*(s+q1h-mZ2)-mZ2*q1)/mW2/q2*uk + 4.*(2.*s*uk+2.*mW2*uk+5.*s*s+2.*q1h*s-2.*mZ2*s)/q1/q2h*uk + 4.*(2.*s*uk-s*s-2.*q1h*s+2.*mW2*s+2.*mW2*q1h)/q1/q2h/q2*tk*uk + ((2.*uk+s)*(s+q1h)+s*(q2+q2h)+2.*q2*(s+q2h)-q1*s+q1*q2+q1h*q2h ) /mW2/mZ2*uk + 8.*s*(uk-q1h+mZ2)/q1/q2*uk + 4.*s*(-uk+s-q2+q1+q1h)/mZ2/q2h*uk + 4.*s*(-uk-q2+q1h)/mZ2/q1*uk + 8.*(mZ2*uk-s*s+mW2*s-2.*mZ2*q1-2.*mZ2*q1h)/q2h/q2*uk + 2.*(-uk-9.*s-4.*q2-5.*q2h-3.*q1-4.*q1h+8.*mZ2)/mW2*uk + 2.*(-4.*uk+3.*s+5.*q1+4.*q1h)/q2h*uk + 2.*(s*tk+q2*tk+s*s-q2*q2+q1h*q2)/mW2/mZ2*tk - 8.*s*(tk+s+q1h)/mW2/q2*tk + 2.*(-tk+3.*s+q2-q1h)/mW2*tk - 8.*s*s*s/q1h/q2 - 2.*s*q2*(s+q2)/mW2/mZ2 + 2.*s*(2.*s+q2)/mZ2 + 2.*s*(2.*s+q2)/mW2 - 16.*s*s/q1h - 2.*s - 16.*s*s/q1h/q2*tk - 8.*s/q2*tk - 16.*s/q1h*tk + 6.*s/mZ2*tk + 4.*s/q1*uk + 4.*s/mZ2*uk + 12.*uk + 4.*s*(tk+q1h-mW2)/mZ2/q1/q2h*tk*uk + 2.*(s+4.*q1+5.*q1h-4.*mZ2)/q2*uk - 4.*s*s*s/q1h/q1/q2h/q2*tk*uk - 4.*s*s/q1h/q2h/q2*tk*uk - 4.*s*s/q1h/q1/q2*tk*uk + 8.*s*s/mW2/q1h/q2*tk*uk - 4.*s*s/q1h/q1/q2h*tk*uk + 4.*(s+mZ2)/mW2/q2*tk*uk - 4.*s/q1h/q2h*tk*uk - 4.*s/q1h/q1*tk*uk + 12.*s/mW2/q1h*tk*uk - (s+4.*q2)/mW2/mZ2*tk*uk - 4.*(s+2.*mZ2)/q2h/q2*tk*uk - 4.*(3.*s+2.*q1h)/q1/q2*tk*uk - 8.*mW2/q1/q2h*tk*uk + 8./q2h*tk*uk + 8./q1*tk*uk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); swap(q1h,q2h); // Note this swap is done in accordance with MC@NLO. // It is not in NPB 383(1992)3-44 Eq.C.4! swap(tk,uk); swap(q1,q2h); swap(q2,q1h); Val += (uk*s*(uk+3.*s+q1h)+s*s*(s+mZ2)-(s+uk)*(2.*mZ2*s+3.*mW2*s+mW2*q1h) ) * 8./q1/q2h/q2*uk - (uk*(uk+3.*s+q1h-mW2)-(q2+s)*(q2-s)+s*(q2-mW2)+q1h*(q2-mW2)+mW2*q2 ) * 4.*s/mZ2/q1/q2h*uk - 4.*((s+uk+q2h-2.*mZ2)*(s+q1h-mZ2)-mZ2*q1)/mW2/q2*uk + 4.*(2.*s*uk+2.*mW2*uk+5.*s*s+2.*q1h*s-2.*mZ2*s)/q1/q2h*uk + 4.*(2.*s*uk-s*s-2.*q1h*s+2.*mW2*s+2.*mW2*q1h)/q1/q2h/q2*tk*uk + ((2.*uk+s)*(s+q1h)+s*(q2+q2h)+2.*q2*(s+q2h)-q1*s+q1*q2+q1h*q2h ) /mW2/mZ2*uk + 8.*s*(uk-q1h+mZ2)/q1/q2*uk + 4.*s*(-uk+s-q2+q1+q1h)/mZ2/q2h*uk + 4.*s*(-uk-q2+q1h)/mZ2/q1*uk + 8.*(mZ2*uk-s*s+mW2*s-2.*mZ2*q1-2.*mZ2*q1h)/q2h/q2*uk + 2.*(-uk-9.*s-4.*q2-5.*q2h-3.*q1-4.*q1h+8.*mZ2)/mW2*uk + 2.*(-4.*uk+3.*s+5.*q1+4.*q1h)/q2h*uk + 2.*(s*tk+q2*tk+s*s-q2*q2+q1h*q2)/mW2/mZ2*tk - 8.*s*(tk+s+q1h)/mW2/q2*tk + 2.*(-tk+3.*s+q2-q1h)/mW2*tk - 8.*s*s*s/q1h/q2 - 2.*s*q2*(s+q2)/mW2/mZ2 + 2.*s*(2.*s+q2)/mZ2 + 2.*s*(2.*s+q2)/mW2 - 16.*s*s/q1h - 2.*s - 16.*s*s/q1h/q2*tk - 8.*s/q2*tk - 16.*s/q1h*tk + 6.*s/mZ2*tk + 4.*s/q1*uk + 4.*s/mZ2*uk + 12.*uk + 4.*s*(tk+q1h-mW2)/mZ2/q1/q2h*tk*uk + 2.*(s+4.*q1+5.*q1h-4.*mZ2)/q2*uk - 4.*s*s*s/q1h/q1/q2h/q2*tk*uk - 4.*s*s/q1h/q2h/q2*tk*uk - 4.*s*s/q1h/q1/q2*tk*uk + 8.*s*s/mW2/q1h/q2*tk*uk - 4.*s*s/q1h/q1/q2h*tk*uk + 4.*(s+mZ2)/mW2/q2*tk*uk - 4.*s/q1h/q2h*tk*uk - 4.*s/q1h/q1*tk*uk + 12.*s/mW2/q1h*tk*uk - (s+4.*q2)/mW2/mZ2*tk*uk - 4.*(s+2.*mZ2)/q2h/q2*tk*uk - 4.*(3.*s+2.*q1h)/q1/q2*tk*uk - 8.*mW2/q1/q2h*tk*uk + 8./q2h*tk*uk + 8./q1*tk*uk; swap(tk,uk); swap(q1,q2h); swap(q2,q1h); swap(mW2,mZ2); swap(q1,q1h); swap(q2,q2h); Val += (uk*s*(uk+3.*s+q1h)+s*s*(s+mZ2)-(s+uk)*(2.*mZ2*s+3.*mW2*s+mW2*q1h) ) * 8./q1/q2h/q2*uk - (uk*(uk+3.*s+q1h-mW2)-(q2+s)*(q2-s)+s*(q2-mW2)+q1h*(q2-mW2)+mW2*q2 ) * 4.*s/mZ2/q1/q2h*uk - 4.*((s+uk+q2h-2.*mZ2)*(s+q1h-mZ2)-mZ2*q1)/mW2/q2*uk + 4.*(2.*s*uk+2.*mW2*uk+5.*s*s+2.*q1h*s-2.*mZ2*s)/q1/q2h*uk + 4.*(2.*s*uk-s*s-2.*q1h*s+2.*mW2*s+2.*mW2*q1h)/q1/q2h/q2*tk*uk + ((2.*uk+s)*(s+q1h)+s*(q2+q2h)+2.*q2*(s+q2h)-q1*s+q1*q2+q1h*q2h ) /mW2/mZ2*uk + 8.*s*(uk-q1h+mZ2)/q1/q2*uk + 4.*s*(-uk+s-q2+q1+q1h)/mZ2/q2h*uk + 4.*s*(-uk-q2+q1h)/mZ2/q1*uk + 8.*(mZ2*uk-s*s+mW2*s-2.*mZ2*q1-2.*mZ2*q1h)/q2h/q2*uk + 2.*(-uk-9.*s-4.*q2-5.*q2h-3.*q1-4.*q1h+8.*mZ2)/mW2*uk + 2.*(-4.*uk+3.*s+5.*q1+4.*q1h)/q2h*uk + 2.*(s*tk+q2*tk+s*s-q2*q2+q1h*q2)/mW2/mZ2*tk - 8.*s*(tk+s+q1h)/mW2/q2*tk + 2.*(-tk+3.*s+q2-q1h)/mW2*tk - 8.*s*s*s/q1h/q2 - 2.*s*q2*(s+q2)/mW2/mZ2 + 2.*s*(2.*s+q2)/mZ2 + 2.*s*(2.*s+q2)/mW2 - 16.*s*s/q1h - 2.*s - 16.*s*s/q1h/q2*tk - 8.*s/q2*tk - 16.*s/q1h*tk + 6.*s/mZ2*tk + 4.*s/q1*uk + 4.*s/mZ2*uk + 12.*uk + 4.*s*(tk+q1h-mW2)/mZ2/q1/q2h*tk*uk + 2.*(s+4.*q1+5.*q1h-4.*mZ2)/q2*uk - 4.*s*s*s/q1h/q1/q2h/q2*tk*uk - 4.*s*s/q1h/q2h/q2*tk*uk - 4.*s*s/q1h/q1/q2*tk*uk + 8.*s*s/mW2/q1h/q2*tk*uk - 4.*s*s/q1h/q1/q2h*tk*uk + 4.*(s+mZ2)/mW2/q2*tk*uk - 4.*s/q1h/q2h*tk*uk - 4.*s/q1h/q1*tk*uk + 12.*s/mW2/q1h*tk*uk - (s+4.*q2)/mW2/mZ2*tk*uk - 4.*(s+2.*mZ2)/q2h/q2*tk*uk - 4.*(3.*s+2.*q1h)/q1/q2*tk*uk - 8.*mW2/q1/q2h*tk*uk + 8./q2h*tk*uk + 8./q1*tk*uk; swap(mW2,mZ2); swap(q1,q1h); swap(q2,q2h); return Val; } Energy2 t_u_Ruu(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1h,Energy2 q2h, Energy2 mW2, Energy2 mZ2) { return t_u_Rdd(s,tk,uk,q1h,q2h,mZ2,mW2); } Energy4 t_u_RZds(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1,Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2) { Energy4 Val(0.*GeV2*GeV2); Energy2 sig(mZ2+mW2); Val += ( q1*q2*(5./2.*s*s+5.*s*tk+3.*tk*tk)+(tk*uk*uk+q1*q1*q2)*(tk+s) + q1*(tk*tk*uk+s*uk*uk-s*s*tk+s*s*uk)+q1*q1*q1*(uk+s)-q1*q1*s*s2 ) * 8./q1/q2 - ( tk*tk*(4.*uk+s+q1-2.*q2)+tk*(sqr(q1+q2)-q1*s-3.*q2*s-2.*q1*q1) - q1*s*(4.*s-2.*q1-q2)+tk*uk*(q1+3.*s) ) * 4.*sig/q1/q2 - 4.*sig*sig*(s*(2.*s+q1)+tk*(uk+5./2.*tk+5.*s+q1+q2) )/mW2/mZ2 + 2.*sig*s2*(4.*sqr(s+tk)+tk*(uk+s+4.*q1+2.*q2)+2.*q1*(2.*s+q1) )/mW2/mZ2 + 4.*sig*sig*(s2+s-q1+q2)/q1/q2*tk - 16.*mW2*mZ2*(tk*uk/2.+q2*tk-q1*s)/q1/q2 - 4.*s2*s2*q1*(tk+s+q1)/mW2/mZ2 + sig*sig*sig*(uk+tk)/mW2/mZ2 + 4.*mW2*mZ2*sig*(uk+tk)/q1/q2; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); Val += ( q1*q2*(5./2.*s*s+5.*s*tk+3.*tk*tk)+(tk*uk*uk+q1*q1*q2)*(tk+s) + q1*(tk*tk*uk+s*uk*uk-s*s*tk+s*s*uk)+q1*q1*q1*(uk+s)-q1*q1*s*s2 ) * 8./q1/q2 - ( tk*tk*(4.*uk+s+q1-2.*q2)+tk*(sqr(q1+q2)-q1*s-3.*q2*s-2.*q1*q1) - q1*s*(4.*s-2.*q1-q2)+tk*uk*(q1+3.*s) ) * 4.*sig/q1/q2 - 4.*sig*sig*(s*(2.*s+q1)+tk*(uk+5./2.*tk+5.*s+q1+q2) )/mW2/mZ2 + 2.*sig*s2*(4.*sqr(s+tk)+tk*(uk+s+4.*q1+2.*q2)+2.*q1*(2.*s+q1) )/mW2/mZ2 + 4.*sig*sig*(s2+s-q1+q2)/q1/q2*tk - 16.*mW2*mZ2*(tk*uk/2.+q2*tk-q1*s)/q1/q2 - 4.*s2*s2*q1*(tk+s+q1)/mW2/mZ2 + sig*sig*sig*(uk+tk)/mW2/mZ2 + 4.*mW2*mZ2*sig*(uk+tk)/q1/q2; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); return Val; } Energy4 t_u_RZda(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1,Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2) { Energy4 Val(0.*GeV2*GeV2); Val += 4.*mZ2*(2.*uk*uk-s*tk+q1*(uk-tk-s+q1+0.5*q2)+q2*(s-3.*q2) ) /q1/q2*tk - 4.*mZ2*mZ2*(q1-tk-2.*s-q2)/q1/q2*tk - 2.*mZ2*(tk+2.*s+2.*q2)/mW2*tk - 2.*s2*(s+2.*q2)/mZ2*tk + 8.*mW2*mZ2*mZ2/q1/q2*tk + 2.*mZ2*mZ2/mW2*tk; swap(mW2,mZ2); // N.B. Here we subtract! Val -= 4.*mZ2*(2.*uk*uk-s*tk+q1*(uk-tk-s+q1+0.5*q2)+q2*(s-3.*q2) ) /q1/q2*tk - 4.*mZ2*mZ2*(q1-tk-2.*s-q2)/q1/q2*tk - 2.*mZ2*(tk+2.*s+2.*q2)/mW2*tk - 2.*s2*(s+2.*q2)/mZ2*tk + 8.*mW2*mZ2*mZ2/q1/q2*tk + 2.*mZ2*mZ2/mW2*tk; swap(mW2,mZ2); swap(q1,q2); // N.B. Here we subtract! swap(tk,uk); Val -= 4.*mZ2*(2.*uk*uk-s*tk+q1*(uk-tk-s+q1+0.5*q2)+q2*(s-3.*q2) ) /q1/q2*tk - 4.*mZ2*mZ2*(q1-tk-2.*s-q2)/q1/q2*tk - 2.*mZ2*(tk+2.*s+2.*q2)/mW2*tk - 2.*s2*(s+2.*q2)/mZ2*tk + 8.*mW2*mZ2*mZ2/q1/q2*tk + 2.*mZ2*mZ2/mW2*tk; swap(q1,q2); swap(tk,uk); swap(mW2,mZ2); // N.B. Here we add! swap(q1,q2); swap(tk,uk); Val += 4.*mZ2*(2.*uk*uk-s*tk+q1*(uk-tk-s+q1+0.5*q2)+q2*(s-3.*q2) ) /q1/q2*tk - 4.*mZ2*mZ2*(q1-tk-2.*s-q2)/q1/q2*tk - 2.*mZ2*(tk+2.*s+2.*q2)/mW2*tk - 2.*s2*(s+2.*q2)/mZ2*tk + 8.*mW2*mZ2*mZ2/q1/q2*tk + 2.*mZ2*mZ2/mW2*tk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); return Val; } Energy4 t_u_RZd(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1 , Energy2 q2 , Energy2 s2, Energy2 mW2, Energy2 mZ2) { Energy4 Val(0.*GeV2*GeV2); Val = t_u_RZds(s,tk,uk,q1,q2,s2,mW2,mZ2) + t_u_RZda(s,tk,uk,q1,q2,s2,mW2,mZ2); return Val; } Energy4 t_u_RZu(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1h, Energy2 q2h, Energy2 s2, Energy2 mW2, Energy2 mZ2) { Energy4 Val(0.*GeV2*GeV2); Val = t_u_RZd(s,tk,uk,q1h,q2h,s2,mZ2,mW2); return Val; } Energy6 t_u_RZs(Energy2 s,Energy2 tk,Energy2 uk,Energy2 q1,Energy2 q2, Energy2 s2,Energy2 mW2,Energy2 mZ2) { Energy6 Val(0.*GeV2*GeV2*GeV2); Energy2 sig(mZ2+mW2); Val += 2.*sig*sig*s2*( tk*(3.*uk+9.*tk+19.*s+6.*q1+4.*q2)+8.*s*s+6.*q1*s + 2.*q1*q1 )/mW2/mZ2 - 2.*sig*sig*sig*(tk*(3.*uk+6.*tk+11.*s+2.*q1+2.*q2)+2.*s*(2.*s+q1)) / mW2/mZ2 - 2.*sig*s2*s2*(tk*(uk+4.*tk+9.*s+6.*q1+2.*q2)+4.*sqr(s+q1)-2.*q1*s) /mW2/mZ2 - 16.*sig*(2.*tk*(uk/2.-tk-s+q1+q2)-s*(3.*s/2.-2.*q1)) + 8.*s2*(s*(s/2.+tk)+4.*q1*(tk+s+q1)) + 4.*s2*s2*s2*q1*(tk+s+q1)/mW2/mZ2 + 8.*sig*sig*(2.*tk+s/2.) + 2.*sig*sig*sig*sig*tk/mW2/mZ2 + 32.*mW2*mZ2*s; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); Val += 2.*sig*sig*s2*( tk*(3.*uk+9.*tk+19.*s+6.*q1+4.*q2)+8.*s*s+6.*q1*s + 2.*q1*q1 )/mW2/mZ2 - 2.*sig*sig*sig*(tk*(3.*uk+6.*tk+11.*s+2.*q1+2.*q2)+2.*s*(2.*s+q1)) / mW2/mZ2 - 2.*sig*s2*s2*(tk*(uk+4.*tk+9.*s+6.*q1+2.*q2)+4.*sqr(s+q1)-2.*q1*s) /mW2/mZ2 - 16.*sig*(2.*tk*(uk/2.-tk-s+q1+q2)-s*(3.*s/2.-2.*q1)) + 8.*s2*(s*(s/2.+tk)+4.*q1*(tk+s+q1)) + 4.*s2*s2*s2*q1*(tk+s+q1)/mW2/mZ2 + 8.*sig*sig*(2.*tk+s/2.) + 2.*sig*sig*sig*sig*tk/mW2/mZ2 + 32.*mW2*mZ2*s; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); return Val; } Energy6 t_u_RZa(Energy2 s,Energy2 tk,Energy2 uk,Energy2 q1,Energy2 q2, Energy2 s2,Energy2 mW2,Energy2 mZ2) { Energy6 Val(0.*GeV2*GeV2*GeV2); Val += - 2.*mZ2*(2.*tk+11.*s+18.*q2)*tk - 2.*mZ2*mZ2*(2.*tk+3.*s+2.*q2)/mW2*tk + 2.*mZ2*s2*(tk+3.*s+4.*q2)/mW2*tk - 2.*s2*s2*(s+2.*q2)/mW2*tk + 2.*mZ2*mZ2*mZ2/mW2*tk + 20.*mZ2*mZ2*tk; swap(mW2,mZ2); Val -= - 2.*mZ2*(2.*tk+11.*s+18.*q2)*tk - 2.*mZ2*mZ2*(2.*tk+3.*s+2.*q2)/mW2*tk + 2.*mZ2*s2*(tk+3.*s+4.*q2)/mW2*tk - 2.*s2*s2*(s+2.*q2)/mW2*tk + 2.*mZ2*mZ2*mZ2/mW2*tk + 20.*mZ2*mZ2*tk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); Val -= - 2.*mZ2*(2.*tk+11.*s+18.*q2)*tk - 2.*mZ2*mZ2*(2.*tk+3.*s+2.*q2)/mW2*tk + 2.*mZ2*s2*(tk+3.*s+4.*q2)/mW2*tk - 2.*s2*s2*(s+2.*q2)/mW2*tk + 2.*mZ2*mZ2*mZ2/mW2*tk + 20.*mZ2*mZ2*tk; swap(q1,q2); swap(tk,uk); swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); Val += - 2.*mZ2*(2.*tk+11.*s+18.*q2)*tk - 2.*mZ2*mZ2*(2.*tk+3.*s+2.*q2)/mW2*tk + 2.*mZ2*s2*(tk+3.*s+4.*q2)/mW2*tk - 2.*s2*s2*(s+2.*q2)/mW2*tk + 2.*mZ2*mZ2*mZ2/mW2*tk + 20.*mZ2*mZ2*tk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); return Val; } Energy6 t_u_RZ(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2) { Energy6 Val(0.*GeV2*GeV2*GeV2); Val = t_u_RZs(s,tk,uk,q1,q2,s2,mW2,mZ2) + t_u_RZa(s,tk,uk,q1,q2,s2,mW2,mZ2); return Val; } /***************************************************************************/ // t_u_M_R_qg is the real emission q + qb -> n + g matrix element // exactly as defined in Eqs. C.9 of NPB 383(1992)3-44, multiplied by // tk * uk! Energy2 MEPP2VVPowheg::t_u_M_R_qg(realVVKinematics R) const { // First the Born variables: Energy2 s2(R.s2r()); Energy2 mW2(R.k12r()); Energy2 mZ2(R.k22r()); // Then the rest: Energy2 s(R.sr()); Energy2 tk(R.tkr()); Energy2 uk(R.ukr()); Energy2 q1(R.q1r()); Energy2 q2(R.q2r()); Energy2 q1h(R.q1hatr()); Energy2 q2h(R.q2hatr()); Energy2 w1(R.w1r()); Energy2 w2(R.w2r()); double cosThetaW(sqrt(1.-sin2ThetaW_)); double eZ2(eZ2_); double eZ(eZ_); double gdL(gdL_); double guL(guL_); double gdR(gdR_); double guR(guR_); // W+W- if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { double e2(sqr(gW_)*sin2ThetaW_); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(guL-guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *( 2./3.+2.*eZ*guL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } gdL = gW_/sqrt(2.); guL = 0.; } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(gdL-gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *(-1./3.+2.*eZ*gdL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } guL = gW_/sqrt(2.); gdL = 0.; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { eZ = 0.; eZ2 = 0.; double gV2,gA2; gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL; else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL; else { cout << "MEPP2VVPowheg:" << endl; cout << "ZZ needs 2 down-type / 2 up-type!" << endl; } } Energy2 Val(0.*GeV2); swap(s,tk); swap(q2,w2); swap(q2h,w1); Val = -2.*pi*alphaS_*Fij2_*CF_/NC_ * ( gdL*gdL*t_u_Rdd(s,tk,uk,q1,q2,mW2,mZ2) + 2.*gdL*guL*t_u_Rud(s,tk,uk,q1,q2,q1h,q2h,mW2,mZ2) + guL*guL*t_u_Ruu(s,tk,uk,q1h,q2h,mW2,mZ2) - 2.*eZ/(s2-mW2) * ( gdL * t_u_RZd(s,tk,uk,q1 ,q2 ,s2,mW2,mZ2) - guL * t_u_RZu(s,tk,uk,q1h,q2h,s2,mW2,mZ2) ) + eZ2/sqr(s2-mW2) *t_u_RZ(s,tk,uk,q1,q2,s2,mW2,mZ2) ); swap(s,tk); swap(q2,w2); swap(q2h,w1); Val *= -tk/s * TR_/CF_; return Val; } /***************************************************************************/ // t_u_M_R_gqb is the real emission g + qb -> n + q matrix element // exactly as defined in Eqs. C.9 of NPB 383(1992)3-44, multiplied by // tk * uk! Energy2 MEPP2VVPowheg::t_u_M_R_gqb(realVVKinematics R) const { // First the Born variables: Energy2 s2(R.s2r()); Energy2 mW2(R.k12r()); Energy2 mZ2(R.k22r()); // Then the rest: Energy2 s(R.sr()); Energy2 tk(R.tkr()); Energy2 uk(R.ukr()); Energy2 q1(R.q1r()); Energy2 q2(R.q2r()); Energy2 q1h(R.q1hatr()); Energy2 q2h(R.q2hatr()); Energy2 w1(R.w1r()); Energy2 w2(R.w2r()); double cosThetaW(sqrt(1.-sin2ThetaW_)); double eZ2(eZ2_); double eZ(eZ_); double gdL(gdL_); double guL(guL_); double gdR(gdR_); double guR(guR_); // W+W- if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { double e2(sqr(gW_)*sin2ThetaW_); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(guL-guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *( 2./3.+2.*eZ*guL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } gdL = gW_/sqrt(2.); guL = 0.; } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(gdL-gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *(-1./3.+2.*eZ*gdL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } guL = gW_/sqrt(2.); gdL = 0.; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { eZ = 0.; eZ2 = 0.; double gV2,gA2; gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL; else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL; else { cout << "MEPP2VVPowheg:" << endl; cout << "ZZ needs 2 down-type / 2 up-type!" << endl; } } Energy2 Val(0.*GeV2); swap(s,uk); swap(q1,w1); swap(q1h,w2); Val = -2.*pi*alphaS_*Fij2_*CF_/NC_ * ( gdL*gdL*t_u_Rdd(s,tk,uk,q1,q2,mW2,mZ2) + 2.*gdL*guL*t_u_Rud(s,tk,uk,q1,q2,q1h,q2h,mW2,mZ2) + guL*guL*t_u_Ruu(s,tk,uk,q1h,q2h,mW2,mZ2) - 2.*eZ/(s2-mW2) * ( gdL * t_u_RZd(s,tk,uk,q1 ,q2 ,s2,mW2,mZ2) - guL * t_u_RZu(s,tk,uk,q1h,q2h,s2,mW2,mZ2) ) + eZ2/sqr(s2-mW2) *t_u_RZ(s,tk,uk,q1,q2,s2,mW2,mZ2) ); swap(s,uk); swap(q1,w1); swap(q1h,w2); Val *= -uk/s * TR_/CF_; return Val; } /***************************************************************************/ // The following six functions are I_{dd}^{(0)}, I_{ud}^{(0)}, // I_{uu}^{(0)}, F_{u}^{(0)}, F_{d}^{(0)}, H^{(0)} from Eqs. 3.9 - 3.14 // They make up the Born matrix element. Ixx functions correspond to the // graphs with no TGC, Fx functions are due to non-TGC graphs interfering // with TGC graphs, while the H function is due purely to TGC graphs. double Idd0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); double Iud0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); double Iuu0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); Energy2 Fu0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); Energy2 Fd0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); Energy4 H0 (Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); /***************************************************************************/ // M_Born_WZ is the Born matrix element exactly as defined in Eqs. 3.3-3.14 // of of NPB 383(1992)3-44 (with a spin*colour averaging factor 1./4./NC_/NC_). double MEPP2VVPowheg::M_Born_WZ(bornVVKinematics B) const { Energy2 s(B.sb()); Energy2 t(B.tb()); Energy2 u(B.ub()); Energy2 mW2(B.k12b()); // N.B. the diboson masses are preserved in getting Energy2 mZ2(B.k22b()); // the 2->2 from the 2->3 kinematics. double cosThetaW(sqrt(1.-sin2ThetaW_)); double eZ2(eZ2_); double eZ(eZ_); double gdL(gdL_); double guL(guL_); double gdR(gdR_); double guR(guR_); // W+W- if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { double e2(sqr(gW_)*sin2ThetaW_); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s-mW2)/Fij2_ * (e2*e2/s/s*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s/(s-mW2/sqr(cosThetaW))) +sqr( eZ*(guL-guR)/2./e2*s/(s-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s-mW2) * (gW_*gW_*e2/4./s *( 2./3.+2.*eZ*guL/2./e2*s/(s-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } gdL = gW_/sqrt(2.); guL = 0.; } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s-mW2)/Fij2_ * (e2*e2/s/s*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s/(s-mW2/sqr(cosThetaW))) +sqr( eZ*(gdL-gdR)/2./e2*s/(s-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s-mW2) * (gW_*gW_*e2/4./s *(-1./3.+2.*eZ*gdL/2./e2*s/(s-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } guL = gW_/sqrt(2.); gdL = 0.; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { eZ = 0.; eZ2 = 0.; double gV2,gA2; gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL; else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL; else { cout << "MEPP2VVPowheg:" << endl; cout << "ZZ needs 2 down-type / 2 up-type!" << endl; } } return Fij2_/2./NC_ * ( gdL*gdL*Idd0(s,t,u,mW2,mZ2) + 2.*gdL*guL*Iud0(s,t,u,mW2,mZ2) + guL*guL*Iuu0(s,t,u,mW2,mZ2) - 2.*eZ/(s-mW2) * ( gdL*Fd0(s,t,u,mW2,mZ2) - guL*Fu0(s,t,u,mW2,mZ2) ) + eZ2/sqr(s-mW2) * H0(s,t,u,mW2,mZ2) ); } /***************************************************************************/ double Idd0(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return 8.*((u*t/mW2/mZ2-1.)/4.+s/2.*(mW2+mZ2)/mW2/mZ2) + 8.*(u/t-mW2*mZ2/t/t); } /***************************************************************************/ double Iud0(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return - 8.*((u*t/mW2/mZ2-1.)/4.+s/2.*(mW2+mZ2)/mW2/mZ2) + 8.*s/t/u*(mW2+mZ2); } /***************************************************************************/ double Iuu0(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return Idd0(s,u,t,mW2,mZ2); } /***************************************************************************/ Energy2 Fd0 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return - 8.*s*( (u*t/mW2/mZ2-1.)*(1.-(mW2+mZ2)/s-4.*mW2*mZ2/s/t)/4. + (mW2+mZ2)/2./mW2/mZ2*(s-mW2-mZ2+2.*mW2*mZ2/t) ); } /***************************************************************************/ Energy2 Fu0 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return Fd0(s,u,t,mW2,mZ2); } /***************************************************************************/ Energy4 H0 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return 8.*s*s*(u*t/mW2/mZ2-1.)*( 1./4.-(mW2+mZ2)/2./s + (sqr(mW2+mZ2)+8.*mW2*mZ2)/4./s/s ) + 8.*s*s*(mW2+mZ2)/mW2/mZ2*(s/2.-mW2-mZ2+sqr(mW2-mZ2)/2./s); } /***************************************************************************/ bool MEPP2VVPowheg::sanityCheck() const { bool alarm(false); Energy2 prefacs(8.*pi*alphaS_*S_.sr() /S_.xr() ); Energy2 prefacsp(8.*pi*alphaS_*SCp_.sr() /SCp_.xr() ); Energy2 prefacsm(8.*pi*alphaS_*SCm_.sr() /SCm_.xr() ); Energy2 prefacp(8.*pi*alphaS_*Cp_.sr()/Cp_.xr()); Energy2 prefacm(8.*pi*alphaS_*Cm_.sr()/Cm_.xr()); double xp(Cp_.xr()); double xm(Cm_.xr()); double M_B_WW(M_Born_WW(B_)); double M_B_ZZ(M_Born_ZZ(B_)); double M_V_reg_WW(M_V_regular_WW(S_)); double M_V_reg_ZZ(M_V_regular_ZZ(S_)); Energy2 t_u_qqb_WW(t_u_M_R_qqb_WW(H_)); Energy2 t_u_qqb_ZZ(t_u_M_R_qqb_ZZ(H_)); // Check that the native leading order Herwig matrix // element is equivalent to the WZ leading order matrix // element in NPB 383 (1992) 3-44, with the relevant WZ->WW // WZ->ZZ transformation applied (M_Born_). // if(fabs((lo_me2_ - M_Born_)/M_Born_)>1.e-2) { // alarm=true; // cout << "lo_me2_ - M_Born_ (%) = " // << lo_me2_ - M_Born_ << " (" // << (lo_me2_ - M_Born_)/M_Born_*100. << ")\n"; // } // Check that the transformation from NPB 383 (1992) 3-44 WZ // matrix elements to WW matrix elements actually works, by // comparing them to the explicit WW matrix elements in // NPB 410 (1993) 280-324. if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { if(fabs((M_Born_ -M_B_WW )/M_B_WW )>1.e-6) { alarm=true; cout << "WZ->WW transformation error!\n"; cout << "M_Born_ - M_B_WW (rel) = " << M_Born_ - M_B_WW << " (" << (M_Born_ - M_B_WW)/M_B_WW << ")\n"; cout << "M_Born_ = " << M_Born_ << endl; cout << "M_B_WW = " << M_B_WW << endl; } if(fabs((M_V_regular_-M_V_reg_WW)/M_V_reg_WW)>1.e-6) { alarm=true; cout << "WZ->WW transformation error!\n"; cout << "M_V_regular_ - M_V_reg_WW (rel) = " << M_V_regular_ - M_V_reg_WW << " (" << (M_V_regular_ - M_V_reg_WW)/M_V_reg_WW << ")\n"; cout << "M_V_regular_ = " << M_V_regular_ << endl; cout << "M_V_reg_WW = " << M_V_reg_WW << endl; } if(fabs((t_u_M_R_qqb_-t_u_qqb_WW)/t_u_qqb_WW)>1.e-6) { alarm=true; cout << "WZ->WW transformation error!\n"; cout << "t_u_M_R_qqb_ - t_u_qqb_WW (rel) = " << (t_u_M_R_qqb_ - t_u_qqb_WW)/GeV2 << " (" << (t_u_M_R_qqb_ - t_u_qqb_WW)/t_u_qqb_WW << ")\n"; cout << "t_u_M_R_qqb_ = " << t_u_M_R_qqb_/GeV2 << endl; cout << "t_u_qqb_WW = " << t_u_qqb_WW /GeV2 << endl; } } // Check that the transformation from NPB 383 (1992) 3-44 WZ // matrix elements to ZZ matrix elements actually works, by // comparing them to the explicit ZZ matrix elements in // NPB 357 (1991) 409-438. if(abs(mePartonData()[2]->id())==23&&abs(mePartonData()[3]->id())==23) { if(fabs((M_Born_ -M_B_ZZ )/M_B_ZZ )>1.e-6) { alarm=true; cout << "WZ->ZZ transformation error!\n"; cout << "M_Born_ - M_B_ZZ (rel) = " << M_Born_ - M_B_ZZ << " (" << (M_Born_ - M_B_ZZ)/M_B_ZZ << ")\n"; cout << "M_Born_ = " << M_Born_ << endl; cout << "M_B_ZZ = " << M_B_ZZ << endl; } if(fabs((M_V_regular_-M_V_reg_ZZ)/M_V_reg_ZZ)>1.e-6) { alarm=true; cout << "WZ->ZZ transformation error!\n"; cout << "M_V_regular_ - M_V_reg_ZZ (rel) = " << M_V_regular_ - M_V_reg_ZZ << " (" << (M_V_regular_ - M_V_reg_ZZ)/M_V_reg_ZZ << ")\n"; cout << "M_V_regular_ = " << M_V_regular_ << endl; cout << "M_V_reg_ZZ = " << M_V_reg_ZZ << endl; } if(fabs((t_u_M_R_qqb_-t_u_qqb_ZZ)/t_u_qqb_ZZ)>1.e-6) { alarm=true; cout << "WZ->ZZ transformation error!\n"; cout << "t_u_M_R_qqb_ - t_u_qqb_ZZ (rel) = " << (t_u_M_R_qqb_ - t_u_qqb_ZZ)/GeV2 << " (" << (t_u_M_R_qqb_ - t_u_qqb_ZZ)/t_u_qqb_ZZ << ")\n"; cout << "t_u_M_R_qqb_ = " << t_u_M_R_qqb_/GeV2 << endl; cout << "t_u_qqb_ZZ = " << t_u_qqb_ZZ /GeV2 << endl; } } // Check the soft limit of the q + qbar matrix element. Energy2 absDiff_qqbs = t_u_M_R_qqb(S_) - prefacs*2.*CF_*M_Born_; double relDiff_qqbs = absDiff_qqbs / t_u_M_R_qqb(S_); if(fabs(relDiff_qqbs)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qqb(S_) " << t_u_M_R_qqb(S_) /GeV2 << endl; cout << "t_u_M_R_qqb(S_)-8*pi*alphaS*sHat/x*2*Cab*M_Born_ (rel):\n" << absDiff_qqbs / GeV2 << " (" << relDiff_qqbs << ")\n"; } // Check the positive soft-collinearlimit of the q + qbar matrix element. Energy2 absDiff_qqbsp = t_u_M_R_qqb(SCp_) - prefacsp*2.*CF_*M_Born_; double relDiff_qqbsp = absDiff_qqbsp / t_u_M_R_qqb(SCp_); if(fabs(relDiff_qqbsp)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qqb(SCp_) " << t_u_M_R_qqb(SCp_)/GeV2 << endl; cout << "t_u_M_R_qqb(SCp_)-8*pi*alphaS*sHat/x*2*Cab*M_Born_ (rel):\n" << absDiff_qqbsp / GeV2 << " (" << relDiff_qqbsp << ")\n"; } // Check the negative soft-collinearlimit of the q + qbar matrix element. Energy2 absDiff_qqbsm = t_u_M_R_qqb(SCm_) - prefacsm*2.*CF_*M_Born_; double relDiff_qqbsm = absDiff_qqbsm / t_u_M_R_qqb(SCm_); if(fabs(relDiff_qqbsm)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qqb(SCm_) " << t_u_M_R_qqb(SCm_)/GeV2 << endl; cout << "t_u_M_R_qqb(SCm_)-8*pi*alphaS*sHat/x*2*Cab*M_Born_ (rel):\n" << absDiff_qqbsm / GeV2 << " (" << relDiff_qqbsm << ")\n"; } // Check the positive collinearlimit of the q + qbar matrix element. Energy2 absDiff_qqbp = t_u_M_R_qqb(Cp_) - prefacp*CF_*(1.+xp*xp)*M_Born_; double relDiff_qqbp = absDiff_qqbp / t_u_M_R_qqb(Cp_); if(fabs(relDiff_qqbp)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qqb(Cp_) " << t_u_M_R_qqb(Cp_) /GeV2 << endl; cout << "t_u_M_R_qqb(Cp_)-8*pi*alphaS*sHat/x*(1-x)*Pqq*M_Born_ (rel):\n" << absDiff_qqbp / GeV2 << " (" << relDiff_qqbp << ")\n"; } // Check the negative collinearlimit of the q + qbar matrix element. Energy2 absDiff_qqbm = t_u_M_R_qqb(Cm_) - prefacm*CF_*(1.+xm*xm)*M_Born_; double relDiff_qqbm = absDiff_qqbm / t_u_M_R_qqb(Cm_); if(fabs(relDiff_qqbm)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qqb(Cm_) " << t_u_M_R_qqb(Cm_) /GeV2 << endl; cout << "t_u_M_R_qqb(Cm_)-8*pi*alphaS*sHat/x*(1-x)*Pqq*M_Born_ (rel):\n" << absDiff_qqbm / GeV2 << " (" << relDiff_qqbm << ")\n"; } // Check the positive collinear limit of the g + qbar matrix element. Energy2 absDiff_gqbp = t_u_M_R_gqb(Cp_) - prefacp*(1.-xp)*TR_*(xp*xp+sqr(1.-xp))*M_Born_; double relDiff_gqbp = absDiff_gqbp/ t_u_M_R_gqb(Cp_); if(fabs(relDiff_gqbp)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_gqb(Cp_) " << t_u_M_R_gqb(Cp_) /GeV2 << endl; cout << "t_u_M_R_gqb(Cp_)-8*pi*alphaS*sHat/x*(1-x)*Pgq*M_Born_ (rel):\n" << absDiff_gqbp / GeV2 << " (" << relDiff_gqbp << ")\n"; } // Check the negative collinear limit of the q + g matrix element. Energy2 absDiff_qgm = t_u_M_R_qg(Cm_) - prefacm*(1.-xm)*TR_*(xm*xm+sqr(1.-xm))*M_Born_; double relDiff_qgm = absDiff_qgm / t_u_M_R_qg(Cm_); if(fabs(relDiff_qgm)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qg(Cm_) " << t_u_M_R_qg(Cm_) /GeV2 << endl; cout << "t_u_M_R_qg(Cm_)-8*pi*alphaS*sHat/x*(1-x)*Pgq*M_Born_ (rel):\n" << absDiff_qgm / GeV2 << " (" << relDiff_qgm << ")\n"; } return alarm; } /***************************************************************************/ // M_Born_ZZ is the Born matrix element exactly as defined in Eqs. 2.18-2.19 // of of NPB 357(1991)409-438. double MEPP2VVPowheg::M_Born_ZZ(bornVVKinematics B) const { Energy2 s(B.sb()); Energy2 t(B.tb()); Energy2 u(B.ub()); Energy2 mZ2(B.k22b()); // the 2->2 from the 2->3 kinematics. double cosThetaW(sqrt(1.-sin2ThetaW_)); double gV2,gA2,gX,gY,gZ; gV2 = sqr(guL_/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL_/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); gX = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL_/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL_/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gY = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gZ = gX; if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) gZ = gY; return 1./NC_*sqr(gZ*2.)*(t/u+u/t+4.*mZ2*s/t/u-mZ2*mZ2*(1./t/t+1./u/u)); } /***************************************************************************/ // M_V_regular_ZZ is the one-loop ZZ matrix element exactly as defined in // Eqs. B.1 & B.2 of NPB 357(1991)409-438. double MEPP2VVPowheg::M_V_regular_ZZ(realVVKinematics S) const { Energy2 s(S.bornVariables().sb()); Energy2 t(S.bornVariables().tb()); Energy2 u(S.bornVariables().ub()); Energy2 mZ2(S.k22r()); // the 2->2 from the 2->3 kinematics. double beta(S.betaxr()); // N.B. for x=1 \beta_x=\beta in NPB 383(1992)3-44. double cosThetaW(sqrt(1.-sin2ThetaW_)); double gV2,gA2,gX,gY,gZ; gV2 = sqr(guL_/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL_/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); gX = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL_/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL_/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gY = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gZ = gX; if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) gZ = gY; double M_V_reg(0.); M_V_reg = 2.*s*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/sqr(4.*pi)/2. *( 2.*sqr(t+mZ2)/sqr(beta)/s/t/u + 4.*s/(t-mZ2)/u - ( 16.*t*t*t+(28.*s-68.*mZ2)*t*t+(18.*s*s-36.*mZ2*s+88.*mZ2*mZ2)*t + 18.*mZ2*mZ2*s-36.*mZ2*mZ2*mZ2 )/t/t/s/u + ( 12.*s/(t-mZ2)/u-4.*mZ2*s/sqr(t-mZ2)/u+2.*(t+4.*s)/s/u - 6.*(s*s+mZ2*mZ2)/s/t/u+6.*mZ2*mZ2*(2.*mZ2-s)/t/t/s/u )*log(-t/mZ2) + ( - ( 5.*t*t*t+(8.*s-18.*mZ2)*t*t+(6.*s*s+25.*mZ2*mZ2)*t + 6.*mZ2*mZ2*s-12.*mZ2*mZ2*mZ2 )/t/t/s/u - 12.*mZ2*sqr(t+mZ2)/sqr(sqr(beta))/s/s/t/u + ( 3.*t*t-26.*mZ2*t-25.*mZ2*mZ2)/sqr(beta)/s/t/u )*log(s/mZ2) + ( (-2.*t*t+8.*mZ2*t-2.*s*s-12.*mZ2*mZ2)/u + 4.*mZ2*mZ2*(2.*mZ2-s)/t/u) / (s*t) * ( 2.*sqr(log(-t/mZ2))-4.*log(-t/mZ2)*log((mZ2-t)/mZ2)-4.*ReLi2(t/mZ2)) + ( 4.*(t*t-5.*mZ2*t+s*s+10.*mZ2*mZ2)/s/u + 4.*mZ2*(-s*s+2.*mZ2*s-10.*mZ2*mZ2)/s/t/u + 8.*mZ2*mZ2*mZ2*(2.*mZ2-s)/t/t/s/u ) / (t-mZ2) * (pi*pi/2.+log(-t/mZ2)*log(-t/s)-1./2.*sqr(log(-t/mZ2))) + ( ( (2.*s-3.*mZ2)*t*t+(6.*mZ2*mZ2-8.*mZ2*s)*t+2.*s*s*s-4.*mZ2*s*s + 12.*mZ2*mZ2*s-3.*mZ2*mZ2*mZ2 ) /s/t/u + 12.*mZ2*mZ2*sqr(t+mZ2)/sqr(sqr(beta))/s/s/t/u - (mZ2*t*t-30.*mZ2*mZ2*t-27.*mZ2*mZ2*mZ2)/beta/beta/s/t/u ) / (beta*s) * (pi*pi/3.+sqr(log((1.-beta)/(1.+beta)))+4.*ReLi2(-(1.-beta)/(1.+beta))) + (4.*(t+4.*s-4.*mZ2)/3./s/u+4.*sqr(s-2.*mZ2)/3./s/t/u)*pi*pi ); swap(t,u); M_V_reg += 2.*s*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/sqr(4.*pi)/2. *( 2.*sqr(t+mZ2)/sqr(beta)/s/t/u + 4.*s/(t-mZ2)/u - ( 16.*t*t*t+(28.*s-68.*mZ2)*t*t+(18.*s*s-36.*mZ2*s+88.*mZ2*mZ2)*t + 18.*mZ2*mZ2*s-36.*mZ2*mZ2*mZ2 )/t/t/s/u + ( 12.*s/(t-mZ2)/u-4.*mZ2*s/sqr(t-mZ2)/u+2.*(t+4.*s)/s/u - 6.*(s*s+mZ2*mZ2)/s/t/u+6.*mZ2*mZ2*(2.*mZ2-s)/t/t/s/u )*log(-t/mZ2) + ( - ( 5.*t*t*t+(8.*s-18.*mZ2)*t*t+(6.*s*s+25.*mZ2*mZ2)*t + 6.*mZ2*mZ2*s-12.*mZ2*mZ2*mZ2 )/t/t/s/u - 12.*mZ2*sqr(t+mZ2)/sqr(sqr(beta))/s/s/t/u + ( 3.*t*t-26.*mZ2*t-25.*mZ2*mZ2)/sqr(beta)/s/t/u )*log(s/mZ2) + ( (-2.*t*t+8.*mZ2*t-2.*s*s-12.*mZ2*mZ2)/u + 4.*mZ2*mZ2*(2.*mZ2-s)/t/u) / (s*t) * ( 2.*sqr(log(-t/mZ2))-4.*log(-t/mZ2)*log((mZ2-t)/mZ2)-4.*ReLi2(t/mZ2)) + ( 4.*(t*t-5.*mZ2*t+s*s+10.*mZ2*mZ2)/s/u + 4.*mZ2*(-s*s+2.*mZ2*s-10.*mZ2*mZ2)/s/t/u + 8.*mZ2*mZ2*mZ2*(2.*mZ2-s)/t/t/s/u ) / (t-mZ2) * (pi*pi/2.+log(-t/mZ2)*log(-t/s)-1./2.*sqr(log(-t/mZ2))) + ( ( (2.*s-3.*mZ2)*t*t+(6.*mZ2*mZ2-8.*mZ2*s)*t+2.*s*s*s-4.*mZ2*s*s + 12.*mZ2*mZ2*s-3.*mZ2*mZ2*mZ2 ) /s/t/u + 12.*mZ2*mZ2*sqr(t+mZ2)/sqr(sqr(beta))/s/s/t/u - (mZ2*t*t-30.*mZ2*mZ2*t-27.*mZ2*mZ2*mZ2)/beta/beta/s/t/u ) / (beta*s) * (pi*pi/3.+sqr(log((1.-beta)/(1.+beta)))+4.*ReLi2(-(1.-beta)/(1.+beta))) + (4.*(t+4.*s-4.*mZ2)/3./s/u+4.*sqr(s-2.*mZ2)/3./s/t/u)*pi*pi ); return M_V_reg; } /***************************************************************************/ // t_u_M_R_qqb_ZZ is the real emission q + qb -> n + g matrix element // exactly as defined in Eqs. C.1 of NPB 357(1991)409-438, multiplied by // tk * uk! Energy2 MEPP2VVPowheg::t_u_M_R_qqb_ZZ(realVVKinematics R) const { // First the Born variables: Energy2 mZ2(R.k22r()); // Then the rest: Energy2 s(R.sr()); Energy2 tk(R.tkr()); Energy2 uk(R.ukr()); Energy2 q1(R.q1r()); Energy2 q2(R.q2r()); Energy2 q1h(R.q1hatr()); Energy2 q2h(R.q2hatr()); double cosThetaW(sqrt(1.-sin2ThetaW_)); double gV2,gA2,gX,gY,gZ; gV2 = sqr(guL_/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL_/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); gX = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL_/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL_/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gY = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gZ = gX; if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) gZ = gY; Energy2 t_u_qqb(0.*GeV2); t_u_qqb = (2.*s)*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/2. * ( - ( tk*uk*uk+2.*s*uk*uk-tk*tk*uk - 2.*s*tk*uk+mZ2*(tk*tk-uk*uk+2.*s*uk-2.*s*tk-2.*s*s) )/q1h/q1/q2h/s*tk + 2.*(tk*uk*uk-mZ2*uk*(s+3.*tk)+mZ2*mZ2*(2.*uk-s))/q1/q2/s + ( tk*uk*(uk+s)-mZ2*(uk*uk+3.*tk*uk+3.*s*uk+s*tk) + 2.*mZ2*mZ2*(uk+tk+2.*s) )/q1h/q1/q2/s*tk + ( tk*(uk*uk+tk*uk-s*s)+mZ2*(4.*s*uk-3.*tk*uk-tk*tk+4.*s*s) )/q1h/q2/s - ( tk*uk+s*uk-s*tk-s*s+2.*mZ2*(s-tk) ) /q1h/q1/s*tk + q2*(tk*uk-s*uk-2.*s*tk-2.*s*s)/q1/q2h/s + 2.*(tk*uk-tk*tk-s*tk-s*s+mZ2*(2.*s-uk))/q1/s - 2.*mZ2*(uk*uk-2.*mZ2*uk+2.*mZ2*mZ2)/q1/q1/q2/s*tk + (2.*s*uk+tk*tk+3.*s*tk+2*s*s)/q1h/s + q1*(uk+s)*(uk+tk)/q1h/q2h/s + (tk*uk+s*uk+3.*s*tk+2.*s*s-mZ2*(uk+tk+2.*s))/q1h/q2h/s*uk + (uk-tk)/2./q1h/q2h/s*(q1*(uk+s)/q2/tk-q2*(tk+s)/q1/uk)*tk*uk + (tk-2.*mZ2)*(uk-2.*mZ2)/q1h/q1/q2h/q2*tk*uk - (q1*q1+q2*q2)/q1/q2 - 2.*mZ2*(q2-2.*mZ2)/q1/q1/s*tk ); swap(tk ,uk ); swap(q1 ,q2 ); swap(q1h,q2h); t_u_qqb += (2.*s)*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/2. * ( - ( tk*uk*uk+2.*s*uk*uk-tk*tk*uk - 2.*s*tk*uk+mZ2*(tk*tk-uk*uk+2.*s*uk-2.*s*tk-2.*s*s) )/q1h/q1/q2h/s*tk + 2.*(tk*uk*uk-mZ2*uk*(s+3.*tk)+mZ2*mZ2*(2.*uk-s))/q1/q2/s + ( tk*uk*(uk+s)-mZ2*(uk*uk+3.*tk*uk+3.*s*uk+s*tk) + 2.*mZ2*mZ2*(uk+tk+2.*s) )/q1h/q1/q2/s*tk + ( tk*(uk*uk+tk*uk-s*s)+mZ2*(4.*s*uk-3.*tk*uk-tk*tk+4.*s*s) )/q1h/q2/s - ( tk*uk+s*uk-s*tk-s*s+2.*mZ2*(s-tk) ) /q1h/q1/s*tk + q2*(tk*uk-s*uk-2.*s*tk-2.*s*s)/q1/q2h/s + 2.*(tk*uk-tk*tk-s*tk-s*s+mZ2*(2.*s-uk))/q1/s - 2.*mZ2*(uk*uk-2.*mZ2*uk+2.*mZ2*mZ2)/q1/q1/q2/s*tk + (2.*s*uk+tk*tk+3.*s*tk+2*s*s)/q1h/s + q1*(uk+s)*(uk+tk)/q1h/q2h/s + (tk*uk+s*uk+3.*s*tk+2.*s*s-mZ2*(uk+tk+2.*s))/q1h/q2h/s*uk + (uk-tk)/2./q1h/q2h/s*(q1*(uk+s)/q2/tk-q2*(tk+s)/q1/uk)*tk*uk + (tk-2.*mZ2)*(uk-2.*mZ2)/q1h/q1/q2h/q2*tk*uk - (q1*q1+q2*q2)/q1/q2 - 2.*mZ2*(q2-2.*mZ2)/q1/q1/s*tk ); swap(tk ,uk ); swap(q1 ,q2 ); swap(q1h,q2h); swap(q1 ,q1h); swap(q2 ,q2h); t_u_qqb += (2.*s)*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/2. * ( - ( tk*uk*uk+2.*s*uk*uk-tk*tk*uk - 2.*s*tk*uk+mZ2*(tk*tk-uk*uk+2.*s*uk-2.*s*tk-2.*s*s) )/q1h/q1/q2h/s*tk + 2.*(tk*uk*uk-mZ2*uk*(s+3.*tk)+mZ2*mZ2*(2.*uk-s))/q1/q2/s + ( tk*uk*(uk+s)-mZ2*(uk*uk+3.*tk*uk+3.*s*uk+s*tk) + 2.*mZ2*mZ2*(uk+tk+2.*s) )/q1h/q1/q2/s*tk + ( tk*(uk*uk+tk*uk-s*s)+mZ2*(4.*s*uk-3.*tk*uk-tk*tk+4.*s*s) )/q1h/q2/s - ( tk*uk+s*uk-s*tk-s*s+2.*mZ2*(s-tk) ) /q1h/q1/s*tk + q2*(tk*uk-s*uk-2.*s*tk-2.*s*s)/q1/q2h/s + 2.*(tk*uk-tk*tk-s*tk-s*s+mZ2*(2.*s-uk))/q1/s - 2.*mZ2*(uk*uk-2.*mZ2*uk+2.*mZ2*mZ2)/q1/q1/q2/s*tk + (2.*s*uk+tk*tk+3.*s*tk+2*s*s)/q1h/s + q1*(uk+s)*(uk+tk)/q1h/q2h/s + (tk*uk+s*uk+3.*s*tk+2.*s*s-mZ2*(uk+tk+2.*s))/q1h/q2h/s*uk + (uk-tk)/2./q1h/q2h/s*(q1*(uk+s)/q2/tk-q2*(tk+s)/q1/uk)*tk*uk + (tk-2.*mZ2)*(uk-2.*mZ2)/q1h/q1/q2h/q2*tk*uk - (q1*q1+q2*q2)/q1/q2 - 2.*mZ2*(q2-2.*mZ2)/q1/q1/s*tk ); swap(q1 ,q1h); swap(q2 ,q2h); swap(tk ,uk ); swap(q1 ,q2h); swap(q2 ,q1h); t_u_qqb += (2.*s)*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/2. * ( - ( tk*uk*uk+2.*s*uk*uk-tk*tk*uk - 2.*s*tk*uk+mZ2*(tk*tk-uk*uk+2.*s*uk-2.*s*tk-2.*s*s) )/q1h/q1/q2h/s*tk + 2.*(tk*uk*uk-mZ2*uk*(s+3.*tk)+mZ2*mZ2*(2.*uk-s))/q1/q2/s + ( tk*uk*(uk+s)-mZ2*(uk*uk+3.*tk*uk+3.*s*uk+s*tk) + 2.*mZ2*mZ2*(uk+tk+2.*s) )/q1h/q1/q2/s*tk + ( tk*(uk*uk+tk*uk-s*s)+mZ2*(4.*s*uk-3.*tk*uk-tk*tk+4.*s*s) )/q1h/q2/s - ( tk*uk+s*uk-s*tk-s*s+2.*mZ2*(s-tk) ) /q1h/q1/s*tk + q2*(tk*uk-s*uk-2.*s*tk-2.*s*s)/q1/q2h/s + 2.*(tk*uk-tk*tk-s*tk-s*s+mZ2*(2.*s-uk))/q1/s - 2.*mZ2*(uk*uk-2.*mZ2*uk+2.*mZ2*mZ2)/q1/q1/q2/s*tk + (2.*s*uk+tk*tk+3.*s*tk+2*s*s)/q1h/s + q1*(uk+s)*(uk+tk)/q1h/q2h/s + (tk*uk+s*uk+3.*s*tk+2.*s*s-mZ2*(uk+tk+2.*s))/q1h/q2h/s*uk + (uk-tk)/2./q1h/q2h/s*(q1*(uk+s)/q2/tk-q2*(tk+s)/q1/uk)*tk*uk + (tk-2.*mZ2)*(uk-2.*mZ2)/q1h/q1/q2h/q2*tk*uk - (q1*q1+q2*q2)/q1/q2 - 2.*mZ2*(q2-2.*mZ2)/q1/q1/s*tk ); swap(tk ,uk ); swap(q1 ,q2h); swap(q2 ,q1h); return t_u_qqb; } /***************************************************************************/ // M_B_WW is the Born matrix element exactly as defined in Eqs. 3.2-3.8 // of of NPB 410(1993)280-384. double MEPP2VVPowheg::M_Born_WW(bornVVKinematics B) const { Energy2 s(B.sb()); Energy2 t(B.tb()); Energy2 u(B.ub()); Energy2 mW2(B.k12b()); // N.B. the diboson masses are preserved in getting bool up_type = abs(quark_->id())%2==0 ? true : false; double Qi = up_type ? 2./3. : -1./3. ; double giL = up_type ? guL_/2. : gdL_/2.; double giR = up_type ? guR_/2. : gdR_/2.; double e2 = sqr(gW_)*sin2ThetaW_; double cos2ThetaW(1.-sin2ThetaW_); double ctt_i(gW_*gW_*gW_*gW_/16.); InvEnergy2 cts_i(gW_*gW_*e2/4./s *(Qi+2.*eZ_*giL/e2*s/(s-mW2/cos2ThetaW))); InvEnergy4 css_i(e2*e2/s/s*(sqr(Qi+eZ_*(giL+giR)/e2*s/(s-mW2/cos2ThetaW)) +sqr( eZ_*(giL-giR)/e2*s/(s-mW2/cos2ThetaW))) ); ctt_i *= 8.*Fij2_/gW_/gW_; cts_i *= sqrt(8.*Fij2_/gW_/gW_); if(quark_->id()!=-antiquark_->id()) { cts_i = 0./GeV2; css_i = 0./GeV2/GeV2; } if(!up_type) swap(t,u); double signf = up_type ? 1. : -1.; return 1./4./NC_ * ( ctt_i*( 16.*(u*t/mW2/mW2-1.)*(1./4.+mW2*mW2/t/t)+16.*s/mW2) - cts_i*( 16.*(u*t/mW2/mW2-1.)*(s/4.-mW2/2.-mW2*mW2/t) + 16.*s*(s/mW2-2.+2.*mW2/t) ) *signf + css_i*( 8.*(u*t/mW2/mW2-1.)*(s*s/4.-s*mW2+3.*mW2*mW2) + 8.*s*s*(s/mW2-4.) ) ); } /***************************************************************************/ // M_V_regular_WW is the regular part of the one-loop WW matrix element // exactly as defined in Eqs. C.1 - C.7 of of NPB 410(1993)280-324 *** // modulo a factor 1/(2s) ***, which is a flux factor that those authors // absorb in the matrix element. double MEPP2VVPowheg::M_V_regular_WW(realVVKinematics S) const { Energy2 s(S.bornVariables().sb()); Energy2 t(S.bornVariables().tb()); Energy2 u(S.bornVariables().ub()); Energy2 mW2(S.k12r()); // N.B. the diboson masses are preserved in getting double beta(S.betaxr()); // N.B. for x=1 \beta_x=\beta in NPB 383(1992)3-44. bool up_type = abs(quark_->id())%2==0 ? true : false; double Qi = up_type ? 2./3. : -1./3.; double giL = up_type ? guL_/2. : gdL_/2.; double giR = up_type ? guR_/2. : gdR_/2.; double e2 = sqr(gW_)*sin2ThetaW_; double cos2ThetaW(1.-sin2ThetaW_); double ctt_i(gW_*gW_*gW_*gW_/16.); InvEnergy2 cts_i(gW_*gW_*e2/4./s *(Qi+2.*eZ_*giL/e2*s/(s-mW2/cos2ThetaW))); InvEnergy4 css_i(e2*e2/s/s*(sqr(Qi+eZ_*(giL+giR)/e2*s/(s-mW2/cos2ThetaW)) +sqr( eZ_*(giL-giR)/e2*s/(s-mW2/cos2ThetaW))) ); ctt_i *= 8.*Fij2_/gW_/gW_; cts_i *= sqrt(8.*Fij2_/gW_/gW_); if(quark_->id()!=-antiquark_->id()) { cts_i = 0./GeV2; css_i = 0./GeV2/GeV2; } if(!up_type) swap(t,u); double signf = up_type ? 1. : -1.; InvEnergy4 TildeI4 = ( 2.*sqr(log(-t/mW2))-4.*log((mW2-t)/mW2)*log(-t/mW2) - 4.*ReLi2(t/mW2) )/s/t; InvEnergy2 TildeI3t = 1./(mW2-t) *(sqr(log(mW2/s))/2.-sqr(log(-t/s))/2.-pi*pi/2.); InvEnergy2 TildeI3l = 1./s/beta*( 4.*ReLi2((beta-1.)/(beta+1.)) + sqr(log((1.-beta)/(1.+beta))) + pi*pi/3.); double Fup1_st(0.); Fup1_st = 4.*(80.*t*t+73.*s*t-140.*mW2*t+72.*mW2*mW2)/t/t - 4.*sqr(4.*t+s)/s/beta/beta/t - 128.*(t+2.*s)/mW2 + 64.*t*(t+s)/mW2/mW2 - (32.*(t*t-3.*s*t-3.*mW2*mW2)/t/t+128.*s/(t-mW2))*log(-t/mW2) + ( 8.*(6.*t*t+8.*s*t-19.*mW2*t+12.*mW2*mW2)/t/t - (32.*t*t-128.*s*t-26.*s*s)/s/beta/beta/t + 6.*sqr(4.*t+s)/s/sqr(sqr(beta))/t )*log(s/mW2) + 32.*s*(2.*mW2*mW2/t-u)*TildeI4 - 64.*(t-mW2)*(2.*mW2*mW2/t/t-u/t)*TildeI3t + ( (16.*t*(4.*mW2-u)-49.*s*s+72.*mW2*s-48.*mW2*mW2)/2./t + 2.*(8.*t*t-14.*s*t-3.*s*s)/beta/beta/t - 3.*sqr(4.*t+s)/2./sqr(sqr(beta))/t )*TildeI3l + 32./3.*( 2.*(t+2.*s)/mW2 - (3.*t+2.*s-4.*mW2)/t - t*(t+s)/mW2/mW2 )*pi*pi; Energy2 Jup1_st(0.*GeV2); Jup1_st = -128.*(t*t+2.*s*t+2.*s*s)/mW2 - 16.*(t*t-21.*s*t-26.*mW2*t+34.*mW2*s+17.*mW2*mW2)/t + 64.*s*t*(t+s)/mW2/mW2 +32.*s*s/(t-mW2) + ( 16.*(t-5.*s+2.*mW2)-48.*mW2*(2.*s+mW2)/t + 64.*s*(2.*t+s)/(t-mW2) - 32.*s*s*t/sqr(t-mW2) )*log(-t/mW2) + ( 16.*(4.*t+s)/beta/beta - 16.*(3.*t-2.*s) + 48.*mW2*(2.*t-2.*s-mW2)/t )*log(s/mW2) + 16.*s*(t*(2.*s+u)-2.*mW2*(2.*s+mW2))*TildeI4 + 32.*(t-mW2)*(2.*mW2*(2.*s+mW2)/t-2.*s-u)*TildeI3t + ( 32.*s*t-12.*s*s+32.*mW2*mW2 - 16.*mW2*(2.*t+7.*s)-4.*s*(4.*t+s)/beta/beta )*TildeI3l + 32./3.*( 2.*(t*t+2.*s*t+2.*s*s)/mW2 - s*t*(t+s)/mW2/mW2-2.*mW2*(2.*t-2.*s-mW2)/t-t-4.*s )*pi*pi; Energy4 Kup1_st(0.*GeV2*GeV2); Kup1_st = 16.*( 12.*t*t+20.*s*t-24.*mW2*t+17.*s*s-4.*mW2*s+12.*mW2*mW2 + s*s*t*(t+s)/mW2/mW2-2.*s*(2.*t*t+3.*s*t+2.*s*s)/mW2) *(2.-pi*pi/3.); return pi*alphaS_*CF_/NC_/(sqr(4.*pi)) * ( ctt_i*Fup1_st - cts_i*Jup1_st*signf + css_i*Kup1_st ); } /***************************************************************************/ // t_u_M_R_qqb is the real emission q + qb -> n + g matrix element // exactly as defined in Eqs. C.1 of NPB 383(1992)3-44, multiplied by // tk * uk! Energy2 MEPP2VVPowheg::t_u_M_R_qqb_WW(realVVKinematics R) const { // First the Born variables: Energy2 s2(R.s2r()); Energy2 mW2(R.k12r()); // Then the rest: Energy2 s(R.sr()); Energy2 tk(R.tkr()); Energy2 uk(R.ukr()); Energy2 q1(R.q1r()); Energy2 q2(R.q2r()); Energy2 q1h(R.q1hatr()); Energy2 q2h(R.q2hatr()); bool up_type = abs(quark_->id())%2==0 ? true : false; double Qi = up_type ? 2./3. : -1./3.; double giL = up_type ? guL_/2. : gdL_/2.; double giR = up_type ? guR_/2. : gdR_/2.; double e2 = sqr(gW_)*sin2ThetaW_; double cos2ThetaW(1.-sin2ThetaW_); double ctt_i(gW_*gW_*gW_*gW_/16.); InvEnergy2 cts_i(gW_*gW_*e2/4./s2*(Qi+2.*eZ_*giL/e2*s2/(s2-mW2/cos2ThetaW))); InvEnergy4 css_i(e2*e2/s2/s2*(sqr(Qi+eZ_*(giL+giR)/e2*s2/(s2-mW2/cos2ThetaW)) +sqr( eZ_*(giL-giR)/e2*s2/(s2-mW2/cos2ThetaW))) ); ctt_i *= 8.*Fij2_/gW_/gW_; cts_i *= sqrt(8.*Fij2_/gW_/gW_); if(quark_->id()!=-antiquark_->id()) { cts_i = 0./GeV2; css_i = 0./GeV2/GeV2; } if(!up_type) { swap(q1,q1h); swap(q2,q2h); } double signf = up_type ? 1. : -1.; Energy2 t_u_Xup(0.*GeV2); Energy4 t_u_Yup(0.*GeV2*GeV2); Energy6 t_u_Zup(0.*GeV2*GeV2*GeV2); t_u_Xup = 32.*mW2*(tk*uk+3.*q2*uk+q2*s+q1*q2)/q1/q2/q2*tk + 32.*mW2*q1/q2/q2*uk - 64.*mW2*s/q2 - 32.*tk*(uk-q2)/q1/q2*tk + 64.*mW2*mW2*mW2/q1/q1/q2*tk - 16.*(2.*tk-2.*s-q2)/q2*uk + 16.*s*(2.*s+2.*q1+q2/2.)/q2 - 8.*(4.*tk+uk+9.*s+2.*q2+2.*q1)/mW2*tk - 16.*s*(2.*s+q1)/mW2 - 64.*mW2*mW2*(tk*uk+q2*tk+q1*uk-q2*s/2.)/q1/q2/q2 + 8.*s2*q1*(tk+s+q1)/mW2/mW2; swap(tk,uk); swap(q1,q2); t_u_Xup += 32.*mW2*(tk*uk+3.*q2*uk+q2*s+q1*q2)/q1/q2/q2*tk + 32.*mW2*q1/q2/q2*uk - 64.*mW2*s/q2 - 32.*tk*(uk-q2)/q1/q2*tk + 64.*mW2*mW2*mW2/q1/q1/q2*tk - 16.*(2.*tk-2.*s-q2)/q2*uk + 16.*s*(2.*s+2.*q1+q2/2.)/q2 - 8.*(4.*tk+uk+9.*s+2.*q2+2.*q1)/mW2*tk - 16.*s*(2.*s+q1)/mW2 - 64.*mW2*mW2*(tk*uk+q2*tk+q1*uk-q2*s/2.)/q1/q2/q2 + 8.*s2*q1*(tk+s+q1)/mW2/mW2; swap(tk,uk); swap(q1,q2); t_u_Yup = - 16.*tk*(uk*(uk+s+q1)+q2*(s-2.*q1))/q1/q2*tk - 32.*mW2*mW2*s/q2 - 32.*mW2*mW2*mW2/q1/q2*tk + 16.*(2.*q2*uk+s*s+q1*s+5.*q2*s+q1*q2+2.*q2*q2)/q2*tk - 16.*(q2*q2+s*s-q2*s)/q1*tk + 16.*s*(q1*s+3./2.*q2*s+q1*q2-q1*q1)/q2 + 16.*mW2*tk*(4.*uk+s+q1-2.*q2)/q1/q2*tk + 16.*mW2*(3.*s*uk+q1*uk-q1*s-3.*q2*s-q1*q1+q2*q2)/q1/q2*tk + 16.*mW2*s*(q2-4.*s+2.*q1)/q2 - 8.*s2*(4.*tk+uk+9.*s+4.*q1+2.*q2)/mW2*tk - 16.*s2*(2.*s*s+2.*q1*s+q1*q1)/mW2 - 32.*mW2*mW2*(tk+uk/2.+2.*s-q1)/q1/q2*tk + 8.*s2*s2*q1*(tk+s+q1)/mW2/mW2; swap(tk,uk); swap(q1,q2); t_u_Yup += - 16.*tk*(uk*(uk+s+q1)+q2*(s-2.*q1))/q1/q2*tk - 32.*mW2*mW2*s/q2 - 32.*mW2*mW2*mW2/q1/q2*tk + 16.*(2.*q2*uk+s*s+q1*s+5.*q2*s+q1*q2+2.*q2*q2)/q2*tk - 16.*(q2*q2+s*s-q2*s)/q1*tk + 16.*s*(q1*s+3./2.*q2*s+q1*q2-q1*q1)/q2 + 16.*mW2*tk*(4.*uk+s+q1-2.*q2)/q1/q2*tk + 16.*mW2*(3.*s*uk+q1*uk-q1*s-3.*q2*s-q1*q1+q2*q2)/q1/q2*tk + 16.*mW2*s*(q2-4.*s+2.*q1)/q2 - 8.*s2*(4.*tk+uk+9.*s+4.*q1+2.*q2)/mW2*tk - 16.*s2*(2.*s*s+2.*q1*s+q1*q1)/mW2 - 32.*mW2*mW2*(tk+uk/2.+2.*s-q1)/q1/q2*tk + 8.*s2*s2*q1*(tk+s+q1)/mW2/mW2; swap(tk,uk); swap(q1,q2); t_u_Zup = 8.*s2*(9.*tk+3.*uk+20.*s+10.*q1+4.*q2)*tk + 8.*s2*(17./2.*s*s+10.*q1*s+6.*q1*q1) - 4.*s2*s2*(4.*tk+uk+9.*s+6.*q1+2.*q2)/mW2*tk - 8.*s2*s2*(2.*s*s+3.*q1*s+2.*q1*q1)/mW2 - 16.*mW2*(2.*tk+5.*uk+7.*s+6.*q1+6.*q2)*tk - 16.*mW2*s*(s+6.*q1) + 4.*s2*s2*s2*q1*(tk+s+q1)/mW2/mW2 + 48.*mW2*mW2*s2; swap(tk,uk); swap(q1,q2); t_u_Zup += 8.*s2*(9.*tk+3.*uk+20.*s+10.*q1+4.*q2)*tk + 8.*s2*(17./2.*s*s+10.*q1*s+6.*q1*q1) - 4.*s2*s2*(4.*tk+uk+9.*s+6.*q1+2.*q2)/mW2*tk - 8.*s2*s2*(2.*s*s+3.*q1*s+2.*q1*q1)/mW2 - 16.*mW2*(2.*tk+5.*uk+7.*s+6.*q1+6.*q2)*tk - 16.*mW2*s*(s+6.*q1) + 4.*s2*s2*s2*q1*(tk+s+q1)/mW2/mW2 + 48.*mW2*mW2*s2; swap(tk,uk); swap(q1,q2); return -pi*alphaS_*CF_/NC_ * ( ctt_i*t_u_Xup - cts_i*t_u_Yup*signf + css_i*t_u_Zup ); } /***************************************************************************/ // The game here is to get this helicity amplitude squared to return all the // same values as t_u_M_R_qqb above, TIMES a further factor tk*uk! Energy2 MEPP2VVPowheg::t_u_M_R_qqb_hel_amp(realVVKinematics R) const { using namespace ThePEG::Helicity; // qqb_hel_amps_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half, // PDT::Spin1,PDT::Spin1, // PDT::Spin1)); double sum_hel_amps_sqr(0.); tcPDPtr p1data(quark_); tcPDPtr p2data(antiquark_); tcPDPtr k1data(mePartonData()[2]); tcPDPtr k2data(mePartonData()[3]); tcPDPtr kdata(getParticleData(ParticleID::g)); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorWaveFunction qSpinor(R.p1r(),p1data,incoming); SpinorBarWaveFunction qbSpinor(R.p2r(),p2data,incoming); vector q; vector qb; for(unsigned int ix=0;ix<2;ix++) { qSpinor.reset(ix); qbSpinor.reset(ix); q.push_back(qSpinor); qb.push_back(qbSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.kr(),kdata,outgoing); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(p2data); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorWaveFunction p1_k = ffg->evaluate(mu_UV2(),5,p1data,q[p1hel],g[khel]); SpinorBarWaveFunction p2_k = ffg->evaluate(mu_UV2(),5,p2data,qb[p2hel],g[khel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p1hel=p2hel // but if the production ME is required first fill it with (0.,0.). if((p1hel==p2hel)&&helicityConservation_) { // if(getMatrix) { // if(khel==0) // qqb_hel_amps_(p1hel,p2hel,k1hel,k2hel,0) = Complex(0.,0.); // else // qqb_hel_amps_(p1hel,p2hel,k1hel,k2hel,2) = Complex(0.,0.); // } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_t; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? p2data : tc[ix]; SpinorWaveFunction p1_v1 = ffv1->evaluate(scale(),5,intermediate_t,q[p1hel],v1[k1hel]); SpinorBarWaveFunction p2_v2 = ffv2->evaluate(scale(),5,intermediate_t,qb[p2hel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 t-channel diagrams // q+qb->g+v1+v2, q+qb->v1+g+v2, q+qb->v1+v2+g if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) { diagrams.push_back(ffv1->evaluate(scale(),p1_k,p2_v2,v1[k1hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),p1_v1,p2_v2,g[khel])); diagrams.push_back(ffv2->evaluate(scale(),p1_v1,p2_k,v2[k2hel])); } intermediate_t = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(scale(),5,intermediate_t,q[p1hel],v2[k2hel]); SpinorBarWaveFunction p2_v1 = ffv1->evaluate(scale(),5,intermediate_t,qb[p2hel],v1[k1hel]); // q+qb->g+v2+v1, q+qb->v2+g+v1, q+qb->v2+v1+g if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) { diagrams.push_back(ffv2->evaluate(scale(),p1_k,p2_v1,v2[k2hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),p1_v2,p2_v1,g[khel])); diagrams.push_back(ffv1->evaluate(scale(),p1_v2,p2_k,v1[k1hel])); } } // Note: choosing 3 as the second argument in WWWvertex_->evaluate() // sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which // means the propagator does not contain a width factor (which is // good re. gauge invariance). // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(scale(),3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(scale(),p1_k,qb[p2hel],k1_k2)); diagrams.push_back(ffv1->evaluate(scale(),q[p1hel],p2_k,k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==-p2data->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(scale(),3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(scale(),p1_k,qb[p2hel],k1_k2)); diagrams.push_back(FFZvertex_->evaluate(scale(),q[p1hel],p2_k,k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(scale(),3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(scale(),p1_k,qb[p2hel],k1_k2)); diagrams.push_back(FFPvertex_->evaluate(scale(),q[p1hel],p2_k,k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } /***************************************************************************/ // The game here is to get this helicity amplitude squared to return all the // same values as t_u_M_R_qg above, TIMES a further factor tk*uk! Energy2 MEPP2VVPowheg::t_u_M_R_qg_hel_amp(realVVKinematics R) const { using namespace ThePEG::Helicity; // qg_hel_amps_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1, // PDT::Spin1,PDT::Spin1, // PDT::Spin1Half)); double sum_hel_amps_sqr(0.); tcPDPtr p1data(quark_); tcPDPtr p2data(getParticleData(ParticleID::g)); tcPDPtr k1data(mePartonData()[2]); tcPDPtr k2data(mePartonData()[3]); tcPDPtr kdata (antiquark_->CC()); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorWaveFunction qinSpinor(R.p1r(),p1data,incoming); SpinorBarWaveFunction qoutSpinor(R.kr(),kdata,outgoing); vector qin; vector qout; for(unsigned int ix=0;ix<2;ix++) { qinSpinor.reset(ix); qoutSpinor.reset(ix); qin.push_back(qinSpinor); qout.push_back(qoutSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.p2r(),p2data,incoming); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(kdata->CC()); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorWaveFunction p1_p2 = ffg->evaluate(mu_UV2(),5,p1data,qin[p1hel],g[p2hel]); SpinorBarWaveFunction p2_k = ffg->evaluate(mu_UV2(),5,kdata->CC(),qout[khel],g[p2hel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p1hel!=khel // but if the production ME is required first fill it with (0.,0.). if((p1hel!=khel)&&helicityConservation_) { // if(getMatrix) { // if(p2hel==0) // qg_hel_amps_(p1hel,0,k1hel,k2hel,khel) = Complex(0.,0.); // else // qg_hel_amps_(p1hel,2,k1hel,k2hel,khel) = Complex(0.,0.); // } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_q; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? antiquark_ : tc[ix]; SpinorWaveFunction p1_v1 = ffv1->evaluate(scale(),5,intermediate_q,qin[p1hel],v1[k1hel]); SpinorBarWaveFunction k_v2 = ffv2->evaluate(scale(),5,intermediate_q,qout[khel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 abelian diagrams // q+g->v1+v2+q with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) { diagrams.push_back(ffv2->evaluate(scale(),p1_v1,p2_k,v2[k2hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),p1_v1,k_v2,g[p2hel])); diagrams.push_back(ffv1->evaluate(scale(),p1_p2,k_v2,v1[k1hel])); } intermediate_q = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(scale(),5,intermediate_q,qin[p1hel],v2[k2hel]); SpinorBarWaveFunction k_v1 = ffv1->evaluate(scale(),5,intermediate_q,qout[khel],v1[k1hel]); // q+g->v2+v1+q, with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) { diagrams.push_back(ffv1->evaluate(scale(),p1_v2,p2_k,v1[k1hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),p1_v2,k_v1,g[p2hel])); diagrams.push_back(ffv2->evaluate(scale(),p1_p2,k_v1,v2[k2hel])); } } // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(scale(),3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(scale(),p1_p2,qout[khel],k1_k2)); diagrams.push_back(ffv1->evaluate(scale(),qin[p1hel],p2_k,k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==kdata->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(scale(),3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(scale(),p1_p2,qout[khel],k1_k2)); diagrams.push_back(FFZvertex_->evaluate(scale(),qin[p1hel],p2_k,k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(scale(),3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(scale(),p1_p2,qout[khel],k1_k2)); diagrams.push_back(FFPvertex_->evaluate(scale(),qin[p1hel],p2_k,k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } /***************************************************************************/ // The game here is to get this helicity amplitude squared to return all the // same values as t_u_M_R_gqb above, TIMES a further factor tk*uk! Energy2 MEPP2VVPowheg::t_u_M_R_gqb_hel_amp(realVVKinematics R) const { using namespace ThePEG::Helicity; // gqb_hel_amps_.reset(ProductionMatrixElement(PDT::Spin1,PDT::Spin1Half, // PDT::Spin1,PDT::Spin1, // PDT::Spin1Half)); double sum_hel_amps_sqr(0.); tcPDPtr p1data(getParticleData(ParticleID::g)); tcPDPtr p2data(antiquark_); tcPDPtr k1data(mePartonData()[2]); tcPDPtr k2data(mePartonData()[3]); tcPDPtr kdata (quark_->CC()); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorBarWaveFunction qbinSpinor(R.p2r(),p2data,incoming); SpinorWaveFunction qboutSpinor(R.kr(),kdata,outgoing); vector qbin; vector qbout; for(unsigned int ix=0;ix<2;ix++) { qbinSpinor.reset(ix); qboutSpinor.reset(ix); qbin.push_back(qbinSpinor); qbout.push_back(qboutSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.p1r(),p1data,incoming); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p2data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p2data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(kdata->CC()); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorBarWaveFunction p1_p2 = ffg->evaluate(mu_UV2(),5,p2data,qbin[p2hel],g[p1hel]); SpinorWaveFunction p1_k = ffg->evaluate(mu_UV2(),5,kdata->CC(),qbout[khel],g[p1hel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p2hel!=khel // but if the production ME is required first fill it with (0.,0.). if((p2hel!=khel)&&helicityConservation_) { // if(getMatrix) { // if(p1hel==0) // gqb_hel_amps_(0,p2hel,k1hel,k2hel,khel) = Complex(0.,0.); // else // gqb_hel_amps_(2,p2hel,k1hel,k2hel,khel) = Complex(0.,0.); // } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_q; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? quark_ : tc[ix]; SpinorBarWaveFunction p2_v1 = ffv1->evaluate(scale(),5,intermediate_q,qbin[p2hel],v1[k1hel]); SpinorWaveFunction k_v2 = ffv2->evaluate(scale(),5,intermediate_q,qbout[khel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 abelian diagrams q+g->v1+v2+q // with 2 t-channel propagators, 1 s- and 1 t-channel // and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p2data->id())%2==0))) { diagrams.push_back(ffv2->evaluate(scale(),p1_k,p2_v1,v2[k2hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),k_v2,p2_v1,g[p1hel])); diagrams.push_back(ffv1->evaluate(scale(),k_v2,p1_p2,v1[k1hel])); } intermediate_q = (!(k1data->id()==24&&k2data->id()==-24)) ? p2data : tc[ix]; SpinorBarWaveFunction p2_v2 = ffv2->evaluate(scale(),5,intermediate_q,qbin[p2hel],v2[k2hel]); SpinorWaveFunction k_v1 = ffv1->evaluate(scale(),5,intermediate_q,qbout[khel],v1[k1hel]); // q+g->v2+v1+q, with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p2data->id())%2==1))) { diagrams.push_back(ffv1->evaluate(scale(),p1_k,p2_v2,v1[k1hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),k_v1,p2_v2,g[p1hel])); diagrams.push_back(ffv2->evaluate(scale(),k_v1,p1_p2,v2[k2hel])); } } // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(scale(),3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(scale(),qbout[khel],p1_p2,k1_k2)); diagrams.push_back(ffv1->evaluate(scale(),p1_k,qbin[p2hel],k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p2data->id()==kdata->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(scale(),3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(scale(),qbout[khel],p1_p2,k1_k2)); diagrams.push_back(FFZvertex_->evaluate(scale(),p1_k,qbin[p2hel],k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(scale(),3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(scale(),qbout[khel],p1_p2,k1_k2)); diagrams.push_back(FFPvertex_->evaluate(scale(),p1_k,qbin[p2hel],k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } double MEPP2VVPowheg::lo_me() const { using namespace ThePEG::Helicity; double sum_hel_amps_sqr(0.); tcPDPtr p1data(quark_); tcPDPtr p2data(antiquark_); tcPDPtr k1data(mePartonData()[2]); tcPDPtr k2data(mePartonData()[3]); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); // Should never actually occur. SpinorWaveFunction qSpinor(B_.p1b(),p1data,incoming); SpinorBarWaveFunction qbSpinor(B_.p2b(),p2data,incoming); vector q; vector qb; for(unsigned int ix=0;ix<2;ix++) { qSpinor.reset(ix); qbSpinor.reset(ix); q.push_back(qSpinor); qb.push_back(qbSpinor); } VectorWaveFunction v1Polarization(B_.k1b(),k1data,outgoing); VectorWaveFunction v2Polarization(B_.k2b(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(p2data); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { if((p1hel==p2hel)&&helicityConservation_) continue; for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_t; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? p2data : tc[ix]; SpinorWaveFunction p1_v1 = ffv1->evaluate(scale(),5,intermediate_t,q[p1hel],v1[k1hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 t-channel diagrams // q+qb->v1+v2 if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) diagrams.push_back(ffv2->evaluate(scale(),p1_v1,qb[p2hel],v2[k2hel])); intermediate_t = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(scale(),5,intermediate_t,q[p1hel],v2[k2hel]); // q+qb->v2+v1 if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) diagrams.push_back(ffv1->evaluate(scale(),p1_v2,qb[p2hel],v1[k1hel])); } // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(scale(),3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->v1*->v1+v2 diagrams.push_back(ffv1->evaluate(scale(),q[p1hel],qb[p2hel],k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==-p2data->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->Z0*->v1+v2 tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(scale(),3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(scale(),q[p1hel],qb[p2hel],k1_k2)); // q+qb->gamma*->v1+v2 tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(scale(),3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(scale(),q[p1hel],qb[p2hel],k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr; } RealEmissionProcessPtr MEPP2VVPowheg::generateHardest(RealEmissionProcessPtr born, ShowerInteraction inter) { if(inter==ShowerInteraction::QED) return RealEmissionProcessPtr(); // Now we want to set these data vectors according to the particles we've // received from the current 2->2 hard collision: vector particlesToShower; for(unsigned int ix=0;ixbornIncoming().size();++ix) particlesToShower.push_back(born->bornIncoming()[ix]); qProgenitor_ = particlesToShower[0]; qbProgenitor_ = particlesToShower[1]; showerQuark_ = particlesToShower[0]; showerAntiquark_ = particlesToShower[1]; qHadron_ = dynamic_ptr_cast(born->hadrons()[0]->dataPtr()); qbHadron_ = dynamic_ptr_cast(born->hadrons()[1]->dataPtr()); if(showerQuark_->id()<0) { swap(qProgenitor_,qbProgenitor_); swap(showerQuark_,showerAntiquark_); swap(qHadron_,qbHadron_); } // In _our_ calculation we basically define the +z axis as being given // by the direction of the incoming quark for q+qb & q+g processes and // the incoming gluon for g+qbar processes. So now we might need to flip // the beams, bjorken x values, colliding partons accordingly: flipped_ = showerQuark_->momentum().z() cmap; // undecayed gauge bosons if(born->bornOutgoing().size()==2) { for(unsigned int ix=0;ixbornOutgoing().size();++ix) { particlesToShower.push_back(born->bornOutgoing()[ix]); } V1_ = particlesToShower[2]; V2_ = particlesToShower[3]; } else if(born->bornOutgoing().size()==4) { // If the vector bosons have decayed already then we may want to // to get the children_ (and any associated photons) to correct // spin correlations: children_.clear(); map clines; for(unsigned int ix=0;ixbornOutgoing().size();++ix) { tPPtr original = born->bornOutgoing()[ix]; PPtr copy = original->dataPtr()->produceParticle(original->momentum()); children_.push_back(copy); cmap.push_back(ix); // sort out colour if(original->colourLine()) { map::iterator cit = clines.find(original->colourLine()); if(cit!=clines.end()) { cit->second->addColoured(copy); } else { ColinePtr newline = new_ptr(ColourLine()); clines[original->colourLine()] = newline; newline->addColoured(copy); } } // and anticolour else if(original->antiColourLine()) { map::iterator cit = clines.find(original->antiColourLine()); if(cit!=clines.end()) { cit->second->addAntiColoured(copy); } else { ColinePtr newline = new_ptr(ColourLine()); clines[original->antiColourLine()] = newline; newline->addAntiColoured(copy); } } } assert(children_.size()==4); PPtr V[2]; for(unsigned int ix=0;ix<2;++ix) { int charge = children_[0+2*ix]->dataPtr()->iCharge()+ children_[1+2*ix]->dataPtr()->iCharge(); Lorentz5Momentum psum =children_[0+2*ix]->momentum()+ children_[1+2*ix]->momentum(); psum.rescaleMass(); if(charge==-3) V[ix] = getParticleData(ParticleID::Wminus)->produceParticle(psum); else if(charge==0) V[ix] = getParticleData(ParticleID::Z0)->produceParticle(psum); else if(charge==3) V[ix] = getParticleData(ParticleID::Wplus)->produceParticle(psum); else assert(false); } V1_ = V[0]; V2_ = V[1]; if(children_[0]->id()<0) { swap(children_[0],children_[1]); swap(cmap[0],cmap[1]); } if(children_[2]->id()<0) { swap(children_[2],children_[3]); swap(cmap[2],cmap[3]); } } else assert(false); gluon_ = getParticleData(ParticleID::g)->produceParticle(); // Abort the run if V1_ and V2_ are not just pointers to different gauge bosons if(!V1_||!V2_) throw Exception() << "MEPP2VVPowheg::generateHardest()\n" << "one or both of the gauge boson pointers is null." << Exception::abortnow; if(!(abs(V1_->id())==24||V1_->id()==23)||!(abs(V2_->id())==24||V2_->id()==23)) throw Exception() << "MEPP2VVPowheg::generateHardest()\nmisidentified gauge bosons" << "V1_ = " << V1_->PDGName() << "\n" << "V2_ = " << V2_->PDGName() << "\n" << Exception::abortnow; // Order the gauge bosons in the same way as in the NLO calculation // (the same way as in the NLO matrix element): // W+(->e+,nu_e) W-(->e-,nu_ebar) (MCFM: 61 [nproc]) bool order = false; if((V1_->id()==-24&&V2_->id()== 24) || // W+/-(mu+,nu_mu / mu-,nu_mubar) Z(nu_e,nu_ebar) (MCFM: 72+77 [nproc]) (V1_->id()== 23&&abs(V2_->id())== 24) ) { swap(V1_,V2_); order = true; swap(cmap[0],cmap[2]); swap(cmap[1],cmap[3]); swap(children_[0],children_[2]); swap(children_[1],children_[3]); } // *** N.B. *** // We should not have to do a swap in the ZZ case, even if the different // (off-shell) masses of the Z's are taken into account by generating // the Born variables using the WZ LO/NLO matrix element(s), because // those transformed matrix elements are, according to mathematica, // symmetric in the momenta (and therefore also the masses) of the 2 Z's. // Now we want to construct a bornVVKinematics object. The // constructor for that needs all 4 momenta, q, qbar, V1_, V2_ // in that order, as well as the Bjorken xq and xqbar. // Get the momenta first: vector theBornMomenta; theBornMomenta.push_back(showerQuark_->momentum()); theBornMomenta.push_back(showerAntiquark_->momentum()); theBornMomenta.push_back(V1_->momentum()); theBornMomenta.push_back(V2_->momentum()); // N.B. if the showerQuark_ travels in the -z direction the born kinematics object // will detect this and rotate all particles by pi about the y axis! // Leading order momentum fractions: tcPPtr qHadron = generator()->currentEvent()->primaryCollision()->incoming().first; tcPPtr qbHadron = generator()->currentEvent()->primaryCollision()->incoming().second; assert(qHadron->children().size()>0&&qbHadron->children().size()>0); if(qHadron->children()[0]->id()<0) swap(qHadron,qbHadron); // quark and antiquark momentum fractions respectively double xa = showerQuark_ ->momentum().z()/qHadron ->momentum().z(); double xb = showerAntiquark_->momentum().z()/qbHadron->momentum().z(); // Create the object containing all 2->2 __kinematic__ information: B_ = bornVVKinematics(theBornMomenta,xa,xb); // lo_me_ is the colour & spin averaged n-body matrix element squared: lo_me_ = lo_me(true); // Attempt to generate some radiative variables and their kinematics: vector theRealMomenta; channel_ = 999; if(!getEvent(theRealMomenta,channel_)) { born->pT()[ShowerInteraction::QCD] = min_pT_; return born; } // Set the maximum pT for subsequent emissions: born->pT()[ShowerInteraction::QCD] = pT_ < min_pT_ ? min_pT_ : pT_; // Determine whether the quark or antiquark emitted: fermionNumberOfMother_=0; if((channel_==0&&theRealMomenta[0].z()/theRealMomenta[4].z()>=ZERO)|| channel_==2) fermionNumberOfMother_ = 1; else if((channel_==0&&theRealMomenta[0].z()/theRealMomenta[4].z()0.1*GeV||inMinusOut.x()>0.1*GeV|| inMinusOut.y()>0.1*GeV||inMinusOut.z()>0.1*GeV) cout << "MEPP2VVPowheg::generateHardest\n" << "Momentum imbalance in V1 V2 rest frame\n" << "P_in minus P_out = " << inMinusOut/GeV << endl; // From the radiative kinematics we now have to form ShowerParticle objects: PPtr p1,p2,k; PPtr k1 = V1_->dataPtr()->produceParticle(theRealMomenta[2]); PPtr k2 = V2_->dataPtr()->produceParticle(theRealMomenta[3]); // q+qbar -> V1+V2+g if(channel_==0) { p1 = showerQuark_ ->dataPtr()->produceParticle(theRealMomenta[0]); p2 = showerAntiquark_->dataPtr()->produceParticle(theRealMomenta[1]); k = gluon_ ->dataPtr()->produceParticle(theRealMomenta[4]); k->incomingColour(p1); k->incomingColour(p2,true); } // q+g -> V1+V2+q else if(channel_==1) { p1 = showerQuark_ ->dataPtr() ->produceParticle(theRealMomenta[0]); p2 = gluon_ ->dataPtr() ->produceParticle(theRealMomenta[1]); k = showerAntiquark_->dataPtr()->CC()->produceParticle(theRealMomenta[4]); k->incomingColour(p2); p2->colourConnect(p1); } // g+qbar -> V1+V2+qbar else { p1 = gluon_ ->dataPtr() ->produceParticle(theRealMomenta[0]); p2 = showerAntiquark_->dataPtr() ->produceParticle(theRealMomenta[1]); k = showerQuark_ ->dataPtr()->CC()->produceParticle(theRealMomenta[4]); k->incomingColour(p1,true); p1->colourConnect(p2,true); } Lorentz5Momentum pmother,pspect; if(fermionNumberOfMother_==1) { pmother = theRealMomenta[0]-theRealMomenta[4]; pspect = theRealMomenta[1]; } else { pmother = theRealMomenta[1]-theRealMomenta[4]; pspect = theRealMomenta[0]; } unsigned int iemit = fermionNumberOfMother_==1 ? 0 : 1; unsigned int ispect = fermionNumberOfMother_==1 ? 1 : 0; // fill the output if(showerQuark_ !=born->bornIncoming()[0]) { born->incoming().push_back(p2); born->incoming().push_back(p1); swap(iemit,ispect); } else { born->incoming().push_back(p1); born->incoming().push_back(p2); } born->emitter (iemit); born->spectator(ispect); pair xnew; for(unsigned int ix=0;ixincoming().size();++ix) { double x = born->incoming()[ix]->momentum().rho()/born->hadrons()[ix]->momentum().rho(); if(ix==0) xnew.first = x; else if (ix==1) xnew.second = x; } born->x(xnew); born->interaction(ShowerInteraction::QCD); // if gauge bosons not decayed, we're done if(born->bornOutgoing().size()==2) { born->emitted(4); if(!order) { born->outgoing().push_back(k1); born->outgoing().push_back(k2); } else { born->outgoing().push_back(k2); born->outgoing().push_back(k1); } born->outgoing().push_back(k); return born; } // Recalculate the hard vertex for this event: // For spin correlations, if an emission occurs go calculate the relevant // combination of amplitudes for the ProductionMatrixElement. if(realMESpinCorrelations_) { // Here we reset the realVVKinematics n+1 momenta to be those // of the lab frame in order to calculate the spin correlations. // Note that these momenta are not used for anything else after // this. R_.p1r(theRealMomenta[0]); R_.p2r(theRealMomenta[1]); R_.k1r(theRealMomenta[2]); R_.k2r(theRealMomenta[3]); R_.kr (theRealMomenta[4]); if(channel_==0) t_u_M_R_qqb_hel_amp(R_,true); else if(channel_==1) t_u_M_R_qg_hel_amp (R_,true); else if(channel_==2) t_u_M_R_gqb_hel_amp(R_,true); recalculateVertex(); } born->emitted(6); for(unsigned int ix=0;ixoutgoing().push_back(children_[cmap[ix]]); born->outgoing().push_back(k); // return the result return born; } double MEPP2VVPowheg::getResult(int channel, realVVKinematics R, Energy pT) { // This routine should return the integrand of the exact Sudakov form factor, // defined precisely as // KH 19th August - next 2 lines changed for phi in 0->pi not 0->2pi // \Delta(pT) = exp[ - \int_{pT}^{pTmax} dpT dYk d\phi/pi * getResult(...) ] // (Where phi is in 0->pi NOT 0->2*pi !) // Get pi for the prefactor: using Constants::pi; // Get the VV invariant mass^2: Energy2 p2 = B_.sb(); // Get the momentum fractions for the n+1 body event: double x1 = R.x1r(); double x2 = R.x2r(); // Reject the event if the x1 and x2 values are outside the phase space: if(x1<0.||x1>1.||x2<0.||x2>1.||x1*x2maximumCMEnergy())) return 0.; // Get the momentum fractions for the n body event: double x1b = B_.x1b(); double x2b = B_.x2b(); // Get the mandelstam variables needed to calculate the n+1 body matrix element: Energy2 s = R.sr() ; Energy2 t_u_MR_o_MB; double lo_lumi, nlo_lumi; // The luminosity function for the leading order n-body process: lo_lumi = qHadron_ ->pdf()->xfx(qHadron_ ,showerQuark_ ->dataPtr(),PDFScale_,x1b)* qbHadron_->pdf()->xfx(qbHadron_,showerAntiquark_->dataPtr(),PDFScale_,x2b); // Now we calculate the luminosity functions (product of the two pdfs) for the // real emission process(es) and also their matrix elements: // q + qbar -> V + V + g if(channel==0) { nlo_lumi = qHadron_ ->pdf()->xfx(qHadron_ ,showerQuark_ ->dataPtr() ,PDFScale_,x1) * qbHadron_->pdf()->xfx(qbHadron_,showerAntiquark_->dataPtr() ,PDFScale_,x2); t_u_MR_o_MB = t_u_M_R_qqb_hel_amp(R,false)/lo_me_; } // q + g -> V + V + q else if(channel==1) { nlo_lumi = qHadron_ ->pdf()->xfx(qHadron_ ,showerQuark_->dataPtr() ,PDFScale_,x1) * qbHadron_->pdf()->xfx(qbHadron_,getParticleData(ParticleID::g),PDFScale_,x2); t_u_MR_o_MB = t_u_M_R_qg_hel_amp(R,false)/lo_me_; } // g + qbar -> V + V + qbar else { nlo_lumi = qHadron_ ->pdf()->xfx(qHadron_ ,getParticleData(ParticleID::g),PDFScale_,x1) * qbHadron_->pdf()->xfx(qbHadron_,showerAntiquark_->dataPtr() ,PDFScale_,x2); t_u_MR_o_MB = t_u_M_R_gqb_hel_amp(R,false)/lo_me_; } // Multiply ratio of the real emission matrix elements to the Born matrix element // by the ratio of the pdfs for the real emission and born processes to get theWeight if(lo_lumi<=0.||nlo_lumi<=0.) return 0.; else return t_u_MR_o_MB * ( nlo_lumi/lo_lumi * p2/s ) * sqr(p2/s)/8./pi/pi / pT / p2 * GeV; } bool MEPP2VVPowheg::getEvent(vector & theRealMomenta, unsigned int & channel) { // Invariant mass of the colliding hadrons: Energy2 S = sqr(generator()->maximumCMEnergy()); // Born variables which are preserved (mass and rapidity of the diboson system): Energy2 p2 = B_.sb(); double Yb = B_.Yb(); // Born variables which are not preserved but are needed (the momentum fractions): double x1b(B_.x1b()), x2b(B_.x2b()); double x12b(x1b*x1b), x22b(x2b*x2b); // Maximum jet pT (half of the hadronic C.O.M. energy. N.B. this is overestimated a lot): Energy starting_pT = sqrt(S)/2.; // Initialize the pT_ *integration limit* i.e. the pT of the generated emission: pT_ = ZERO; // The pT *integration variable*: Energy pT; // The x_1 & x_2 momentum fractions corresponding to incoming momenta p1 & p2: double x1_(-999.), x2_(-999.); double x1 (-999.), x2 (-999.); // The jet rapidity *integration variable* and its limits: double Yk, minYk(-8.0), maxYk(8.0); // The theta2 integration variable (the azimuthal angle of the gluon w.r.t // V1 in the V1 & V2 rest frame: double theta2; // The realVVKinematics object corresponding to the current integration // set of integration variables: realVVKinematics R; // The veto algorithm rejection weight and a corresponding flag: double rejectionWeight; bool rejectEmission ; // Initialize the flag indicating the selected radiation channel: channel=999; // Some product of constants used for the crude distribution: double a(0.); for(int j=0;j<3;j++) { pT=starting_pT; a =(maxYk-minYk)*prefactor_[j]/2./b0_; do { // Generate next pT according to exp[- \int^{pTold}_{pT} dpT a*(power-1)/(pT^power)] // pT = GeV/pow( pow(GeV/pT,power_-1.) - log(UseRandom::rnd())/a // , 1./(power_-1.) ); // Generate next pT according to exp[- \int^{pTold}_{pT} dpT alpha1loop*prefactor/pT ] pT = LambdaQCD_*exp( 0.5*exp( log(log(sqr(pT/LambdaQCD_)))+log(UseRandom::rnd())/a ) ); // Generate rapidity of the jet: Yk = minYk + UseRandom::rnd()*(maxYk - minYk); // Generate the theta2 radiative variable: // KH 19th August - next line changed for phi in 0->pi not 0->2pi // theta2 = UseRandom::rnd() * 2.*Constants::pi; theta2 = UseRandom::rnd() * Constants::pi; // eT of the diboson system: Energy eT = sqrt(pT*pT+p2); // Calculate the eT and then solve for x_{\oplus} & x_{\ominus}: x1 = (pT*exp( Yk)+eT*exp( Yb))/sqrt(S); x2 = (pT*exp(-Yk)+eT*exp(-Yb))/sqrt(S); // Calculate the xr radiative variable: double xr(p2/(x1*x2*S)); // Then use this to calculate the y radiative variable: double y(-((xr+1.)/(xr-1.))*(xr*sqr(x1/x1b)-1.)/(xr*sqr(x1/x1b)+1.)); // The y value above should equal the one commented out below this line: // double y( ((xr+1.)/(xr-1.))*(xr*sqr(x2/x2b)-1.)/(xr*sqr(x2/x2b)+1.)); // Now we get the lower limit on the x integration, xbar: double omy(1.-y), opy(1.+y); double xbar1 = 2.*opy*x12b/(sqrt(sqr(1.+x12b)*sqr(omy)+16.*y*x12b)+omy*(1.-x1b)*(1.+x1b)); double xbar2 = 2.*omy*x22b/(sqrt(sqr(1.+x22b)*sqr(opy)-16.*y*x22b)+opy*(1.-x2b)*(1.+x2b)); double xbar = max(xbar1,xbar2); // Now we can calculate xtilde: double xt = (xr-xbar)/(1.-xbar); // Finally we can make the realVVKinematics object: R = realVVKinematics(B_,xt,y,theta2); // The next thing we have to do is set the QCD, EW and PDF scales using R: setTheScales(pT); // ... and so calculate rejection weight: rejectionWeight = getResult(j,R,pT); // If generating according to exp[- \int^{pTold}_{pT} dpT a*(power-1)/(pT^power)] // rejectionWeight/= showerAlphaS_->overestimateValue()*prefactor_[j]*pow(GeV/pT,power_); // If generating according to exp[- \int^{pTold}_{pT} dpT alpha1loop*prefactor/pT ] rejectionWeight/= 1./b0_/log(sqr(pT/LambdaQCD_))*prefactor_[j]*GeV/pT; rejectEmission = UseRandom::rnd()>rejectionWeight; // The event is a no-emission event if pT goes past min_pT_ - basically set to // outside the histogram bounds (hopefully histogram objects just ignore it then). if(pT1.) { ostringstream stream; stream << "MEPP2VVPowheg::getEvent weight for channel " << j << " is greater than one: " << rejectionWeight << endl; generator()->logWarning( Exception(stream.str(), Exception::warning) ); } } while(rejectEmission); // set pT of emission etc if(pT>pT_) { channel = j; pT_ = pT; Yk_ = Yk; R_ = R ; x1_ = x1; x2_ = x2; } } // Was this an (overall) no emission event? if(pT_3) throw Exception() << "MEPP2VVPowheg::getEvent() channel = " << channel << " pT = " << pT/GeV << " pT_ = " << pT_/GeV << Exception::abortnow; // Work out the momenta in the lab frame, reserving the mass and rapidity // of the VV system: LorentzRotation yzRotation; yzRotation.setRotateX(-atan2(pT_/GeV,sqrt(p2)/GeV)); LorentzRotation boostFrompTisZero; boostFrompTisZero.setBoostY(-pT_/sqrt(p2+pT_*pT_)); LorentzRotation boostFromYisZero; boostFromYisZero.setBoostZ(tanh(Yb)); theRealMomenta.resize(5); theRealMomenta[0] = Lorentz5Momentum(ZERO,ZERO, x1_*sqrt(S)/2., x1_*sqrt(S)/2.,ZERO); theRealMomenta[1] = Lorentz5Momentum(ZERO,ZERO,-x2_*sqrt(S)/2., x2_*sqrt(S)/2.,ZERO); theRealMomenta[2] = boostFromYisZero*boostFrompTisZero*yzRotation*(R_.k1r()); theRealMomenta[3] = boostFromYisZero*boostFrompTisZero*yzRotation*(R_.k2r()); theRealMomenta[4] = Lorentz5Momentum(ZERO, pT_, pT_*sinh(Yk_), pT_*cosh(Yk_),ZERO); return true; } void MEPP2VVPowheg::setTheScales(Energy pT) { // Work out the scales we want to use in the matrix elements and the pdfs: // Scale for alpha_S: pT^2 of the diboson system. QCDScale_ = max(pT*pT,sqr(min_pT_)); // Scale for real emission PDF: // pT^2+mVV^2 - as mcfm does in the case of a single W/Z boson). // Energy2 PDFScale_ = max(R.pT2_in_lab(),sqr(min_pT_))+R.s2r(); // pT^2 - as advocated by Nason & Ridolfi for ZZ production & Alioli et al for gg->h: PDFScale_ = max(pT*pT,sqr(min_pT_)); // Scale of electroweak vertices: mVV^2 the invariant mass of the diboson system. // EWScale_ = B_.sb(); // ... And this choice is more like what can be seen in mcatnlo_vbmain.f (weird). EWScale_ = 0.5*(B_.k12b()+B_.k22b()); return; } /***************************************************************************/ // This is identical to the code in the Powheg matrix element. It should // equal t_u_M_R_qqb in there, which is supposed to be the real emission ME // times tk*uk. Energy2 MEPP2VVPowheg::t_u_M_R_qqb_hel_amp(realVVKinematics R, bool getMatrix) const { using namespace ThePEG::Helicity; ProductionMatrixElement qqb_hel_amps(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1 ,PDT::Spin1 , PDT::Spin1); double sum_hel_amps_sqr(0.); tcPDPtr p1data(showerQuark_->dataPtr()); tcPDPtr p2data(showerAntiquark_->dataPtr()); tcPDPtr k1data(V1_->dataPtr()); tcPDPtr k2data(V2_->dataPtr()); tcPDPtr kdata(getParticleData(ParticleID::g)); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorWaveFunction qSpinor(R.p1r(),p1data,incoming); SpinorBarWaveFunction qbSpinor(R.p2r(),p2data,incoming); vector q; vector qb; for(unsigned int ix=0;ix<2;ix++) { qSpinor.reset(ix); qbSpinor.reset(ix); q.push_back(qSpinor); qb.push_back(qbSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.kr(),kdata,outgoing); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(p2data); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorWaveFunction p1_k = ffg->evaluate(QCDScale_,5,p1data,q[p1hel],g[khel]); SpinorBarWaveFunction p2_k = ffg->evaluate(QCDScale_,5,p2data,qb[p2hel],g[khel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p1hel=p2hel // but if the production ME is required first fill it with (0.,0.). if((p1hel==p2hel)&&helicityConservation_) { if(getMatrix) { if(khel==0) qqb_hel_amps(p1hel,p2hel,k1hel,k2hel,0) = Complex(0.,0.); else qqb_hel_amps(p1hel,p2hel,k1hel,k2hel,2) = Complex(0.,0.); } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_t; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? p2data : tc[ix]; // Note: choosing 5 as the second argument ffvX_->evaluate() sets // option 5 in thepeg/Helicity/Vertex/VertexBase.cc, which makes // the (fermion) propagator denominator massless: 1/p^2. // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams SpinorWaveFunction p1_v1 = ffv1->evaluate(EWScale_,5,intermediate_t,q[p1hel],v1[k1hel]); - SpinorBarWaveFunction p2_v2 = ffv2->evaluate(EWScale_,5,intermediate_t,qb[p2hel],v2[k2hel]); + SpinorBarWaveFunction p2_v2 = ffv2->evaluate(EWScale_,5,intermediate_t->CC(),qb[p2hel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 t-channel diagrams // q+qb->g+v1+v2, q+qb->v1+g+v2, q+qb->v1+v2+g if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) { diagrams.push_back(ffv1->evaluate(EWScale_,p1_k,p2_v2,v1[k1hel])); diagrams.push_back(ffg->evaluate(QCDScale_,p1_v1,p2_v2,g[khel])); diagrams.push_back(ffv2->evaluate(EWScale_,p1_v1,p2_k,v2[k2hel])); } intermediate_t = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(EWScale_,5,intermediate_t,q[p1hel],v2[k2hel]); - SpinorBarWaveFunction p2_v1 = ffv1->evaluate(EWScale_,5,intermediate_t,qb[p2hel],v1[k1hel]); + SpinorBarWaveFunction p2_v1 = ffv1->evaluate(EWScale_,5,intermediate_t->CC(),qb[p2hel],v1[k1hel]); // q+qb->g+v2+v1, q+qb->v2+g+v1, q+qb->v2+v1+g if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) { diagrams.push_back(ffv2->evaluate(EWScale_,p1_k,p2_v1,v2[k2hel])); diagrams.push_back(ffg->evaluate(QCDScale_,p1_v2,p2_v1,g[khel])); diagrams.push_back(ffv1->evaluate(EWScale_,p1_v2,p2_k,v1[k1hel])); } } // Note: choosing 3 as the second argument in WWWvertex_->evaluate() // sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which // means the propagator does not contain a width factor (which is // good re. gauge invariance). // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(EWScale_,3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(EWScale_,p1_k,qb[p2hel],k1_k2)); diagrams.push_back(ffv1->evaluate(EWScale_,q[p1hel],p2_k,k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==-p2data->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(EWScale_,3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(EWScale_,p1_k,qb[p2hel],k1_k2)); diagrams.push_back(FFZvertex_->evaluate(EWScale_,q[p1hel],p2_k,k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(EWScale_,3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(EWScale_,p1_k,qb[p2hel],k1_k2)); diagrams.push_back(FFPvertex_->evaluate(EWScale_,q[p1hel],p2_k,k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } /***************************************************************************/ // This is identical to the code in the Powheg matrix element. It should // equal t_u_M_R_qg in there, which is supposed to be the real emission ME // times tk*uk. Energy2 MEPP2VVPowheg::t_u_M_R_qg_hel_amp(realVVKinematics R, bool getMatrix) const { using namespace ThePEG::Helicity; ProductionMatrixElement qg_hel_amps(PDT::Spin1Half,PDT::Spin1, PDT::Spin1,PDT::Spin1, PDT::Spin1Half); double sum_hel_amps_sqr(0.); tcPDPtr p1data(showerQuark_->dataPtr()); tcPDPtr p2data(getParticleData(ParticleID::g)); tcPDPtr k1data(V1_->dataPtr()); tcPDPtr k2data(V2_->dataPtr()); tcPDPtr kdata (showerAntiquark_->dataPtr()->CC()); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorWaveFunction qinSpinor(R.p1r(),p1data,incoming); SpinorBarWaveFunction qoutSpinor(R.kr(),kdata,outgoing); vector qin; vector qout; for(unsigned int ix=0;ix<2;ix++) { qinSpinor.reset(ix); qoutSpinor.reset(ix); qin.push_back(qinSpinor); qout.push_back(qoutSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.p2r(),p2data,incoming); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(kdata->CC()); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorWaveFunction p1_p2 = ffg->evaluate(QCDScale_,5,p1data,qin[p1hel],g[p2hel]); SpinorBarWaveFunction p2_k = ffg->evaluate(QCDScale_,5,kdata->CC(),qout[khel],g[p2hel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p1hel!=khel // but if the production ME is required first fill it with (0.,0.). if((p1hel!=khel)&&helicityConservation_) { if(getMatrix) { if(p2hel==0) qg_hel_amps(p1hel,0,k1hel,k2hel,khel) = Complex(0.,0.); else qg_hel_amps(p1hel,2,k1hel,k2hel,khel) = Complex(0.,0.); } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_q; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? showerAntiquark_->dataPtr() : tc[ix]; SpinorWaveFunction p1_v1 = ffv1->evaluate(EWScale_,5,intermediate_q,qin[p1hel],v1[k1hel]); - SpinorBarWaveFunction k_v2 = ffv2->evaluate(EWScale_,5,intermediate_q,qout[khel],v2[k2hel]); + SpinorBarWaveFunction k_v2 = ffv2->evaluate(EWScale_,5,intermediate_q->CC(),qout[khel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 abelian diagrams // q+g->v1+v2+q with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) { diagrams.push_back(ffv2->evaluate(EWScale_,p1_v1,p2_k,v2[k2hel])); diagrams.push_back(ffg->evaluate(QCDScale_,p1_v1,k_v2,g[p2hel])); diagrams.push_back(ffv1->evaluate(EWScale_,p1_p2,k_v2,v1[k1hel])); } intermediate_q = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(EWScale_,5,intermediate_q,qin[p1hel],v2[k2hel]); - SpinorBarWaveFunction k_v1 = ffv1->evaluate(EWScale_,5,intermediate_q,qout[khel],v1[k1hel]); + SpinorBarWaveFunction k_v1 = ffv1->evaluate(EWScale_,5,intermediate_q->CC(),qout[khel],v1[k1hel]); // q+g->v2+v1+q, with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) { diagrams.push_back(ffv1->evaluate(EWScale_,p1_v2,p2_k,v1[k1hel])); diagrams.push_back(ffg->evaluate(QCDScale_,p1_v2,k_v1,g[p2hel])); diagrams.push_back(ffv2->evaluate(EWScale_,p1_p2,k_v1,v2[k2hel])); } } // Note: choosing 3 as the second argument in WWWvertex_->evaluate() // sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which // means the propagator does not contain a width factor (which is // good re. gauge invariance). // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(EWScale_,3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(EWScale_,p1_p2,qout[khel],k1_k2)); diagrams.push_back(ffv1->evaluate(EWScale_,qin[p1hel],p2_k,k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==kdata->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(EWScale_,3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(EWScale_,p1_p2,qout[khel],k1_k2)); diagrams.push_back(FFZvertex_->evaluate(EWScale_,qin[p1hel],p2_k,k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(EWScale_,3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(EWScale_,p1_p2,qout[khel],k1_k2)); diagrams.push_back(FFPvertex_->evaluate(EWScale_,qin[p1hel],p2_k,k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } /***************************************************************************/ // This is identical to the code in the Powheg matrix element. It should // equal t_u_M_R_gqb in there, which is supposed to be the real emission ME // times tk*uk. Energy2 MEPP2VVPowheg::t_u_M_R_gqb_hel_amp(realVVKinematics R, bool getMatrix) const { using namespace ThePEG::Helicity; ProductionMatrixElement gqb_hel_amps(PDT::Spin1,PDT::Spin1Half, PDT::Spin1,PDT::Spin1, PDT::Spin1Half); double sum_hel_amps_sqr(0.); tcPDPtr p1data(getParticleData(ParticleID::g)); tcPDPtr p2data(showerAntiquark_->dataPtr()); tcPDPtr k1data(V1_->dataPtr()); tcPDPtr k2data(V2_->dataPtr()); tcPDPtr kdata (showerQuark_->dataPtr()->CC()); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorBarWaveFunction qbinSpinor(R.p2r(),p2data,incoming); SpinorWaveFunction qboutSpinor(R.kr(),kdata,outgoing); vector qbin; vector qbout; for(unsigned int ix=0;ix<2;ix++) { qbinSpinor.reset(ix); qboutSpinor.reset(ix); qbin.push_back(qbinSpinor); qbout.push_back(qboutSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.p1r(),p1data,incoming); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p2data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p2data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(kdata->CC()); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorBarWaveFunction p1_p2 = ffg->evaluate(QCDScale_,5,p2data,qbin[p2hel],g[p1hel]); SpinorWaveFunction p1_k = ffg->evaluate(QCDScale_,5,kdata->CC(),qbout[khel],g[p1hel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p2hel!=khel // but if the production ME is required first fill it with (0.,0.). if((p2hel!=khel)&&helicityConservation_) { if(getMatrix) { if(p1hel==0) gqb_hel_amps(0,p2hel,k1hel,k2hel,khel) = Complex(0.,0.); else gqb_hel_amps(2,p2hel,k1hel,k2hel,khel) = Complex(0.,0.); } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_q; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? showerQuark_->dataPtr() : tc[ix]; - SpinorBarWaveFunction p2_v1 = ffv1->evaluate(EWScale_,5,intermediate_q,qbin[p2hel],v1[k1hel]); + SpinorBarWaveFunction p2_v1 = ffv1->evaluate(EWScale_,5,intermediate_q->CC(),qbin[p2hel],v1[k1hel]); SpinorWaveFunction k_v2 = ffv2->evaluate(EWScale_,5,intermediate_q,qbout[khel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 abelian diagrams q+g->v1+v2+q // with 2 t-channel propagators, 1 s- and 1 t-channel // and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p2data->id())%2==0))) { diagrams.push_back(ffv2->evaluate(EWScale_,p1_k,p2_v1,v2[k2hel])); diagrams.push_back(ffg->evaluate(QCDScale_,k_v2,p2_v1,g[p1hel])); diagrams.push_back(ffv1->evaluate(EWScale_,k_v2,p1_p2,v1[k1hel])); } intermediate_q = (!(k1data->id()==24&&k2data->id()==-24)) ? p2data : tc[ix]; - SpinorBarWaveFunction p2_v2 = ffv2->evaluate(EWScale_,5,intermediate_q,qbin[p2hel],v2[k2hel]); + SpinorBarWaveFunction p2_v2 = ffv2->evaluate(EWScale_,5,intermediate_q->CC(),qbin[p2hel],v2[k2hel]); SpinorWaveFunction k_v1 = ffv1->evaluate(EWScale_,5,intermediate_q,qbout[khel],v1[k1hel]); // q+g->v2+v1+q, with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p2data->id())%2==1))) { diagrams.push_back(ffv1->evaluate(EWScale_,p1_k,p2_v2,v1[k1hel])); diagrams.push_back(ffg->evaluate(QCDScale_,k_v1,p2_v2,g[p1hel])); diagrams.push_back(ffv2->evaluate(EWScale_,k_v1,p1_p2,v2[k2hel])); } } // Note: choosing 3 as the second argument in WWWvertex_->evaluate() // sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which // means the propagator does not contain a width factor (which is // good re. gauge invariance). // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(EWScale_,3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(EWScale_,qbout[khel],p1_p2,k1_k2)); diagrams.push_back(ffv1->evaluate(EWScale_,p1_k,qbin[p2hel],k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p2data->id()==kdata->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(EWScale_,3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(EWScale_,qbout[khel],p1_p2,k1_k2)); diagrams.push_back(FFZvertex_->evaluate(EWScale_,p1_k,qbin[p2hel],k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(EWScale_,3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(EWScale_,qbout[khel],p1_p2,k1_k2)); diagrams.push_back(FFPvertex_->evaluate(EWScale_,p1_k,qbin[p2hel],k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } /***************************************************************************/ // This returns exactly the same value as lo_me2_ when you put it in MEPP2VVPowheg.cc double MEPP2VVPowheg::lo_me(bool getMatrix) const { using namespace ThePEG::Helicity; ProductionMatrixElement lo_hel_amps(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1 ,PDT::Spin1); double sum_hel_amps_sqr(0.); tcPDPtr p1data(showerQuark_->dataPtr()); tcPDPtr p2data(showerAntiquark_->dataPtr()); tcPDPtr k1data(V1_->dataPtr()); tcPDPtr k2data(V2_->dataPtr()); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); // Should never actually occur. // If you want to reproduce the spin correlations of MEPP2VV // you should evaluate this ME using the lab frame momenta // instead of the bornVVKinematics ones (partonic C.O.M. frame). SpinorWaveFunction qSpinor; SpinorBarWaveFunction qbSpinor; if(!getMatrix) { qSpinor=SpinorWaveFunction(B_.p1b(),p1data,incoming); qbSpinor=SpinorBarWaveFunction(B_.p2b(),p2data,incoming); } else { qSpinor=SpinorWaveFunction(showerQuark_->momentum(),p1data,incoming); qbSpinor=SpinorBarWaveFunction(showerAntiquark_->momentum(),p2data,incoming); } vector q; vector qb; for(unsigned int ix=0;ix<2;ix++) { qSpinor.reset(ix); qbSpinor.reset(ix); q.push_back(qSpinor); qb.push_back(qbSpinor); } // If you want to reproduce the spin correlations of MEPP2VV // you should evaluate this ME using the lab frame momenta // instead of the bornVVKinematics ones (partonic C.O.M. frame). VectorWaveFunction v1Polarization; VectorWaveFunction v2Polarization; if(!getMatrix) { v1Polarization=VectorWaveFunction(B_.k1b(),k1data,outgoing); v2Polarization=VectorWaveFunction(B_.k2b(),k2data,outgoing); } else { v1Polarization=VectorWaveFunction(V1_->momentum(),k1data,outgoing); v2Polarization=VectorWaveFunction(V2_->momentum(),k2data,outgoing); } vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(p2data); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { if((p1hel==p2hel)&&helicityConservation_) { lo_hel_amps(p1hel,p2hel,k1hel,k2hel) = Complex(0.,0.); continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_t; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? p2data : tc[ix]; SpinorWaveFunction p1_v1 = ffv1->evaluate(EWScale_,5,intermediate_t,q[p1hel],v1[k1hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 t-channel diagrams // q+qb->v1+v2 if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) diagrams.push_back(ffv2->evaluate(EWScale_,p1_v1,qb[p2hel],v2[k2hel])); intermediate_t = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(EWScale_,5,intermediate_t,q[p1hel],v2[k2hel]); // q+qb->v2+v1 if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) diagrams.push_back(ffv1->evaluate(EWScale_,p1_v2,qb[p2hel],v1[k1hel])); } // Note: choosing 3 as the second argument in WWWvertex_->evaluate() // sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which // means the propagator does not contain a width factor (which is // good re. gauge invariance). // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(EWScale_,3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->v1*->v1+v2 diagrams.push_back(ffv1->evaluate(EWScale_,q[p1hel],qb[p2hel],k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==-p2data->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->Z0*->v1+v2 tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(EWScale_,3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(EWScale_,q[p1hel],qb[p2hel],k1_k2)); // q+qb->gamma*->v1+v2 tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(EWScale_,3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(EWScale_,q[p1hel],qb[p2hel],k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr; } /***************************************************************************/ // This member selects a [2-body] decay mode and assigns children to the // vector bosons with momenta which are isotropic in their rest frames. bool MEPP2VVPowheg::isotropicDecayer() { using namespace ThePEG::Helicity; // Generate the children's momenta isotropically in // the rest frames of V1 and V2: double cth,phi; // First V1's children: cth = UseRandom::rnd()*2.-1.; phi = UseRandom::rnd()*2.*Constants::pi; Energy m1(V1_->momentum().m()); Energy m3(children_[0]->data().constituentMass()); Energy m4(children_[1]->data().constituentMass()); Energy p34(triangleFn(sqr(m1),sqr(m3),sqr(m4)) /2./m1); if(std::isnan(double(p34/MeV))||cth>1.||cth<-1.) return false; Energy pT34(p34*sqrt(1.-cth)*sqrt(1.+cth)); Lorentz5Momentum k3(pT34*sin(phi),pT34*cos(phi),p34 *cth, sqrt(p34*p34+sqr(m3)),m3); Lorentz5Momentum k4(-k3); k4.setE(sqrt(p34*p34+sqr(m4))); k4.setTau(m4); Boost boostToV1RF(R_.k1r().boostVector()); k3.boost(boostToV1RF); k3.rescaleRho(); k4.boost(boostToV1RF); k4.rescaleRho(); // Second V2's children: cth = UseRandom::rnd()*2.-1.; phi = UseRandom::rnd()*2.*Constants::pi; Energy m2(V2_->momentum().m()); Energy m5(children_[2]->data().constituentMass()); Energy m6(children_[3]->data().constituentMass()); Energy p56(triangleFn(sqr(m2),sqr(m5),sqr(m6)) /2./m2); if(std::isnan(double(p56/MeV))||cth>1.||cth<-1.) return false; Energy pT56(p56*sqrt(1.-cth)*sqrt(1.+cth)); Lorentz5Momentum k5(pT56*sin(phi),pT56*cos(phi),p56*cth, sqrt(p56*p56+sqr(m5)),m5); Lorentz5Momentum k6(-k5); k6.setE(sqrt(p56*p56+sqr(m6))); k6.setTau(m6); Boost boostToV2RF(R_.k2r().boostVector()); k5.boost(boostToV2RF); k5.rescaleRho(); k6.boost(boostToV2RF); k6.rescaleRho(); // Assign the momenta to the children: children_[0]->set5Momentum(k3); children_[1]->set5Momentum(k4); children_[2]->set5Momentum(k5); children_[3]->set5Momentum(k6); return true; } // Override 2->2 production matrix here: void MEPP2VVPowheg::recalculateVertex() { // Zero the squared amplitude; this equals sum_hel_amps_sqr if all // is working as it should: Complex productionMatrix2(0.,0.); for(unsigned int k1hel=0;k1hel<3;++k1hel) for(unsigned int k2hel=0;k2hel<3;++k2hel) productionMatrix2 += productionMatrix_[k1hel][k1hel][k2hel][k2hel]; // Get the vector wavefunctions: VectorWaveFunction v1Polarization; VectorWaveFunction v2Polarization; v1Polarization=VectorWaveFunction(R_.k1r(),V1_->dataPtr(),outgoing); v2Polarization=VectorWaveFunction(R_.k2r(),V2_->dataPtr(),outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } AbstractFFVVertexPtr ffv1 = V1_->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = V2_->id()==23 ? FFZvertex_ : FFWvertex_; bool vetoed(true); while(vetoed) { // Decay the bosons isotropically in their rest frames: isotropicDecayer(); // Get the spinor wavefunctions: SpinorWaveFunction k3Spinor(children_[0]->momentum(),children_[0]->dataPtr(),outgoing); SpinorBarWaveFunction k4Spinor(children_[1]->momentum(),children_[1]->dataPtr(),outgoing); SpinorWaveFunction k5Spinor(children_[2]->momentum(),children_[2]->dataPtr(),outgoing); SpinorBarWaveFunction k6Spinor(children_[3]->momentum(),children_[3]->dataPtr(),outgoing); vector k3,k5; vector k4,k6; for(unsigned int ix=0;ix<2;ix++) { k3Spinor.reset(ix); k4Spinor.reset(ix); k3.push_back(k3Spinor); k4.push_back(k4Spinor); k5Spinor.reset(ix); k6Spinor.reset(ix); k5.push_back(k5Spinor); k6.push_back(k6Spinor); } DecayMEPtr decayAmps(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1Half,PDT::Spin1Half))); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k3hel=0;k3hel<2;++k3hel) { for(unsigned int k4hel=0;k4hel<2;++k4hel) { (*decayAmps)(k1hel,k3hel,k4hel) = ffv1->evaluate(EWScale_,k3[k3hel],k4[k4hel],v1[k1hel]); } } } Complex V1decayMatrix[3][3]; for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k1helpr=0;k1helpr<3;++k1helpr) { Complex theElement(0.,0.); for(unsigned int k3hel=0;k3hel<2;++k3hel) { for(unsigned int k4hel=0;k4hel<2;++k4hel) { theElement += (*decayAmps)(k1hel,k3hel,k4hel) *conj((*decayAmps)(k1helpr,k3hel,k4hel)); } } V1decayMatrix[k1hel][k1helpr] = theElement; } } Complex V1decayMatrix2(0.,0.); for(unsigned int k1hel=0;k1hel<3;++k1hel) V1decayMatrix2 += V1decayMatrix[k1hel][k1hel]; for(unsigned int k2hel=0;k2hel<3;++k2hel) { for(unsigned int k5hel=0;k5hel<2;++k5hel) { for(unsigned int k6hel=0;k6hel<2;++k6hel) { (*decayAmps)(k2hel,k5hel,k6hel) = ffv2->evaluate(EWScale_,k5[k5hel],k6[k6hel],v2[k2hel]); } } } Complex V2decayMatrix[3][3]; for(unsigned int k2hel=0;k2hel<3;++k2hel) { for(unsigned int k2helpr=0;k2helpr<3;++k2helpr) { Complex theElement(0.,0.); for(unsigned int k5hel=0;k5hel<2;++k5hel) { for(unsigned int k6hel=0;k6hel<2;++k6hel) { theElement += (*decayAmps)(k2hel,k5hel,k6hel) *conj((*decayAmps)(k2helpr,k5hel,k6hel)); } } V2decayMatrix[k2hel][k2helpr] = theElement; } } Complex V2decayMatrix2(0.,0.); for(unsigned int k2hel=0;k2hel<3;++k2hel) V2decayMatrix2 += V2decayMatrix[k2hel][k2hel]; // Contract the production matrix and the decay matrices: Complex meTimesV1V2denominators(0.,0.); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k1helpr=0;k1helpr<3;++k1helpr) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { for(unsigned int k2helpr=0;k2helpr<3;++k2helpr) { meTimesV1V2denominators += productionMatrix_[k1hel][k1helpr][k2hel][k2helpr] *V1decayMatrix[k1hel][k1helpr] *V2decayMatrix[k2hel][k2helpr]; } } } } if(imag(meTimesV1V2denominators)/real(meTimesV1V2denominators)>1.e-7) cout << "MEPP2VVPowheg warning\n" << "the matrix element's imaginary part is large " << meTimesV1V2denominators << endl; if(imag(productionMatrix2)/real(productionMatrix2)>1.e-7) cout << "MEPP2VVPowheg warning\n" << "the production matrix element's imaginary part is large " << productionMatrix2 << endl; if(imag(V1decayMatrix2)/real(V1decayMatrix2)>1.e-7) cout << "MEPP2VVPowheg warning\n" << "the V1 decay matrix element's imaginary part is large " << V1decayMatrix2 << endl; if(imag(V2decayMatrix2)/real(V2decayMatrix2)>1.e-7) cout << "MEPP2VVPowheg warning\n" << "the V2 decay matrix element's imaginary part is large " << V2decayMatrix2 << endl; // Need branching ratio at least in here I would think ---> double decayWeight( real(meTimesV1V2denominators) / real(productionMatrix2*V1decayMatrix2*V2decayMatrix2)); if(decayWeight>1.) cout << "MEPP2VVPowheg::recalculateVertex decayWeight > 1., decayWeight = " << decayWeight << endl; if(decayWeight<0.) cout << "MEPP2VVPowheg::recalculateVertex decayWeight < 0., decayWeight = " << decayWeight << endl; if(UseRandom::rnd()=ZERO) { return sqrt(lambda2); } else { generator()->log() << "MEPP2VVPowheg::triangleFn " << "kinematic instability, imaginary triangle function\n"; return -999999.*GeV2; } } diff --git a/Shower/QTilde/QTildeShowerHandler.cc b/Shower/QTilde/QTildeShowerHandler.cc --- a/Shower/QTilde/QTildeShowerHandler.cc +++ b/Shower/QTilde/QTildeShowerHandler.cc @@ -1,3220 +1,3205 @@ // -*- C++ -*- // // QTildeShowerHandler.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 QTildeShowerHandler class. // #include "QTildeShowerHandler.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/RefVector.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/EventRecord/Particle.h" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Utilities/EnumIO.h" #include "Herwig/Shower/QTilde/Base/ShowerParticle.h" #include "Herwig/PDF/MPIPDF.h" #include "Herwig/PDF/MinBiasPDF.h" #include "Herwig/Shower/QTilde/Base/ShowerTree.h" #include "Herwig/Shower/QTilde/Base/HardTree.h" #include "Herwig/Shower/QTilde/Kinematics/KinematicsReconstructor.h" #include "Herwig/Shower/QTilde/Base/PartnerFinder.h" #include "Herwig/PDF/HwRemDecayer.h" #include "Herwig/Shower/QTilde/Base/ShowerVertex.h" #include "ThePEG/Repository/CurrentGenerator.h" #include "Herwig/MatrixElement/Matchbox/Base/SubtractedME.h" #include "Herwig/MatrixElement/Matchbox/MatchboxFactory.h" #include "ThePEG/PDF/PartonExtractor.h" #include "Herwig/Shower/RealEmissionProcess.h" #include "Herwig/Shower/QTilde/Kinematics/FS_QTildeShowerKinematics1to2.h" #include "Herwig/Shower/QTilde/Kinematics/IS_QTildeShowerKinematics1to2.h" #include "Herwig/Shower/QTilde/Kinematics/Decay_QTildeShowerKinematics1to2.h" using namespace Herwig; bool QTildeShowerHandler::_hardEmissionWarn = true; bool QTildeShowerHandler::_missingTruncWarn = true; QTildeShowerHandler::QTildeShowerHandler() : _maxtry(100), _meCorrMode(1), _reconOpt(0), _hardVetoReadOption(false), _iptrms(ZERO), _beta(0.), _gamma(ZERO), _iptmax(), _limitEmissions(0), _initialenhance(1.), _finalenhance(1.), _nReWeight(100), _reWeight(false), interaction_(ShowerInteraction::Both), _trunc_Mode(true), _hardEmission(1), - _spinOpt(1), _softOpt(2), _hardPOWHEG(false), muPt(ZERO) + _softOpt(2), _hardPOWHEG(false), muPt(ZERO) {} QTildeShowerHandler::~QTildeShowerHandler() {} IBPtr QTildeShowerHandler::clone() const { return new_ptr(*this); } IBPtr QTildeShowerHandler::fullclone() const { return new_ptr(*this); } void QTildeShowerHandler::persistentOutput(PersistentOStream & os) const { os << _splittingGenerator << _maxtry << _meCorrMode << _hardVetoReadOption - << _limitEmissions << _spinOpt << _softOpt << _hardPOWHEG + << _limitEmissions << _softOpt << _hardPOWHEG << ounit(_iptrms,GeV) << _beta << ounit(_gamma,GeV) << ounit(_iptmax,GeV) << _vetoes << _fullShowerVetoes << _nReWeight << _reWeight << _trunc_Mode << _hardEmission << _reconOpt << ounit(muPt,GeV) << oenum(interaction_) << _reconstructor << _partnerfinder; } void QTildeShowerHandler::persistentInput(PersistentIStream & is, int) { is >> _splittingGenerator >> _maxtry >> _meCorrMode >> _hardVetoReadOption - >> _limitEmissions >> _spinOpt >> _softOpt >> _hardPOWHEG + >> _limitEmissions >> _softOpt >> _hardPOWHEG >> iunit(_iptrms,GeV) >> _beta >> iunit(_gamma,GeV) >> iunit(_iptmax,GeV) >> _vetoes >> _fullShowerVetoes >> _nReWeight >> _reWeight >> _trunc_Mode >> _hardEmission >> _reconOpt >> iunit(muPt,GeV) >> ienum(interaction_) >> _reconstructor >> _partnerfinder; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigQTildeShowerHandler("Herwig::QTildeShowerHandler", "HwShower.so"); void QTildeShowerHandler::Init() { static ClassDocumentation documentation ("TheQTildeShowerHandler class is the main class" " for the angular-ordered parton shower", "The Shower evolution was performed using an algorithm described in " "\\cite{Marchesini:1983bm,Marchesini:1987cf,Gieseke:2003rz,Bahr:2008pv}.", "%\\cite{Marchesini:1983bm}\n" "\\bibitem{Marchesini:1983bm}\n" " G.~Marchesini and B.~R.~Webber,\n" " ``Simulation Of QCD Jets Including Soft Gluon Interference,''\n" " Nucl.\\ Phys.\\ B {\\bf 238}, 1 (1984).\n" " %%CITATION = NUPHA,B238,1;%%\n" "%\\cite{Marchesini:1987cf}\n" "\\bibitem{Marchesini:1987cf}\n" " G.~Marchesini and B.~R.~Webber,\n" " ``Monte Carlo Simulation of General Hard Processes with Coherent QCD\n" " Radiation,''\n" " Nucl.\\ Phys.\\ B {\\bf 310}, 461 (1988).\n" " %%CITATION = NUPHA,B310,461;%%\n" "%\\cite{Gieseke:2003rz}\n" "\\bibitem{Gieseke:2003rz}\n" " S.~Gieseke, P.~Stephens and B.~Webber,\n" " ``New formalism for QCD parton showers,''\n" " JHEP {\\bf 0312}, 045 (2003)\n" " [arXiv:hep-ph/0310083].\n" " %%CITATION = JHEPA,0312,045;%%\n" ); static Reference interfaceSplitGen("SplittingGenerator", "A reference to the SplittingGenerator object", &Herwig::QTildeShowerHandler::_splittingGenerator, false, false, true, false); static Parameter interfaceMaxTry ("MaxTry", "The maximum number of attempts to generate the shower from a" " particular ShowerTree", &QTildeShowerHandler::_maxtry, 100, 1, 100000, false, false, Interface::limited); static Parameter interfaceNReWeight ("NReWeight", "The number of attempts for the shower when reweighting", &QTildeShowerHandler::_nReWeight, 100, 10, 10000, false, false, Interface::limited); static Switch ifaceMECorrMode ("MECorrMode", "Choice of the ME Correction Mode", &QTildeShowerHandler::_meCorrMode, 1, false, false); static SwitchOption on (ifaceMECorrMode,"HardPlusSoft","hard+soft on", 1); static SwitchOption hard (ifaceMECorrMode,"Hard","only hard on", 2); static SwitchOption soft (ifaceMECorrMode,"Soft","only soft on", 3); static Switch ifaceHardVetoReadOption ("HardVetoReadOption", "Apply read-in scale veto to all collisions or just the primary one?", &QTildeShowerHandler::_hardVetoReadOption, false, false, false); static SwitchOption AllCollisions (ifaceHardVetoReadOption, "AllCollisions", "Read-in pT veto applied to primary and secondary collisions.", false); static SwitchOption PrimaryCollision (ifaceHardVetoReadOption, "PrimaryCollision", "Read-in pT veto applied to primary but not secondary collisions.", true); static Parameter ifaceiptrms ("IntrinsicPtGaussian", "RMS of intrinsic pT of Gaussian distribution:\n" "2*(1-Beta)*exp(-sqr(intrinsicpT/RMS))/sqr(RMS)", &QTildeShowerHandler::_iptrms, GeV, ZERO, ZERO, 1000000.0*GeV, false, false, Interface::limited); static Parameter ifacebeta ("IntrinsicPtBeta", "Proportion of inverse quadratic distribution in generating intrinsic pT.\n" "(1-Beta) is the proportion of Gaussian distribution", &QTildeShowerHandler::_beta, 0, 0, 1, false, false, Interface::limited); static Parameter ifacegamma ("IntrinsicPtGamma", "Parameter for inverse quadratic:\n" "2*Beta*Gamma/(sqr(Gamma)+sqr(intrinsicpT))", &QTildeShowerHandler::_gamma,GeV, ZERO, ZERO, 100000.0*GeV, false, false, Interface::limited); static Parameter ifaceiptmax ("IntrinsicPtIptmax", "Upper bound on intrinsic pT for inverse quadratic", &QTildeShowerHandler::_iptmax,GeV, ZERO, ZERO, 100000.0*GeV, false, false, Interface::limited); static RefVector ifaceVetoes ("Vetoes", "The vetoes to be checked during showering", &QTildeShowerHandler::_vetoes, -1, false,false,true,true,false); static RefVector interfaceFullShowerVetoes ("FullShowerVetoes", "The vetos to be appliede on the full final state of the shower", &QTildeShowerHandler::_fullShowerVetoes, -1, false, false, true, false, false); static Switch interfaceLimitEmissions ("LimitEmissions", "Limit the number and type of emissions for testing", &QTildeShowerHandler::_limitEmissions, 0, false, false); static SwitchOption interfaceLimitEmissionsNoLimit (interfaceLimitEmissions, "NoLimit", "Allow an arbitrary number of emissions", 0); static SwitchOption interfaceLimitEmissionsOneInitialStateEmission (interfaceLimitEmissions, "OneInitialStateEmission", "Allow one emission in the initial state and none in the final state", 1); static SwitchOption interfaceLimitEmissionsOneFinalStateEmission (interfaceLimitEmissions, "OneFinalStateEmission", "Allow one emission in the final state and none in the initial state", 2); static SwitchOption interfaceLimitEmissionsHardOnly (interfaceLimitEmissions, "HardOnly", "Only allow radiation from the hard ME correction", 3); static SwitchOption interfaceLimitEmissionsOneEmission (interfaceLimitEmissions, "OneEmission", "Allow one emission in either the final state or initial state, but not both", 4); static Switch interfaceTruncMode ("TruncatedShower", "Include the truncated shower?", &QTildeShowerHandler::_trunc_Mode, 1, false, false); static SwitchOption interfaceTruncMode0 (interfaceTruncMode,"No","Truncated Shower is OFF", 0); static SwitchOption interfaceTruncMode1 (interfaceTruncMode,"Yes","Truncated Shower is ON", 1); static Switch interfaceHardEmission ("HardEmission", "Whether to use ME corrections or POWHEG for the hardest emission", &QTildeShowerHandler::_hardEmission, 0, false, false); static SwitchOption interfaceHardEmissionNone (interfaceHardEmission, "None", "No Corrections", 0); static SwitchOption interfaceHardEmissionMECorrection (interfaceHardEmission, "MECorrection", "Old fashioned ME correction", 1); static SwitchOption interfaceHardEmissionPOWHEG (interfaceHardEmission, "POWHEG", "Powheg style hard emission", 2); static Switch interfaceInteractions ("Interactions", "The interactions to be used in the shower", &QTildeShowerHandler::interaction_, ShowerInteraction::Both, false, false); static SwitchOption interfaceInteractionsQCD (interfaceInteractions, "QCD", "Only QCD radiation", ShowerInteraction::QCD); static SwitchOption interfaceInteractionsQED (interfaceInteractions, "QED", "Only QEd radiation", ShowerInteraction::QED); static SwitchOption interfaceInteractionsQCDandQED (interfaceInteractions, "QCDandQED", "Both QED and QCD radiation", ShowerInteraction::Both); static Switch interfaceReconstructionOption ("ReconstructionOption", "Treatment of the reconstruction of the transverse momentum of " "a branching from the evolution scale.", &QTildeShowerHandler::_reconOpt, 0, false, false); static SwitchOption interfaceReconstructionOptionCutOff (interfaceReconstructionOption, "CutOff", "Use the cut-off masses in the calculation", 0); static SwitchOption interfaceReconstructionOptionOffShell5 (interfaceReconstructionOption, "OffShell5", "Try and preserve q2 but if pt negative just zero it", 5); - static Switch interfaceSpinCorrelations - ("SpinCorrelations", - "Treatment of spin correlations in the parton shower", - &QTildeShowerHandler::_spinOpt, 1, false, false); - static SwitchOption interfaceSpinCorrelationsNo - (interfaceSpinCorrelations, - "No", - "No spin correlations", - 0); - static SwitchOption interfaceSpinCorrelationsSpin - (interfaceSpinCorrelations, - "Yes", - "Include the azimuthal spin correlations only", - 1); - static Switch interfaceSoftCorrelations ("SoftCorrelations", "Option for the treatment of soft correlations in the parton shower", &QTildeShowerHandler::_softOpt, 2, false, false); static SwitchOption interfaceSoftCorrelationsNone (interfaceSoftCorrelations, "No", "No soft correlations", 0); static SwitchOption interfaceSoftCorrelationsFull (interfaceSoftCorrelations, "Full", "Use the full eikonal", 1); static SwitchOption interfaceSoftCorrelationsSingular (interfaceSoftCorrelations, "Singular", "Use original Webber-Marchisini form", 2); static Switch interfaceHardPOWHEG ("HardPOWHEG", "Treatment of powheg emissions which are too hard to have a shower interpretation", &QTildeShowerHandler::_hardPOWHEG, false, false, false); static SwitchOption interfaceHardPOWHEGAsShower (interfaceHardPOWHEG, "AsShower", "Still interpret as shower emissions", false); static SwitchOption interfaceHardPOWHEGRealEmission (interfaceHardPOWHEG, "RealEmission", "Generate shower from the real emmission configuration", true); static Reference interfaceKinematicsReconstructor ("KinematicsReconstructor", "Reference to the KinematicsReconstructor object", &QTildeShowerHandler::_reconstructor, false, false, true, false, false); static Reference interfacePartnerFinder ("PartnerFinder", "Reference to the PartnerFinder object", &QTildeShowerHandler::_partnerfinder, false, false, true, false, false); } tPPair QTildeShowerHandler::cascade(tSubProPtr sub, XCPtr xcomb) { // use me for reference in tex file etc useMe(); prepareCascade(sub); // set things up in the base class resetWeights(); hard_=ShowerTreePtr(); decay_.clear(); done_.clear(); // start of the try block for the whole showering process unsigned int countFailures=0; while (countFailuresoutgoing().begin(), currentSubProcess()->outgoing().end()), hard,decay); ShowerTree::constructTrees(hard_,decay_,hard,decay); // if no hard process if(!hard_) throw Exception() << "Shower starting with a decay" << "is not implemented" << Exception::runerror; // perform the shower for the hard process showerHardProcess(hard_,xcomb); done_.push_back(hard_); hard_->updateAfterShower(decay_); // if no decaying particles to shower break out of the loop if(decay_.empty()) break; // shower the decay products while(!decay_.empty()) { // find particle whose production process has been showered ShowerDecayMap::iterator dit = decay_.begin(); while(!dit->second->parent()->hasShowered() && dit!=decay_.end()) ++dit; assert(dit!=decay_.end()); // get the particle ShowerTreePtr decayingTree = dit->second; // remove it from the multimap decay_.erase(dit); // make sure the particle has been decayed QTildeShowerHandler::decay(decayingTree,decay_); // now shower the decay showerDecay(decayingTree); done_.push_back(decayingTree); decayingTree->updateAfterShower(decay_); } // suceeded break out of the loop break; } catch (KinematicsReconstructionVeto) { resetWeights(); ++countFailures; } catch ( ... ) { hard_=ShowerTreePtr(); decay_.clear(); done_.clear(); throw; } } // if loop exited because of too many tries, throw event away if (countFailures >= maxtry()) { resetWeights(); hard_=ShowerTreePtr(); decay_.clear(); done_.clear(); throw Exception() << "Too many tries for main while loop " << "in QTildeShowerHandler::cascade()." << Exception::eventerror; } //enter the particles in the event record fillEventRecord(); // clear storage hard_=ShowerTreePtr(); decay_.clear(); done_.clear(); // non hadronic case return if (!isResolvedHadron(incomingBeams().first ) && !isResolvedHadron(incomingBeams().second) ) return incomingBeams(); // remake the remnants (needs to be after the colours are sorted // out in the insertion into the event record) if ( firstInteraction() ) return remakeRemnant(sub->incoming()); //Return the new pair of incoming partons. remakeRemnant is not //necessary here, because the secondary interactions are not yet //connected to the remnants. return make_pair(findFirstParton(sub->incoming().first ), findFirstParton(sub->incoming().second)); } void QTildeShowerHandler::fillEventRecord() { // create a new step StepPtr pstep = newStep(); assert(!done_.empty()); assert(done_[0]->isHard()); // insert the steps for(unsigned int ix=0;ixfillEventRecord(pstep,doISR(),doFSR()); } } HardTreePtr QTildeShowerHandler::generateCKKW(ShowerTreePtr ) const { return HardTreePtr(); } void QTildeShowerHandler::doinit() { ShowerHandler::doinit(); // check on the reweighting for(unsigned int ix=0;ix<_fullShowerVetoes.size();++ix) { if(_fullShowerVetoes[ix]->behaviour()==1) { _reWeight = true; break; } } if(_reWeight && maximumTries()<_nReWeight) { throw Exception() << "Reweight being performed in the shower but the number of attempts for the" << "shower is less than that for the reweighting.\n" << "Maximum number of attempt for the shower " << fullName() << ":MaxTry is " << maximumTries() << "\nand for reweighting is " << fullName() << ":NReWeight is " << _nReWeight << "\n" << "we recommend the number of attempts is 10 times the number for reweighting\n" << Exception::runerror; } ShowerTree::_vmin2 = vMin(); ShowerTree::_spaceTime = includeSpaceTime(); } void QTildeShowerHandler::doinitrun() { ShowerHandler::doinitrun(); ShowerTree::_vmin2 = vMin(); ShowerTree::_spaceTime = includeSpaceTime(); } void QTildeShowerHandler::generateIntrinsicpT(vector particlesToShower) { _intrinsic.clear(); if ( !ipTon() || !doISR() ) return; // don't do anything for the moment for secondary scatters if( !firstInteraction() ) return; // generate intrinsic pT for(unsigned int ix=0;ixprogenitor()->isFinalState()) continue; if(!particlesToShower[ix]->progenitor()->dataPtr()->coloured()) continue; Energy ipt; if(UseRandom::rnd() > _beta) { ipt=_iptrms*sqrt(-log(UseRandom::rnd())); } else { ipt=_gamma*sqrt(pow(1.+sqr(_iptmax/_gamma), UseRandom::rnd())-1.); } pair pt = make_pair(ipt,UseRandom::rnd(Constants::twopi)); _intrinsic[particlesToShower[ix]] = pt; } } void QTildeShowerHandler::setupMaximumScales(const vector & p, XCPtr xcomb) { // let POWHEG events radiate freely if(_hardEmission==2&&hardTree()) { vector::const_iterator ckt = p.begin(); for (; ckt != p.end(); ckt++) (*ckt)->maxHardPt(Constants::MaxEnergy); return; } // return if no vetos if (!restrictPhasespace()) return; // find out if hard partonic subprocess. bool isPartonic(false); map::const_iterator cit = _currenttree->incomingLines().begin(); Lorentz5Momentum pcm; for(; cit!=currentTree()->incomingLines().end(); ++cit) { pcm += cit->first->progenitor()->momentum(); isPartonic |= cit->first->progenitor()->coloured(); } // find minimum pt from hard process, the maximum pt from all outgoing // coloured lines (this is simpler and more general than // 2stu/(s^2+t^2+u^2)). Maximum scale for scattering processes will // be transverse mass. Energy ptmax = generator()->maximumCMEnergy(); // general case calculate the scale if ( !hardScaleIsMuF() || (hardVetoReadOption()&&!firstInteraction()) ) { // scattering process if(currentTree()->isHard()) { assert(xcomb); // coloured incoming particles if (isPartonic) { map::const_iterator cjt = currentTree()->outgoingLines().begin(); for(; cjt!=currentTree()->outgoingLines().end(); ++cjt) { if (cjt->first->progenitor()->coloured()) ptmax = min(ptmax,cjt->first->progenitor()->momentum().mt()); } } if (ptmax == generator()->maximumCMEnergy() ) ptmax = pcm.m(); if(hardScaleIsMuF()&&hardVetoReadOption()&& !firstInteraction()) { ptmax=min(ptmax,sqrt(xcomb->lastShowerScale())); } } // decay, incoming() is the decaying particle. else { ptmax = currentTree()->incomingLines().begin()->first ->progenitor()->momentum().mass(); } } // hepeup.SCALUP is written into the lastXComb by the // LesHouchesReader itself - use this by user's choice. // Can be more general than this. else { if(currentTree()->isHard()) { assert(xcomb); ptmax = sqrt( xcomb->lastShowerScale() ); } else { ptmax = currentTree()->incomingLines().begin()->first ->progenitor()->momentum().mass(); } } ptmax *= hardScaleFactor(); // set maxHardPt for all progenitors. For partonic processes this // is now the max pt in the FS, for non-partonic processes or // processes with no coloured FS the invariant mass of the IS vector::const_iterator ckt = p.begin(); for (; ckt != p.end(); ckt++) (*ckt)->maxHardPt(ptmax); } void QTildeShowerHandler::setupHardScales(const vector & p, XCPtr xcomb) { if ( hardScaleIsMuF() && (!hardVetoReadOption() || firstInteraction()) ) { Energy hardScale = ZERO; if(currentTree()->isHard()) { assert(xcomb); hardScale = sqrt( xcomb->lastShowerScale() ); } else { hardScale = currentTree()->incomingLines().begin()->first ->progenitor()->momentum().mass(); } hardScale *= hardScaleFactor(); vector::const_iterator ckt = p.begin(); for (; ckt != p.end(); ckt++) (*ckt)->hardScale(hardScale); muPt = hardScale; } } void QTildeShowerHandler::showerHardProcess(ShowerTreePtr hard, XCPtr xcomb) { _hardme = HwMEBasePtr(); // extract the matrix element tStdXCombPtr lastXC = dynamic_ptr_cast(xcomb); if(lastXC) { _hardme = dynamic_ptr_cast(lastXC->matrixElement()); } _decayme = HwDecayerBasePtr(); // set the current tree currentTree(hard); hardTree(HardTreePtr()); // work out the type of event currentTree()->xcombPtr(dynamic_ptr_cast(xcomb)); currentTree()->identifyEventType(); checkFlags(); // generate the showering doShowering(true,xcomb); } RealEmissionProcessPtr QTildeShowerHandler::hardMatrixElementCorrection(bool hard) { // set the initial enhancement factors for the soft correction _initialenhance = 1.; _finalenhance = 1.; // see if we can get the correction from the matrix element // or decayer RealEmissionProcessPtr real; if(hard) { if(_hardme&&_hardme->hasMECorrection()) { _hardme->initializeMECorrection(_currenttree->perturbativeProcess(), _initialenhance,_finalenhance); if(hardMEC()) real = _hardme->applyHardMatrixElementCorrection(_currenttree->perturbativeProcess()); } } else { if(_decayme&&_decayme->hasMECorrection()) { _decayme->initializeMECorrection(_currenttree->perturbativeProcess(), _initialenhance,_finalenhance); if(hardMEC()) real = _decayme->applyHardMatrixElementCorrection(_currenttree->perturbativeProcess()); } } return real; } ShowerParticleVector QTildeShowerHandler::createTimeLikeChildren(tShowerParticlePtr, IdList ids) { // Create the ShowerParticle objects for the two children of // the emitting particle; set the parent/child relationship // if same as definition create particles, otherwise create cc ShowerParticleVector children; for(unsigned int ix=0;ix<2;++ix) { children.push_back(new_ptr(ShowerParticle(ids[ix+1],true))); if(children[ix]->id()==_progenitor->id()&&!ids[ix+1]->stable()&&abs(ids[ix+1]->id())!=ParticleID::tauminus) children[ix]->set5Momentum(Lorentz5Momentum(_progenitor->progenitor()->mass())); else children[ix]->set5Momentum(Lorentz5Momentum(ids[ix+1]->mass())); } return children; } bool QTildeShowerHandler::timeLikeShower(tShowerParticlePtr particle, ShowerInteraction type, Branching fb, bool first) { // don't do anything if not needed if(_limitEmissions == 1 || hardOnly() || ( _limitEmissions == 2 && _nfs != 0) || ( _limitEmissions == 4 && _nfs + _nis != 0) ) { if(particle->spinInfo()) particle->spinInfo()->develop(); return false; } // generate the emission ShowerParticleVector children; // generate the emission if(!fb.kinematics) fb = selectTimeLikeBranching(particle,type,HardBranchingPtr()); // no emission, return if(!fb.kinematics) { if(particle->spinInfo()) particle->spinInfo()->develop(); return false; } Branching fc[2] = {Branching(),Branching()}; assert(fb.kinematics); // has emitted // Assign the shower kinematics to the emitting particle. particle->showerKinematics(fb.kinematics); // check highest pT if(fb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(fb.kinematics->pT()); // create the children children = createTimeLikeChildren(particle,fb.ids); // update the children particle->showerKinematics()-> updateChildren(particle, children,fb.type); // update number of emissions ++_nfs; if(_limitEmissions!=0) { if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); if(particle->spinInfo()) particle->spinInfo()->develop(); return true; } // select branchings for children fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr()); fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr()); // shower the first particle if(fc[0].kinematics) timeLikeShower(children[0],type,fc[0],false); if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); // shower the second particle if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],false); if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); if(_reconOpt>=1) particle->showerKinematics()->updateParent(particle, children,fb.type); // branching has happened if(first&&!children.empty()) particle->showerKinematics()->resetChildren(particle,children); if(particle->spinInfo()) particle->spinInfo()->develop(); return true; } bool QTildeShowerHandler::spaceLikeShower(tShowerParticlePtr particle, PPtr beam, ShowerInteraction type) { //using the pdf's associated with the ShowerHandler assures, that //modified pdf's are used for the secondary interactions via //CascadeHandler::resetPDFs(...) tcPDFPtr pdf; if(firstPDF().particle() == _beam) pdf = firstPDF().pdf(); if(secondPDF().particle() == _beam) pdf = secondPDF().pdf(); Energy freeze = pdfFreezingScale(); // don't do anything if not needed if(_limitEmissions == 2 || hardOnly() || ( _limitEmissions == 1 && _nis != 0 ) || ( _limitEmissions == 4 && _nis + _nfs != 0 ) ) { if(particle->spinInfo()) particle->spinInfo()->develop(); return false; } Branching bb; // generate branching while (true) { bb=_splittingGenerator->chooseBackwardBranching(*particle,beam, _initialenhance, _beam,type, pdf,freeze); // return if no emission if(!bb.kinematics) { if(particle->spinInfo()) particle->spinInfo()->develop(); return false; } // if not vetoed break if(!spaceLikeVetoed(bb,particle)) break; // otherwise reset scale and continue particle->vetoEmission(bb.type,bb.kinematics->scale()); if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr()); } // assign the splitting function and shower kinematics particle->showerKinematics(bb.kinematics); if(bb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(bb.kinematics->pT()); // For the time being we are considering only 1->2 branching // particles as in Sudakov form factor tcPDPtr part[2]={bb.ids[0],bb.ids[2]}; // Now create the actual particles, make the otherChild a final state // particle, while the newParent is not ShowerParticlePtr newParent = new_ptr(ShowerParticle(part[0],false)); ShowerParticlePtr otherChild = new_ptr(ShowerParticle(part[1],true,true)); ShowerParticleVector theChildren; theChildren.push_back(particle); theChildren.push_back(otherChild); //this updates the evolution scale particle->showerKinematics()-> updateParent(newParent, theChildren,bb.type); // update the history if needed _currenttree->updateInitialStateShowerProduct(_progenitor,newParent); _currenttree->addInitialStateBranching(particle,newParent,otherChild); // for the reconstruction of kinematics, parent/child // relationships are according to the branching process: // now continue the shower ++_nis; bool emitted = _limitEmissions==0 ? spaceLikeShower(newParent,beam,type) : false; if(newParent->spinInfo()) newParent->spinInfo()->develop(); // now reconstruct the momentum if(!emitted) { if(_intrinsic.find(_progenitor)==_intrinsic.end()) { bb.kinematics->updateLast(newParent,ZERO,ZERO); } else { pair kt=_intrinsic[_progenitor]; bb.kinematics->updateLast(newParent, kt.first*cos(kt.second), kt.first*sin(kt.second)); } } particle->showerKinematics()-> updateChildren(newParent, theChildren,bb.type); if(_limitEmissions!=0) { if(particle->spinInfo()) particle->spinInfo()->develop(); return true; } // perform the shower of the final-state particle timeLikeShower(otherChild,type,Branching(),true); updateHistory(otherChild); if(theChildren[1]->spinInfo()) theChildren[1]->spinInfo()->develop(); // return the emitted if(particle->spinInfo()) particle->spinInfo()->develop(); return true; } void QTildeShowerHandler::showerDecay(ShowerTreePtr decay) { // work out the type of event currentTree()->xcombPtr(StdXCombPtr()); currentTree()->identifyEventType(); _decayme = HwDecayerBasePtr(); _hardme = HwMEBasePtr(); // find the decayer // try the normal way if possible tDMPtr dm = decay->incomingLines().begin()->first->original() ->decayMode(); if(!dm) dm = decay->incomingLines().begin()->first->copy() ->decayMode(); if(!dm) dm = decay->incomingLines().begin()->first->progenitor()->decayMode(); // otherwise make a string and look it up if(!dm) { string tag = decay->incomingLines().begin()->first->original()->dataPtr()->name() + "->"; OrderedParticles outgoing; for(map::const_iterator it=decay->outgoingLines().begin();it!=decay->outgoingLines().end();++it) { if(abs(decay->incomingLines().begin()->first->original()->id()) == ParticleID::t && abs(it->first->original()->id())==ParticleID::Wplus && decay->treelinks().size() == 1) { ShowerTreePtr Wtree = decay->treelinks().begin()->first; for(map::const_iterator it2=Wtree->outgoingLines().begin();it2!=Wtree->outgoingLines().end();++it2) { outgoing.insert(it2->first->original()->dataPtr()); } } else { outgoing.insert(it->first->original()->dataPtr()); } } for(OrderedParticles::const_iterator it=outgoing.begin(); it!=outgoing.end();++it) { if(it!=outgoing.begin()) tag += ","; tag +=(**it).name(); } tag += ";"; dm = findDecayMode(tag); } if(dm) _decayme = dynamic_ptr_cast(dm->decayer()); // set the ShowerTree to be showered currentTree(decay); decay->applyTransforms(); hardTree(HardTreePtr()); // generate the showering doShowering(false,XCPtr()); // if no vetos // force calculation of spin correlations SpinPtr spInfo = decay->incomingLines().begin()->first->progenitor()->spinInfo(); if(spInfo) { if(!spInfo->developed()) spInfo->needsUpdate(); spInfo->develop(); } } bool QTildeShowerHandler::spaceLikeDecayShower(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minmass,ShowerInteraction type, Branching fb) { // don't do anything if not needed if(_limitEmissions == 1 || hardOnly() || ( _limitEmissions == 3 && _nis != 0) || ( _limitEmissions == 4 && _nfs + _nis != 0) ) { return false; } // generate the emission ShowerParticleVector children; // generate the emission if(!fb.kinematics) fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type, HardBranchingPtr()); // no emission, return if(!fb.kinematics) return false; Branching fc[2]; if(particle->virtualMass()==ZERO) particle->virtualMass(_progenitor->progenitor()->mass()); fc[0] = Branching(); fc[1] = Branching(); assert(fb.kinematics); // has emitted // Assign the shower kinematics to the emitting particle. particle->showerKinematics(fb.kinematics); if(fb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(fb.kinematics->pT()); // create the ShowerParticle objects for the two children children = createTimeLikeChildren(particle,fb.ids); // updateChildren the children particle->showerKinematics()-> updateChildren(particle, children, fb.type); // select branchings for children fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass, type,HardBranchingPtr()); fc[1] = selectTimeLikeBranching (children[1],type,HardBranchingPtr()); // old default ++_nis; // shower the first particle _currenttree->updateInitialStateShowerProduct(_progenitor,children[0]); _currenttree->addInitialStateBranching(particle,children[0],children[1]); if(fc[0].kinematics) spaceLikeDecayShower(children[0],maxScales,minmass,type,Branching()); // shower the second particle if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],true); updateHistory(children[1]); // TODO NEED AN UPDATE HERE FOR RECONOPT!=0 // branching has happened return true; } vector QTildeShowerHandler::setupShower(bool hard) { RealEmissionProcessPtr real; // generate hard me if needed if(_hardEmission==1) { real = hardMatrixElementCorrection(hard); if(real&&!real->outgoing().empty()) setupMECorrection(real); } // generate POWHEG hard emission if needed else if(_hardEmission==2) hardestEmission(hard); // set the initial colour partners setEvolutionPartners(hard,interaction_,false); // get the particles to be showered vector particlesToShower = currentTree()->extractProgenitors(); // return the answer return particlesToShower; } void QTildeShowerHandler::setEvolutionPartners(bool hard,ShowerInteraction type, bool clear) { // match the particles in the ShowerTree and hardTree if(hardTree() && !hardTree()->connect(currentTree())) throw Exception() << "Can't match trees in " << "QTildeShowerHandler::setEvolutionPartners()" << Exception::eventerror; // extract the progenitors vector particles = currentTree()->extractProgenitorParticles(); // clear the partners if needed if(clear) { for(unsigned int ix=0;ixpartner(ShowerParticlePtr()); particles[ix]->clearPartners(); } } // sort out the colour partners if(hardTree()) { // find the partner for(unsigned int ix=0;ixparticles()[particles[ix]]->branchingParticle()->partner(); if(!partner) continue; for(map::const_iterator it=hardTree()->particles().begin(); it!=hardTree()->particles().end();++it) { if(it->second->branchingParticle()==partner) { particles[ix]->partner(it->first); break; } } if(!particles[ix]->partner()) throw Exception() << "Can't match partners in " << "QTildeShowerHandler::setEvolutionPartners()" << Exception::eventerror; } } // Set the initial evolution scales partnerFinder()-> setInitialEvolutionScales(particles,!hard,interaction_,!_hardtree); if(hardTree() && _hardPOWHEG) { bool tooHard=false; map::const_iterator eit=hardTree()->particles().end(); for(unsigned int ix=0;ix::const_iterator mit = hardTree()->particles().find(particles[ix]); Energy hardScale(ZERO); ShowerPartnerType type(ShowerPartnerType::Undefined); // final-state if(particles[ix]->isFinalState()) { if(mit!= eit && !mit->second->children().empty()) { hardScale = mit->second->scale(); type = mit->second->type(); } } // initial-state else { if(mit!= eit && mit->second->parent()) { hardScale = mit->second->parent()->scale(); type = mit->second->parent()->type(); } } if(type!=ShowerPartnerType::Undefined) { if(type==ShowerPartnerType::QED) { tooHard |= particles[ix]->scales().QED_noAOscales().QCD_c_noAOscales().QCD_ac_noAOchildren().empty()) { ShowerParticleVector theChildren; for(unsigned int ix=0;ixchildren().size();++ix) { ShowerParticlePtr part = dynamic_ptr_cast (particle->children()[ix]); theChildren.push_back(part); } // update the history if needed if(particle==_currenttree->getFinalStateShowerProduct(_progenitor)) _currenttree->updateFinalStateShowerProduct(_progenitor, particle,theChildren); _currenttree->addFinalStateBranching(particle,theChildren); for(unsigned int ix=0;ixprogenitor()->partner()) return false; progenitor()->progenitor()->initializeFinalState(); if(hardTree()) { map::const_iterator eit=hardTree()->particles().end(), mit = hardTree()->particles().find(progenitor()->progenitor()); if( mit != eit && !mit->second->children().empty() ) { bool output=truncatedTimeLikeShower(progenitor()->progenitor(), mit->second ,type,Branching(),true); if(output) updateHistory(progenitor()->progenitor()); return output; } } // do the shower bool output = hardOnly() ? false : timeLikeShower(progenitor()->progenitor() ,type,Branching(),true) ; if(output) updateHistory(progenitor()->progenitor()); return output; } bool QTildeShowerHandler::startSpaceLikeShower(PPtr parent, ShowerInteraction type) { // initialise the basis vectors if(!progenitor()->progenitor()->partner()) return false; progenitor()->progenitor()->initializeInitialState(parent); if(hardTree()) { map::const_iterator eit =hardTree()->particles().end(), mit = hardTree()->particles().find(progenitor()->progenitor()); if( mit != eit && mit->second->parent() ) { return truncatedSpaceLikeShower( progenitor()->progenitor(), parent, mit->second->parent(), type ); } } // perform the shower return hardOnly() ? false : spaceLikeShower(progenitor()->progenitor(),parent,type); } bool QTildeShowerHandler:: startSpaceLikeDecayShower(const ShowerParticle::EvolutionScales & maxScales, Energy minimumMass,ShowerInteraction type) { // set up the particle basis vectors if(!progenitor()->progenitor()->partner()) return false; progenitor()->progenitor()->initializeDecay(); if(hardTree()) { map::const_iterator eit =hardTree()->particles().end(), mit = hardTree()->particles().find(progenitor()->progenitor()); if( mit != eit && mit->second->parent() ) { HardBranchingPtr branch=mit->second; while(branch->parent()) branch=branch->parent(); return truncatedSpaceLikeDecayShower(progenitor()->progenitor(),maxScales, minimumMass, branch ,type, Branching()); } } // perform the shower return hardOnly() ? false : spaceLikeDecayShower(progenitor()->progenitor(),maxScales,minimumMass,type,Branching()); } bool QTildeShowerHandler::timeLikeVetoed(const Branching & fb, ShowerParticlePtr particle) { // work out type of interaction ShowerInteraction type = convertInteraction(fb.type); // check whether emission was harder than largest pt of hard subprocess if ( restrictPhasespace() && fb.kinematics->pT() > _progenitor->maxHardPt() ) return true; // soft matrix element correction veto if( softMEC()) { if(_hardme && _hardme->hasMECorrection()) { if(_hardme->softMatrixElementVeto(particle, _progenitor->progenitor(), particle->isFinalState(), _progenitor->highestpT(), fb.ids, fb.kinematics->z(), fb.kinematics->scale(), fb.kinematics->pT())) return true; } else if(_decayme && _decayme->hasMECorrection()) { if(_decayme->softMatrixElementVeto(particle, _progenitor->progenitor(), particle->isFinalState(), _progenitor->highestpT(), fb.ids, fb.kinematics->z(), fb.kinematics->scale(), fb.kinematics->pT())) return true; } } // veto on maximum pt if(fb.kinematics->pT()>_progenitor->maximumpT(type)) return true; // general vetos if (fb.kinematics && !_vetoes.empty()) { bool vetoed=false; for (vector::iterator v = _vetoes.begin(); v != _vetoes.end(); ++v) { bool test = (**v).vetoTimeLike(_progenitor,particle,fb,currentTree()); switch((**v).vetoType()) { case ShowerVeto::Emission: vetoed |= test; break; case ShowerVeto::Shower: if(test) throw VetoShower(); break; case ShowerVeto::Event: if(test) throw Veto(); break; } } if(vetoed) return true; } if ( firstInteraction() && profileScales() ) { double weight = profileScales()-> hardScaleProfile(_progenitor->hardScale(),fb.kinematics->pT()); if ( UseRandom::rnd() > weight ) return true; } return false; } bool QTildeShowerHandler::spaceLikeVetoed(const Branching & bb, ShowerParticlePtr particle) { // work out type of interaction ShowerInteraction type = convertInteraction(bb.type); // check whether emission was harder than largest pt of hard subprocess if (restrictPhasespace() && bb.kinematics->pT() > _progenitor->maxHardPt()) return true; // apply the soft correction if( softMEC() && _hardme && _hardme->hasMECorrection() ) { if(_hardme->softMatrixElementVeto(particle, _progenitor->progenitor(), particle->isFinalState(), _progenitor->highestpT(), bb.ids, bb.kinematics->z(), bb.kinematics->scale(), bb.kinematics->pT())) return true; } // the more general vetos // check vs max pt for the shower if(bb.kinematics->pT()>_progenitor->maximumpT(type)) return true; if (!_vetoes.empty()) { bool vetoed=false; for (vector::iterator v = _vetoes.begin(); v != _vetoes.end(); ++v) { bool test = (**v).vetoSpaceLike(_progenitor,particle,bb,currentTree()); switch ((**v).vetoType()) { case ShowerVeto::Emission: vetoed |= test; break; case ShowerVeto::Shower: if(test) throw VetoShower(); break; case ShowerVeto::Event: if(test) throw Veto(); break; } } if (vetoed) return true; } if ( firstInteraction() && profileScales() ) { double weight = profileScales()-> hardScaleProfile(_progenitor->hardScale(),bb.kinematics->pT()); if ( UseRandom::rnd() > weight ) return true; } return false; } bool QTildeShowerHandler::spaceLikeDecayVetoed( const Branching & fb, ShowerParticlePtr particle) { // work out type of interaction ShowerInteraction type = convertInteraction(fb.type); // apply the soft correction if( softMEC() && _decayme && _decayme->hasMECorrection() ) { if(_decayme->softMatrixElementVeto(particle, _progenitor->progenitor(), particle->isFinalState(), _progenitor->highestpT(), fb.ids, fb.kinematics->z(), fb.kinematics->scale(), fb.kinematics->pT())) return true; } // veto on hardest pt in the shower if(fb.kinematics->pT()> _progenitor->maximumpT(type)) return true; // general vetos if (!_vetoes.empty()) { bool vetoed=false; for (vector::iterator v = _vetoes.begin(); v != _vetoes.end(); ++v) { bool test = (**v).vetoSpaceLike(_progenitor,particle,fb,currentTree()); switch((**v).vetoType()) { case ShowerVeto::Emission: vetoed |= test; break; case ShowerVeto::Shower: if(test) throw VetoShower(); break; case ShowerVeto::Event: if(test) throw Veto(); break; } if (vetoed) return true; } } return false; } void QTildeShowerHandler::hardestEmission(bool hard) { HardTreePtr ISRTree; // internal POWHEG in production or decay if( (( _hardme && _hardme->hasPOWHEGCorrection()!=0 ) || ( _decayme && _decayme->hasPOWHEGCorrection()!=0 ) ) ) { RealEmissionProcessPtr real; unsigned int type(0); // production if(_hardme) { assert(hard); real = _hardme->generateHardest( currentTree()->perturbativeProcess(), interaction_); type = _hardme->hasPOWHEGCorrection(); } // decay else { assert(!hard); real = _decayme->generateHardest( currentTree()->perturbativeProcess() ); type = _decayme->hasPOWHEGCorrection(); } if(real) { // set up ther hard tree if(!real->outgoing().empty()) _hardtree = new_ptr(HardTree(real)); // set up the vetos currentTree()->setVetoes(real->pT(),type); } // store initial state POWHEG radiation if(_hardtree && _hardme && _hardme->hasPOWHEGCorrection()==1) ISRTree = _hardtree; } else if (hard) { // Get minimum pT cutoff used in shower approximation Energy maxpt = 1.*GeV; if ( currentTree()->showerApproximation() ) { int colouredIn = 0; int colouredOut = 0; for( map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it = currentTree()->outgoingLines().begin(); it != currentTree()->outgoingLines().end(); ++it ) { if( it->second->coloured() ) ++colouredOut; } for( map< ShowerProgenitorPtr, ShowerParticlePtr >::iterator it = currentTree()->incomingLines().begin(); it != currentTree()->incomingLines().end(); ++it ) { if( it->second->coloured() ) ++colouredIn; } if ( currentTree()->showerApproximation()->ffPtCut() == currentTree()->showerApproximation()->fiPtCut() && currentTree()->showerApproximation()->ffPtCut() == currentTree()->showerApproximation()->iiPtCut() ) maxpt = currentTree()->showerApproximation()->ffPtCut(); else if ( colouredIn == 2 && colouredOut == 0 ) maxpt = currentTree()->showerApproximation()->iiPtCut(); else if ( colouredIn == 0 && colouredOut > 1 ) maxpt = currentTree()->showerApproximation()->ffPtCut(); else if ( colouredIn == 2 && colouredOut == 1 ) maxpt = min(currentTree()->showerApproximation()->iiPtCut(), currentTree()->showerApproximation()->fiPtCut()); else if ( colouredIn == 1 && colouredOut > 1 ) maxpt = min(currentTree()->showerApproximation()->ffPtCut(), currentTree()->showerApproximation()->fiPtCut()); else maxpt = min(min(currentTree()->showerApproximation()->iiPtCut(), currentTree()->showerApproximation()->fiPtCut()), currentTree()->showerApproximation()->ffPtCut()); } // Generate hardtree from born and real emission subprocesses _hardtree = generateCKKW(currentTree()); // Find transverse momentum of hardest emission if (_hardtree){ for(set::iterator it=_hardtree->branchings().begin(); it!=_hardtree->branchings().end();++it) { if ((*it)->parent() && (*it)->status()==HardBranching::Incoming) maxpt=(*it)->branchingParticle()->momentum().perp(); if ((*it)->children().size()==2 && (*it)->status()==HardBranching::Outgoing){ if ((*it)->branchingParticle()->id()!=21 && abs((*it)->branchingParticle()->id())>5 ){ if ((*it)->children()[0]->branchingParticle()->id()==21 || abs((*it)->children()[0]->branchingParticle()->id())<6) maxpt=(*it)->children()[0]->branchingParticle()->momentum().perp(); else if ((*it)->children()[1]->branchingParticle()->id()==21 || abs((*it)->children()[1]->branchingParticle()->id())<6) maxpt=(*it)->children()[1]->branchingParticle()->momentum().perp(); } else { if ( abs((*it)->branchingParticle()->id())<6){ if (abs((*it)->children()[0]->branchingParticle()->id())<6) maxpt = (*it)->children()[1]->branchingParticle()->momentum().perp(); else maxpt = (*it)->children()[0]->branchingParticle()->momentum().perp(); } else maxpt = (*it)->children()[1]->branchingParticle()->momentum().perp(); } } } } // Hardest (pt) emission should be the first powheg emission. maxpt=min(sqrt(lastXCombPtr()->lastShowerScale()),maxpt); // set maximum pT for subsequent emissions from S events if ( currentTree()->isPowhegSEvent() ) { for( map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it = currentTree()->outgoingLines().begin(); it != currentTree()->outgoingLines().end(); ++it ) { if( ! it->second->coloured() ) continue; it->first->maximumpT(maxpt, ShowerInteraction::QCD ); } for( map< ShowerProgenitorPtr, ShowerParticlePtr >::iterator it = currentTree()->incomingLines().begin(); it != currentTree()->incomingLines().end(); ++it ) { if( ! it->second->coloured() ) continue; it->first->maximumpT(maxpt, ShowerInteraction::QCD ); } } } else _hardtree = generateCKKW(currentTree()); // if hard me doesn't have a FSR powheg // correction use decay powheg correction if (_hardme && _hardme->hasPOWHEGCorrection()<2) { addFSRUsingDecayPOWHEG(ISRTree); } // connect the trees if(_hardtree) { connectTrees(currentTree(),_hardtree,hard); } } void QTildeShowerHandler::addFSRUsingDecayPOWHEG(HardTreePtr ISRTree) { // check for intermediate colour singlet resonance const ParticleVector inter = _hardme->subProcess()->intermediates(); if (inter.size()!=1 || inter[0]->momentum().m2()/GeV2 < 0 || inter[0]->dataPtr()->iColour()!=PDT::Colour0) { return; } // ignore cases where outgoing particles are not coloured map out = currentTree()->outgoingLines(); if (out.size() != 2 || out. begin()->second->dataPtr()->iColour()==PDT::Colour0 || out.rbegin()->second->dataPtr()->iColour()==PDT::Colour0) { return; } // look up decay mode tDMPtr dm; string tag; string inParticle = inter[0]->dataPtr()->name() + "->"; vector outParticles; outParticles.push_back(out.begin ()->first->progenitor()->dataPtr()->name()); outParticles.push_back(out.rbegin()->first->progenitor()->dataPtr()->name()); for (int it=0; it<2; ++it){ tag = inParticle + outParticles[it] + "," + outParticles[(it+1)%2] + ";"; dm = generator()->findDecayMode(tag); if(dm) break; } // get the decayer HwDecayerBasePtr decayer; if(dm) decayer = dynamic_ptr_cast(dm->decayer()); // check if decayer has a FSR POWHEG correction if (!decayer || decayer->hasPOWHEGCorrection()<2) { return; } // generate the hardest emission // create RealEmissionProcess PPtr in = new_ptr(*inter[0]); RealEmissionProcessPtr newProcess(new_ptr(RealEmissionProcess())); newProcess->bornIncoming().push_back(in); newProcess->bornOutgoing().push_back(out.begin ()->first->progenitor()); newProcess->bornOutgoing().push_back(out.rbegin()->first->progenitor()); // generate the FSR newProcess = decayer->generateHardest(newProcess); HardTreePtr FSRTree; if(newProcess) { // set up ther hard tree if(!newProcess->outgoing().empty()) FSRTree = new_ptr(HardTree(newProcess)); // set up the vetos currentTree()->setVetoes(newProcess->pT(),2); } if(!FSRTree) return; // if there is no ISRTree make _hardtree from FSRTree if (!ISRTree){ vector inBranch,hardBranch; for(map::const_iterator cit =currentTree()->incomingLines().begin(); cit!=currentTree()->incomingLines().end();++cit ) { inBranch.push_back(new_ptr(HardBranching(cit->second,SudakovPtr(), HardBranchingPtr(), HardBranching::Incoming))); inBranch.back()->beam(cit->first->original()->parents()[0]); hardBranch.push_back(inBranch.back()); } if(inBranch[0]->branchingParticle()->dataPtr()->coloured()) { inBranch[0]->colourPartner(inBranch[1]); inBranch[1]->colourPartner(inBranch[0]); } for(set::iterator it=FSRTree->branchings().begin(); it!=FSRTree->branchings().end();++it) { if((**it).branchingParticle()->id()!=in->id()) hardBranch.push_back(*it); } hardBranch[2]->colourPartner(hardBranch[3]); hardBranch[3]->colourPartner(hardBranch[2]); HardTreePtr newTree = new_ptr(HardTree(hardBranch,inBranch, ShowerInteraction::QCD)); _hardtree = newTree; } // Otherwise modify the ISRTree to include the emission in FSRTree else { vector FSROut, ISROut; set::iterator itFSR, itISR; // get outgoing particles for(itFSR =FSRTree->branchings().begin(); itFSR!=FSRTree->branchings().end();++itFSR){ if ((**itFSR).status()==HardBranching::Outgoing) FSROut.push_back((*itFSR)->branchingParticle()); } for(itISR =ISRTree->branchings().begin(); itISR!=ISRTree->branchings().end();++itISR){ if ((**itISR).status()==HardBranching::Outgoing) ISROut.push_back((*itISR)->branchingParticle()); } // find COM frame formed by outgoing particles LorentzRotation eventFrameFSR, eventFrameISR; eventFrameFSR = ((FSROut[0]->momentum()+FSROut[1]->momentum()).findBoostToCM()); eventFrameISR = ((ISROut[0]->momentum()+ISROut[1]->momentum()).findBoostToCM()); // find rotation between ISR and FSR frames int j=0; if (ISROut[0]->id()!=FSROut[0]->id()) j=1; eventFrameISR.rotateZ( (eventFrameFSR*FSROut[0]->momentum()).phi()- (eventFrameISR*ISROut[j]->momentum()).phi() ); eventFrameISR.rotateY( (eventFrameFSR*FSROut[0]->momentum()).theta()- (eventFrameISR*ISROut[j]->momentum()).theta() ); eventFrameISR.invert(); for (itFSR=FSRTree->branchings().begin(); itFSR!=FSRTree->branchings().end();++itFSR){ if ((**itFSR).branchingParticle()->id()==in->id()) continue; for (itISR =ISRTree->branchings().begin(); itISR!=ISRTree->branchings().end();++itISR){ if ((**itISR).status()==HardBranching::Incoming) continue; if ((**itFSR).branchingParticle()->id()== (**itISR).branchingParticle()->id()){ // rotate FSRTree particle to ISRTree event frame (**itISR).branchingParticle()->setMomentum(eventFrameISR* eventFrameFSR* (**itFSR).branchingParticle()->momentum()); (**itISR).branchingParticle()->rescaleMass(); // add the children of the FSRTree particles to the ISRTree if(!(**itFSR).children().empty()){ (**itISR).addChild((**itFSR).children()[0]); (**itISR).addChild((**itFSR).children()[1]); // rotate momenta to ISRTree event frame (**itISR).children()[0]->branchingParticle()->setMomentum(eventFrameISR* eventFrameFSR* (**itFSR).children()[0]->branchingParticle()->momentum()); (**itISR).children()[1]->branchingParticle()->setMomentum(eventFrameISR* eventFrameFSR* (**itFSR).children()[1]->branchingParticle()->momentum()); } } } } _hardtree = ISRTree; } } bool QTildeShowerHandler::truncatedTimeLikeShower(tShowerParticlePtr particle, HardBranchingPtr branch, ShowerInteraction type, Branching fb, bool first) { // select a branching if we don't have one if(!fb.kinematics) fb = selectTimeLikeBranching(particle,type,branch); // must be an emission, the forced one it not a truncated one assert(fb.kinematics); ShowerParticleVector children; Branching fc[2] = {Branching(),Branching()}; // Assign the shower kinematics to the emitting particle. particle->showerKinematics(fb.kinematics); if(fb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(fb.kinematics->pT()); // create the children children = createTimeLikeChildren(particle,fb.ids); // update the children particle->showerKinematics()-> updateChildren(particle, children,fb.type); // select branchings for children if(!fc[0].kinematics) { // select branching for first particle if(!fb.hard && fb.iout ==1 ) fc[0] = selectTimeLikeBranching(children[0],type,branch); else if(fb.hard && !branch->children()[0]->children().empty() ) fc[0] = selectTimeLikeBranching(children[0],type,branch->children()[0]); else fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr()); } // select branching for the second particle if(!fc[1].kinematics) { // select branching for first particle if(!fb.hard && fb.iout ==2 ) fc[1] = selectTimeLikeBranching(children[1],type,branch); else if(fb.hard && !branch->children()[1]->children().empty() ) fc[1] = selectTimeLikeBranching(children[1],type,branch->children()[1]); else fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr()); } // shower the first particle if(fc[0].kinematics) { // the parent has truncated emission and following line if(!fb.hard && fb.iout == 1) truncatedTimeLikeShower(children[0],branch,type,fc[0],false); // hard emission and subsquent hard emissions else if(fb.hard && !branch->children()[0]->children().empty() ) truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false); // normal shower else timeLikeShower(children[0],type,fc[0],false); } if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); // shower the second particle if(fc[1].kinematics) { // the parent has truncated emission and following line if(!fb.hard && fb.iout == 2) truncatedTimeLikeShower(children[1],branch,type,fc[1],false); // hard emission and subsquent hard emissions else if(fb.hard && !branch->children()[1]->children().empty() ) truncatedTimeLikeShower(children[1],branch->children()[1],type,fc[1],false); else timeLikeShower(children[1],type,fc[1],false); } if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); // branching has happened particle->showerKinematics()->updateParent(particle, children,fb.type); if(first&&!children.empty()) particle->showerKinematics()->resetChildren(particle,children); if(particle->spinInfo()) particle->spinInfo()->develop(); // TODO NEED AN UPDATE HERE FOR RECONOPT!=0 ? return true; } bool QTildeShowerHandler::truncatedSpaceLikeShower(tShowerParticlePtr particle, PPtr beam, HardBranchingPtr branch, ShowerInteraction type) { tcPDFPtr pdf; if(firstPDF().particle() == beamParticle()) pdf = firstPDF().pdf(); if(secondPDF().particle() == beamParticle()) pdf = secondPDF().pdf(); Energy freeze = pdfFreezingScale(); Branching bb; // parameters of the force branching double z(0.); HardBranchingPtr timelike; for( unsigned int ix = 0; ix < branch->children().size(); ++ix ) { if( branch->children()[ix]->status() ==HardBranching::Outgoing) { timelike = branch->children()[ix]; } if( branch->children()[ix]->status() ==HardBranching::Incoming ) z = branch->children()[ix]->z(); } // generate truncated branching tcPDPtr part[2]; if(z>=0.&&z<=1.) { while (true) { if( !isTruncatedShowerON() || hardOnly() ) break; bb = splittingGenerator()->chooseBackwardBranching( *particle, beam, 1., beamParticle(), type , pdf,freeze); if( !bb.kinematics || bb.kinematics->scale() < branch->scale() ) { bb = Branching(); break; } // particles as in Sudakov form factor part[0] = bb.ids[0]; part[1] = bb.ids[2]; double zsplit = bb.kinematics->z(); // apply the vetos for the truncated shower // if doesn't carry most of momentum ShowerInteraction type2 = convertInteraction(bb.type); if(type2==branch->sudakov()->interactionType() && zsplit < 0.5) { particle->vetoEmission(bb.type,bb.kinematics->scale()); continue; } // others if( part[0]->id() != particle->id() || // if particle changes type bb.kinematics->pT() > progenitor()->maximumpT(type2) || // pt veto bb.kinematics->scale() < branch->scale()) { // angular ordering veto particle->vetoEmission(bb.type,bb.kinematics->scale()); continue; } // and those from the base class if(spaceLikeVetoed(bb,particle)) { particle->vetoEmission(bb.type,bb.kinematics->scale()); continue; } break; } } if( !bb.kinematics ) { //do the hard emission ShoKinPtr kinematics = new_ptr(IS_QTildeShowerKinematics1to2( branch->scale(), z, branch->phi(), branch->children()[0]->pT(), branch->sudakov() )); // assign the splitting function and shower kinematics particle->showerKinematics( kinematics ); if(kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(kinematics->pT()); // For the time being we are considering only 1->2 branching // Now create the actual particles, make the otherChild a final state // particle, while the newParent is not ShowerParticlePtr newParent = new_ptr( ShowerParticle( branch->branchingParticle()->dataPtr(), false ) ); ShowerParticlePtr otherChild = new_ptr( ShowerParticle( timelike->branchingParticle()->dataPtr(), true, true ) ); ShowerParticleVector theChildren; theChildren.push_back( particle ); theChildren.push_back( otherChild ); particle->showerKinematics()-> updateParent( newParent, theChildren, branch->type()); // update the history if needed currentTree()->updateInitialStateShowerProduct( progenitor(), newParent ); currentTree()->addInitialStateBranching( particle, newParent, otherChild ); // for the reconstruction of kinematics, parent/child // relationships are according to the branching process: // now continue the shower bool emitted=false; if(!hardOnly()) { if( branch->parent() ) { emitted = truncatedSpaceLikeShower( newParent, beam, branch->parent() , type); } else { emitted = spaceLikeShower( newParent, beam , type); } } if( !emitted ) { if( intrinsicpT().find( progenitor() ) == intrinsicpT().end() ) { kinematics->updateLast( newParent, ZERO, ZERO ); } else { pair kt = intrinsicpT()[progenitor()]; kinematics->updateLast( newParent, kt.first*cos( kt.second ), kt.first*sin( kt.second ) ); } } particle->showerKinematics()-> updateChildren( newParent, theChildren,bb.type); if(hardOnly()) return true; // perform the shower of the final-state particle if( timelike->children().empty() ) { timeLikeShower( otherChild , type,Branching(),true); } else { truncatedTimeLikeShower( otherChild, timelike , type,Branching(), true); } updateHistory(otherChild); // return the emitted return true; } // assign the splitting function and shower kinematics particle->showerKinematics( bb.kinematics ); if(bb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(bb.kinematics->pT()); // For the time being we are considering only 1->2 branching // Now create the actual particles, make the otherChild a final state // particle, while the newParent is not ShowerParticlePtr newParent = new_ptr( ShowerParticle( part[0], false ) ); ShowerParticlePtr otherChild = new_ptr( ShowerParticle( part[1], true, true ) ); ShowerParticleVector theChildren; theChildren.push_back( particle ); theChildren.push_back( otherChild ); particle->showerKinematics()-> updateParent( newParent, theChildren, bb.type); // update the history if needed currentTree()->updateInitialStateShowerProduct( progenitor(), newParent ); currentTree()->addInitialStateBranching( particle, newParent, otherChild ); // for the reconstruction of kinematics, parent/child // relationships are according to the branching process: // now continue the shower bool emitted = truncatedSpaceLikeShower( newParent, beam, branch,type); // now reconstruct the momentum if( !emitted ) { if( intrinsicpT().find( progenitor() ) == intrinsicpT().end() ) { bb.kinematics->updateLast( newParent, ZERO, ZERO ); } else { pair kt = intrinsicpT()[ progenitor() ]; bb.kinematics->updateLast( newParent, kt.first*cos( kt.second ), kt.first*sin( kt.second ) ); } } particle->showerKinematics()-> updateChildren( newParent, theChildren, bb.type); // perform the shower of the final-state particle timeLikeShower( otherChild , type,Branching(),true); updateHistory(otherChild); // return the emitted return true; } bool QTildeShowerHandler:: truncatedSpaceLikeDecayShower(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minmass, HardBranchingPtr branch, ShowerInteraction type, Branching fb) { // select a branching if we don't have one if(!fb.kinematics) fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type,branch); // must be an emission, the forced one it not a truncated one assert(fb.kinematics); ShowerParticleVector children; Branching fc[2]={Branching(),Branching()}; // Assign the shower kinematics to the emitting particle. particle->showerKinematics(fb.kinematics); if(fb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(fb.kinematics->pT()); // create the ShowerParticle objects for the two children children = createTimeLikeChildren(particle,fb.ids); // updateChildren the children particle->showerKinematics()-> updateChildren(particle, children, fb.type); // select branchings for children if(!fc[0].kinematics) { if(children[0]->id()==particle->id()) { // select branching for first particle if(!fb.hard) fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type,branch); else if(fb.hard && ! branch->children()[0]->children().empty() ) fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type, branch->children()[0]); else fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type, HardBranchingPtr()); } else { // select branching for first particle if(fb.hard && !branch->children()[0]->children().empty() ) fc[0] = selectTimeLikeBranching(children[0],type,branch->children()[0]); else fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr()); } } // select branching for the second particle if(!fc[1].kinematics) { if(children[1]->id()==particle->id()) { // select branching for first particle if(!fb.hard) fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type,branch); else if(fb.hard && ! branch->children()[1]->children().empty() ) fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type, branch->children()[1]); else fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type, HardBranchingPtr()); } else { if(fb.hard && !branch->children()[1]->children().empty() ) fc[1] = selectTimeLikeBranching(children[1],type,branch->children()[1]); else fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr()); } } // old default // update the history if needed currentTree()->updateInitialStateShowerProduct(progenitor(),children[0]); currentTree()->addInitialStateBranching(particle,children[0],children[1]); // shower the first particle if(fc[0].kinematics) { if(children[0]->id()==particle->id()) { if(!fb.hard) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch,type,fc[0]); else if(fb.hard && ! branch->children()[0]->children().empty() ) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch->children()[0],type,fc[0]); else spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[0]); } else { if(fb.hard && !branch->children()[0]->children().empty() ) truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false); // normal shower else timeLikeShower(children[0],type,fc[0],false); } } // shower the second particle if(fc[1].kinematics) { if(children[0]->id()==particle->id()) { if(!fb.hard) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch,type,fc[1]); else if(fb.hard && ! branch->children()[0]->children().empty() ) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch->children()[0],type,fc[1]); else spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[1]); } else { if(fb.hard && !branch->children()[0]->children().empty() ) truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[1],false); // normal shower else timeLikeShower(children[0],type,fc[1],false); } } updateHistory(children[1]); // TODO DO WE NEED A CHECK IF RECONPT !=0 return true; } void QTildeShowerHandler::connectTrees(ShowerTreePtr showerTree, HardTreePtr hardTree, bool hard ) { ShowerParticleVector particles; // find the Sudakovs for(set::iterator cit=hardTree->branchings().begin(); cit!=hardTree->branchings().end();++cit) { // Sudakovs for ISR if((**cit).parent()&&(**cit).status()==HardBranching::Incoming) { ++_nis; array br; br[0] = (**cit).parent()->branchingParticle()->id(); br[1] = (**cit). branchingParticle()->id(); br[2] = (**cit).parent()->children()[0]==*cit ? (**cit).parent()->children()[1]->branchingParticle()->id() : (**cit).parent()->children()[0]->branchingParticle()->id(); BranchingList branchings = splittingGenerator()->initialStateBranchings(); if(br[1]<0&&br[0]==br[1]) { br[0] = abs(br[0]); br[1] = abs(br[1]); } else if(br[1]<0) { br[1] = -br[1]; br[2] = -br[2]; } long index = abs(br[1]); SudakovPtr sudakov; for(BranchingList::const_iterator cjt = branchings.lower_bound(index); cjt != branchings.upper_bound(index); ++cjt ) { IdList ids = cjt->second.particles; if(ids[0]->id()==br[0]&&ids[1]->id()==br[1]&&ids[2]->id()==br[2]) { sudakov=cjt->second.sudakov; break; } } if(!sudakov) throw Exception() << "Can't find Sudakov for the hard emission in " << "QTildeShowerHandler::connectTrees() for ISR" << Exception::runerror; (**cit).parent()->sudakov(sudakov); } // Sudakovs for FSR else if(!(**cit).children().empty()) { ++_nfs; array br; br[0] = (**cit) .branchingParticle()->id(); br[1] = (**cit).children()[0]->branchingParticle()->id(); br[2] = (**cit).children()[1]->branchingParticle()->id(); BranchingList branchings = splittingGenerator()->finalStateBranchings(); if(br[0]<0) { br[0] = abs(br[0]); br[1] = abs(br[1]); br[2] = abs(br[2]); } long index = br[0]; SudakovPtr sudakov; for(BranchingList::const_iterator cjt = branchings.lower_bound(index); cjt != branchings.upper_bound(index); ++cjt ) { IdList ids = cjt->second.particles; if(ids[0]->id()==br[0]&&ids[1]->id()==br[1]&&ids[2]->id()==br[2]) { sudakov=cjt->second.sudakov; break; } } if(!sudakov) { throw Exception() << "Can't find Sudakov for the hard emission in " << "QTildeShowerHandler::connectTrees()" << Exception::runerror; } (**cit).sudakov(sudakov); } } // calculate the evolution scale for(set::iterator cit=hardTree->branchings().begin(); cit!=hardTree->branchings().end();++cit) { particles.push_back((*cit)->branchingParticle()); } partnerFinder()-> setInitialEvolutionScales(particles,!hard,interaction_,true); hardTree->partnersSet(true); // inverse reconstruction if(hard) { kinematicsReconstructor()-> deconstructHardJets(hardTree,interaction_); } else kinematicsReconstructor()-> deconstructDecayJets(hardTree,interaction_); // now reset the momenta of the showering particles vector particlesToShower=showerTree->extractProgenitors(); // match them map partners; for(set::const_iterator bit=hardTree->branchings().begin(); bit!=hardTree->branchings().end();++bit) { Energy2 dmin( 1e30*GeV2 ); ShowerProgenitorPtr partner; for(vector::const_iterator pit=particlesToShower.begin(); pit!=particlesToShower.end();++pit) { if(partners.find(*pit)!=partners.end()) continue; if( (**bit).branchingParticle()->id() != (**pit).progenitor()->id() ) continue; if( (**bit).branchingParticle()->isFinalState() != (**pit).progenitor()->isFinalState() ) continue; if( (**pit).progenitor()->isFinalState() ) { Energy2 dtest = sqr( (**pit).progenitor()->momentum().x() - (**bit).showerMomentum().x() ) + sqr( (**pit).progenitor()->momentum().y() - (**bit).showerMomentum().y() ) + sqr( (**pit).progenitor()->momentum().z() - (**bit).showerMomentum().z() ) + sqr( (**pit).progenitor()->momentum().t() - (**bit).showerMomentum().t() ); // add mass difference for identical particles (e.g. Z0 Z0 production) dtest += 1e10*sqr((**pit).progenitor()->momentum().m()-(**bit).showerMomentum().m()); if( dtest < dmin ) { partner = *pit; dmin = dtest; } } else { // ensure directions are right if((**pit).progenitor()->momentum().z()/(**bit).showerMomentum().z()>ZERO) { partner = *pit; break; } } } if(!partner) throw Exception() << "Failed to match shower and hard trees in QTildeShowerHandler::hardestEmission" << Exception::eventerror; partners[partner] = *bit; } for(vector::const_iterator pit=particlesToShower.begin(); pit!=particlesToShower.end();++pit) { HardBranchingPtr partner = partners[*pit]; if((**pit).progenitor()->dataPtr()->stable()) { (**pit).progenitor()->set5Momentum(partner->showerMomentum()); (**pit).copy()->set5Momentum(partner->showerMomentum()); } else { Lorentz5Momentum oldMomentum = (**pit).progenitor()->momentum(); Lorentz5Momentum newMomentum = partner->showerMomentum(); LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass()); (**pit).progenitor()->transform(boost); (**pit).copy() ->transform(boost); boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass()); (**pit).progenitor()->transform(boost); (**pit).copy() ->transform(boost); } } // correction boosts for daughter trees for(map >::const_iterator tit = showerTree->treelinks().begin(); tit != showerTree->treelinks().end();++tit) { ShowerTreePtr decayTree = tit->first; map::const_iterator cit = decayTree->incomingLines().begin(); // reset the momentum of the decay particle Lorentz5Momentum oldMomentum = cit->first->progenitor()->momentum(); Lorentz5Momentum newMomentum = tit->second.second->momentum(); LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass()); decayTree->transform(boost,true); boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass()); decayTree->transform(boost,true); } } void QTildeShowerHandler::doShowering(bool hard,XCPtr xcomb) { // zero number of emissions _nis = _nfs = 0; // if MC@NLO H event and limited emissions // indicate both final and initial state emission if ( currentTree()->isMCatNLOHEvent() && _limitEmissions != 0 ) { _nis = _nfs = 1; } // extract particles to shower vector particlesToShower(setupShower(hard)); // check if we should shower bool colCharge = false; for(unsigned int ix=0;ixprogenitor()->dataPtr()->coloured() || particlesToShower[ix]->progenitor()->dataPtr()->charged()) { colCharge = true; break; } } if(!colCharge) { _currenttree->hasShowered(true); return; } // setup the maximum scales for the shower if (restrictPhasespace()) setupMaximumScales(particlesToShower,xcomb); // set the hard scales for the profiles setupHardScales(particlesToShower,xcomb); // specific stuff for hard processes and decays Energy minmass(ZERO), mIn(ZERO); // hard process generate the intrinsic p_T once and for all if(hard) { generateIntrinsicpT(particlesToShower); } // decay compute the minimum mass of the final-state else { for(unsigned int ix=0;ixprogenitor()->isFinalState()) { if(particlesToShower[ix]->progenitor()->dataPtr()->stable()) minmass += particlesToShower[ix]->progenitor()->dataPtr()->constituentMass(); else minmass += particlesToShower[ix]->progenitor()->mass(); } else { mIn = particlesToShower[ix]->progenitor()->mass(); } } // throw exception if decay can't happen if ( minmass > mIn ) { throw Exception() << "QTildeShowerHandler.cc: Mass of decaying particle is " << "below constituent masses of decay products." << Exception::eventerror; } } // setup for reweighted bool reWeighting = _reWeight && hard && ShowerHandler::currentHandler()->firstInteraction(); double eventWeight=0.; unsigned int nTryReWeight(0); // create random particle vector (only need to do once) vector tmp; unsigned int nColouredIncoming = 0; while(particlesToShower.size()>0){ unsigned int xx=UseRandom::irnd(particlesToShower.size()); tmp.push_back(particlesToShower[xx]); particlesToShower.erase(particlesToShower.begin()+xx); } particlesToShower=tmp; for(unsigned int ix=0;ixprogenitor()->isFinalState() && particlesToShower[ix]->progenitor()->coloured()) ++nColouredIncoming; } bool switchRecon = hard && nColouredIncoming !=1; // main shower loop unsigned int ntry(0); bool reconstructed = false; do { // clear results of last attempt if needed if(ntry!=0) { currentTree()->clear(); setEvolutionPartners(hard,interaction_,true); _nis = _nfs = 0; // if MC@NLO H event and limited emissions // indicate both final and initial state emission if ( currentTree()->isMCatNLOHEvent() && _limitEmissions != 0 ) { _nis = _nfs = 1; } for(unsigned int ix=0; ixprogenitor()->spinInfo(); if(spin && spin->decayVertex() && dynamic_ptr_cast(spin->decayVertex())) { spin->decayVertex(VertexPtr()); } } for(unsigned int ix=0;ixprogenitor()->isFinalState() || (hard && !particlesToShower[ix]->progenitor()->isFinalState())) { if(particlesToShower[ix]->progenitor()->spinInfo()) particlesToShower[ix]->progenitor()->spinInfo()->reset(); } } } // loop over particles for(unsigned int ix=0;ixprogenitor()->isFinalState()) { if(!doFSR()) continue; // perform shower progenitor()->hasEmitted(startTimeLikeShower(interaction_)); } // initial-state radiation else { if(!doISR()) continue; // hard process if(hard) { // get the PDF setBeamParticle(_progenitor->beam()); if(!beamParticle()) { throw Exception() << "Incorrect type of beam particle in " << "QTildeShowerHandler::doShowering(). " << "This should not happen for conventional choices but may happen if you have used a" << " non-default choice and have not changed the create ParticleData line in the input files" << " for this particle to create BeamParticleData." << Exception::runerror; } // perform the shower // set the beam particle tPPtr beamparticle=progenitor()->original(); if(!beamparticle->parents().empty()) beamparticle=beamparticle->parents()[0]; // generate the shower progenitor()->hasEmitted(startSpaceLikeShower(beamparticle, interaction_)); } // decay else { // skip colour and electrically neutral particles if(!progenitor()->progenitor()->dataPtr()->coloured() && !progenitor()->progenitor()->dataPtr()->charged()) { progenitor()->hasEmitted(false); continue; } // perform shower // set the scales correctly. The current scale is the maximum scale for // emission not the starting scale ShowerParticle::EvolutionScales maxScales(progenitor()->progenitor()->scales()); progenitor()->progenitor()->scales() = ShowerParticle::EvolutionScales(); if(progenitor()->progenitor()->dataPtr()->charged()) { progenitor()->progenitor()->scales().QED = progenitor()->progenitor()->mass(); progenitor()->progenitor()->scales().QED_noAO = progenitor()->progenitor()->mass(); } if(progenitor()->progenitor()->hasColour()) { progenitor()->progenitor()->scales().QCD_c = progenitor()->progenitor()->mass(); progenitor()->progenitor()->scales().QCD_c_noAO = progenitor()->progenitor()->mass(); } if(progenitor()->progenitor()->hasAntiColour()) { progenitor()->progenitor()->scales().QCD_ac = progenitor()->progenitor()->mass(); progenitor()->progenitor()->scales().QCD_ac_noAO = progenitor()->progenitor()->mass(); } // perform the shower progenitor()->hasEmitted(startSpaceLikeDecayShower(maxScales,minmass, interaction_)); } } } // do the kinematic reconstruction, checking if it worked reconstructed = hard ? kinematicsReconstructor()-> reconstructHardJets (currentTree(),intrinsicpT(),interaction_, switchRecon && ntry>maximumTries()/2) : kinematicsReconstructor()-> reconstructDecayJets(currentTree(),interaction_); if(!reconstructed) continue; // apply vetos on the full shower for(vector::const_iterator it=_fullShowerVetoes.begin(); it!=_fullShowerVetoes.end();++it) { int veto = (**it).applyVeto(currentTree()); if(veto<0) continue; // veto the shower if(veto==0) { reconstructed = false; break; } // veto the shower and reweight else if(veto==1) { reconstructed = false; break; } // veto the event else if(veto==2) { throw Veto(); } } if(reWeighting) { if(reconstructed) eventWeight += 1.; reconstructed=false; ++nTryReWeight; if(nTryReWeight==_nReWeight) { reWeighting = false; if(eventWeight==0.) throw Veto(); } } } while(!reconstructed&&maximumTries()>++ntry); // check if failed to generate the shower if(ntry==maximumTries()) { if(hard) throw ShowerHandler::ShowerTriesVeto(ntry); else throw Exception() << "Failed to generate the shower after " << ntry << " attempts in QTildeShowerHandler::showerDecay()" << Exception::eventerror; } // handle the weights and apply any reweighting required if(nTryReWeight>0) { tStdEHPtr seh = dynamic_ptr_cast(generator()->currentEventHandler()); static bool first = true; if(seh) { seh->reweight(eventWeight/double(nTryReWeight)); } else if(first) { generator()->log() << "Reweighting the shower only works with internal Herwig7 processes" << "Presumably you are showering Les Houches Events. These will not be" << "reweighted\n"; first = false; } } // tree has now showered _currenttree->hasShowered(true); hardTree(HardTreePtr()); } void QTildeShowerHandler:: convertHardTree(bool hard,ShowerInteraction type) { map cmap; // incoming particles for(map::const_iterator cit=currentTree()->incomingLines().begin();cit!=currentTree()->incomingLines().end();++cit) { map::const_iterator mit = hardTree()->particles().find(cit->first->progenitor()); // put the colour lines in the map ShowerParticlePtr oldParticle = cit->first->progenitor(); ShowerParticlePtr newParticle = mit->second->branchingParticle(); ColinePtr cLine = oldParticle-> colourLine(); ColinePtr aLine = oldParticle->antiColourLine(); if(newParticle->colourLine() && cmap.find(newParticle-> colourLine())==cmap.end()) cmap[newParticle-> colourLine()] = cLine; if(newParticle->antiColourLine() && cmap.find(newParticle->antiColourLine())==cmap.end()) cmap[newParticle->antiColourLine()] = aLine; // check whether or not particle emits bool emission = mit->second->parent(); if(emission) { if(newParticle->colourLine()) { ColinePtr ctemp = newParticle-> colourLine(); ctemp->removeColoured(newParticle); } if(newParticle->antiColourLine()) { ColinePtr ctemp = newParticle->antiColourLine(); ctemp->removeAntiColoured(newParticle); } newParticle = mit->second->parent()->branchingParticle(); } // get the new colour lines ColinePtr newCLine,newALine; // sort out colour lines if(newParticle->colourLine()) { ColinePtr ctemp = newParticle-> colourLine(); ctemp->removeColoured(newParticle); if(cmap.find(ctemp)!=cmap.end()) { newCLine = cmap[ctemp]; } else { newCLine = new_ptr(ColourLine()); cmap[ctemp] = newCLine; } } // and anticolour lines if(newParticle->antiColourLine()) { ColinePtr ctemp = newParticle->antiColourLine(); ctemp->removeAntiColoured(newParticle); if(cmap.find(ctemp)!=cmap.end()) { newALine = cmap[ctemp]; } else { newALine = new_ptr(ColourLine()); cmap[ctemp] = newALine; } } // remove colour lines from old particle if(aLine) { aLine->removeAntiColoured(cit->first->copy()); aLine->removeAntiColoured(cit->first->progenitor()); } if(cLine) { cLine->removeColoured(cit->first->copy()); cLine->removeColoured(cit->first->progenitor()); } // add particle to colour lines if(newCLine) newCLine->addColoured (newParticle); if(newALine) newALine->addAntiColoured(newParticle); // insert new particles cit->first->copy(newParticle); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newParticle,1,false))); cit->first->progenitor(sp); currentTree()->incomingLines()[cit->first]=sp; cit->first->perturbative(!emission); // and the emitted particle if needed if(emission) { ShowerParticlePtr newOut = mit->second->parent()->children()[1]->branchingParticle(); if(newOut->colourLine()) { ColinePtr ctemp = newOut-> colourLine(); ctemp->removeColoured(newOut); assert(cmap.find(ctemp)!=cmap.end()); cmap[ctemp]->addColoured (newOut); } if(newOut->antiColourLine()) { ColinePtr ctemp = newOut->antiColourLine(); ctemp->removeAntiColoured(newOut); assert(cmap.find(ctemp)!=cmap.end()); cmap[ctemp]->addAntiColoured(newOut); } ShowerParticlePtr sout=new_ptr(ShowerParticle(*newOut,1,true)); ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(cit->first->original(),newOut,sout)); out->perturbative(false); currentTree()->outgoingLines().insert(make_pair(out,sout)); } if(hard) { // sort out the value of x if(mit->second->beam()->momentum().z()>ZERO) { sp->x(newParticle->momentum(). plus()/mit->second->beam()->momentum(). plus()); } else { sp->x(newParticle->momentum().minus()/mit->second->beam()->momentum().minus()); } } } // outgoing particles for(map::const_iterator cit=currentTree()->outgoingLines().begin();cit!=currentTree()->outgoingLines().end();++cit) { map >::const_iterator tit; for(tit = currentTree()->treelinks().begin(); tit != currentTree()->treelinks().end();++tit) { if(tit->second.first && tit->second.second==cit->first->progenitor()) break; } map::const_iterator mit = hardTree()->particles().find(cit->first->progenitor()); if(mit==hardTree()->particles().end()) continue; // put the colour lines in the map ShowerParticlePtr oldParticle = cit->first->progenitor(); ShowerParticlePtr newParticle = mit->second->branchingParticle(); ShowerParticlePtr newOut; ColinePtr cLine = oldParticle-> colourLine(); ColinePtr aLine = oldParticle->antiColourLine(); if(newParticle->colourLine() && cmap.find(newParticle-> colourLine())==cmap.end()) cmap[newParticle-> colourLine()] = cLine; if(newParticle->antiColourLine() && cmap.find(newParticle->antiColourLine())==cmap.end()) cmap[newParticle->antiColourLine()] = aLine; // check whether or not particle emits bool emission = !mit->second->children().empty(); if(emission) { if(newParticle->colourLine()) { ColinePtr ctemp = newParticle-> colourLine(); ctemp->removeColoured(newParticle); } if(newParticle->antiColourLine()) { ColinePtr ctemp = newParticle->antiColourLine(); ctemp->removeAntiColoured(newParticle); } newParticle = mit->second->children()[0]->branchingParticle(); newOut = mit->second->children()[1]->branchingParticle(); if(newParticle->id()!=oldParticle->id()&&newParticle->id()==newOut->id()) swap(newParticle,newOut); } // get the new colour lines ColinePtr newCLine,newALine; // sort out colour lines if(newParticle->colourLine()) { ColinePtr ctemp = newParticle-> colourLine(); ctemp->removeColoured(newParticle); if(cmap.find(ctemp)!=cmap.end()) { newCLine = cmap[ctemp]; } else { newCLine = new_ptr(ColourLine()); cmap[ctemp] = newCLine; } } // and anticolour lines if(newParticle->antiColourLine()) { ColinePtr ctemp = newParticle->antiColourLine(); ctemp->removeAntiColoured(newParticle); if(cmap.find(ctemp)!=cmap.end()) { newALine = cmap[ctemp]; } else { newALine = new_ptr(ColourLine()); cmap[ctemp] = newALine; } } // remove colour lines from old particle if(aLine) { aLine->removeAntiColoured(cit->first->copy()); aLine->removeAntiColoured(cit->first->progenitor()); } if(cLine) { cLine->removeColoured(cit->first->copy()); cLine->removeColoured(cit->first->progenitor()); } // special for unstable particles if(newParticle->id()==oldParticle->id() && (tit!=currentTree()->treelinks().end()||!oldParticle->dataPtr()->stable())) { Lorentz5Momentum oldMomentum = oldParticle->momentum(); Lorentz5Momentum newMomentum = newParticle->momentum(); LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass()); if(tit!=currentTree()->treelinks().end()) tit->first->transform(boost,false); oldParticle->transform(boost); boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass()); oldParticle->transform(boost); if(tit!=currentTree()->treelinks().end()) tit->first->transform(boost,false); newParticle=oldParticle; } // add particle to colour lines if(newCLine) newCLine->addColoured (newParticle); if(newALine) newALine->addAntiColoured(newParticle); // insert new particles cit->first->copy(newParticle); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newParticle,1,true))); cit->first->progenitor(sp); currentTree()->outgoingLines()[cit->first]=sp; cit->first->perturbative(!emission); // and the emitted particle if needed if(emission) { if(newOut->colourLine()) { ColinePtr ctemp = newOut-> colourLine(); ctemp->removeColoured(newOut); assert(cmap.find(ctemp)!=cmap.end()); cmap[ctemp]->addColoured (newOut); } if(newOut->antiColourLine()) { ColinePtr ctemp = newOut->antiColourLine(); ctemp->removeAntiColoured(newOut); assert(cmap.find(ctemp)!=cmap.end()); cmap[ctemp]->addAntiColoured(newOut); } ShowerParticlePtr sout=new_ptr(ShowerParticle(*newOut,1,true)); ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(cit->first->original(),newOut,sout)); out->perturbative(false); currentTree()->outgoingLines().insert(make_pair(out,sout)); } // update any decay products if(tit!=currentTree()->treelinks().end()) currentTree()->updateLink(tit->first,make_pair(cit->first,sp)); } // reset the tree currentTree()->resetShowerProducts(); // reextract the particles and set the colour partners vector particles = currentTree()->extractProgenitorParticles(); // clear the partners for(unsigned int ix=0;ixpartner(ShowerParticlePtr()); particles[ix]->clearPartners(); } // clear the tree hardTree(HardTreePtr()); // Set the initial evolution scales partnerFinder()-> setInitialEvolutionScales(particles,!hard,type,!_hardtree); } Branching QTildeShowerHandler::selectTimeLikeBranching(tShowerParticlePtr particle, ShowerInteraction type, HardBranchingPtr branch) { Branching fb; unsigned int iout=0; while (true) { // break if doing truncated shower and no truncated shower needed if(branch && (!isTruncatedShowerON()||hardOnly())) break; fb=_splittingGenerator->chooseForwardBranching(*particle,_finalenhance,type); // no emission break if(!fb.kinematics) break; // special for truncated shower if(branch) { // check haven't evolved too far if(fb.kinematics->scale() < branch->scale()) { fb=Branching(); break; } // find the truncated line iout=0; if(fb.ids[1]->id()!=fb.ids[2]->id()) { if(fb.ids[1]->id()==particle->id()) iout=1; else if (fb.ids[2]->id()==particle->id()) iout=2; } else if(fb.ids[1]->id()==particle->id()) { if(fb.kinematics->z()>0.5) iout=1; else iout=2; } // apply the vetos for the truncated shower // no flavour changing branchings if(iout==0) { particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } double zsplit = iout==1 ? fb.kinematics->z() : 1-fb.kinematics->z(); // only if same interaction for forced branching ShowerInteraction type2 = convertInteraction(fb.type); // and evolution if(type2==branch->sudakov()->interactionType()) { if(zsplit < 0.5 || // hardest line veto fb.kinematics->scale()*zsplit < branch->scale() ) { // angular ordering veto particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } } // pt veto if(fb.kinematics->pT() > progenitor()->maximumpT(type2)) { particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } } // standard vetos for all emissions if(timeLikeVetoed(fb,particle)) { particle->vetoEmission(fb.type,fb.kinematics->scale()); if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr()); continue; } // special for already decayed particles // don't allow flavour changing branchings bool vetoDecay = false; for(map >::const_iterator tit = currentTree()->treelinks().begin(); tit != currentTree()->treelinks().end();++tit) { if(tit->second.first == progenitor()) { map::const_iterator it = currentTree()->outgoingLines().find(progenitor()); if(it!=currentTree()->outgoingLines().end() && particle == it->second && fb.ids[0]!=fb.ids[1] && fb.ids[1]!=fb.ids[2]) { vetoDecay = true; break; } } } if(vetoDecay) { particle->vetoEmission(fb.type,fb.kinematics->scale()); if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr()); continue; } break; } // normal case if(!branch) { if(fb.kinematics) fb.hard = false; return fb; } // truncated emission if(fb.kinematics) { fb.hard = false; fb.iout = iout; return fb; } // otherwise need to return the hard emission // construct the kinematics for the hard emission ShoKinPtr showerKin = new_ptr(FS_QTildeShowerKinematics1to2( branch->scale(), branch->children()[0]->z(), branch->phi(), branch->children()[0]->pT(), branch->sudakov() )); IdList idlist(3); idlist[0] = particle->dataPtr(); idlist[1] = branch->children()[0]->branchingParticle()->dataPtr(); idlist[2] = branch->children()[1]->branchingParticle()->dataPtr(); fb = Branching( showerKin, idlist, branch->sudakov(),branch->type() ); fb.hard = true; fb.iout=0; // return it return fb; } Branching QTildeShowerHandler::selectSpaceLikeDecayBranching(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minmass,ShowerInteraction type, HardBranchingPtr branch) { Branching fb; unsigned int iout=0; while (true) { // break if doing truncated shower and no truncated shower needed if(branch && (!isTruncatedShowerON()||hardOnly())) break; // select branching fb=_splittingGenerator->chooseDecayBranching(*particle,maxScales,minmass, _initialenhance,type); // return if no radiation if(!fb.kinematics) break; // special for truncated shower if(branch) { // check haven't evolved too far if(fb.kinematics->scale() < branch->scale()) { fb=Branching(); break; } // find the truncated line iout=0; if(fb.ids[1]->id()!=fb.ids[2]->id()) { if(fb.ids[1]->id()==particle->id()) iout=1; else if (fb.ids[2]->id()==particle->id()) iout=2; } else if(fb.ids[1]->id()==particle->id()) { if(fb.kinematics->z()>0.5) iout=1; else iout=2; } // apply the vetos for the truncated shower // no flavour changing branchings if(iout==0) { particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } ShowerInteraction type2 = convertInteraction(fb.type); double zsplit = iout==1 ? fb.kinematics->z() : 1-fb.kinematics->z(); if(type2==branch->sudakov()->interactionType()) { if(zsplit < 0.5 || // hardest line veto fb.kinematics->scale()*zsplit < branch->scale() ) { // angular ordering veto particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } } // pt veto if(fb.kinematics->pT() > progenitor()->maximumpT(type2)) { particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } } // if not vetoed break if(spaceLikeDecayVetoed(fb,particle)) { // otherwise reset scale and continue particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } break; } // normal case if(!branch) { if(fb.kinematics) fb.hard = false; return fb; } // truncated emission if(fb.kinematics) { fb.hard = false; fb.iout = iout; return fb; } // otherwise need to return the hard emission // construct the kinematics for the hard emission ShoKinPtr showerKin = new_ptr(Decay_QTildeShowerKinematics1to2( branch->scale(), branch->children()[0]->z(), branch->phi(), branch->children()[0]->pT(), branch->sudakov())); IdList idlist(3); idlist[0] = particle->dataPtr(); idlist[1] = branch->children()[0]->branchingParticle()->dataPtr(); idlist[2] = branch->children()[1]->branchingParticle()->dataPtr(); // create the branching fb = Branching( showerKin, idlist, branch->sudakov(),ShowerPartnerType::QCDColourLine ); fb.hard=true; fb.iout=0; // return it return fb; } void QTildeShowerHandler::checkFlags() { string error = "Inconsistent hard emission set-up in QTildeShowerHandler::showerHardProcess(). "; if ( ( currentTree()->isMCatNLOSEvent() || currentTree()->isMCatNLOHEvent() ) ) { if (_hardEmission ==2 ) throw Exception() << error << "Cannot generate POWHEG matching with MC@NLO shower " << "approximation. Add 'set QTildeShowerHandler:HardEmission 0' to input file." << Exception::runerror; if ( canHandleMatchboxTrunc() ) throw Exception() << error << "Cannot use truncated qtilde shower with MC@NLO shower " << "approximation. Set LHCGenerator:EventHandler" << ":CascadeHandler to '/Herwig/Shower/ShowerHandler' or " << "'/Herwig/Shower/Dipole/DipoleShowerHandler'." << Exception::runerror; } else if ( ((currentTree()->isPowhegSEvent() || currentTree()->isPowhegHEvent()) ) && _hardEmission != 2){ if ( canHandleMatchboxTrunc()) throw Exception() << error << "Unmatched events requested for POWHEG shower " << "approximation. Set QTildeShowerHandler:HardEmission to " << "'POWHEG'." << Exception::runerror; else if (_hardEmissionWarn) { _hardEmissionWarn = false; _hardEmission=2; throw Exception() << error << "Unmatched events requested for POWHEG shower " << "approximation. Changing QTildeShowerHandler:HardEmission from " << _hardEmission << " to 2" << Exception::warning; } } if ( currentTree()->isPowhegSEvent() || currentTree()->isPowhegHEvent()) { if (currentTree()->showerApproximation()->needsTruncatedShower() && !canHandleMatchboxTrunc() ) throw Exception() << error << "Current shower handler cannot generate truncated shower. " << "Set Generator:EventHandler:CascadeHandler to " << "'/Herwig/Shower/PowhegShowerHandler'." << Exception::runerror; } else if ( currentTree()->truncatedShower() && _missingTruncWarn) { _missingTruncWarn=false; throw Exception() << "Warning: POWHEG shower approximation used without " << "truncated shower. Set Generator:EventHandler:" << "CascadeHandler to '/Herwig/Shower/PowhegShowerHandler' and " << "'MEMatching:TruncatedShower Yes'." << Exception::warning; } // else if ( !dipme && _hardEmissionMode > 1 && // firstInteraction()) // throw Exception() << error // << "POWHEG matching requested for LO events. Include " // << "'set Factory:ShowerApproximation MEMatching' in input file." // << Exception::runerror; } tPPair QTildeShowerHandler::remakeRemnant(tPPair oldp){ // get the parton extractor PartonExtractor & pex = *lastExtractor(); // get the new partons tPPair newp = make_pair(findFirstParton(oldp.first ), findFirstParton(oldp.second)); // if the same do nothing if(newp == oldp) return oldp; // Creates the new remnants and returns the new PartonBinInstances // ATTENTION Broken here for very strange configuration PBIPair newbins = pex.newRemnants(oldp, newp, newStep()); newStep()->addIntermediate(newp.first); newStep()->addIntermediate(newp.second); // return the new partons return newp; } PPtr QTildeShowerHandler::findFirstParton(tPPtr seed) const{ if(seed->parents().empty()) return seed; tPPtr parent = seed->parents()[0]; //if no parent there this is a loose end which will //be connected to the remnant soon. if(!parent || parent == incomingBeams().first || parent == incomingBeams().second ) return seed; else return findFirstParton(parent); } void QTildeShowerHandler::decay(ShowerTreePtr tree, ShowerDecayMap & decay) { // must be one incoming particle assert(tree->incomingLines().size()==1); // apply any transforms tree->applyTransforms(); // if already decayed return if(!tree->outgoingLines().empty()) return; // now we need to replace the particle with a new copy after the shower // find particle after the shower map >::const_iterator tit = tree->parent()->treelinks().find(tree); assert(tit!=tree->parent()->treelinks().end()); ShowerParticlePtr newparent=tit->second.second; PerturbativeProcessPtr newProcess = new_ptr(PerturbativeProcess()); newProcess->incoming().push_back(make_pair(newparent,PerturbativeProcessPtr())); DecayProcessMap decayMap; ShowerHandler::decay(newProcess,decayMap); ShowerTree::constructTrees(tree,decay,newProcess,decayMap); } namespace { ShowerProgenitorPtr findFinalStateLine(ShowerTreePtr tree, long id, Lorentz5Momentum momentum) { map::iterator partner; Energy2 dmin(1e30*GeV2); for(map::iterator cit =tree->outgoingLines().begin(); cit!=tree->outgoingLines().end(); ++cit) { if(cit->second->id()!=id) continue; Energy2 test = sqr(cit->second->momentum().x()-momentum.x())+ sqr(cit->second->momentum().y()-momentum.y())+ sqr(cit->second->momentum().z()-momentum.z())+ sqr(cit->second->momentum().t()-momentum.t()); if(testfirst; } ShowerProgenitorPtr findInitialStateLine(ShowerTreePtr tree, long id, Lorentz5Momentum momentum) { map::iterator partner; Energy2 dmin(1e30*GeV2); for(map::iterator cit =tree->incomingLines().begin(); cit!=tree->incomingLines().end(); ++cit) { if(cit->second->id()!=id) continue; Energy2 test = sqr(cit->second->momentum().x()-momentum.x())+ sqr(cit->second->momentum().y()-momentum.y())+ sqr(cit->second->momentum().z()-momentum.z())+ sqr(cit->second->momentum().t()-momentum.t()); if(testfirst; } void fixSpectatorColours(PPtr newSpect,ShowerProgenitorPtr oldSpect, ColinePair & cline,ColinePair & aline, bool reconnect) { cline.first = oldSpect->progenitor()->colourLine(); cline.second = newSpect->colourLine(); aline.first = oldSpect->progenitor()->antiColourLine(); aline.second = newSpect->antiColourLine(); if(!reconnect) return; if(cline.first) { cline.first ->removeColoured(oldSpect->copy()); cline.first ->removeColoured(oldSpect->progenitor()); cline.second->removeColoured(newSpect); cline.first ->addColoured(newSpect); } if(aline.first) { aline.first ->removeAntiColoured(oldSpect->copy()); aline.first ->removeAntiColoured(oldSpect->progenitor()); aline.second->removeAntiColoured(newSpect); aline.first ->addAntiColoured(newSpect); } } void fixInitialStateEmitter(ShowerTreePtr tree, PPtr newEmit,PPtr emitted, ShowerProgenitorPtr emitter, ColinePair cline,ColinePair aline,double x) { // sort out the colours if(emitted->dataPtr()->iColour()==PDT::Colour8) { // emitter if(cline.first && cline.first == emitter->progenitor()->antiColourLine() && cline.second !=newEmit->antiColourLine()) { // sort out not radiating line ColinePtr col = emitter->progenitor()->colourLine(); if(col) { col->removeColoured(emitter->copy()); col->removeColoured(emitter->progenitor()); newEmit->colourLine()->removeColoured(newEmit); col->addColoured(newEmit); } } else if(aline.first && aline.first == emitter->progenitor()->colourLine() && aline.second !=newEmit->colourLine()) { // sort out not radiating line ColinePtr anti = emitter->progenitor()->antiColourLine(); if(anti) { anti->removeAntiColoured(emitter->copy()); anti->removeAntiColoured(emitter->progenitor()); newEmit->colourLine()->removeAntiColoured(newEmit); anti->addAntiColoured(newEmit); } } else assert(false); // emitted if(cline.first && cline.second==emitted->colourLine()) { cline.second->removeColoured(emitted); cline.first->addColoured(emitted); } else if(aline.first && aline.second==emitted->antiColourLine()) { aline.second->removeAntiColoured(emitted); aline.first->addAntiColoured(emitted); } else assert(false); } else { if(emitter->progenitor()->antiColourLine() ) { ColinePtr col = emitter->progenitor()->antiColourLine(); col->removeAntiColoured(emitter->copy()); col->removeAntiColoured(emitter->progenitor()); if(newEmit->antiColourLine()) { newEmit->antiColourLine()->removeAntiColoured(newEmit); col->addAntiColoured(newEmit); } else if (emitted->colourLine()) { emitted->colourLine()->removeColoured(emitted); col->addColoured(emitted); } else assert(false); } if(emitter->progenitor()->colourLine() ) { ColinePtr col = emitter->progenitor()->colourLine(); col->removeColoured(emitter->copy()); col->removeColoured(emitter->progenitor()); if(newEmit->colourLine()) { newEmit->colourLine()->removeColoured(newEmit); col->addColoured(newEmit); } else if (emitted->antiColourLine()) { emitted->antiColourLine()->removeAntiColoured(emitted); col->addAntiColoured(emitted); } else assert(false); } } // update the emitter emitter->copy(newEmit); ShowerParticlePtr sp = new_ptr(ShowerParticle(*newEmit,1,false)); sp->x(x); emitter->progenitor(sp); tree->incomingLines()[emitter]=sp; emitter->perturbative(false); // add emitted sp=new_ptr(ShowerParticle(*emitted,1,true)); ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(emitter->original(),emitted,sp)); gluon->perturbative(false); tree->outgoingLines().insert(make_pair(gluon,sp)); } void fixFinalStateEmitter(ShowerTreePtr tree, PPtr newEmit,PPtr emitted, ShowerProgenitorPtr emitter, ColinePair cline,ColinePair aline) { map >::const_iterator tit; // special case if decayed for(tit = tree->treelinks().begin(); tit != tree->treelinks().end();++tit) { if(tit->second.first && tit->second.second==emitter->progenitor()) break; } // sort out the colour lines if(cline.first && cline.first == emitter->progenitor()->antiColourLine() && cline.second !=newEmit->antiColourLine()) { // sort out not radiating line ColinePtr col = emitter->progenitor()->colourLine(); if(col) { col->removeColoured(emitter->copy()); col->removeColoured(emitter->progenitor()); newEmit->colourLine()->removeColoured(newEmit); col->addColoured(newEmit); } } else if(aline.first && aline.first == emitter->progenitor()->colourLine() && aline.second !=newEmit->colourLine()) { // sort out not radiating line ColinePtr anti = emitter->progenitor()->antiColourLine(); if(anti) { anti->removeAntiColoured(emitter->copy()); anti->removeAntiColoured(emitter->progenitor()); newEmit->colourLine()->removeAntiColoured(newEmit); anti->addAntiColoured(newEmit); } } else assert(false); // update the emitter emitter->copy(newEmit); ShowerParticlePtr sp = new_ptr(ShowerParticle(*newEmit,1,true)); emitter->progenitor(sp); tree->outgoingLines()[emitter]=sp; emitter->perturbative(false); // update for decaying particles if(tit!=tree->treelinks().end()) tree->updateLink(tit->first,make_pair(emitter,sp)); // add the emitted particle // sort out the colour if(cline.first && cline.second==emitted->antiColourLine()) { cline.second->removeAntiColoured(emitted); cline.first->addAntiColoured(emitted); } else if(aline.first && aline.second==emitted->colourLine()) { aline.second->removeColoured(emitted); aline.first->addColoured(emitted); } else assert(false); sp=new_ptr(ShowerParticle(*emitted,1,true)); ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(emitter->original(), emitted,sp)); gluon->perturbative(false); tree->outgoingLines().insert(make_pair(gluon,sp)); } } void QTildeShowerHandler::setupMECorrection(RealEmissionProcessPtr real) { assert(real); // II emission if(real->emitter() < real->incoming().size() && real->spectator() < real->incoming().size()) { // recoiling system for( map::const_iterator cjt= currentTree()->outgoingLines().begin(); cjt != currentTree()->outgoingLines().end();++cjt ) { cjt->first->progenitor()->transform(real->transformation()); cjt->first->copy()->transform(real->transformation()); } // the the radiating system ShowerProgenitorPtr emitter,spectator; unsigned int iemit = real->emitter(); unsigned int ispect = real->spectator(); int ig = int(real->emitted())-int(real->incoming().size()); emitter = findInitialStateLine(currentTree(), real->bornIncoming()[iemit]->id(), real->bornIncoming()[iemit]->momentum()); spectator = findInitialStateLine(currentTree(), real->bornIncoming()[ispect]->id(), real->bornIncoming()[ispect]->momentum()); // sort out the colours ColinePair cline,aline; fixSpectatorColours(real->incoming()[ispect],spectator,cline,aline,true); // update the spectator spectator->copy(real->incoming()[ispect]); ShowerParticlePtr sp(new_ptr(ShowerParticle(*real->incoming()[ispect],1,false))); sp->x(ispect ==0 ? real->x().first :real->x().second); spectator->progenitor(sp); currentTree()->incomingLines()[spectator]=sp; spectator->perturbative(true); // now for the emitter fixInitialStateEmitter(currentTree(),real->incoming()[iemit],real->outgoing()[ig], emitter,cline,aline,iemit ==0 ? real->x().first :real->x().second); } // FF emission else if(real->emitter() >= real->incoming().size() && real->spectator() >= real->incoming().size()) { assert(real->outgoing()[real->emitted()-real->incoming().size()]->id()==ParticleID::g); // find the emitter and spectator in the shower tree ShowerProgenitorPtr emitter,spectator; int iemit = int(real->emitter())-int(real->incoming().size()); emitter = findFinalStateLine(currentTree(), real->bornOutgoing()[iemit]->id(), real->bornOutgoing()[iemit]->momentum()); int ispect = int(real->spectator())-int(real->incoming().size()); spectator = findFinalStateLine(currentTree(), real->bornOutgoing()[ispect]->id(), real->bornOutgoing()[ispect]->momentum()); map >::const_iterator tit; // first the spectator // special case if decayed for(tit = currentTree()->treelinks().begin(); tit != currentTree()->treelinks().end();++tit) { if(tit->second.first && tit->second.second==spectator->progenitor()) break; } // sort out the colours ColinePair cline,aline; fixSpectatorColours(real->outgoing()[ispect],spectator,cline,aline,true); // update the spectator spectator->copy(real->outgoing()[ispect]); ShowerParticlePtr sp(new_ptr(ShowerParticle(*real->outgoing()[ispect],1,true))); spectator->progenitor(sp); currentTree()->outgoingLines()[spectator]=sp; spectator->perturbative(true); // update for decaying particles if(tit!=currentTree()->treelinks().end()) currentTree()->updateLink(tit->first,make_pair(spectator,sp)); // now the emitting particle int ig = int(real->emitted())-int(real->incoming().size()); fixFinalStateEmitter(currentTree(),real->outgoing()[iemit], real->outgoing()[ig], emitter,cline,aline); } // IF emission else { // scattering process if(real->incoming().size()==2) { ShowerProgenitorPtr emitter,spectator; unsigned int iemit = real->emitter(); unsigned int ispect = real->spectator(); int ig = int(real->emitted())-int(real->incoming().size()); ColinePair cline,aline; // incoming spectator if(ispect<2) { spectator = findInitialStateLine(currentTree(), real->bornIncoming()[ispect]->id(), real->bornIncoming()[ispect]->momentum()); fixSpectatorColours(real->incoming()[ispect],spectator,cline,aline,true); // update the spectator spectator->copy(real->incoming()[ispect]); ShowerParticlePtr sp(new_ptr(ShowerParticle(*real->incoming()[ispect],1,false))); sp->x(ispect ==0 ? real->x().first :real->x().second); spectator->progenitor(sp); currentTree()->incomingLines()[spectator]=sp; spectator->perturbative(true); } // outgoing spectator else { spectator = findFinalStateLine(currentTree(), real->bornOutgoing()[ispect-real->incoming().size()]->id(), real->bornOutgoing()[ispect-real->incoming().size()]->momentum()); // special case if decayed map >::const_iterator tit; for(tit = currentTree()->treelinks().begin(); tit != currentTree()->treelinks().end();++tit) { if(tit->second.first && tit->second.second==spectator->progenitor()) break; } fixSpectatorColours(real->outgoing()[ispect-real->incoming().size()],spectator,cline,aline,true); // update the spectator spectator->copy(real->outgoing()[ispect-real->incoming().size()]); ShowerParticlePtr sp(new_ptr(ShowerParticle(*real->outgoing()[ispect-real->incoming().size()],1,true))); spectator->progenitor(sp); currentTree()->outgoingLines()[spectator]=sp; spectator->perturbative(true); // update for decaying particles if(tit!=currentTree()->treelinks().end()) currentTree()->updateLink(tit->first,make_pair(spectator,sp)); } // incoming emitter if(iemit<2) { emitter = findInitialStateLine(currentTree(), real->bornIncoming()[iemit]->id(), real->bornIncoming()[iemit]->momentum()); fixInitialStateEmitter(currentTree(),real->incoming()[iemit],real->outgoing()[ig], emitter,aline,cline,iemit ==0 ? real->x().first :real->x().second); } // outgoing emitter else { emitter = findFinalStateLine(currentTree(), real->bornOutgoing()[iemit-real->incoming().size()]->id(), real->bornOutgoing()[iemit-real->incoming().size()]->momentum()); fixFinalStateEmitter(currentTree(),real->outgoing()[iemit-real->incoming().size()], real->outgoing()[ig],emitter,aline,cline); } } // decay process else { assert(real->spectator()==0); unsigned int iemit = real->emitter()-real->incoming().size(); int ig = int(real->emitted())-int(real->incoming().size()); ColinePair cline,aline; // incoming spectator ShowerProgenitorPtr spectator = findInitialStateLine(currentTree(), real->bornIncoming()[0]->id(), real->bornIncoming()[0]->momentum()); fixSpectatorColours(real->incoming()[0],spectator,cline,aline,false); // find the emitter ShowerProgenitorPtr emitter = findFinalStateLine(currentTree(), real->bornOutgoing()[iemit]->id(), real->bornOutgoing()[iemit]->momentum()); // recoiling system for( map::const_iterator cjt= currentTree()->outgoingLines().begin(); cjt != currentTree()->outgoingLines().end();++cjt ) { if(cjt->first==emitter) continue; cjt->first->progenitor()->transform(real->transformation()); cjt->first->copy()->transform(real->transformation()); } // sort out the emitter fixFinalStateEmitter(currentTree(),real->outgoing()[iemit], real->outgoing()[ig],emitter,aline,cline); } } // clean up the shower tree _currenttree->resetShowerProducts(); } diff --git a/Shower/QTilde/QTildeShowerHandler.h b/Shower/QTilde/QTildeShowerHandler.h --- a/Shower/QTilde/QTildeShowerHandler.h +++ b/Shower/QTilde/QTildeShowerHandler.h @@ -1,858 +1,846 @@ // -*- C++ -*- #ifndef Herwig_QTildeShowerHandler_H #define Herwig_QTildeShowerHandler_H // // This is the declaration of the QTildeShowerHandler class. // #include "QTildeShowerHandler.fh" #include "Herwig/Shower/ShowerHandler.h" #include "Herwig/Shower/QTilde/SplittingFunctions/SplittingGenerator.h" #include "Herwig/Shower/QTilde/Base/ShowerTree.h" #include "Herwig/Shower/QTilde/Base/ShowerProgenitor.fh" #include "Herwig/Shower/QTilde/Base/HardTree.h" #include "Herwig/Shower/QTilde/Base/Branching.h" #include "Herwig/Shower/QTilde/Base/ShowerVeto.h" #include "Herwig/Shower/QTilde/Base/FullShowerVeto.h" #include "Herwig/Shower/QTilde/Kinematics/KinematicsReconstructor.fh" #include "Herwig/Shower/QTilde/Base/PartnerFinder.fh" #include "Herwig/Shower/QTilde/SplittingFunctions/SudakovFormFactor.fh" #include "Herwig/MatrixElement/HwMEBase.h" #include "Herwig/Decay/HwDecayerBase.h" #include "Herwig/MatrixElement/Matchbox/Matching/ShowerApproximation.h" #include "Herwig/Shower/RealEmissionProcess.h" #include "Herwig/Utilities/Statistic.h" namespace Herwig { using namespace ThePEG; /** * The QTildeShowerHandler class. * * @see \ref QTildeShowerHandlerInterfaces "The interfaces" * defined for QTildeShowerHandler. */ class QTildeShowerHandler: public ShowerHandler { public: /** * Pointer to an XComb object */ typedef Ptr::pointer XCPtr; public: /** @name Standard constructors and destructors. */ //@{ /** * The default constructor. */ QTildeShowerHandler(); /** * The destructor. */ virtual ~QTildeShowerHandler(); //@} public: /** * At the end of the Showering, transform ShowerParticle objects * into ThePEG particles and fill the event record with them. * Notice that the parent/child relationships and the * transformation from ShowerColourLine objects into ThePEG * ColourLine ones must be properly handled. */ void fillEventRecord(); /** * Return the relevant hard scale to be used in the profile scales */ virtual Energy hardScale() const { return muPt; } /** * Hook to allow vetoing of event after showering hard sub-process * as in e.g. MLM merging. */ virtual bool showerHardProcessVeto() const { return false; } /** * Generate hard emissions for CKKW etc */ virtual HardTreePtr generateCKKW(ShowerTreePtr tree) const; /** * Members to perform the shower */ //@{ /** * Perform the shower of the hard process */ virtual void showerHardProcess(ShowerTreePtr,XCPtr); /** * Perform the shower of a decay */ virtual void showerDecay(ShowerTreePtr); //@} /** * Access to the flags and shower variables */ //@{ /** * Get the SplittingGenerator */ tSplittingGeneratorPtr splittingGenerator() const { return _splittingGenerator; } /** * Mode for hard emissions */ int hardEmission() const {return _hardEmission;} //@} /** * Connect the Hard and Shower trees */ virtual void connectTrees(ShowerTreePtr showerTree, HardTreePtr hardTree, bool hard ); /** * Access to switches for spin correlations */ //@{ /** - * Spin Correlations - */ - unsigned int spinCorrelations() const { - return _spinOpt; - } - - /** * Soft correlations */ unsigned int softCorrelations() const { return _softOpt; } /** * Any correlations */ - bool correlations() const { - return _spinOpt!=0||_softOpt!=0; + virtual bool correlations() const { + return spinCorrelations()!=0||_softOpt!=0; } //@} public: /** * Access methods to access the objects */ //@{ /** * Access to the KinematicsReconstructor object */ tKinematicsReconstructorPtr kinematicsReconstructor() const { return _reconstructor; } /** * Access to the PartnerFinder object */ tPartnerFinderPtr partnerFinder() const { return _partnerfinder; } //@} protected: /** * Perform the shower */ void doShowering(bool hard,XCPtr); /** * Generate the hard matrix element correction */ virtual RealEmissionProcessPtr hardMatrixElementCorrection(bool); /** * Generate the hardest emission */ virtual void hardestEmission(bool hard); /** * Set up for applying a matrix element correction */ void setupMECorrection(RealEmissionProcessPtr real); /** * Extract the particles to be showered, set the evolution scales * and apply the hard matrix element correction * @param hard Whether this is a hard process or decay * @return The particles to be showered */ virtual vector setupShower(bool hard); /** * set the colour partners */ virtual void setEvolutionPartners(bool hard,ShowerInteraction, bool clear); /** * Methods to perform the evolution of an individual particle, including * recursive calling on the products */ //@{ /** * It does the forward evolution of the time-like input particle * (and recursively for all its radiation products). * accepting only emissions which conforms to the showerVariables * and soft matrix element correction. * If at least one emission has occurred then the method returns true. * @param particle The particle to be showered */ virtual bool timeLikeShower(tShowerParticlePtr particle, ShowerInteraction, Branching fb, bool first); /** * It does the backward evolution of the space-like input particle * (and recursively for all its time-like radiation products). * accepting only emissions which conforms to the showerVariables. * If at least one emission has occurred then the method returns true * @param particle The particle to be showered * @param beam The beam particle */ virtual bool spaceLikeShower(tShowerParticlePtr particle,PPtr beam, ShowerInteraction); /** * If does the forward evolution of the input on-shell particle * involved in a decay * (and recursively for all its time-like radiation products). * accepting only emissions which conforms to the showerVariables. * @param particle The particle to be showered * @param maxscale The maximum scale for the shower. * @param minimumMass The minimum mass of the final-state system */ virtual bool spaceLikeDecayShower(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minimumMass,ShowerInteraction, Branching fb); /** * Truncated shower from a time-like particle */ virtual bool truncatedTimeLikeShower(tShowerParticlePtr particle, HardBranchingPtr branch, ShowerInteraction type, Branching fb, bool first); /** * Truncated shower from a space-like particle */ virtual bool truncatedSpaceLikeShower(tShowerParticlePtr particle,PPtr beam, HardBranchingPtr branch, ShowerInteraction type); /** * Truncated shower from a time-like particle */ virtual bool truncatedSpaceLikeDecayShower(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minimumMass, HardBranchingPtr branch, ShowerInteraction type, Branching fb); //@} /** * Switches for matrix element corrections */ //@{ /** * Any ME correction? */ bool MECOn() const { return _hardEmission == 1; } /** * Any hard ME correction? */ bool hardMEC() const { return _hardEmission == 1 && (_meCorrMode == 1 || _meCorrMode == 2); } /** * Any soft ME correction? */ bool softMEC() const { return _hardEmission == 1 && (_meCorrMode == 1 || _meCorrMode > 2); } //@} /** * Is the truncated shower on? */ bool isTruncatedShowerON() const {return _trunc_Mode;} /** * Switch for intrinsic pT */ //@{ /** * Any intrinsic pT? */ bool ipTon() const { return _iptrms != ZERO || ( _beta == 1.0 && _gamma != ZERO && _iptmax !=ZERO ); } //@} /**@name Additional shower vetoes */ //@{ /** * Insert a veto. */ void addVeto (ShowerVetoPtr v) { _vetoes.push_back(v); } /** * Remove a veto. */ void removeVeto (ShowerVetoPtr v) { vector::iterator vit = find(_vetoes.begin(),_vetoes.end(),v); if (vit != _vetoes.end()) _vetoes.erase(vit); } //@} /** * Switches for vetoing hard emissions */ //@{ /** * Returns true if the hard veto read-in is to be applied to only * the primary collision and false otherwise. */ bool hardVetoReadOption() const {return _hardVetoReadOption;} //@} /** * Enhancement factors for radiation needed to generate the soft matrix * element correction. */ //@{ /** * Access the enhancement factor for initial-state radiation */ double initialStateRadiationEnhancementFactor() const { return _initialenhance; } /** * Access the enhancement factor for final-state radiation */ double finalStateRadiationEnhancementFactor() const { return _finalenhance; } /** * Set the enhancement factor for initial-state radiation */ void initialStateRadiationEnhancementFactor(double in) { _initialenhance=in; } /** * Set the enhancement factor for final-state radiation */ void finalStateRadiationEnhancementFactor(double in) { _finalenhance=in; } //@} /** * Access to set/get the HardTree currently beinging showered */ //@{ /** * The HardTree currently being showered */ tHardTreePtr hardTree() {return _hardtree;} /** * The HardTree currently being showered */ void hardTree(tHardTreePtr in) {_hardtree = in;} //@} /** * Access/set the beam particle for the current initial-state shower */ //@{ /** * Get the beam particle data */ Ptr::const_pointer beamParticle() const { return _beam; } /** * Set the beam particle data */ void setBeamParticle(Ptr::const_pointer in) { _beam=in; } //@} /** * Set/Get the current tree being evolver for inheriting classes */ //@{ /** * Get the tree */ tShowerTreePtr currentTree() { return _currenttree; } /** * Set the tree */ void currentTree(tShowerTreePtr tree) { _currenttree=tree; } //@} /** * Access the maximum number of attempts to generate the shower */ unsigned int maximumTries() const { return _maxtry; } /** * Set/Get the ShowerProgenitor for the current shower */ //@{ /** * Access the progenitor */ ShowerProgenitorPtr progenitor() { return _progenitor; } /** * Set the progenitor */ void progenitor(ShowerProgenitorPtr in) { _progenitor=in; } //@} /** * Calculate the intrinsic \f$p_T\f$. */ virtual void generateIntrinsicpT(vector); /** * Access to the intrinsic \f$p_T\f$ for inheriting classes */ map > & intrinsicpT() { return _intrinsic; } /** * find the maximally allowed pt acc to the hard process. */ void setupMaximumScales(const vector &,XCPtr); /** * find the relevant hard scales for profile scales. */ void setupHardScales(const vector &,XCPtr); /** * Convert the HardTree into an extra shower emission */ void convertHardTree(bool hard,ShowerInteraction type); protected: /** * Find the parton extracted from the incoming particle after ISR */ PPtr findFirstParton(tPPtr seed) const; /** * Fix Remnant connections after ISR */ tPPair remakeRemnant(tPPair oldp); protected: /** * Start the shower of a timelike particle */ virtual bool startTimeLikeShower(ShowerInteraction); /** * Update of the time-like stuff */ void updateHistory(tShowerParticlePtr particle); /** * Start the shower of a spacelike particle */ virtual bool startSpaceLikeShower(PPtr,ShowerInteraction); /** * Start the shower of a spacelike particle */ virtual bool startSpaceLikeDecayShower(const ShowerParticle::EvolutionScales & maxScales, Energy minimumMass,ShowerInteraction); /** * Select the branching for the next time-like emission */ Branching selectTimeLikeBranching(tShowerParticlePtr particle, ShowerInteraction type, HardBranchingPtr branch); /** * Select the branching for the next space-like emission in a decay */ Branching selectSpaceLikeDecayBranching(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minmass,ShowerInteraction type, HardBranchingPtr branch); /** * Create the timelike child of a branching */ ShowerParticleVector createTimeLikeChildren(tShowerParticlePtr particle, IdList ids); /** * Vetos for the timelike shower */ virtual bool timeLikeVetoed(const Branching &,ShowerParticlePtr); /** * Vetos for the spacelike shower */ virtual bool spaceLikeVetoed(const Branching &,ShowerParticlePtr); /** * Vetos for the spacelike shower */ virtual bool spaceLikeDecayVetoed(const Branching &,ShowerParticlePtr); /** * Only generate the hard emission, for testing only. */ bool hardOnly() const {return _limitEmissions==3;} /** * Check the flags */ void checkFlags(); /** * */ void addFSRUsingDecayPOWHEG(HardTreePtr ISRTree); 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: /** * The main method which manages the showering of a subprocess. */ virtual tPPair cascade(tSubProPtr sub, XCPtr xcomb); /** * Decay a ShowerTree */ void decay(ShowerTreePtr tree, ShowerDecayMap & decay); protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const; /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const; //@} protected: /** * 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(); /** * Initialize this object. Called in the run phase just before * a run begins. */ virtual void doinitrun(); //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ QTildeShowerHandler & operator=(const QTildeShowerHandler &); private: /** * Stuff from the ShowerHandler */ //@{ /** * The ShowerTree for the hard process */ ShowerTreePtr hard_; /** * The ShowerTree for the decays */ ShowerDecayMap decay_; /** * The ShowerTrees for which the initial shower */ vector done_; //@} private : /** * Pointer to the splitting generator */ SplittingGeneratorPtr _splittingGenerator; /** * Maximum number of tries to generate the shower of a particular tree */ unsigned int _maxtry; /** * Matrix element correction switch */ unsigned int _meCorrMode; /** * Control of the reconstruction option */ unsigned int _reconOpt; /** * If hard veto pT scale is being read-in this determines * whether the read-in value is applied to primary and * secondary (MPI) scatters or just the primary one, with * the usual computation of the veto being performed for * the secondary (MPI) scatters. */ bool _hardVetoReadOption; /** * rms intrinsic pT of Gaussian distribution */ Energy _iptrms; /** * Proportion of inverse quadratic intrinsic pT distribution */ double _beta; /** * Parameter for inverse quadratic: 2*Beta*Gamma/(sqr(Gamma)+sqr(intrinsicpT)) */ Energy _gamma; /** * Upper bound on intrinsic pT for inverse quadratic */ Energy _iptmax; /** * Limit the number of emissions for testing */ unsigned int _limitEmissions; /** * The progenitor of the current shower */ ShowerProgenitorPtr _progenitor; /** * Matrix element */ HwMEBasePtr _hardme; /** * Decayer */ HwDecayerBasePtr _decayme; /** * The ShowerTree currently being showered */ ShowerTreePtr _currenttree; /** * The HardTree currently being showered */ HardTreePtr _hardtree; /** * Radiation enhancement factors for use with the veto algorithm * if needed by the soft matrix element correction */ //@{ /** * Enhancement factor for initial-state radiation */ double _initialenhance; /** * Enhancement factor for final-state radiation */ double _finalenhance; //@} /** * The beam particle data for the current initial-state shower */ Ptr::const_pointer _beam; /** * Storage of the intrinsic \f$p_t\f$ of the particles */ map > _intrinsic; /** * Vetoes */ vector _vetoes; /** * Full Shower Vetoes */ vector _fullShowerVetoes; /** * Number of iterations for reweighting */ unsigned int _nReWeight; /** * Whether or not we are reweighting */ bool _reWeight; /** * number of IS emissions */ unsigned int _nis; /** * Number of FS emissions */ unsigned int _nfs; /** * The option for wqhich interactions to use */ ShowerInteraction interaction_; /** * Truncated shower switch */ bool _trunc_Mode; /** * Count of the number of truncated emissions */ unsigned int _truncEmissions; /** * Mode for the hard emissions */ int _hardEmission; /** - * Option to include spin correlations - */ - unsigned int _spinOpt; - - /** * Option for the kernal for soft correlations */ unsigned int _softOpt; /** * Option for hard radiation in POWHEG events */ bool _hardPOWHEG; /** * True if no warnings about incorrect hard emission * mode setting have been issued yet */ static bool _hardEmissionWarn; /** * True if no warnings about missing truncated shower * have been issued yet */ static bool _missingTruncWarn; /** * The relevant hard scale to be used in the profile scales */ Energy muPt; private: /** * Pointer to the various objects */ //@{ /** * Pointer to the KinematicsReconstructor object */ KinematicsReconstructorPtr _reconstructor; /** * Pointer to the PartnerFinder object */ PartnerFinderPtr _partnerfinder; //@} }; } #endif /* HERWIG_QTildeShowerHandler_H */ diff --git a/Shower/ShowerHandler.cc b/Shower/ShowerHandler.cc --- a/Shower/ShowerHandler.cc +++ b/Shower/ShowerHandler.cc @@ -1,1097 +1,1114 @@ // -*- C++ -*- // // ShowerHandler.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 ShowerHandler class. // #include "ShowerHandler.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/ParVector.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Command.h" #include "ThePEG/PDF/PartonExtractor.h" #include "ThePEG/PDF/PartonBinInstance.h" #include "Herwig/PDT/StandardMatchers.h" #include "ThePEG/Cuts/Cuts.h" #include "ThePEG/Handlers/StandardXComb.h" #include "ThePEG/Utilities/Throw.h" #include "ThePEG/Utilities/StringUtils.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Repository/EventGenerator.h" #include "Herwig/Utilities/EnumParticles.h" #include "Herwig/PDF/MPIPDF.h" #include "Herwig/PDF/MinBiasPDF.h" #include "ThePEG/Handlers/EventHandler.h" #include "Herwig/PDF/HwRemDecayer.h" #include #include "ThePEG/Utilities/DescribeClass.h" #include "Herwig/Decay/DecayIntegrator.h" #include "Herwig/Decay/DecayPhaseSpaceMode.h" using namespace Herwig; DescribeClass describeShowerHandler ("Herwig::ShowerHandler","HwShower.so"); ShowerHandler::~ShowerHandler() {} tShowerHandlerPtr ShowerHandler::currentHandler_ = tShowerHandlerPtr(); void ShowerHandler::doinit() { CascadeHandler::doinit(); // copy particles to decay before showering from input vector to the // set used in the simulation if ( particlesDecayInShower_.empty() ) { for(unsigned int ix=0;ixunrestrictedPhasespace() && restrictPhasespace() ) { generator()->log() << "ShowerApproximation warning: The scale profile chosen requires an unrestricted phase space,\n" << "however, the phase space was set to be restricted. Will switch to unrestricted phase space.\n" << flush; restrictPhasespace_ = false; } } } IBPtr ShowerHandler::clone() const { return new_ptr(*this); } IBPtr ShowerHandler::fullclone() const { return new_ptr(*this); } ShowerHandler::ShowerHandler() : maxtry_(10),maxtryMPI_(10),maxtryDP_(10),maxtryDecay_(100), factorizationScaleFactor_(1.0), renormalizationScaleFactor_(1.0), hardScaleFactor_(1.0), restrictPhasespace_(true), maxPtIsMuF_(false), - pdfFreezingScale_(2.5*GeV), + spinOpt_(1), pdfFreezingScale_(2.5*GeV), doFSR_(true), doISR_(true), splitHardProcess_(true), includeSpaceTime_(false), vMin_(0.1*GeV2), reweight_(1.0) { inputparticlesDecayInShower_.push_back( 6 ); // top inputparticlesDecayInShower_.push_back( 23 ); // Z0 inputparticlesDecayInShower_.push_back( 24 ); // W+/- inputparticlesDecayInShower_.push_back( 25 ); // h0 } void ShowerHandler::doinitrun(){ CascadeHandler::doinitrun(); //can't use isMPIOn here, because the EventHandler is not set at that stage if(MPIHandler_) { MPIHandler_->initialize(); if(MPIHandler_->softInt()) remDec_->initSoftInteractions(MPIHandler_->Ptmin(), MPIHandler_->beta()); } } void ShowerHandler::dofinish() { CascadeHandler::dofinish(); if(MPIHandler_) MPIHandler_->finalize(); } void ShowerHandler::persistentOutput(PersistentOStream & os) const { os << remDec_ << ounit(pdfFreezingScale_,GeV) << maxtry_ << maxtryMPI_ << maxtryDP_ << maxtryDecay_ << inputparticlesDecayInShower_ << particlesDecayInShower_ << MPIHandler_ << PDFA_ << PDFB_ << PDFARemnant_ << PDFBRemnant_ << includeSpaceTime_ << ounit(vMin_,GeV2) << factorizationScaleFactor_ << renormalizationScaleFactor_ << hardScaleFactor_ << restrictPhasespace_ << maxPtIsMuF_ << hardScaleProfile_ - << showerVariations_ << doFSR_ << doISR_ << splitHardProcess_; + << showerVariations_ << doFSR_ << doISR_ << splitHardProcess_ + << spinOpt_; } void ShowerHandler::persistentInput(PersistentIStream & is, int) { is >> remDec_ >> iunit(pdfFreezingScale_,GeV) >> maxtry_ >> maxtryMPI_ >> maxtryDP_ >> maxtryDecay_ >> inputparticlesDecayInShower_ >> particlesDecayInShower_ >> MPIHandler_ >> PDFA_ >> PDFB_ >> PDFARemnant_ >> PDFBRemnant_ >> includeSpaceTime_ >> iunit(vMin_,GeV2) >> factorizationScaleFactor_ >> renormalizationScaleFactor_ >> hardScaleFactor_ >> restrictPhasespace_ >> maxPtIsMuF_ >> hardScaleProfile_ - >> showerVariations_ >> doFSR_ >> doISR_ >> splitHardProcess_; + >> showerVariations_ >> doFSR_ >> doISR_ >> splitHardProcess_ + >> spinOpt_; } void ShowerHandler::Init() { static ClassDocumentation documentation ("Main driver class for the showering."); static Reference interfaceRemDecayer("RemDecayer", "A reference to the Remnant Decayer object", &Herwig::ShowerHandler::remDec_, false, false, true, false); static Parameter interfacePDFFreezingScale ("PDFFreezingScale", "The PDF freezing scale", &ShowerHandler::pdfFreezingScale_, GeV, 2.5*GeV, 2.0*GeV, 10.0*GeV, false, false, Interface::limited); static Parameter interfaceMaxTry ("MaxTry", "The maximum number of attempts for the main showering loop", &ShowerHandler::maxtry_, 10, 1, 100, false, false, Interface::limited); static Parameter interfaceMaxTryMPI ("MaxTryMPI", "The maximum number of regeneration attempts for an additional scattering", &ShowerHandler::maxtryMPI_, 10, 0, 100, false, false, Interface::limited); static Parameter interfaceMaxTryDP ("MaxTryDP", "The maximum number of regeneration attempts for an additional hard scattering", &ShowerHandler::maxtryDP_, 10, 0, 100, false, false, Interface::limited); static ParVector interfaceDecayInShower ("DecayInShower", "PDG codes of the particles to be decayed in the shower", &ShowerHandler::inputparticlesDecayInShower_, -1, 0l, -10000000l, 10000000l, false, false, Interface::limited); static Reference interfaceMPIHandler ("MPIHandler", "The object that administers all additional scatterings.", &ShowerHandler::MPIHandler_, false, false, true, true); static Reference interfacePDFA ("PDFA", "The PDF for beam particle A. Overrides the particle's own PDF setting." "By default used for both the shower and forced splitting in the remnant", &ShowerHandler::PDFA_, false, false, true, true, false); static Reference interfacePDFB ("PDFB", "The PDF for beam particle B. Overrides the particle's own PDF setting." "By default used for both the shower and forced splitting in the remnant", &ShowerHandler::PDFB_, false, false, true, true, false); static Reference interfacePDFARemnant ("PDFARemnant", "The PDF for beam particle A used to generate forced splittings of the remnant." " This overrides both the particle's own PDF setting and the value set by PDFA if used.", &ShowerHandler::PDFARemnant_, false, false, true, true, false); static Reference interfacePDFBRemnant ("PDFBRemnant", "The PDF for beam particle B used to generate forced splittings of the remnant." " This overrides both the particle's own PDF setting and the value set by PDFB if used.", &ShowerHandler::PDFBRemnant_, false, false, true, true, false); static Switch interfaceIncludeSpaceTime ("IncludeSpaceTime", "Whether to include the model for the calculation of space-time distances", &ShowerHandler::includeSpaceTime_, false, false, false); static SwitchOption interfaceIncludeSpaceTimeYes (interfaceIncludeSpaceTime, "Yes", "Include the model", true); static SwitchOption interfaceIncludeSpaceTimeNo (interfaceIncludeSpaceTime, "No", "Only include the displacement from the particle-s lifetime for decaying particles", false); static Parameter interfaceMinimumVirtuality ("MinimumVirtuality", "The minimum virtuality for the space-time model", &ShowerHandler::vMin_, GeV2, 0.1*GeV2, 0.0*GeV2, 1000.0*GeV2, false, false, Interface::limited); static Parameter interfaceFactorizationScaleFactor ("FactorizationScaleFactor", "The factorization scale factor.", &ShowerHandler::factorizationScaleFactor_, 1.0, 0.0, 0, false, false, Interface::lowerlim); static Parameter interfaceRenormalizationScaleFactor ("RenormalizationScaleFactor", "The renormalization scale factor.", &ShowerHandler::renormalizationScaleFactor_, 1.0, 0.0, 0, false, false, Interface::lowerlim); static Parameter interfaceHardScaleFactor ("HardScaleFactor", "The hard scale factor.", &ShowerHandler::hardScaleFactor_, 1.0, 0.0, 0, false, false, Interface::lowerlim); static Parameter interfaceMaxTryDecay ("MaxTryDecay", "The maximum number of attempts to generate a decay", &ShowerHandler::maxtryDecay_, 200, 10, 0, false, false, Interface::lowerlim); static Reference interfaceHardScaleProfile ("HardScaleProfile", "The hard scale profile to use.", &ShowerHandler::hardScaleProfile_, false, false, true, true, false); static Switch interfaceMaxPtIsMuF ("MaxPtIsMuF", "", &ShowerHandler::maxPtIsMuF_, false, false, false); static SwitchOption interfaceMaxPtIsMuFYes (interfaceMaxPtIsMuF, "Yes", "", true); static SwitchOption interfaceMaxPtIsMuFNo (interfaceMaxPtIsMuF, "No", "", false); static Switch interfaceRestrictPhasespace ("RestrictPhasespace", "Switch on or off phasespace restrictions", &ShowerHandler::restrictPhasespace_, true, false, false); static SwitchOption interfaceRestrictPhasespaceYes (interfaceRestrictPhasespace, "Yes", "Perform phasespace restrictions", true); static SwitchOption interfaceRestrictPhasespaceNo (interfaceRestrictPhasespace, "No", "Do not perform phasespace restrictions", false); static Command interfaceAddVariation ("AddVariation", "Add a shower variation.", &ShowerHandler::doAddVariation, false); static Switch interfaceDoFSR ("DoFSR", "Switch on or off final state radiation.", &ShowerHandler::doFSR_, true, false, false); static SwitchOption interfaceDoFSRYes (interfaceDoFSR, "Yes", "Switch on final state radiation.", true); static SwitchOption interfaceDoFSRNo (interfaceDoFSR, "No", "Switch off final state radiation.", false); static Switch interfaceDoISR ("DoISR", "Switch on or off initial state radiation.", &ShowerHandler::doISR_, true, false, false); static SwitchOption interfaceDoISRYes (interfaceDoISR, "Yes", "Switch on initial state radiation.", true); static SwitchOption interfaceDoISRNo (interfaceDoISR, "No", "Switch off initial state radiation.", false); static Switch interfaceSplitHardProcess ("SplitHardProcess", "Whether or not to try and split the hard process into production and decay processes", &ShowerHandler::splitHardProcess_, true, false, false); static SwitchOption interfaceSplitHardProcessYes (interfaceSplitHardProcess, "Yes", "Split the hard process", true); static SwitchOption interfaceSplitHardProcessNo (interfaceSplitHardProcess, "No", "Don't split the hard process", false); + + static Switch interfaceSpinCorrelations + ("SpinCorrelations", + "Treatment of spin correlations in the parton shower", + &ShowerHandler::spinOpt_, 1, false, false); + static SwitchOption interfaceSpinCorrelationsNo + (interfaceSpinCorrelations, + "No", + "No spin correlations", + 0); + static SwitchOption interfaceSpinCorrelationsSpin + (interfaceSpinCorrelations, + "Yes", + "Include the azimuthal spin correlations", + 1); } Energy ShowerHandler::hardScale() const { assert(false); } void ShowerHandler::cascade() { useMe(); // Initialise the weights in the event object // so that any variations are output regardless of // whether showering occurs for the given event initializeWeights(); // get the PDF's from ThePEG (if locally overridden use the local versions) tcPDFPtr first = PDFA_ ? tcPDFPtr(PDFA_) : firstPDF().pdf(); tcPDFPtr second = PDFB_ ? tcPDFPtr(PDFB_) : secondPDF().pdf(); resetPDFs(make_pair(first,second)); // set the PDFs for the remnant if( ! rempdfs_.first) rempdfs_.first = PDFARemnant_ ? PDFPtr(PDFARemnant_) : const_ptr_cast(first); if( ! rempdfs_.second) rempdfs_.second = PDFBRemnant_ ? PDFPtr(PDFBRemnant_) : const_ptr_cast(second); // get the incoming partons tPPair incomingPartons = eventHandler()->currentCollision()->primarySubProcess()->incoming(); // and the parton bins PBIPair incomingBins = make_pair(lastExtractor()->partonBinInstance(incomingPartons.first), lastExtractor()->partonBinInstance(incomingPartons.second)); // and the incoming hadrons tPPair incomingHadrons = eventHandler()->currentCollision()->incoming(); remnantDecayer()->setHadronContent(incomingHadrons); // check if incoming hadron == incoming parton // and get the incoming hadron if exists or parton otherwise incoming_ = make_pair(incomingBins.first ? incomingBins.first ->particle() : incomingPartons.first, incomingBins.second ? incomingBins.second->particle() : incomingPartons.second); // check the collision is of the beam particles // and if not boost collision to the right frame // i.e. the hadron-hadron CMF of the collision bool btotal(false); LorentzRotation rtotal; if(incoming_.first != incomingHadrons.first || incoming_.second != incomingHadrons.second ) { btotal = true; boostCollision(false); } // set the current ShowerHandler setCurrentHandler(); // first shower the hard process try { SubProPtr sub = eventHandler()->currentCollision()->primarySubProcess(); incomingPartons = cascade(sub,lastXCombPtr()); } catch(ShowerTriesVeto &veto){ throw Exception() << "Failed to generate the shower after " << veto.tries << " attempts in ShowerHandler::cascade()" << Exception::eventerror; } if(showerHardProcessVeto()) throw Veto(); // if a non-hadron collision return (both incoming non-hadronic) if( ( !incomingBins.first|| !isResolvedHadron(incomingBins.first ->particle()))&& ( !incomingBins.second|| !isResolvedHadron(incomingBins.second->particle()))) { // boost back to lab if needed if(btotal) boostCollision(true); // perform the reweighting for the hard process shower combineWeights(); // unset the current ShowerHandler unSetCurrentHandler(); return; } // get the remnants for hadronic collision pair remnants(getRemnants(incomingBins)); // set the starting scale of the forced splitting to the PDF freezing scale remnantDecayer()->initialize(remnants, incoming_, *currentStep(), pdfFreezingScale()); // do the first forcedSplitting try { remnantDecayer()->doSplit(incomingPartons, make_pair(rempdfs_.first,rempdfs_.second), true); } catch (ExtraScatterVeto) { throw Exception() << "Remnant extraction failed in " << "ShowerHandler::cascade() from primary interaction" << Exception::eventerror; } // perform the reweighting for the hard process shower combineWeights(); // if no MPI return if( !isMPIOn() ) { remnantDecayer()->finalize(); // boost back to lab if needed if(btotal) boostCollision(true); // unset the current ShowerHandler unSetCurrentHandler(); return; } // generate the multiple scatters use modified pdf's now: setMPIPDFs(); // additional "hard" processes unsigned int tries(0); // This is the loop over additional hard scatters (most of the time // only one, but who knows...) for(unsigned int i=1; i <= getMPIHandler()->additionalHardProcs(); i++){ //counter for regeneration unsigned int multSecond = 0; // generate the additional scatters while( multSecond < getMPIHandler()->multiplicity(i) ) { // generate the hard scatter tStdXCombPtr lastXC = getMPIHandler()->generate(i); SubProPtr sub = lastXC->construct(); // add to the Step newStep()->addSubProcess(sub); // increment the counters tries++; multSecond++; if(tries == maxtryDP_) throw Exception() << "Failed to establish the requested number " << "of additional hard processes. If this error " << "occurs often, your selection of additional " << "scatter is probably unphysical" << Exception::eventerror; // Generate the shower. If not possible veto the event try { incomingPartons = cascade(sub,lastXC); } catch(ShowerTriesVeto &veto){ throw Exception() << "Failed to generate the shower of " << "a secondary hard process after " << veto.tries << " attempts in Evolver::showerHardProcess()" << Exception::eventerror; } try { // do the forcedSplitting remnantDecayer()->doSplit(incomingPartons, make_pair(remmpipdfs_.first,remmpipdfs_.second), false); } catch(ExtraScatterVeto){ //remove all particles associated with the subprocess newStep()->removeParticle(incomingPartons.first); newStep()->removeParticle(incomingPartons.second); //remove the subprocess from the list newStep()->removeSubProcess(sub); //regenerate the scattering multSecond--; continue; } // connect with the remnants but don't set Remnant colour, // because that causes problems due to the multiple colour lines. if ( !remnants.first ->extract(incomingPartons.first , false) || !remnants.second->extract(incomingPartons.second, false) ) throw Exception() << "Remnant extraction failed in " << "ShowerHandler::cascade() for additional scatter" << Exception::runerror; } // perform the reweighting for the additional hard scatter shower combineWeights(); } // the underlying event processes unsigned int ptveto(1), veto(0); unsigned int max(getMPIHandler()->multiplicity()); for(unsigned int i=0; i maxtryMPI_) break; //generate PSpoint tStdXCombPtr lastXC = getMPIHandler()->generate(); SubProPtr sub = lastXC->construct(); //If Algorithm=1 additional scatters of the signal type // with pt > ptmin have to be vetoed //with probability 1/(m+1), where m is the number of occurances in this event if( getMPIHandler()->Algorithm() == 1 ){ //get the pT Energy pt = sub->outgoing().front()->momentum().perp(); if(pt > getMPIHandler()->PtForVeto() && UseRandom::rnd() < 1./(ptveto+1) ){ ptveto++; i--; continue; } } // add to the SubProcess to the step newStep()->addSubProcess(sub); // Run the Shower. If not possible veto the scattering try { incomingPartons = cascade(sub,lastXC); } // discard this extra scattering, but try the next one catch(ShowerTriesVeto) { newStep()->removeSubProcess(sub); //regenerate the scattering veto++; i--; continue; } try{ //do the forcedSplitting remnantDecayer()->doSplit(incomingPartons, make_pair(remmpipdfs_.first,remmpipdfs_.second), false); } catch (ExtraScatterVeto) { //remove all particles associated with the subprocess newStep()->removeParticle(incomingPartons.first); newStep()->removeParticle(incomingPartons.second); //remove the subprocess from the list newStep()->removeSubProcess(sub); //regenerate the scattering veto++; i--; continue; } //connect with the remnants but don't set Remnant colour, //because that causes problems due to the multiple colour lines. if ( !remnants.first ->extract(incomingPartons.first , false) || !remnants.second->extract(incomingPartons.second, false) ) throw Exception() << "Remnant extraction failed in " << "ShowerHandler::cascade() for MPI hard scattering" << Exception::runerror; //reset veto counter veto = 0; // perform the reweighting for the MPI process shower combineWeights(); } // finalize the remnants remnantDecayer()->finalize(getMPIHandler()->colourDisrupt(), getMPIHandler()->softMultiplicity()); // boost back to lab if needed if(btotal) boostCollision(true); // unset the current ShowerHandler unSetCurrentHandler(); getMPIHandler()->clean(); resetPDFs(make_pair(first,second)); } void ShowerHandler::initializeWeights() { if ( !showerVariations().empty() ) { tEventPtr event = eventHandler()->currentEvent(); for ( map::const_iterator var = showerVariations().begin(); var != showerVariations().end(); ++var ) { // Check that this is behaving as intended //map::iterator wi = event->optionalWeights().find(var->first); //assert(wi == event->optionalWeights().end() ); event->optionalWeights()[var->first] = 1.0; currentWeights_[var->first] = 1.0; } } reweight_ = 1.0; } void ShowerHandler::resetWeights() { for ( map::iterator w = currentWeights_.begin(); w != currentWeights_.end(); ++w ) { w->second = 1.0; } reweight_ = 1.0; } void ShowerHandler::combineWeights() { tEventPtr event = eventHandler()->currentEvent(); for ( map::const_iterator w = currentWeights_.begin(); w != currentWeights_.end(); ++w ) { map::iterator ew = event->optionalWeights().find(w->first); if ( ew != event->optionalWeights().end() ) ew->second *= w->second; else { assert(false && "Weight name unknown."); //event->optionalWeights()[w->first] = w->second; } } if ( reweight_ != 1.0 ) { Ptr::tptr eh = dynamic_ptr_cast::tptr>(eventHandler()); if ( !eh ) { throw Exception() << "ShowerHandler::combineWeights() : Cross section reweighting " << "through the shower is currently only available with standard " << "event generators" << Exception::runerror; } eh->reweight(reweight_); } } string ShowerHandler::doAddVariation(string in) { if ( in.empty() ) return "expecting a name and a variation specification"; string name = StringUtils::car(in); ShowerVariation var; string res = var.fromInFile(StringUtils::cdr(in)); if ( res.empty() ) { if ( !var.firstInteraction && !var.secondaryInteractions ) { // TODO what about decay showers? return "variation does not apply to any shower"; } if ( var.renormalizationScaleFactor == 1.0 && var.factorizationScaleFactor == 1.0 ) { return "variation does not vary anything"; } /* Repository::clog() << "adding a variation with tag '" << name << "' using\nxir = " << var.renormalizationScaleFactor << " xif = " << var.factorizationScaleFactor << "\napplying to:\n" << "first interaction = " << var.firstInteraction << " " << "secondary interactions = " << var.secondaryInteractions << "\n" << flush; */ showerVariations()[name] = var; } return res; } tPPair ShowerHandler::cascade(tSubProPtr, XCPtr) { assert(false); } ShowerHandler::RemPair ShowerHandler::getRemnants(PBIPair incomingBins) { RemPair remnants; // first beam particle if(incomingBins.first&&!incomingBins.first->remnants().empty()) { remnants.first = dynamic_ptr_cast(incomingBins.first->remnants()[0] ); if(remnants.first) { ParticleVector children=remnants.first->children(); for(unsigned int ix=0;ixdataPtr()==remnants.first->dataPtr()) remnants.first = dynamic_ptr_cast(children[ix]); } //remove existing colour lines from the remnants if(remnants.first->colourLine()) remnants.first->colourLine()->removeColoured(remnants.first); if(remnants.first->antiColourLine()) remnants.first->antiColourLine()->removeAntiColoured(remnants.first); } } // seconnd beam particle if(incomingBins.second&&!incomingBins. second->remnants().empty()) { remnants.second = dynamic_ptr_cast(incomingBins.second->remnants()[0] ); if(remnants.second) { ParticleVector children=remnants.second->children(); for(unsigned int ix=0;ixdataPtr()==remnants.second->dataPtr()) remnants.second = dynamic_ptr_cast(children[ix]); } //remove existing colour lines from the remnants if(remnants.second->colourLine()) remnants.second->colourLine()->removeColoured(remnants.second); if(remnants.second->antiColourLine()) remnants.second->antiColourLine()->removeAntiColoured(remnants.second); } } assert(remnants.first || remnants.second); return remnants; } namespace { void addChildren(tPPtr in,set & particles) { particles.insert(in); for(unsigned int ix=0;ixchildren().size();++ix) addChildren(in->children()[ix],particles); } } void ShowerHandler::boostCollision(bool boost) { // calculate boost from lab to rest if(!boost) { Lorentz5Momentum ptotal=incoming_.first ->momentum()+incoming_.second->momentum(); boost_ = LorentzRotation(-ptotal.boostVector()); Axis axis((boost_*incoming_.first ->momentum()).vect().unit()); if(axis.perp2()>0.) { double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); boost_.rotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); } } // first call performs the boost and second inverse // get the particles to be boosted set particles; addChildren(incoming_.first,particles); addChildren(incoming_.second,particles); // apply the boost for(set::const_iterator cit=particles.begin(); cit!=particles.end();++cit) { (*cit)->transform(boost_); } if(!boost) boost_.invert(); } void ShowerHandler::setMPIPDFs() { if ( !mpipdfs_.first ) { // first have to check for MinBiasPDF tcMinBiasPDFPtr first = dynamic_ptr_cast(firstPDF().pdf()); if(first) mpipdfs_.first = new_ptr(MPIPDF(first->originalPDF())); else mpipdfs_.first = new_ptr(MPIPDF(firstPDF().pdf())); } if ( !mpipdfs_.second ) { tcMinBiasPDFPtr second = dynamic_ptr_cast(secondPDF().pdf()); if(second) mpipdfs_.second = new_ptr(MPIPDF(second->originalPDF())); else mpipdfs_.second = new_ptr(MPIPDF(secondPDF().pdf())); } if( !remmpipdfs_.first ) { tcMinBiasPDFPtr first = dynamic_ptr_cast(rempdfs_.first); if(first) remmpipdfs_.first = new_ptr(MPIPDF(first->originalPDF())); else remmpipdfs_.first = new_ptr(MPIPDF(rempdfs_.first)); } if( !remmpipdfs_.second ) { tcMinBiasPDFPtr second = dynamic_ptr_cast(rempdfs_.second); if(second) remmpipdfs_.second = new_ptr(MPIPDF(second->originalPDF())); else remmpipdfs_.second = new_ptr(MPIPDF(rempdfs_.second)); } // reset the PDFs stored in the base class resetPDFs(mpipdfs_); } bool ShowerHandler::isResolvedHadron(tPPtr particle) { if(!HadronMatcher::Check(particle->data())) return false; for(unsigned int ix=0;ixchildren().size();++ix) { if(particle->children()[ix]->id()==ParticleID::Remnant) return true; } return false; } namespace { bool decayProduct(tSubProPtr subProcess, tPPtr particle) { // must be time-like and not incoming if(particle->momentum().m2()<=ZERO|| particle == subProcess->incoming().first|| particle == subProcess->incoming().second) return false; // if only 1 outgoing and this is it if(subProcess->outgoing().size()==1 && subProcess->outgoing()[0]==particle) return true; // must not be the s-channel intermediate otherwise if(find(subProcess->incoming().first->children().begin(), subProcess->incoming().first->children().end(),particle)!= subProcess->incoming().first->children().end()&& find(subProcess->incoming().second->children().begin(), subProcess->incoming().second->children().end(),particle)!= subProcess->incoming().second->children().end()&& subProcess->incoming().first ->children().size()==1&& subProcess->incoming().second->children().size()==1) return false; // if non-coloured this is enough if(!particle->dataPtr()->coloured()) return true; // if coloured must be unstable if(particle->dataPtr()->stable()) return false; // must not have same particle type as a child int id = particle->id(); for(unsigned int ix=0;ixchildren().size();++ix) if(particle->children()[ix]->id()==id) return false; // otherwise its a decaying particle return true; } PPtr findParent(PPtr original, bool & isHard, set outgoingset, tSubProPtr subProcess) { PPtr parent=original; isHard |=(outgoingset.find(original) != outgoingset.end()); if(!original->parents().empty()) { PPtr orig=original->parents()[0]; if(decayProduct(subProcess,orig)) parent=findParent(orig,isHard,outgoingset,subProcess); } return parent; } } void ShowerHandler::findDecayProducts(PPtr in,PerturbativeProcessPtr hard, DecayProcessMap & decay) const { ParticleVector children=in->children(); for(ParticleVector::const_iterator it=children.begin(); it!=children.end();++it) { // if decayed or should be decayed in shower make the PerturbaitveProcess bool radiates = false; if(!(**it).children().empty()) { // remove d,u,s,c,b quarks and leptons other than on-shell taus if( StandardQCDPartonMatcher::Check((**it).id()) || ( LeptonMatcher::Check((**it).id()) && !(abs((**it).id())==ParticleID::tauminus && abs((**it).mass()-(**it).dataPtr()->mass())id()==(**it).id()) { foundParticle = true; } else if((**it).children()[iy]->id()==ParticleID::g || (**it).children()[iy]->id()==ParticleID::gamma) { foundGauge = true; } } radiates = foundParticle && foundGauge; } } if(radiates) { findDecayProducts(*it,hard,decay); } else if(!(**it).children().empty()|| (decaysInShower((**it).id())&&!(**it).dataPtr()->stable())) { createDecayProcess(*it,hard,decay); } else { hard->outgoing().push_back(make_pair(*it,PerturbativeProcessPtr())); } } } void ShowerHandler::splitHardProcess(tPVector tagged, PerturbativeProcessPtr & hard, DecayProcessMap & decay) const { // temporary storage of the particles set hardParticles; // tagged particles in a set set outgoingset(tagged.begin(),tagged.end()); bool isHard=false; // loop over the tagged particles for (tParticleVector::const_iterator taggedP = tagged.begin(); taggedP != tagged.end(); ++taggedP) { // skip remnants if (eventHandler()->currentCollision()&& eventHandler()->currentCollision()->isRemnant(*taggedP)) continue; // find the parent and whether its a decaying particle bool isDecayProd=false; // check if hard isHard |=(outgoingset.find(*taggedP) != outgoingset.end()); if(splitHardProcess_) { tPPtr parent = *taggedP; // check if from s channel decaying colourless particle while(parent&&!parent->parents().empty()&&!isDecayProd) { parent = parent->parents()[0]; if(parent == subProcess_->incoming().first || parent == subProcess_->incoming().second ) break; isDecayProd = decayProduct(subProcess_,parent); } if (isDecayProd) hardParticles.insert(findParent(parent,isHard,outgoingset,subProcess_)); } if (!isDecayProd) hardParticles.insert(*taggedP); } // there must be something to shower if(hardParticles.empty()) throw Exception() << "No particles to shower in " << "ShowerHandler::splitHardProcess()" << Exception::eventerror; // must be a hard process if(!isHard) throw Exception() << "Starting on decay not yet implemented in " << "ShowerHandler::splitHardProcess()" << Exception::runerror; // create the hard process hard = new_ptr(PerturbativeProcess()); // incoming particles hard->incoming().push_back(make_pair(subProcess_->incoming().first ,PerturbativeProcessPtr())); hard->incoming().push_back(make_pair(subProcess_->incoming().second,PerturbativeProcessPtr())); // outgoing particles for(set::const_iterator it=hardParticles.begin();it!=hardParticles.end();++it) { // if decayed or should be decayed in shower make the tree PPtr orig = *it; bool radiates = false; if(!orig->children().empty()) { // remove d,u,s,c,b quarks and leptons other than on-shell taus if( StandardQCDPartonMatcher::Check(orig->id()) || ( LeptonMatcher::Check(orig->id()) && !(abs(orig->id())==ParticleID::tauminus && abs(orig->mass()-orig->dataPtr()->mass())children().size();++iy) { if(orig->children()[iy]->id()==orig->id()) { foundParticle = true; } else if(orig->children()[iy]->id()==ParticleID::g || orig->children()[iy]->id()==ParticleID::gamma) { foundGauge = true; } } radiates = foundParticle && foundGauge; } } if(radiates) { findDecayProducts(orig,hard,decay); } else if(!(**it).children().empty()|| (decaysInShower((**it).id())&&!(**it).dataPtr()->stable())) { createDecayProcess(*it,hard,decay); } else { hard->outgoing().push_back(make_pair(*it,PerturbativeProcessPtr())); } } } void ShowerHandler::createDecayProcess(PPtr in,PerturbativeProcessPtr hard, DecayProcessMap & decay) const { // there must be an incoming particle assert(in); // create the new process and connect with the parent PerturbativeProcessPtr newDecay=new_ptr(PerturbativeProcess()); newDecay->incoming().push_back(make_pair(in,hard)); Energy width=in->dataPtr()->generateWidth(in->mass()); decay.insert(make_pair(width,newDecay)); hard->outgoing().push_back(make_pair(in,newDecay)); // we need to deal with the decay products if decayed ParticleVector children = in->children(); if(!children.empty()) { for(ParticleVector::const_iterator it = children.begin(); it!= children.end(); ++it) { // if decayed or should be decayed in shower make the tree in->abandonChild(*it); bool radiates = false; if(!(**it).children().empty()) { if(StandardQCDPartonMatcher::Check((**it).id())|| (LeptonMatcher::Check((**it).id())&& !(abs((**it).id())==ParticleID::tauminus && abs((**it).mass()-(**it).dataPtr()->mass())id()==(**it).id()) { foundParticle = true; } else if((**it).children()[iy]->id()==ParticleID::g || (**it).children()[iy]->id()==ParticleID::gamma) { foundGauge = true; } } radiates = foundParticle && foundGauge; } // finally assume all non-decaying particles are in this class // pr 27/11/15 not sure about this bit // if(!radiates) { // radiates = !decaysInShower((**it).id()); // } } if(radiates) { findDecayProducts(*it,newDecay,decay); } else if(!(**it).children().empty()|| (decaysInShower((**it).id())&&!(**it).dataPtr()->stable())) { createDecayProcess(*it,newDecay,decay); } else { newDecay->outgoing().push_back(make_pair(*it,PerturbativeProcessPtr())); } } } } tDMPtr ShowerHandler::decay(PerturbativeProcessPtr process, DecayProcessMap & decayMap, bool radPhotons ) const { PPtr parent = process->incoming()[0].first; assert(parent); if(parent->spinInfo()) parent->spinInfo()->decay(true); unsigned int ntry = 0; ParticleVector children; tDMPtr dm = DMPtr(); while (true) { // exit if fails if (++ntry>=maxtryDecay_) throw Exception() << "Failed to perform decay in ShowerHandler::decay()" << " after " << maxtryDecay_ << " attempts for " << parent->PDGName() << Exception::eventerror; // select decay mode dm = parent->data().selectMode(*parent); if(!dm) throw Exception() << "Failed to select decay mode in ShowerHandler::decay()" << "for " << parent->PDGName() << Exception::eventerror; if(!dm->decayer()) throw Exception() << "No Decayer for selected decay mode " << " in ShowerHandler::decay()" << Exception::runerror; // start of try block try { children = dm->decayer()->decay(*dm, *parent); // if no children have another go if(children.empty()) continue; if(radPhotons){ // generate radiation in the decay tDecayIntegratorPtr hwdec=dynamic_ptr_cast(dm->decayer()); if (hwdec && hwdec->canGeneratePhotons()) children = hwdec->generatePhotons(*parent,children); } // set up parent parent->decayMode(dm); // add children for (unsigned int i = 0, N = children.size(); i < N; ++i ) { children[i]->setLabVertex(parent->labDecayVertex()); //parent->addChild(children[i]); } // if succeeded break out of loop break; } catch(Veto) { } } assert(!children.empty()); for(ParticleVector::const_iterator it = children.begin(); it!= children.end(); ++it) { if(!(**it).children().empty()|| (decaysInShower((**it).id())&&!(**it).dataPtr()->stable())) { createDecayProcess(*it,process,decayMap); } else { process->outgoing().push_back(make_pair(*it,PerturbativeProcessPtr())); } } return dm; } // Note: The tag must be constructed from an ordered particle container. tDMPtr ShowerHandler::findDecayMode(const string & tag) const { static map cache; map::const_iterator pos = cache.find(tag); if ( pos != cache.end() ) return pos->second; tDMPtr dm = CurrentGenerator::current().findDecayMode(tag); cache[tag] = dm; return dm; } /** * Operator for the particle ordering * @param p1 The first ParticleData object * @param p2 The second ParticleData object */ bool ShowerHandler::ParticleOrdering::operator() (tcPDPtr p1, tcPDPtr p2) { return abs(p1->id()) > abs(p2->id()) || ( abs(p1->id()) == abs(p2->id()) && p1->id() > p2->id() ) || ( p1->id() == p2->id() && p1->fullName() > p2->fullName() ); } diff --git a/Shower/ShowerHandler.h b/Shower/ShowerHandler.h --- a/Shower/ShowerHandler.h +++ b/Shower/ShowerHandler.h @@ -1,847 +1,880 @@ // -*- C++ -*- // // ShowerHandler.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_ShowerHandler_H #define HERWIG_ShowerHandler_H // // This is the declaration of the ShowerHandler class. // #include "ThePEG/Handlers/EventHandler.h" #include "ThePEG/Handlers/CascadeHandler.h" #include "ShowerVariation.h" #include "Herwig/PDF/HwRemDecayer.fh" #include "ThePEG/EventRecord/RemnantParticle.fh" #include "UEBase.h" #include "PerturbativeProcess.h" #include "Herwig/MatrixElement/Matchbox/Matching/HardScaleProfile.h" #include "ShowerHandler.fh" namespace Herwig { using namespace ThePEG; /** \ingroup Shower * * This class is the main driver of the shower: it is responsible for * the proper handling of all other specific collaborating classes * and for the storing of the produced particles in the event record. * * @see \ref ShowerHandlerInterfaces "The interfaces" * * @see ThePEG::CascadeHandler * @see MPIHandler * @see HwRemDecayer */ class ShowerHandler: public CascadeHandler { public: /** * Typedef for a pair of ThePEG::RemnantParticle pointers. */ typedef pair RemPair; public: /** * Default constructor */ ShowerHandler(); /** * Destructor */ virtual ~ShowerHandler(); public: /** * The main method which manages the multiple interactions and starts * the shower by calling cascade(sub, lastXC). */ virtual void cascade(); /** * pointer to "this", the current ShowerHandler. */ static const tShowerHandlerPtr currentHandler() { assert(currentHandler_); return currentHandler_; } + /** + * pointer to "this", the current ShowerHandler. + */ + static bool currentHandlerIsSet() { + return currentHandler_; + } + public: /** * Hook to allow vetoing of event after showering hard sub-process * as in e.g. MLM merging. */ virtual bool showerHardProcessVeto() const { return false; } /** * Return true, if this cascade handler will perform reshuffling from hard * process masses. */ virtual bool isReshuffling() const { return true; } /** * Return true, if the shower handler can generate a truncated * shower for POWHEG style events generated using Matchbox */ virtual bool canHandleMatchboxTrunc() const { return false; } /** * Get the PDF freezing scale */ Energy pdfFreezingScale() const { return pdfFreezingScale_; } /** * Get the local PDFs. */ PDFPtr getPDFA() const {return PDFA_;} /** * Get the local PDFs. */ PDFPtr getPDFB() const {return PDFB_;} /** * Return true if currently the primary subprocess is showered. */ bool firstInteraction() const { if (!eventHandler()->currentCollision())return true; return ( subProcess_ == eventHandler()->currentCollision()->primarySubProcess() ); } /** * Return the remnant decayer. */ tHwRemDecPtr remnantDecayer() const { return remDec_; } /** * Split the hard process into production and decays * @param tagged The tagged particles from the StepHandler * @param hard The hard perturbative process * @param decay The decay particles */ void splitHardProcess(tPVector tagged, PerturbativeProcessPtr & hard, DecayProcessMap & decay) const; /** * Information if the Showerhandler splits the hard process. */ bool doesSplitHardProcess()const {return splitHardProcess_;} /** * Decay a particle. * radPhotons switches the generation of photon * radiation on/off. * Required for Dipole Shower but not QTilde Shower. */ tDMPtr decay(PerturbativeProcessPtr, DecayProcessMap & decay, bool radPhotons = false) const; /** * Cached lookup of decay modes. * Generator::findDecayMode() is not efficient. */ tDMPtr findDecayMode(const string & tag) const; /** * A struct to order the particles in the same way as in the DecayMode's */ struct ParticleOrdering { bool operator() (tcPDPtr p1, tcPDPtr p2); }; /** * A container for ordered particles required * for constructing tags for decay mode lookup. */ typedef multiset OrderedParticles; public: /** * @name Switches for initial- and final-state radiation */ //@{ /** * Switch for any radiation */ bool doRadiation() const {return doFSR_ || doISR_;} /** * Switch on or off final state radiation. */ bool doFSR() const { return doFSR_;} /** * Switch on or off initial state radiation. */ bool doISR() const { return doISR_;} //@} public: /** * @name Switches for scales */ //@{ /** * Return true if maximum pt should be deduced from the factorization scale */ bool hardScaleIsMuF() const { return maxPtIsMuF_; } /** * The factorization scale factor. */ double factorizationScaleFactor() const { return factorizationScaleFactor_; } /** * The renormalization scale factor. */ double renFac() const { return renormalizationScaleFactor_; } /** * The factorization scale factor. */ double facFac() const { return factorizationScaleFactor_; } /** * The renormalization scale factor. */ double renormalizationScaleFactor() const { return renormalizationScaleFactor_; } /** * The scale factor for the hard scale */ double hardScaleFactor() const { return hardScaleFactor_; } /** * Return true, if the phase space restrictions of the dipole shower should * be applied. */ bool restrictPhasespace() const { return restrictPhasespace_; } /** * Return profile scales */ Ptr::tptr profileScales() const { return hardScaleProfile_; } /** * Return the relevant hard scale to be used in the profile scales */ virtual Energy hardScale() const; /** * Return information about shower phase space choices */ virtual int showerPhaseSpaceOption() const { assert(false && "not implemented in general"); return -1; } //@} public: /** * Access the shower variations */ map& showerVariations() { return showerVariations_; } /** * Return the shower variations */ const map& showerVariations() const { return showerVariations_; } /** * Access the current Weights */ map& currentWeights() { return currentWeights_; } /** * Return the current Weights */ const map& currentWeights() const { return currentWeights_; } /** * Change the current reweighting factor */ void reweight(double w) { reweight_ = w; } /** * Return the current reweighting factor */ double reweight() const { return reweight_; } +public : + + /** + * Access to switches for spin correlations + */ + //@{ + /** + * Spin Correlations + */ + unsigned int spinCorrelations() const { + return spinOpt_; + } + + /** + * Any correlations + */ + virtual bool correlations() const { + return spinOpt_!=0; + } + //@} + public: /** * struct that is used to catch exceptions which are thrown * due to energy conservation issues of additional scatters */ struct ExtraScatterVeto {}; /** * struct that is used to catch exceptions which are thrown * due to fact that the Shower has been invoked more than * a defined threshold on a certain configuration */ struct ShowerTriesVeto { /** variable to store the number of attempts */ const int tries; /** constructor */ ShowerTriesVeto(int t) : tries(t) {} }; 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 Functions to perform the cascade */ //@{ /** * The main method which manages the showering of a subprocess. */ virtual tPPair cascade(tSubProPtr sub, XCPtr xcomb); /** * Set up for the cascade */ void prepareCascade(tSubProPtr sub) { current_ = currentStep(); subProcess_ = sub; } /** * Boost all the particles in the collision so that the collision always occurs * in the rest frame with the incoming particles along the z axis */ void boostCollision(bool boost); //@} protected: /** * Set/unset the current shower handler */ //@{ /** * Set the current handler */ void setCurrentHandler() { currentHandler_ = tShowerHandlerPtr(this); } /** * Unset the current handler */ void unSetCurrentHandler() { currentHandler_ = tShowerHandlerPtr(); } //@} protected: /** * @name Members relating to the underlying event and MPI */ //@{ /** * Return true if multiple parton interactions are switched on * and can be used for this beam setup. */ bool isMPIOn() const { return MPIHandler_ && MPIHandler_->beamOK(); } /** * Access function for the MPIHandler, it should only be called after * checking with isMPIOn. */ tUEBasePtr getMPIHandler() const { assert(MPIHandler_); return MPIHandler_; } /** * Is a beam particle where hadronic structure is resolved */ bool isResolvedHadron(tPPtr); /** * Get the remnants from the ThePEG::PartonBinInstance es and * do some checks. */ RemPair getRemnants(PBIPair incbins); /** * Reset the PDF's after the hard collision has been showered */ void setMPIPDFs(); //@} public: /** * Check if a particle decays in the shower * @param id The PDG code for the particle */ bool decaysInShower(long id) const { return ( particlesDecayInShower_.find( abs(id) ) != particlesDecayInShower_.end() ); } protected: /** * Members to handle splitting up of hard process and decays */ //@{ /** * Find decay products from the hard process and create decay processes * @param parent The parent particle * @param hard The hard process * @param decay The decay processes */ void findDecayProducts(PPtr parent, PerturbativeProcessPtr hard, DecayProcessMap & decay) const; /** * Find decay products from the hard process and create decay processes * @param parent The parent particle * @param hard The parent hard process * @param decay The decay processes */ void createDecayProcess(PPtr parent,PerturbativeProcessPtr hard, DecayProcessMap & decay) const; //@} /** * @name Functions to return information relevant to the process being showered */ //@{ /** * Return the currently used SubProcess. */ tSubProPtr currentSubProcess() const { assert(subProcess_); return subProcess_; } /** * Access to the incoming beam particles */ tPPair incomingBeams() const { return incoming_; } //@} protected: /** * Weight handling for shower variations */ //@ /** * Combine the variation weights which have been encountered */ void combineWeights(); /** * Initialise the weights in currentEvent() */ void initializeWeights(); /** * Reset the current weights */ void resetWeights(); //@} protected: /** * Return the maximum number of attempts for showering * a given subprocess. */ unsigned int maxtry() const { return maxtry_; } protected: /** * Parameters for the space-time model */ //@{ /** * Whether or not to include spa-cetime distances in the shower */ bool includeSpaceTime() const {return includeSpaceTime_;} /** * The minimum virtuality for the space-time model */ Energy2 vMin() const {return vMin_;} //@} protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const; /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const; //@} protected: /** @name Standard Interfaced functions. */ //@{ /** * Initialize this object after the setup phase before saving an * EventGenerator to disk. * @throws InitException if object could not be initialized properly. */ virtual void doinit(); /** * Initialize this object. Called in the run phase just before * a run begins. */ virtual void doinitrun(); /** * Finalize this object. Called in the run phase just after a * run has ended. Used eg. to write out statistics. */ virtual void dofinish(); //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ ShowerHandler & operator=(const ShowerHandler &); private: /** * pointer to "this", the current ShowerHandler. */ static tShowerHandlerPtr currentHandler_; /** * a MPIHandler to administer the creation of several (semihard) * partonic interactions. */ UEBasePtr MPIHandler_; /** * Pointer to the HwRemDecayer */ HwRemDecPtr remDec_; private: /** * Maximum tries for various stages of the showering process */ //@{ /** * Maximum number of attempts for the * main showering loop */ unsigned int maxtry_; /** * Maximum number of attempts for the regeneration of an additional * scattering, before the number of scatters is reduced. */ unsigned int maxtryMPI_; /** * Maximum number of attempts for the regeneration of an additional * hard scattering, before this event is vetoed. */ unsigned int maxtryDP_; /** * Maximum number of attempts to generate a decay */ unsigned int maxtryDecay_; //@} private: /** * Factors for the various scales */ //@{ /** * The factorization scale factor. */ double factorizationScaleFactor_; /** * The renormalization scale factor. */ double renormalizationScaleFactor_; /** * The scale factor for the hard scale */ double hardScaleFactor_; /** * True, if the phase space restrictions of the dipole shower should * be applied. */ bool restrictPhasespace_; /** * True if maximum pt should be deduced from the factorization scale */ bool maxPtIsMuF_; /** * The profile scales */ Ptr::ptr hardScaleProfile_; //@} + /** + * Option to include spin correlations + */ + unsigned int spinOpt_; + private: /** * Storage of information about the current event */ //@{ /** * The incoming beam particles for the current collision */ tPPair incoming_; /** * Boost to get back to the lab */ LorentzRotation boost_; /** * Const pointer to the currently handeled ThePEG::SubProcess */ tSubProPtr subProcess_; /** * Const pointer to the current step */ tcStepPtr current_; //@} private: /** * PDFs to be used for the various stages and related parameters */ //@{ /** * The PDF freezing scale */ Energy pdfFreezingScale_; /** * PDFs to be used for the various stages and related parameters */ //@{ /** * The PDF for beam particle A. Overrides the particle's own PDF setting. */ PDFPtr PDFA_; /** * The PDF for beam particle B. Overrides the particle's own PDF setting. */ PDFPtr PDFB_; /** * The PDF for beam particle A for remnant splitting. Overrides the particle's own PDF setting. */ PDFPtr PDFARemnant_; /** * The PDF for beam particle B for remnant splitting. Overrides the particle's own PDF setting. */ PDFPtr PDFBRemnant_; /** * The MPI PDF's to be used for secondary scatters. */ pair mpipdfs_; /** * The MPI PDF's to be used for secondary scatters. */ pair rempdfs_; /** * The MPI PDF's to be used for secondary scatters. */ pair remmpipdfs_; //@} private: /** * @name Parameters for initial- and final-state radiation */ //@{ /** * Switch on or off final state radiation. */ bool doFSR_; /** * Switch on or off initial state radiation. */ bool doISR_; //@} private: /** * @name Parameters for particle decays */ //@{ /** * Whether or not to split into hard and decay trees */ bool splitHardProcess_; /** * PDG codes of the particles which decay during showering * this is fast storage for use during running */ set particlesDecayInShower_; /** * PDG codes of the particles which decay during showering * this is a vector that is interfaced so they can be changed */ vector inputparticlesDecayInShower_; //@} private: /** * Parameters for the space-time model */ //@{ /** * Whether or not to include spa-cetime distances in the shower */ bool includeSpaceTime_; /** * The minimum virtuality for the space-time model */ Energy2 vMin_; //@} private: /** * Parameters relevant for reweight and variations */ //@{ /** * The shower variations */ map showerVariations_; /** * Command to add a shower variation */ string doAddVariation(string); /** * A reweighting factor applied by the showering */ double reweight_; /** * The shower variation weights */ map currentWeights_; //@} }; } #endif /* HERWIG_ShowerHandler_H */ diff --git a/Tests/python/make_input_files.py b/Tests/python/make_input_files.py --- a/Tests/python/make_input_files.py +++ b/Tests/python/make_input_files.py @@ -1,1801 +1,1791 @@ #! /usr/bin/env python import logging,sys,os from string import strip, Template import sys if sys.version_info[:3] < (2,4,0): print "rivet scripts require Python version >= 2.4.0... exiting" sys.exit(1) if __name__ == "__main__": import logging from optparse import OptionParser, OptionGroup parser = OptionParser(usage="%prog name [...]") simulation="" numberOfAddedProcesses=0 def addProcess(thefactory,theProcess,Oas,Oew,scale,mergedlegs,NLOprocesses): global numberOfAddedProcesses global simulation numberOfAddedProcesses+=1 res ="set "+thefactory+":OrderInAlphaS "+Oas+"\n" res+="set "+thefactory+":OrderInAlphaEW "+Oew+"\n" res+="do "+thefactory+":Process "+theProcess+" " if ( mergedlegs != 0 ): if simulation!="Merging": print "simulation is not Merging, trying to add merged legs." sys.exit(1) res+="[" for j in range(mergedlegs): res+=" j " res+="]" res+="\n" if (NLOprocesses!=0): if simulation!="Merging": print "simulation is not Merging, trying to add NLOProcesses." sys.exit(1) res+="set MergingFactory:NLOProcesses %s \n" % NLOprocesses if ( scale != "" ): res+="set "+thefactory+":ScaleChoice /Herwig/MatrixElements/Matchbox/Scales/"+scale+"\n" return res def addLeptonPairCut(minmass,maxmass): return "set /Herwig/Cuts/LeptonPairMassCut:MinMass "+minmass+"*GeV\nset /Herwig/Cuts/LeptonPairMassCut:MaxMass "+maxmass+"*GeV\n" didaddfirstjet=False def addFirstJet(ptcut): global didaddfirstjet if(didaddfirstjet): logging.error("Can only add jetcut once.") sys.exit(1) res="set /Herwig/Cuts/Cuts:JetFinder /Herwig/Cuts/JetFinder\n" res+="insert /Herwig/Cuts/Cuts:MultiCuts 0 /Herwig/Cuts/JetCuts\n" res+="insert /Herwig/Cuts/JetCuts:JetRegions 0 /Herwig/Cuts/FirstJet\n" if(ptcut!=""): res+="set /Herwig/Cuts/FirstJet:PtMin "+ptcut+".*GeV\n" didaddfirstjet=True return res didaddsecondjet=False def addSecondJet(ptcut): global didaddsecondjet if(didaddsecondjet): logging.error("Can only add second jetcut once.") sys.exit(1) res="insert /Herwig/Cuts/JetCuts:JetRegions 0 /Herwig/Cuts/SecondJet\n" res+="set /Herwig/Cuts/SecondJet:PtMin "+ptcut+".*GeV\n" didaddsecondjet=True return res didaddjetpair=False def addJetPairCut(minmass): global didaddjetpair if(didaddjetpair): logging.error("Can only add second jetcut once.") sys.exit(1) res="""\ create ThePEG::JetPairRegion /Herwig/Cuts/JetPairMass JetCuts.so set /Herwig/Cuts/JetPairMass:FirstRegion /Herwig/Cuts/FirstJet set /Herwig/Cuts/JetPairMass:SecondRegion /Herwig/Cuts/SecondJet insert /Herwig/Cuts/JetCuts:JetPairRegions 0 /Herwig/Cuts/JetPairMass set /Herwig/Cuts/JetPairMass:MassMin {mm}.*GeV """.format(mm=minmass) didaddjetpair=True return res addedBRReweighter=False def addBRReweighter(): global addedBRReweighter if(addedBRReweighter): logging.error("Can only add BRReweighter once.") sys.exit(1) res="create Herwig::BranchingRatioReweighter /Herwig/Generators/BRReweighter\n" res+="insert /Herwig/Generators/EventGenerator:EventHandler:PostHadronizationHandlers 0 /Herwig/Generators/BRReweighter\n" addedBRReweighter=True return res def setHardProcessWidthToZero(list1): res="" for i in list1: res+="set /Herwig/Particles/"+i+":HardProcessWidth 0.\n" return res selecteddecaymode=False def selectDecayMode(particle,decaymodes): global selecteddecaymode res="do /Herwig/Particles/"+particle+":SelectDecayModes" for decay in decaymodes: res+=" /Herwig/Particles/"+particle+"/"+decay res+="\n" selecteddecaymode=True return res def jet_kt_cut(energy): return "set /Herwig/Cuts/JetKtCut:MinKT {E}*GeV\n".format(E=energy) def mhatmin_cut(energy): return "set /Herwig/Cuts/Cuts:MHatMin {E}*GeV\n".format(E=energy) def mhat_minm_maxm(e1,e2,e3): return """\ set /Herwig/Cuts/Cuts:MHatMin {e1}*GeV set /Herwig/Cuts/MassCut:MinM {e2}*GeV set /Herwig/Cuts/MassCut:MaxM {e3}*GeV """.format(**locals()) def collider_lumi(energy): return "set /Herwig/Generators/EventGenerator:EventHandler:LuminosityFunction:Energy {E}*GeV\n".format(E=energy) def insert_ME(me,process=None,ifname='Process'): result = "insert /Herwig/MatrixElements/SubProcess:MatrixElements 0 /Herwig/MatrixElements/{me}\n".format(**locals()) if process is not None: result += "set /Herwig/MatrixElements/{me}:{ifname} {process}".format(**locals()) return result def particlegroup(name,*particles): result = ["do /Herwig/MatrixElements/Matchbox/Factory:StartParticleGroup {n}".format(n=name)] for p in particles: result.append( "insert /Herwig/MatrixElements/Matchbox/Factory:ParticleGroup 0 /Herwig/Particles/{p}".format(p=p) ) result.append("do /Herwig/MatrixElements/Matchbox/Factory:EndParticleGroup") return '\n'.join(result) # settings for four flavour scheme fourFlavour=""" read Matchbox/FourFlavourScheme.in {bjetgroup} set /Herwig/Cuts/MatchboxJetMatcher:Group bjet """.format(bjetgroup=particlegroup('bjet','b','bbar','c', 'cbar', 's','sbar','d','dbar','u','ubar','g')) ME_Upsilon = """\ create Herwig::MEee2VectorMeson /Herwig/MatrixElements/MEUpsilon HwMELepton.so set /Herwig/MatrixElements/MEUpsilon:VectorMeson /Herwig/Particles/Upsilon(4S) set /Herwig/MatrixElements/MEUpsilon:Coupling 0.0004151809 """ + insert_ME("MEUpsilon") (opts, args) = parser.parse_args() ## Check args if len(args) != 1: logging.error("Must specify at least input file") sys.exit(1) name = args[0] print name # select the template to load # collider KNOWN_COLLIDERS = [ "BFactory", "LEP", "DIS", "TVT", "LHC-GammaGamma", "LHC", "ISR", "SppS", "Star", ] collider = "" for cand_collider in KNOWN_COLLIDERS: if cand_collider in name: collider = cand_collider break del cand_collider assert collider have_hadronic_collider = collider in ["TVT","LHC","ISR","SppS","Star"] thefactory="Factory" parameters = { 'shower' : '', 'bscheme' : '', } # istart determines how many name parts need to be skipped istart = 1 # Dipole shower with Matchbox Powheg if "Dipole-Matchbox-Powheg" in name : istart = 4 simulation="Matchbox" parameters["shower"] = "read Matchbox/Powheg-DipoleShower.in\n" # Dipole shower with internal Powheg - Todo: Finish modifying template files. ''' elif "Dipole-Powheg" in name : istart = 3 simulation="Powheg" parameters["shower"] = "set /Herwig/EventHandlers/EventHandler:CascadeHandler /Herwig/DipoleShower/DipoleShowerHandler\nread snippets/Dipole_AutoTune_prel.in\n" ''' # Dipole shower with MCatNLO elif "Dipole-MCatNLO" in name : istart = 3 simulation="Matchbox" parameters["shower"] = "read Matchbox/MCatNLO-DipoleShower.in\n" # Dipole shower with Matchbox LO elif "Dipole-Matchbox-LO" in name : istart = 4 simulation="Matchbox" parameters["shower"] = "read Matchbox/LO-DipoleShower.in\n" # Dipole shower with internal LO elif "Dipole" in name : istart = 2 simulation="" parameters["shower"] = "set /Herwig/EventHandlers/EventHandler:CascadeHandler /Herwig/DipoleShower/DipoleShowerHandler\nread snippets/Dipole_AutoTune_prel.in\n" # AO shower with Matchbox Powheg elif "Matchbox-Powheg" in name : istart = 3 simulation="Matchbox" parameters["shower"] = "read Matchbox/Powheg-DefaultShower.in\n" # AO shower with MCatNLO elif "Matchbox" in name : istart = 2 simulation="Matchbox" parameters["shower"] = "read Matchbox/MCatNLO-DefaultShower.in\n" # AO shower with inernal Powheg elif "Powheg" in name : istart = 2 simulation="Powheg" # Dipole shower with merging elif "Merging" in name : istart = 2 simulation="Merging" thefactory="MergingFactory" # Flavour settings for Matchbox if simulation=="Matchbox" : parameters["bscheme"] = "read Matchbox/FiveFlavourScheme.in\n" if "Dipole" in parameters["shower"] : parameters["bscheme"] += "read Matchbox/FiveFlavourNoBMassScheme.in\n" if collider not in ['DIS','LEP'] : parameters["nlo"] = "read Matchbox/MadGraph-OpenLoops.in\n" # Flavour settings for dipole shower with internal ME if simulation=="" and "Dipole" in parameters["shower"] : parameters["bscheme"] = "read snippets/DipoleShowerFiveFlavours.in" # find the template if simulation=="" : if collider=="LHC-GammaGamma" : istart += 1 templateName="Hadron-Gamma.in" elif have_hadronic_collider : templateName="Hadron.in" elif collider != "BFactory" : templateName= "%s.in" % collider else : templateName= "LEP.in" else : if have_hadronic_collider : templateName= "Hadron-%s.in" % simulation elif collider != "BFactory" : templateName= "%s-%s.in" % (collider,simulation) else : templateName= "LEP-%s.in" % simulation # work out the name of the parameter file parameterName="-".join(name.split("-")[istart:]) del istart class StringBuilder(object): """ Avoid expensive string additions until the end by building up a list first. This helper class avoids rewriting all the += lower down to list operations. """ def __init__(self, init = None): self.lines = [] if init is None else [init] def __iadd__(self, line): self.lines.append(line) return self def __str__(self): return '\n'.join(self.lines) # work out the process and parameters process=StringBuilder() # Bfactory if(collider=="BFactory") : if(simulation=="") : if(parameterName=="10.58-res") : process += ME_Upsilon elif(parameterName=="10.58") : process += ME_Upsilon process += "set /Herwig/MatrixElements/MEee2gZ2qq:MaximumFlavour 4\n" else : process+=insert_ME("MEee2gZ2qq") process+= "set /Herwig/MatrixElements/MEee2gZ2qq:MaximumFlavour 4\n" elif(simulation=="Powheg") : process = StringBuilder("set /Herwig/MatrixElements/PowhegMEee2gZ2qq:MaximumFlavour 4\n") elif(simulation=="Matchbox" ) : process = StringBuilder(addProcess(thefactory,"e- e+ -> u ubar","0","2","",0,0)) process+=addProcess(thefactory,"e- e+ -> d dbar","0","2","",0,0) process+=addProcess(thefactory,"e- e+ -> c cbar","0","2","",0,0) process+=addProcess(thefactory,"e- e+ -> s sbar","0","2","",0,0) elif(simulation=="Merging" ) : logging.warning("BFactory not explicitly tested for %s " % simulation) sys.exit(0) # DIS elif(collider=="DIS") : if(simulation=="") : if "NoME" in parameterName : process = StringBuilder("set /Herwig/Shower/ShowerHandler:HardEmission None") parameterName=parameterName.replace("NoME-","") else : process = StringBuilder("") elif(simulation=="Powheg") : process = StringBuilder("") elif(simulation=="Matchbox" ) : if "e-" in parameterName : process = StringBuilder(addProcess(thefactory,"e- p -> e- j","0","2","",0,0)) else : process = StringBuilder(addProcess(thefactory,"e+ p -> e+ j","0","2","",0,0)) elif(simulation=="Merging" ) : if "e-" in parameterName : process = StringBuilder(addProcess(thefactory,"e- p -> e- j","0","2","",2,2)) else : process = StringBuilder(addProcess(thefactory,"e+ p -> e+ j","0","2","",2,2)) # LEP elif(collider=="LEP") : if(simulation=="") : if "gg" in parameterName : process = StringBuilder("create Herwig::MEee2Higgs2SM /Herwig/MatrixElements/MEee2Higgs2SM\n") process+=insert_ME("MEee2Higgs2SM","Gluon","Allowed") else : process = StringBuilder(insert_ME("MEee2gZ2qq")) if(parameterName=="10") : process+="set /Herwig/MatrixElements/MEee2gZ2qq:MaximumFlavour 4" elif(simulation=="Powheg") : process = StringBuilder() if(parameterName=="10") : process = StringBuilder("set /Herwig/MatrixElements/PowhegMEee2gZ2qq:MaximumFlavour 4") elif(simulation=="Matchbox" ) : if(parameterName=="10") : process = StringBuilder(addProcess(thefactory,"e- e+ -> u ubar","0","2","",0,0)) process+=addProcess(thefactory,"e- e+ -> d dbar","0","2","",0,0) process+=addProcess(thefactory,"e- e+ -> c cbar","0","2","",0,0) process+=addProcess(thefactory,"e- e+ -> s sbar","0","2","",0,0) else : process = StringBuilder(addProcess(thefactory,"e- e+ -> j j","0","2","",0,0)) elif(simulation=="Merging" ) : if(parameterName=="10") : process = StringBuilder(addProcess(thefactory,"e- e+ -> j j","0","2","",2,2)) process+="read Matchbox/FourFlavourScheme.in" else : process = StringBuilder(addProcess(thefactory,"e- e+ -> j j","0","2","",2,2)) # TVT elif(collider=="TVT") : process = StringBuilder("set /Herwig/Generators/EventGenerator:EventHandler:BeamB /Herwig/Particles/pbar-\n") if "Run-II" in parameterName : process+=collider_lumi(1960.0) elif "Run-I" in parameterName : process+=collider_lumi(1800.0) elif "900" in parameterName : process+=collider_lumi(900.0) elif "630" in parameterName : process+=collider_lumi(630.0) elif "300" in parameterName : process+=collider_lumi(300.0) if(simulation=="") : if "PromptPhoton" in parameterName : process+=insert_ME("MEGammaJet") process+="set /Herwig/Cuts/PhotonKtCut:MinKT 15.\n" elif "DiPhoton-GammaGamma" in parameterName : process+=insert_ME("MEGammaGamma") process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n" parameterName=parameterName.replace("-GammaGamma","") elif "DiPhoton-GammaJet" in parameterName : process+=insert_ME("MEGammaJet") process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n" parameterName=parameterName.replace("-GammaJet","") elif "UE" in parameterName : if "Dipole" in parameters["shower"]: process+="read snippets/MB-DipoleShower.in\n" else: process+="read snippets/MB.in\n" process+="read snippets/Diffraction.in\n" process += "set /Herwig/Decays/DecayHandler:LifeTimeOption 0\n" process += "set /Herwig/Decays/DecayHandler:MaxLifeTime 10*mm\n" elif "Jets" in parameterName : process+=insert_ME("MEQCD2to2") process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n" if "Run-II-Jets-10" in parameterName : process+=jet_kt_cut( 30.)+mhatmin_cut(500.) elif "Run-II-Jets-11" in parameterName: process+=jet_kt_cut( 30.)+mhatmin_cut(900.) elif "Run-I-Jets-1" in parameterName : process+=jet_kt_cut( 20.) elif "Run-I-Jets-2" in parameterName : process+=jet_kt_cut( 40.) elif "Run-I-Jets-3" in parameterName : process+=jet_kt_cut( 65.) elif "Run-I-Jets-4" in parameterName : process+=jet_kt_cut( 90.) elif "Run-I-Jets-5" in parameterName : process+=jet_kt_cut(160.) elif "Run-I-Jets-6" in parameterName : process+=jet_kt_cut( 30.)+mhatmin_cut(100.) elif "Run-I-Jets-7" in parameterName : process+=jet_kt_cut( 30.)+mhatmin_cut(400.) elif "Run-I-Jets-8" in parameterName : process+=jet_kt_cut( 30.)+mhatmin_cut(700.) elif "Run-II-Jets-0" in parameterName : process+=jet_kt_cut( 15.) elif "Run-II-Jets-1" in parameterName : process+=jet_kt_cut( 25.) elif "Run-II-Jets-2" in parameterName : process+=jet_kt_cut( 40.) elif "Run-II-Jets-3" in parameterName : process+=jet_kt_cut( 60.) elif "Run-II-Jets-4" in parameterName : process+=jet_kt_cut( 85.) elif "Run-II-Jets-5" in parameterName : process+=jet_kt_cut(110.) elif "Run-II-Jets-6" in parameterName : process+=jet_kt_cut(160.) elif "Run-II-Jets-7" in parameterName : process+=jet_kt_cut(250.) elif "Run-II-Jets-8" in parameterName : process+=jet_kt_cut( 30.)+mhatmin_cut(100.) elif "Run-II-Jets-9" in parameterName : process+=jet_kt_cut( 30.)+mhatmin_cut(300.) elif "900-Jets-1" in parameterName : process+=jet_kt_cut( 10.) elif "300-Jets-1" in parameterName : process+=jet_kt_cut( 6.) elif "630-Jets-1" in parameterName : process+=jet_kt_cut( 20.) elif "630-Jets-2" in parameterName : process+=jet_kt_cut( 40.) elif "630-Jets-3" in parameterName : process+=jet_kt_cut( 75.) elif "900-Jets-1" in parameterName : process+=jet_kt_cut( 10.) elif "Run-I-WZ" in parameterName : process+=insert_ME("MEqq2W2ff","Electron") process+=insert_ME("MEqq2gZ2ff","Electron") elif "Run-II-W" in parameterName or "Run-I-W" in parameterName : process+=insert_ME("MEqq2W2ff","Electron") elif "Run-II-Z-e" in parameterName or "Run-I-Z" in parameterName : process +=insert_ME("MEqq2gZ2ff","Electron") elif "Run-II-Z-LowMass-mu" in parameterName : process +=insert_ME("MEqq2gZ2ff","Muon") process+=addLeptonPairCut("25","70") elif "Run-II-Z-HighMass-mu" in parameterName : process +=insert_ME("MEqq2gZ2ff","Muon") process+=addLeptonPairCut("150","600") elif "Run-II-Z-mu" in parameterName : process +=insert_ME("MEqq2gZ2ff","Muon") elif(simulation=="Powheg") : if "Run-I-WZ" in parameterName : process+=insert_ME("PowhegMEqq2W2ff","Electron") process+=insert_ME("PowhegMEqq2gZ2ff","Electron") elif "Run-II-W" in parameterName or "Run-I-W" in parameterName : process+=insert_ME("PowhegMEqq2W2ff","Electron") elif "Run-II-Z-e" in parameterName or "Run-I-Z" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Electron") elif "Run-II-Z-LowMass-mu" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Muon") process+=addLeptonPairCut("25","70") elif "Run-II-Z-HighMass-mu" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Muon") process+=addLeptonPairCut("150","600") elif "Run-II-Z-mu" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Muon") elif "DiPhoton-GammaGamma" in parameterName : process+=insert_ME("MEGammaGammaPowheg","GammaGamma") process+=insert_ME("MEGammaGamma","gg") process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n" process+=jet_kt_cut(5.) parameterName=parameterName.replace("-GammaGamma","") elif "DiPhoton-GammaJet" in parameterName : process+=insert_ME("MEGammaGammaPowheg","VJet") process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n" process+=jet_kt_cut(5.) parameterName=parameterName.replace("-GammaJet","") elif(simulation=="Matchbox" or simulation=="Merging" ) : if "Jets" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p -> j j","2","0","MaxJetPtScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p -> j j","2","0","MaxJetPtScale",1,0) process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n" if "Run-II-Jets-10" in parameterName : process+=addFirstJet("30") process+=addSecondJet("25") process+=addJetPairCut("500") elif "Run-II-Jets-11" in parameterName : process+=addFirstJet("30") process+=addSecondJet("25") process+=addJetPairCut("900") elif "Run-II-Jets-12" in parameterName : process+=addFirstJet("30") process+=addSecondJet("25") process+=addJetPairCut("300") elif "Run-I-Jets-1" in parameterName : process+=addFirstJet("20") elif "Run-I-Jets-2" in parameterName : process+=addFirstJet("40") elif "Run-I-Jets-3" in parameterName : process+=addFirstJet("65") elif "Run-I-Jets-4" in parameterName : process+=addFirstJet("90") elif "Run-I-Jets-5" in parameterName : process+=addFirstJet("160") elif "Run-I-Jets-6" in parameterName : process+=addFirstJet("30")+addSecondJet("25")+addJetPairCut("100") elif "Run-I-Jets-7" in parameterName : process+=addFirstJet("30")+addSecondJet("25")+addJetPairCut("400") elif "Run-I-Jets-8" in parameterName : process+=addFirstJet("30")+addSecondJet("25")+addJetPairCut("700") elif "Run-II-Jets-0" in parameterName : process+=addFirstJet("15") elif "Run-II-Jets-1" in parameterName : process+=addFirstJet("25") elif "Run-II-Jets-2" in parameterName : process+=addFirstJet("40") elif "Run-II-Jets-3" in parameterName : process+=addFirstJet("60") elif "Run-II-Jets-4" in parameterName : process+=addFirstJet("85") elif "Run-II-Jets-5" in parameterName : process+=addFirstJet("110") elif "Run-II-Jets-6" in parameterName : process+=addFirstJet("160") elif "Run-II-Jets-7" in parameterName : process+=addFirstJet("250") elif "Run-II-Jets-8" in parameterName : process+=addFirstJet("30")+addSecondJet("25")+addJetPairCut("100") elif "Run-II-Jets-9" in parameterName : process+=addFirstJet("30")+addSecondJet("25")+addJetPairCut("300") elif "900-Jets-1" in parameterName : process+=addFirstJet("10") elif "300-Jets-1" in parameterName : process+=addFirstJet("6") elif "630-Jets-1" in parameterName : process+=addFirstJet("20") elif "630-Jets-2" in parameterName : process+=addFirstJet("40") elif "630-Jets-3" in parameterName : process+=addFirstJet("75") elif "900-Jets-1" in parameterName : process+=addFirstJet("10") else : logging.error("Exit 00007") sys.exit(1) elif "Run-I-WZ" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p pbar e+ e-","0","2","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p pbar e+ nu","0","2","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p pbar e- nu","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=particlegroup('epm','e+','e-') process+=particlegroup('epmnu','e+','e-','nu_e','nu_ebar') process+=addProcess(thefactory,"p pbar epm epmnu","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("60","120") elif "Run-II-W" in parameterName or "Run-I-W" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p pbar e+ nu","0","2","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p pbar e- nu","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=particlegroup('epm','e+','e-') process+=addProcess(thefactory,"p pbar epm nu","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("60","120") elif "Run-II-Z-e" in parameterName or "Run-I-Z" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p pbar e+ e-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p pbar e+ e-","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("60","120") elif "Run-II-Z-LowMass-mu" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p pbar mu+ mu-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p pbar mu+ mu-","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("25","70") elif "Run-II-Z-HighMass-mu" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p pbar mu+ mu-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p pbar mu+ mu-","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("150","600") elif "Run-II-Z-mu" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p pbar mu+ mu-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p pbar mu+ mu-","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("60","120") # Star elif(collider=="Star" ) : process = StringBuilder("set /Herwig/Decays/DecayHandler:LifeTimeOption 0\n") process+= "set /Herwig/Decays/DecayHandler:MaxLifeTime 10*mm\n" process+= "set /Herwig/Generators/EventGenerator:EventHandler:BeamB /Herwig/Particles/p+\n" process+= collider_lumi(200.0) process+= "set /Herwig/Cuts/Cuts:X2Min 0.01\n" if(simulation=="") : if "UE" in parameterName : if "Dipole" in parameters["shower"]: process+="read snippets/MB-DipoleShower.in\n" else: process+="read snippets/MB.in\n" process+="read snippets/Diffraction.in\n" else : process+=insert_ME("MEQCD2to2") process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n" if "Jets-1" in parameterName : process+=jet_kt_cut(2.) elif "Jets-2" in parameterName : process+=jet_kt_cut(5.) elif "Jets-3" in parameterName : process+=jet_kt_cut(20.) elif "Jets-4" in parameterName : process+=jet_kt_cut(25.) else : logging.error("Star not supported for %s " % simulation) sys.exit(1) # ISR and SppS elif(collider=="ISR" or collider =="SppS" ) : process = StringBuilder("set /Herwig/Decays/DecayHandler:LifeTimeOption 0\n") process+="set /Herwig/Decays/DecayHandler:MaxLifeTime 10*mm\n" if(collider=="SppS") : process = StringBuilder("set /Herwig/Generators/EventGenerator:EventHandler:BeamB /Herwig/Particles/pbar-\n") if "30" in parameterName : process+=collider_lumi( 30.4) elif "44" in parameterName : process+=collider_lumi( 44.4) elif "53" in parameterName : process+=collider_lumi( 53.0) elif "62" in parameterName : process+=collider_lumi( 62.2) elif "63" in parameterName : process+=collider_lumi( 63.0) elif "200" in parameterName : process+=collider_lumi(200.0) elif "500" in parameterName : process+=collider_lumi(500.0) elif "546" in parameterName : process+=collider_lumi(546.0) elif "900" in parameterName : process+=collider_lumi(900.0) if(simulation=="") : if "Dipole" in parameters["shower"]: process+="read snippets/MB-DipoleShower.in\n" else: process+="read snippets/MB.in\n" process+="read snippets/Diffraction.in\n" else : logging.error(" SppS and ISR not supported for %s " % simulation) sys.exit(1) # LHC elif(collider=="LHC") : if parameterName.startswith("7-") : process = StringBuilder(collider_lumi(7000.0)) elif parameterName.startswith("8-") : process = StringBuilder(collider_lumi(8000.0)) elif parameterName.startswith("13-") : process = StringBuilder(collider_lumi(13000.0)) elif parameterName.startswith("900") : process = StringBuilder(collider_lumi(900.0)) elif parameterName.startswith("2360") : process = StringBuilder(collider_lumi(2360.0)) elif parameterName.startswith("2760") : process = StringBuilder(collider_lumi(2760.0)) else : process = StringBuilder(collider_lumi(7000.0)) if(simulation=="") : if "8-VBF" in parameterName : process+=insert_ME("MEPP2HiggsVBF") elif "VBF" in parameterName : process+=selectDecayMode("h0",["h0->tau-,tau+;"]) process+=addBRReweighter() process+="set /Herwig/Particles/tau-:Stable Stable\n" process+=insert_ME("MEPP2HiggsVBF") elif "ggHJet" in parameterName : process+=selectDecayMode("h0",["h0->tau-,tau+;"]) process+=addBRReweighter() process+="set /Herwig/Particles/tau-:Stable Stable\n" process+=insert_ME("MEHiggsJet") process+=jet_kt_cut(20.) elif "8-ggH" in parameterName : process+=insert_ME("MEHiggs") process+=insert_ME("MEHiggsJet","qqbar") process+=jet_kt_cut(0.0) elif "ggH" in parameterName : process+=selectDecayMode("h0",["h0->tau-,tau+;"]) process+=addBRReweighter() process+="set /Herwig/Particles/tau-:Stable Stable\n" process+=insert_ME("MEHiggs") process+=insert_ME("MEHiggsJet","qqbar") process+=jet_kt_cut(0.0) elif "PromptPhoton" in parameterName : process+=insert_ME("MEGammaJet") if "PromptPhoton-1" in parameterName : process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n" elif "PromptPhoton-2" in parameterName : process+="set /Herwig/Cuts/PhotonKtCut:MinKT 25.\n" elif "PromptPhoton-3" in parameterName : process+="set /Herwig/Cuts/PhotonKtCut:MinKT 80.\n" elif "PromptPhoton-4" in parameterName : process+="set /Herwig/Cuts/PhotonKtCut:MinKT 150.\n" elif "DiPhoton-GammaGamma" in parameterName : process+=insert_ME("MEGammaGamma") process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n" parameterName=parameterName.replace("-GammaGamma","") elif "DiPhoton-GammaJet" in parameterName : process+=insert_ME("MEGammaJet") process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n" parameterName=parameterName.replace("-GammaJet","") elif "8-WH" in parameterName : process+=insert_ME("MEPP2WH") process+=jet_kt_cut(0.0) elif "8-ZH" in parameterName : process+=insert_ME("MEPP2ZH") process+=jet_kt_cut(0.0) elif "WH" in parameterName : process+=selectDecayMode("h0",["h0->b,bbar;"]) process+=selectDecayMode("W+",["W+->nu_e,e+;", "W+->nu_mu,mu+;"]) process+=addBRReweighter() process+=insert_ME("MEPP2WH") process+=jet_kt_cut(0.0) elif "ZH" in parameterName : process+=selectDecayMode("h0",["h0->b,bbar;"]) process+=selectDecayMode("Z0",["Z0->e-,e+;", "Z0->mu-,mu+;"]) process+=addBRReweighter() process+=insert_ME("MEPP2ZH") process+=jet_kt_cut(0.0) elif "UE" in parameterName : if "Dipole" in parameters["shower"]: process+="read snippets/MB-DipoleShower.in\n" else: process+="set /Herwig/Shower/ShowerHandler:IntrinsicPtGaussian 2.2*GeV\n" process+="read snippets/MB.in\n" process+="read snippets/Diffraction.in\n" if "Long" in parameterName : process += "set /Herwig/Decays/DecayHandler:MaxLifeTime 100*mm\n" elif "8-DiJets" in parameterName or "7-DiJets" in parameterName : process+=insert_ME("MEQCD2to2") process+="set MEQCD2to2:MaximumFlavour 5\n" process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n" if "-A" in parameterName : process+=jet_kt_cut(45.) process+="set /Herwig/Cuts/JetKtCut:MinEta -3.\n" process+="set /Herwig/Cuts/JetKtCut:MaxEta 3.\n" elif "-B" in parameterName : process+=jet_kt_cut(20.) process+="set /Herwig/Cuts/JetKtCut:MinEta -2.7\n" process+="set /Herwig/Cuts/JetKtCut:MaxEta 2.7\n" elif "-C" in parameterName : process+=jet_kt_cut(20.) process+="set /Herwig/Cuts/JetKtCut:MinEta -4.8\n" process+="set /Herwig/Cuts/JetKtCut:MaxEta 4.8\n" if "DiJets-1" in parameterName : process+=mhatmin_cut(90.) elif "DiJets-2" in parameterName : process+=mhatmin_cut(200.) elif "DiJets-3" in parameterName : process+=mhatmin_cut(450.) elif "DiJets-4" in parameterName : process+=mhatmin_cut(750.) elif "DiJets-5" in parameterName : process+=mhatmin_cut(950.) elif "DiJets-6" in parameterName : process+=mhatmin_cut(1550.) elif "DiJets-7" in parameterName : process+=mhatmin_cut(2150.) elif "DiJets-8" in parameterName : process+=mhatmin_cut(2750.) elif( "7-Jets" in parameterName or "8-Jets" in parameterName or "13-Jets" in parameterName ) : process+=insert_ME("MEQCD2to2") process+="set MEQCD2to2:MaximumFlavour 5\n" process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n" if "Jets-10" in parameterName : process+=jet_kt_cut(1800.) elif "Jets-0" in parameterName : process+=jet_kt_cut(5.) elif "Jets-1" in parameterName : process+=jet_kt_cut(10.) elif "Jets-2" in parameterName : process+=jet_kt_cut(20.) elif "Jets-3" in parameterName : process+=jet_kt_cut(40.) elif "Jets-4" in parameterName : process+=jet_kt_cut(70.) elif "Jets-5" in parameterName : process+=jet_kt_cut(150.) elif "Jets-6" in parameterName : process+=jet_kt_cut(200.) elif "Jets-7" in parameterName : process+=jet_kt_cut(300.) elif "Jets-8" in parameterName : process+=jet_kt_cut(500.) elif "Jets-9" in parameterName : process+=jet_kt_cut(800.) elif("7-Charm" in parameterName or "7-Bottom" in parameterName) : if "7-Bottom" in parameterName : process+="cp MEHeavyQuark MEBottom\n" process+="set MEBottom:QuarkType Bottom\n" process+=insert_ME("MEBottom") else : process+="cp MEHeavyQuark MECharm\n" process+="set MECharm:QuarkType Charm\n" process+=insert_ME("MECharm") process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n" if "-0" in parameterName : if "7-Bottom" in parameterName : process+="set MEBottom:Process Pair\n" process+=jet_kt_cut(0.) elif "-1" in parameterName : process+=jet_kt_cut(5.) elif "-2" in parameterName : process+=jet_kt_cut(20.) elif "-3" in parameterName : process+=jet_kt_cut(50.) elif "-4" in parameterName : process+=jet_kt_cut(80.) elif "-5" in parameterName : process+=jet_kt_cut(110.) elif "-6" in parameterName : process+=jet_kt_cut(30.)+mhatmin_cut(90.) elif "-7" in parameterName : process+=jet_kt_cut(30.)+mhatmin_cut(340.) elif "-8" in parameterName : process+=jet_kt_cut(30.)+mhatmin_cut(500.) elif "Top-L" in parameterName : process+="set MEHeavyQuark:QuarkType Top\n" process+=insert_ME("MEHeavyQuark") process+=selectDecayMode("t",["t->nu_e,e+,b;", "t->nu_mu,mu+,b;"]) process+=addBRReweighter() elif "Top-SL" in parameterName : process+="set MEHeavyQuark:QuarkType Top\n" process+=insert_ME("MEHeavyQuark") process+="set /Herwig/Particles/t:Synchronized Not_synchronized\n" process+="set /Herwig/Particles/tbar:Synchronized Not_synchronized\n" process+=selectDecayMode("t",["t->nu_e,e+,b;","t->nu_mu,mu+,b;"]) process+=selectDecayMode("tbar",["tbar->b,bbar,cbar;", "tbar->bbar,cbar,d;", "tbar->bbar,cbar,s;", "tbar->bbar,s,ubar;", "tbar->bbar,ubar,d;"]) process+=addBRReweighter() elif "Top-All" in parameterName : process+="set MEHeavyQuark:QuarkType Top\n" process+=insert_ME("MEHeavyQuark") elif "WZ" in parameterName : process+=insert_ME("MEPP2VV","WZ") process+=selectDecayMode("W+",["W+->nu_e,e+;", "W+->nu_mu,mu+;"]) process+=selectDecayMode("W-",["W-->nu_ebar,e-;", "W-->nu_mubar,mu-;"]) process+=selectDecayMode("Z0",["Z0->e-,e+;", "Z0->mu-,mu+;"]) process+=addBRReweighter() elif "WW-emu" in parameterName : process+=insert_ME("MEPP2VV","WW") process+="set /Herwig/Particles/W+:Synchronized 0\n" process+="set /Herwig/Particles/W-:Synchronized 0\n" process+=selectDecayMode("W+",["W+->nu_e,e+;"]) process+=selectDecayMode("W-",["W-->nu_mubar,mu-;"]) process+=addBRReweighter() elif "WW-ll" in parameterName : process+=insert_ME("MEPP2VV","WW") process+=selectDecayMode("W+",["W+->nu_e,e+;","W+->nu_mu,mu+;","W+->nu_tau,tau+;"]) process+=addBRReweighter() elif "ZZ-ll" in parameterName : process+=insert_ME("MEPP2VV","ZZ") process+=selectDecayMode("Z0",["Z0->e-,e+;", "Z0->mu-,mu+;", "Z0->tau-,tau+;"]) process+=addBRReweighter() elif "ZZ-lv" in parameterName : process+=insert_ME("MEPP2VV","ZZ") process+=selectDecayMode("Z0",["Z0->e-,e+;", "Z0->mu-,mu+;", "Z0->tau-,tau+;", "Z0->nu_e,nu_ebar;", "Z0->nu_mu,nu_mubar;", "Z0->nu_tau,nu_taubar;"]) process+=addBRReweighter() elif "W-Z-e" in parameterName : process+=insert_ME("MEqq2gZ2ff","Electron") process+=insert_ME("MEqq2W2ff","Electron") elif "W-Z-mu" in parameterName : process+=insert_ME("MEqq2gZ2ff","Muon") process+=insert_ME("MEqq2W2ff","Muon") elif "W-e" in parameterName : process+=insert_ME("MEqq2W2ff","Electron") elif "W-mu" in parameterName : process+=insert_ME("MEqq2W2ff","Muon") elif "Z-e" in parameterName : process+=insert_ME("MEqq2gZ2ff","Electron") elif "Z-mu" in parameterName : process+=insert_ME("MEqq2gZ2ff","Muon") elif "Z-LowMass-e" in parameterName : process+=insert_ME("MEqq2gZ2ff","Electron") process+=mhat_minm_maxm(20,20,70) elif "Z-MedMass-e" in parameterName : process+=insert_ME("MEqq2gZ2ff","Electron") process+=mhat_minm_maxm(40,40,130) elif "Z-LowMass-mu" in parameterName : process+=insert_ME("MEqq2gZ2ff","Muon") process+=mhat_minm_maxm(10,10,70) elif "Z-Mass1" in parameterName : process+=mhat_minm_maxm(10,10,35) if "-e" in parameterName : process+=insert_ME("MEqq2gZ2ff","Electron") else : process+=insert_ME("MEqq2gZ2ff","Muon") elif "Z-Mass2" in parameterName : process+=mhat_minm_maxm(25,25,70) if "-e" in parameterName : process+=insert_ME("MEqq2gZ2ff","Electron") else : process+=insert_ME("MEqq2gZ2ff","Muon") elif "Z-Mass3" in parameterName : process+=mhat_minm_maxm(60,60,120) if "-e" in parameterName : process+=insert_ME("MEqq2gZ2ff","Electron") else : process+=insert_ME("MEqq2gZ2ff","Muon") elif "Z-Mass4" in parameterName : process+=mhat_minm_maxm(110,110,8000) if "-e" in parameterName : process+=insert_ME("MEqq2gZ2ff","Electron") else : process+=insert_ME("MEqq2gZ2ff","Muon") elif "Z-HighMass1" in parameterName : process+=mhat_minm_maxm(116,116,400) if "-e" in parameterName : process+=insert_ME("MEqq2gZ2ff","Electron") else : process+=insert_ME("MEqq2gZ2ff","Muon") elif "Z-HighMass2" in parameterName : process+=mhat_minm_maxm(400,400,7000) if "-e" in parameterName : process+=insert_ME("MEqq2gZ2ff","Electron") else : process+=insert_ME("MEqq2gZ2ff","Muon") elif "W-Jet" in parameterName : process+=insert_ME("MEWJet","Electron","WDecay") if "W-Jet-1-e" in parameterName : process+="set /Herwig/Cuts/WBosonKtCut:MinKT 100.0*GeV\n" parameterName=parameterName.replace("W-Jet-1-e","W-Jet-e") elif "W-Jet-2-e" in parameterName : process+="set /Herwig/Cuts/WBosonKtCut:MinKT 190.0*GeV\n" parameterName=parameterName.replace("W-Jet-2-e","W-Jet-e") elif "W-Jet-3-e" in parameterName : process+="set /Herwig/Cuts/WBosonKtCut:MinKT 270.0*GeV\n" parameterName=parameterName.replace("W-Jet-3-e","W-Jet-e") elif "Z-Jet" in parameterName : if "-e" in parameterName : process+=insert_ME("MEZJet","Electron","ZDecay") if "Z-Jet-0-e" in parameterName : process+="set /Herwig/Cuts/ZBosonKtCut:MinKT 35.0*GeV\n" parameterName=parameterName.replace("Z-Jet-0-e","Z-Jet-e") elif "Z-Jet-1-e" in parameterName : process+="set /Herwig/Cuts/ZBosonKtCut:MinKT 100.0*GeV\n" parameterName=parameterName.replace("Z-Jet-1-e","Z-Jet-e") elif "Z-Jet-2-e" in parameterName : process+="set /Herwig/Cuts/ZBosonKtCut:MinKT 190.0*GeV\n" parameterName=parameterName.replace("Z-Jet-2-e","Z-Jet-e") elif "Z-Jet-3-e" in parameterName : process+="set /Herwig/Cuts/ZBosonKtCut:MinKT 270.0*GeV\n" parameterName=parameterName.replace("Z-Jet-3-e","Z-Jet-e") else : process+=insert_ME("MEZJet","Muon","ZDecay") process+="set /Herwig/Cuts/ZBosonKtCut:MinKT 35.0*GeV\n" parameterName=parameterName.replace("Z-Jet-0-mu","Z-Jet-mu") elif "WGamma" in parameterName : process+=insert_ME("MEPP2VGamma","1") process+="set MEPP2VGamma:MassOption 1" process+="set /Herwig/Cuts/PhotonKtCut:MinKT 10.\n" if "-e" in parameterName : process+=selectDecayMode("W+",["W+->nu_e,e+;"]) process+=addBRReweighter() else : process+=selectDecayMode("W+",["W+->nu_mu,mu+;"]) process+=addBRReweighter() elif "ZGamma" in parameterName : process+=insert_ME("MEPP2VGamma","2") process+="set /Herwig/Cuts/PhotonKtCut:MinKT 10.\n" if "-e" in parameterName : process+=selectDecayMode("Z0",["Z0->e-,e+;"]) process+=addBRReweighter() else : process+=selectDecayMode("Z0",["Z0->mu-,mu+;"]) process+=addBRReweighter() else : logging.error(" Process %s not supported for internal matrix elements" % name) sys.exit(1) elif(simulation=="Powheg") : if "8-VBF" in parameterName : process+=insert_ME("PowhegMEPP2HiggsVBF") elif "VBF" in parameterName : process+=selectDecayMode("h0",["h0->tau-,tau+;"]) process+=addBRReweighter() process+="set /Herwig/Particles/tau-:Stable Stable\n" process+=insert_ME("PowhegMEPP2HiggsVBF") elif "ggHJet" in parameterName : logging.error(" Process %s not supported for POWHEG matrix elements" % name) sys.exit(1) elif "8-ggH" in parameterName : process+=insert_ME("PowhegMEHiggs") elif "ggH" in parameterName : process+=selectDecayMode("h0",["h0->tau-,tau+;"]) process+=addBRReweighter() process+="set /Herwig/Particles/tau-:Stable Stable\n" process+=insert_ME("PowhegMEHiggs") elif "8-WH" in parameterName : process+=insert_ME("PowhegMEPP2WH") process+=jet_kt_cut(0.0) elif "8-ZH" in parameterName : process+=insert_ME("PowhegMEPP2ZH") process+=jet_kt_cut(0.0) elif "WH" in parameterName : process+=selectDecayMode("h0",["h0->b,bbar;"]) process+=selectDecayMode("W+",["W+->nu_e,e+;", "W+->nu_mu,mu+;"]) process+=addBRReweighter() process+=insert_ME("PowhegMEPP2WH") process+=jet_kt_cut(0.0) elif "ZH" in parameterName : process+=selectDecayMode("h0",["h0->b,bbar;"]) process+=selectDecayMode("Z0",["Z0->e-,e+;", "Z0->mu-,mu+;"]) process+=addBRReweighter() process+=insert_ME("PowhegMEPP2ZH") process+=jet_kt_cut(0.0) elif "UE" in parameterName : logging.error(" Process %s not supported for powheg matrix elements" % name) sys.exit(1) elif "WZ" in parameterName : process+="create Herwig::HwDecayHandler /Herwig/NewPhysics/DecayHandler\n" process+="set /Herwig/NewPhysics/DecayHandler:NewStep No\n" process+="set /Herwig/Shower/ShowerHandler:SplitHardProcess No\n"; process+="set /Herwig/Decays/ZDecayer:PhotonGenerator NULL\n"; - process+="set /Herwig/Decays/ZPowhegDecayer:PhotonGenerator NULL\n"; process+="set /Herwig/Decays/WDecayer:PhotonGenerator NULL\n"; - process+="set /Herwig/Decays/WPowhegDecayer:PhotonGenerator NULL\n"; process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 0 /Herwig/Particles/tau-\n" process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 1 /Herwig/Particles/tau+\n" process+="insert /Herwig/Generators/EventGenerator:EventHandler:PreCascadeHandlers 0 /Herwig/NewPhysics/DecayHandler\n" process+=insert_ME("PowhegMEPP2VV","WZ") process+=selectDecayMode("W+",["W+->nu_e,e+;", "W+->nu_mu,mu+;"]) process+=selectDecayMode("W-",["W-->nu_ebar,e-;", "W-->nu_mubar,mu-;"]) process+=selectDecayMode("Z0",["Z0->e-,e+;", "Z0->mu-,mu+;"]) process+=addBRReweighter() elif "WW-emu" in parameterName : process+="create Herwig::HwDecayHandler /Herwig/NewPhysics/DecayHandler\n" process+="set /Herwig/NewPhysics/DecayHandler:NewStep No\n" process+="set /Herwig/Shower/ShowerHandler:SplitHardProcess No\n"; process+="set /Herwig/Decays/ZDecayer:PhotonGenerator NULL\n"; - process+="set /Herwig/Decays/ZPowhegDecayer:PhotonGenerator NULL\n"; process+="set /Herwig/Decays/WDecayer:PhotonGenerator NULL\n"; - process+="set /Herwig/Decays/WPowhegDecayer:PhotonGenerator NULL\n"; process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 0 /Herwig/Particles/tau-\n" process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 1 /Herwig/Particles/tau+\n" process+="insert /Herwig/Generators/EventGenerator:EventHandler:PreCascadeHandlers 0 /Herwig/NewPhysics/DecayHandler\n" process+=insert_ME("PowhegMEPP2VV","WW") process+="set /Herwig/Particles/W+:Synchronized 0\n" process+="set /Herwig/Particles/W-:Synchronized 0\n" process+=selectDecayMode("W+",["W+->nu_e,e+;"]) process+=selectDecayMode("W-",["W-->nu_mubar,mu-;"]) process+=addBRReweighter() elif "WW-ll" in parameterName : process+="create Herwig::HwDecayHandler /Herwig/NewPhysics/DecayHandler\n" process+="set /Herwig/NewPhysics/DecayHandler:NewStep No\n" process+="set /Herwig/Shower/ShowerHandler:SplitHardProcess No\n"; process+="set /Herwig/Decays/ZDecayer:PhotonGenerator NULL\n"; - process+="set /Herwig/Decays/ZPowhegDecayer:PhotonGenerator NULL\n"; process+="set /Herwig/Decays/WDecayer:PhotonGenerator NULL\n"; - process+="set /Herwig/Decays/WPowhegDecayer:PhotonGenerator NULL\n"; process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 0 /Herwig/Particles/tau-\n" process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 1 /Herwig/Particles/tau+\n" process+="insert /Herwig/Generators/EventGenerator:EventHandler:PreCascadeHandlers 0 /Herwig/NewPhysics/DecayHandler\n" process+=insert_ME("PowhegMEPP2VV","WW") process+=selectDecayMode("W+",["W+->nu_e,e+;", "W+->nu_mu,mu+;", "W+->nu_tau,tau+;"]) process+=addBRReweighter() elif "ZZ-ll" in parameterName : process+="create Herwig::HwDecayHandler /Herwig/NewPhysics/DecayHandler\n" process+="set /Herwig/NewPhysics/DecayHandler:NewStep No\n" process+="set /Herwig/Shower/ShowerHandler:SplitHardProcess No\n"; process+="set /Herwig/Decays/ZDecayer:PhotonGenerator NULL\n"; - process+="set /Herwig/Decays/ZPowhegDecayer:PhotonGenerator NULL\n"; process+="set /Herwig/Decays/WDecayer:PhotonGenerator NULL\n"; - process+="set /Herwig/Decays/WPowhegDecayer:PhotonGenerator NULL\n"; process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 0 /Herwig/Particles/tau-\n" process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 1 /Herwig/Particles/tau+\n" process+="insert /Herwig/Generators/EventGenerator:EventHandler:PreCascadeHandlers 0 /Herwig/NewPhysics/DecayHandler\n" process+=insert_ME("PowhegMEPP2VV","ZZ") process+=selectDecayMode("Z0",["Z0->e-,e+;", "Z0->mu-,mu+;", "Z0->tau-,tau+;"]) process+=addBRReweighter() elif "ZZ-lv" in parameterName : process+="create Herwig::HwDecayHandler /Herwig/NewPhysics/DecayHandler\n" process+="set /Herwig/NewPhysics/DecayHandler:NewStep No\n" process+="set /Herwig/Shower/ShowerHandler:SplitHardProcess No\n"; process+="set /Herwig/Decays/ZDecayer:PhotonGenerator NULL\n"; - process+="set /Herwig/Decays/ZPowhegDecayer:PhotonGenerator NULL\n"; process+="set /Herwig/Decays/WDecayer:PhotonGenerator NULL\n"; - process+="set /Herwig/Decays/WPowhegDecayer:PhotonGenerator NULL\n"; process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 0 /Herwig/Particles/tau-\n" process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 1 /Herwig/Particles/tau+\n" process+="insert /Herwig/Generators/EventGenerator:EventHandler:PreCascadeHandlers 0 /Herwig/NewPhysics/DecayHandler\n" process+=insert_ME("PowhegMEPP2VV","ZZ") process+=selectDecayMode("Z0",["Z0->e-,e+;", "Z0->mu-,mu+;", "Z0->tau-,tau+;", "Z0->nu_e,nu_ebar;", "Z0->nu_mu,nu_mubar;", "Z0->nu_tau,nu_taubar;"]) process+=addBRReweighter() elif "W-Z-e" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Electron") process+=insert_ME("PowhegMEqq2W2ff","Electron") elif "W-Z-mu" in parameterName : process+=insert_ME("MEqq2gZ2ff","Muon") process+=insert_ME("MEqq2W2ff","Muon") elif "W-e" in parameterName : process+=insert_ME("PowhegMEqq2W2ff","Electron") elif "W-mu" in parameterName : process+=insert_ME("PowhegMEqq2W2ff","Muon") elif "Z-e" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Electron") elif "Z-mu" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Muon") elif "Z-LowMass-e" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Electron") process+=mhat_minm_maxm(20,20,70) elif "Z-MedMass-e" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Electron") process+=mhat_minm_maxm(40,40,130) elif "Z-LowMass-mu" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Muon") process+=mhat_minm_maxm(10,10,70) elif "Z-Mass1" in parameterName : process+=mhat_minm_maxm(10,10,35) if "-e" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Electron") else : process+=insert_ME("PowhegMEqq2gZ2ff","Muon") elif "Z-Mass2" in parameterName : process+=mhat_minm_maxm(25,25,70) if "-e" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Electron") else : process+=insert_ME("PowhegMEqq2gZ2ff","Muon") elif "Z-Mass3" in parameterName : process+=mhat_minm_maxm(60,60,120) if "-e" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Electron") else : process+=insert_ME("PowhegMEqq2gZ2ff","Muon") elif "Z-Mass4" in parameterName : process+=mhat_minm_maxm(110,110,8000) if "-e" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Electron") else : process+=insert_ME("PowhegMEqq2gZ2ff","Muon") elif "Z-HighMass1" in parameterName : process+=mhat_minm_maxm(116,116,400) if "-e" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Electron") else : process+=insert_ME("PowhegMEqq2gZ2ff","Muon") elif "Z-HighMass2" in parameterName : process+=mhat_minm_maxm(400,400,7000) if "-e" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Electron") else : process+=insert_ME("PowhegMEqq2gZ2ff","Muon") elif "DiPhoton-GammaGamma" in parameterName : process+=insert_ME("MEGammaGammaPowheg","GammaGamma") process+=insert_ME("MEGammaGamma","gg") process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n" process+=jet_kt_cut(5.) parameterName=parameterName.replace("-GammaGamma","") elif "DiPhoton-GammaJet" in parameterName : process+=insert_ME("MEGammaGammaPowheg","VJet") process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n" process+=jet_kt_cut(5.) parameterName=parameterName.replace("-GammaJet","") else : logging.error(" Process %s not supported for internal POWHEG matrix elements" % name) sys.exit(1) elif( simulation=="Matchbox" or simulation=="Merging" ) : if "8-VBF" in parameterName : parameters["nlo"] = "read Matchbox/VBFNLO.in\n" if(simulation=="Merging"): process+="cd /Herwig/Merging/\n" process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/Z0\n" process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/W+\n" process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/W-\n" process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/gamma\n" process+="do "+thefactory+":DiagramGenerator:TimeLikeRange 0 0\n" if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p h0 j j","0","3","FixedScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p h0 j j","0","3","FixedScale",1,1) process+=setHardProcessWidthToZero(["h0"]) process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 125.7\n" if "GammaGamma" in parameterName : process+=selectDecayMode("h0",["h0->gamma,gamma;"]) process+=addBRReweighter() elif "WW" in parameterName : process+=selectDecayMode("h0",["h0->W+,W-;"]) process+=addBRReweighter() elif "ZZ" in parameterName : process+=selectDecayMode("h0",["h0->Z0,Z0;"]) process+=addBRReweighter() elif "VBF" in parameterName : process+=selectDecayMode("h0",["h0->tau-,tau+;"]) process+=addBRReweighter() process+="set /Herwig/Particles/tau-:Stable Stable\n" parameters["nlo"] = "read Matchbox/VBFNLO.in\n" if(simulation=="Merging"): process+="cd /Herwig/Merging/\n" process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/Z0\n" process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/W+\n" process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/W-\n" process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/gamma\n" process+="do "+thefactory+":DiagramGenerator:TimeLikeRange 0 0\n" if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p h0 j j","0","3","FixedScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p h0 j j","0","3","FixedScale",1,1) process+=setHardProcessWidthToZero(["h0"]) process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 125.7\n" elif "ggHJet" in parameterName : if(simulation=="Merging"): logging.warning("ggHJet not explicitly tested for %s " % simulation) sys.exit(0) parameters["nlo"] = "read Matchbox/MadGraph-GoSam.in\nread Matchbox/HiggsEffective.in\n" process+=selectDecayMode("h0",["h0->tau-,tau+;"]) process+=addBRReweighter() process+="set /Herwig/Particles/tau-:Stable Stable\n" process+=setHardProcessWidthToZero(["h0"]) process+=addProcess(thefactory,"p p h0 j","3","1","FixedScale",0,0) process+=addFirstJet("20") process+="set "+thefactory+":ScaleChoice /Herwig/MatrixElements/Matchbox/Scales/FixedScale\n" process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 125.7\n" elif "8-ggH" in parameterName : parameters["nlo"] = "read Matchbox/MadGraph-GoSam.in\nread Matchbox/HiggsEffective.in\n" if(simulation=="Merging"): process+= "cd /Herwig/MatrixElements/Matchbox/Amplitudes\nset OpenLoops:HiggsEff On\nset MadGraph:Model heft\n" process+="cd /Herwig/Merging/\n" process+=setHardProcessWidthToZero(["h0"]) if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p h0","2","1","FixedScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p h0","2","1","FixedScale",2,2) process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 125.7\n" if "GammaGamma" in parameterName : process+=selectDecayMode("h0",["h0->gamma,gamma;"]) process+=addBRReweighter() elif "WW" in parameterName : process+=selectDecayMode("h0",["h0->W+,W-;"]) process+=addBRReweighter() elif "ZZ" in parameterName : process+=selectDecayMode("h0",["h0->Z0,Z0;"]) process+=addBRReweighter() elif "ggH" in parameterName : parameters["nlo"] = "read Matchbox/MadGraph-GoSam.in\nread Matchbox/HiggsEffective.in\n" if(simulation=="Merging"): process+= "cd /Herwig/MatrixElements/Matchbox/Amplitudes\nset OpenLoops:HiggsEff On\nset MadGraph:Model heft\n" process+="cd /Herwig/Merging/\n" process+=selectDecayMode("h0",["h0->tau-,tau+;"]) process+=addBRReweighter() process+="set /Herwig/Particles/tau-:Stable Stable\n" process+=setHardProcessWidthToZero(["h0"]) if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p h0","2","1","FixedScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p h0","2","1","FixedScale",2,2) process+="set "+thefactory+":ScaleChoice /Herwig/MatrixElements/Matchbox/Scales/FixedScale\n" process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 125.7\n" elif "8-WH" in parameterName : if(simulation=="Merging"): logging.warning("8-WH not explicitly tested for %s " % simulation) sys.exit(0) process+=setHardProcessWidthToZero(["h0","W+","W-"]) process+=addProcess(thefactory,"p p W+ h0","0","2","FixedScale",0,0) process+=addProcess(thefactory,"p p W- h0","0","2","FixedScale",0,0) process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 125.7\n" if "GammaGamma" in parameterName : process+=selectDecayMode("h0",["h0->gamma,gamma;"]) process+=addBRReweighter() elif "WW" in parameterName : process+=selectDecayMode("h0",["h0->W+,W-;"]) process+=addBRReweighter() elif "ZZ" in parameterName : process+=selectDecayMode("h0",["h0->Z0,Z0;"]) process+=addBRReweighter() elif "8-ZH" in parameterName : if(simulation=="Merging"): logging.warning("8-ZH not explicitly tested for %s " % simulation) sys.exit(0) process+=setHardProcessWidthToZero(["h0","Z0"]) process+=addProcess(thefactory,"p p Z0 h0","0","2","FixedScale",0,0) process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 125.7\n" if "GammaGamma" in parameterName : process+=selectDecayMode("h0",["h0->gamma,gamma;"]) process+=addBRReweighter() elif "WW" in parameterName : process+=selectDecayMode("h0",["h0->W+,W-;"]) process+=addBRReweighter() elif "ZZ" in parameterName : process+=selectDecayMode("h0",["h0->Z0,Z0;"]) process+=addBRReweighter() elif "WH" in parameterName : if(simulation=="Merging"): logging.warning("WH not explicitly tested for %s " % simulation) sys.exit(0) process+=selectDecayMode("h0",["h0->b,bbar;"]) process+=addBRReweighter() process+=setHardProcessWidthToZero(["h0"]) process+=addProcess(thefactory,"p p e+ nu h0","0","3","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p p e- nu h0","0","3","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p p mu+ nu h0","0","3","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p p mu- nu h0","0","3","LeptonPairMassScale",0,0) process+=addLeptonPairCut("60","120") elif "ZH" in parameterName : if(simulation=="Merging"): logging.warning("ZH not explicitly tested for %s " % simulation) sys.exit(0) process+=selectDecayMode("h0",["h0->b,bbar;"]) process+=addBRReweighter() process+=setHardProcessWidthToZero(["h0"]) process+=addProcess(thefactory,"p p e+ e- h0","0","3","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p p mu+ mu- h0","0","3","LeptonPairMassScale",0,0) process+=addLeptonPairCut("60","120") elif "UE" in parameterName : logging.error(" Process %s not supported for Matchbox matrix elements" % name) sys.exit(1) elif "8-DiJets" in parameterName or "7-DiJets" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p j j","2","0","MaxJetPtScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p j j","2","0","MaxJetPtScale",1,1) process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n" if "-A" in parameterName : process+=addFirstJet("45") process+=addSecondJet("25") process+="set /Herwig/Cuts/FirstJet:YRange -3. 3.\n" process+="set /Herwig/Cuts/SecondJet:YRange -3. 3.\n" elif "-B" in parameterName : process+=addFirstJet("20") process+=addSecondJet("15") process+="set /Herwig/Cuts/FirstJet:YRange -2.7 2.7\n" process+="set /Herwig/Cuts/SecondJet:YRange -2.7 2.7\n" elif "-C" in parameterName : process+=addFirstJet("20") process+=addSecondJet("15") process+="set /Herwig/Cuts/FirstJet:YRange -4.8 4.8\n" process+="set /Herwig/Cuts/SecondJet:YRange -4.8 4.8\n" else : logging.error("Exit 00001") sys.exit(1) if "DiJets-1" in parameterName : process+=addJetPairCut("90") elif "DiJets-2" in parameterName : process+=addJetPairCut("200") elif "DiJets-3" in parameterName : process+=addJetPairCut("450") elif "DiJets-4" in parameterName : process+=addJetPairCut("750") elif "DiJets-5" in parameterName : process+=addJetPairCut("950") elif "DiJets-6" in parameterName : process+=addJetPairCut("1550") elif "DiJets-7" in parameterName : process+=addJetPairCut("2150") elif "DiJets-8" in parameterName : process+=addJetPairCut("2750") else : logging.error("Exit 00002") sys.exit(1) elif( "7-Jets" in parameterName or "8-Jets" in parameterName or "13-Jets" in parameterName ) : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p j j","2","0","MaxJetPtScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p j j","2","0","MaxJetPtScale",1,1) process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n" if "Jets-10" in parameterName : process+=addFirstJet("1800") elif "Jets-0" in parameterName : process+=addFirstJet("5") elif "Jets-1" in parameterName : process+=addFirstJet("10") elif "Jets-2" in parameterName : process+=addFirstJet("20") elif "Jets-3" in parameterName : process+=addFirstJet("40") elif "Jets-4" in parameterName : process+=addFirstJet("70") elif "Jets-5" in parameterName : process+=addFirstJet("150") elif "Jets-6" in parameterName : process+=addFirstJet("200") elif "Jets-7" in parameterName : process+=addFirstJet("300") elif "Jets-8" in parameterName : process+=addFirstJet("500") elif "Jets-9" in parameterName : process+=addFirstJet("800") else : logging.error("Exit 00003") sys.exit(1) elif( "7-Charm" in parameterName or "7-Bottom" in parameterName) : parameters["bscheme"]=fourFlavour process+="set /Herwig/Particles/b:HardProcessMass 4.2*GeV\n" process+="set /Herwig/Particles/bbar:HardProcessMass 4.2*GeV\n" if "7-Bottom" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p b bbar","2","0","MaxJetPtScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p b bbar","2","0","MaxJetPtScale",1,0) else: if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p c cbar","2","0","MaxJetPtScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p c cbar","2","0","MaxJetPtScale",1,0) process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n" if "-0" in parameterName : process+=addFirstJet("0") elif "-1" in parameterName : process+=addFirstJet("5") elif "-2" in parameterName : process+=addFirstJet("20") elif "-3" in parameterName : process+=addFirstJet("50") elif "-4" in parameterName : process+=addFirstJet("80") elif "-5" in parameterName : process+=addFirstJet("110") elif "-6" in parameterName : process+=addFirstJet("30") process+=addSecondJet("25") process+=addJetPairCut("90") elif "-7" in parameterName : process+=addFirstJet("30") process+=addSecondJet("25") process+=addJetPairCut("340") elif "-8" in parameterName : process+=addFirstJet("30") process+=addSecondJet("25") process+=addJetPairCut("500") else : logging.error("Exit 00004") sys.exit(1) elif "Top-L" in parameterName : process+=setHardProcessWidthToZero(["t","tbar"]) if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p t tbar","2","0","TopPairMTScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p t tbar","2","0","TopPairMTScale",2,2) process+=selectDecayMode("t",["t->nu_e,e+,b;", "t->nu_mu,mu+,b;"]) process+=addBRReweighter() elif "Top-SL" in parameterName : process+=setHardProcessWidthToZero(["t","tbar"]) if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p t tbar","2","0","TopPairMTScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p t tbar","2","0","TopPairMTScale",2,2) process+="set /Herwig/Particles/t:Synchronized Not_synchronized\n" process+="set /Herwig/Particles/tbar:Synchronized Not_synchronized\n" process+=selectDecayMode("t",["t->nu_e,e+,b;", "t->nu_mu,mu+,b;"]) process+=selectDecayMode("tbar",["tbar->b,bbar,cbar;", "tbar->bbar,cbar,d;", "tbar->bbar,cbar,s;", "tbar->bbar,s,ubar;", "tbar->bbar,ubar,d;"]) process+=addBRReweighter() elif "Top-All" in parameterName : process+=setHardProcessWidthToZero(["t","tbar"]) if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p t tbar","2","0","TopPairMTScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p t tbar","2","0","TopPairMTScale",2,2) elif "WZ" in parameterName : if(simulation=="Merging"): logging.warning("WZ not explicitly tested for %s " % simulation) sys.exit(0) process+=setHardProcessWidthToZero(["W+","W-","Z0"]) process+=addProcess(thefactory,"p p W+ Z0","0","2","FixedScale",0,0) process+=addProcess(thefactory,"p p W- Z0","0","2","FixedScale",0,0) process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 171.6*GeV\n\n" process+=selectDecayMode("W+",["W+->nu_e,e+;", "W+->nu_mu,mu+;"]) process+=selectDecayMode("W-",["W-->nu_ebar,e-;", "W-->nu_mubar,mu-;"]) process+=selectDecayMode("Z0",["Z0->e-,e+;", "Z0->mu-,mu+;"]) process+=addBRReweighter() process+=addLeptonPairCut("60","120") elif "WW-emu" in parameterName : if(simulation=="Merging"): logging.warning("WW-emu not explicitly tested for %s " % simulation) sys.exit(0) process+=setHardProcessWidthToZero(["W+","W-","Z0"]) process+=addProcess(thefactory,"p p W+ W-","0","2","FixedScale",0,0) process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 160.8*GeV\n" process+="set /Herwig/Particles/W+:Synchronized 0\n" process+="set /Herwig/Particles/W-:Synchronized 0\n" process+=selectDecayMode("W+",["W+->nu_e,e+;"]) process+=selectDecayMode("W-",["W-->nu_mubar,mu-;"]) process+=addBRReweighter() parameters["bscheme"] = "read Matchbox/FourFlavourScheme.in\n" process+=addLeptonPairCut("60","120") elif "WW-ll" in parameterName : if(simulation=="Merging"): logging.warning("WW-ll not explicitly tested for %s " % simulation) sys.exit(0) process+=setHardProcessWidthToZero(["W+","W-","Z0"]) process+=addProcess(thefactory,"p p W+ W-","0","2","FixedScale",0,0) process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 160.8*GeV\n" process+=selectDecayMode("W+",["W+->nu_e,e+;", "W+->nu_mu,mu+;", "W+->nu_tau,tau+;"]) process+=addBRReweighter() process+=addLeptonPairCut("60","120") parameters["bscheme"] = "read Matchbox/FourFlavourScheme.in\n" elif "ZZ-ll" in parameterName : if(simulation=="Merging"): logging.warning("ZZ-ll not explicitly tested for %s " % simulation) sys.exit(0) process+=setHardProcessWidthToZero(["W+","W-","Z0"]) process+=addProcess(thefactory,"p p Z0 Z0","0","2","FixedScale",0,0) process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 182.2*GeV\n" process+=selectDecayMode("Z0",["Z0->e-,e+;", "Z0->mu-,mu+;", "Z0->tau-,tau+;"]) process+=addBRReweighter() process+=addLeptonPairCut("60","120") elif "ZZ-lv" in parameterName : if(simulation=="Merging"): logging.warning("ZZ-lv not explicitly tested for %s " % simulation) sys.exit(0) process+=setHardProcessWidthToZero(["W+","W-","Z0"]) process+=addProcess(thefactory,"p p Z0 Z0","0","2","FixedScale",0,0) process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 182.2*GeV\n" process+=selectDecayMode("Z0",["Z0->e-,e+;", "Z0->mu-,mu+;", "Z0->tau-,tau+;", "Z0->nu_e,nu_ebar;", "Z0->nu_mu,nu_mubar;", "Z0->nu_tau,nu_taubar;"]) process+=addBRReweighter() process+=addLeptonPairCut("60","120") elif "W-Z-e" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p p e+ nu","0","2","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p p e- nu","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=particlegroup('epm','e+','e-') process+=particlegroup('epmnu','e+','e-','nu_e','nu_ebar') process+=addProcess(thefactory,"p p epm epmnu","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("60","120") elif "W-Z-mu" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p p mu+ nu","0","2","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p p mu- nu","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=particlegroup('mupm','mu+','mu-') process+=particlegroup('mupmnu','mu+','mu-','nu_mu','nu_mubar') process+=addProcess(thefactory,"p p mupm mupmnu","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("60","120") elif "W-e" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p e+ nu","0","2","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p p e- nu","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=particlegroup('epm','e+','e-') process+=addProcess(thefactory,"p p epm nu","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("60","120") elif "W-mu" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p mu+ nu","0","2","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p p mu- nu","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=particlegroup('mupm','mu+','mu-') process+=addProcess(thefactory,"p p mupm nu","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("60","120") elif "Z-e" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("60","120") elif "Z-mu" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("60","120") elif "Z-jj" in parameterName : if(simulation=="Merging"): logging.warning("Z-jj not explicitly tested for %s " % simulation) sys.exit(0) process+=addProcess(thefactory,"p p e+ e- j j","2","2","LeptonPairMassScale",0,0) process+=addFirstJet("40") process+=addSecondJet("30") process+=addLeptonPairCut("60","120") elif "Z-LowMass-e" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("20","70") elif "Z-MedMass-e" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("40","130") elif "Z-LowMass-mu" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("10","70") elif "Z-Mass1" in parameterName : process+=addLeptonPairCut("10","35") if "-e" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2) else : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2) elif "Z-Mass2" in parameterName : process+=addLeptonPairCut("25","70") if "-e" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2) else : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2) elif "Z-Mass3" in parameterName : process+=addLeptonPairCut("60","120") if "-e" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2) else : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2) elif "Z-Mass4" in parameterName : process+=addLeptonPairCut("115","8000") if "-e" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2) else : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2) elif "Z-HighMass1" in parameterName : process+=addLeptonPairCut("116","400") if "-e" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2) else : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2) elif "Z-HighMass2" in parameterName : process+=addLeptonPairCut("400","7000") if "-e" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2) else : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2) elif "W-Jet" in parameterName : if(simulation=="Merging"): logging.warning("W-Jet not explicitly tested for %s " % simulation) sys.exit(0) process+=addProcess(thefactory,"p p e+ nu j","1","2","HTScale",0,0) process+=addProcess(thefactory,"p p e- nu j","1","2","HTScale",0,0) process+=addLeptonPairCut("60","120") if "W-Jet-1-e" in parameterName : process+=addFirstJet("100") parameterName=parameterName.replace("W-Jet-1-e","W-Jet-e") elif "W-Jet-2-e" in parameterName : process+=addFirstJet("190") parameterName=parameterName.replace("W-Jet-2-e","W-Jet-e") elif "W-Jet-3-e" in parameterName : process+=addFirstJet("270") parameterName=parameterName.replace("W-Jet-3-e","W-Jet-e") else : logging.error("Exit 00005") sys.exit(1) elif "Z-Jet" in parameterName : if(simulation=="Merging"): logging.warning("Z-Jet not explicitly tested for %s " % simulation) sys.exit(0) if "-e" in parameterName : process+=addProcess(thefactory,"p p e+ e- j","1","2","HTScale",0,0) if "Z-Jet-0-e" in parameterName : process+=addFirstJet("35") parameterName=parameterName.replace("Z-Jet-0-e","Z-Jet-e") elif "Z-Jet-1-e" in parameterName : process+=addFirstJet("100") parameterName=parameterName.replace("Z-Jet-1-e","Z-Jet-e") elif "Z-Jet-2-e" in parameterName : process+=addFirstJet("190") parameterName=parameterName.replace("Z-Jet-2-e","Z-Jet-e") elif "Z-Jet-3-e" in parameterName : process+=addFirstJet("270") parameterName=parameterName.replace("Z-Jet-3-e","Z-Jet-e") else : logging.error("Exit 00006") sys.exit(1) else : process+=addProcess(thefactory,"p p mu+ mu- j","1","2","HTScale",0,0) process+=addFirstJet("35") parameterName=parameterName.replace("Z-Jet-0-mu","Z-Jet-mu") process+=addLeptonPairCut("60","120") elif "Z-bb" in parameterName : if(simulation=="Merging"): logging.warning("Z-bb not explicitly tested for %s " % simulation) sys.exit(0) parameters["bscheme"]=fourFlavour process+="set /Herwig/Particles/b:HardProcessMass 4.2*GeV\nset /Herwig/Particles/bbar:HardProcessMass 4.2*GeV\n" process+=addProcess(thefactory,"p p e+ e- b bbar","2","2","FixedScale",0,0) process+=addLeptonPairCut("66","116") process+=addFirstJet("18") process+=addSecondJet("15") process+=addLeptonPairCut("60","120") elif "Z-b" in parameterName : if(simulation=="Merging"): logging.warning("Z-b not explicitly tested for %s " % simulation) sys.exit(0) process+=particlegroup('bjet','b','bbar') process+=addProcess(thefactory,"p p e+ e- bjet","1","2","FixedScale",0,0) process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 91.2*GeV\n" process+=addLeptonPairCut("60","120") process+=addFirstJet("15") elif "W-b" in parameterName : if(simulation=="Merging"): logging.warning("W-b not explicitly tested for %s " % simulation) sys.exit(0) parameters["bscheme"]=fourFlavour process += "set /Herwig/Particles/b:HardProcessMass 4.2*GeV\nset /Herwig/Particles/bbar:HardProcessMass 4.2*GeV\n" process+=addProcess(thefactory,"p p e- nu b bbar","2","2","FixedScale",0,0) process+=addProcess(thefactory,"p p mu+ nu b bbar","2","2","FixedScale",0,0) process += "set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 80.4*GeV\n" process+=addFirstJet("30") process+=addLeptonPairCut("60","120") else : logging.error(" Process %s not supported for Matchbox matrix elements" % name) sys.exit(1) # LHC-GammaGamma elif(collider=="LHC-GammaGamma" ) : if "-7-" in parameterName : process = StringBuilder(collider_lumi(7000.0)) elif "-8-" in parameterName : process = StringBuilder(collider_lumi(8000.0)) else : process = StringBuilder(collider_lumi(7000.0)) if(simulation=="") : if "7" in parameterName : process += insert_ME("MEgg2ff","Muon") else : logging.error(" Process %s not supported for default matrix elements" % name) sys.exit(1) else : logging.error("LHC-GammaGamma not supported for %s " % simulation) sys.exit(1) parameters['parameterFile'] = os.path.join(collider,"{c}-{pn}.in".format(c=collider, pn=parameterName)) parameters['runname'] = 'Rivet-%s' % name parameters['process'] = str(process) #check if selecteddecaymode and addedBRReweighter is consistent if selecteddecaymode and not addedBRReweighter: logging.error("Decaymode was selected but no BRReweighter was added.") sys.exit(1) if addedBRReweighter and not selecteddecaymode: logging.error("BRReweighter was added but no Decaymode was selected.") sys.exit(1) # check that we only add one process if in merging mode: if numberOfAddedProcesses > 1 and simulation =="Merging": logging.error("In Merging only one process is allowed at the moment. See ticket #403.") sys.exit(1) # Check if a process was added for Merging or Matchbox: if numberOfAddedProcesses == 0 and (simulation =="Merging" or simulation =="Matchbox"): logging.error("No process was selected.") sys.exit(1) # get template and write the file with open(os.path.join("Rivet/Templates",templateName), 'r') as f: templateText = f.read() template = Template( templateText ) with open(os.path.join("Rivet",name+".in"), 'w') as f: f.write( template.substitute(parameters) )