Page MenuHomeHEPForge

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/MatrixElement/DIS/DISBase.cc b/MatrixElement/DIS/DISBase.cc
--- a/MatrixElement/DIS/DISBase.cc
+++ b/MatrixElement/DIS/DISBase.cc
@@ -1,1361 +1,1359 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the DISBase class.
//
#include "DISBase.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "Herwig/Utilities/Maths.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/PDT/StandardMatchers.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Repository/CurrentGenerator.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
#include "Herwig/PDT/StandardMatchers.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include <numeric>
#include "Herwig/Shower/Base/ShowerProgenitor.h"
#include "Herwig/Shower/Base/ShowerTree.h"
#include "Herwig/Shower/Base/Branching.h"
#include "Herwig/Shower/Base/HardTree.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
// namespace {
// using namespace Herwig;
// using namespace ThePEG::Helicity;
//
// void debuggingMatrixElement(bool BGF,const Lorentz5Momentum & pin,
// const Lorentz5Momentum & p1,
// const Lorentz5Momentum & p2,
// tcPDPtr gluon,
// const Lorentz5Momentum & pl1,
// const Lorentz5Momentum & pl2,
// const Lorentz5Momentum & pq1,
// const Lorentz5Momentum & pq2,
// tcPDPtr lepton1,tcPDPtr lepton2,
// tcPDPtr quark1 ,tcPDPtr quark2,
// Energy2 Q2,double phi, double x2, double x3,
// double xperp, double zp, double xp,
// const vector<double> & azicoeff,
// bool normalize) {
// tcHwSMPtr hwsm=ThePEG::dynamic_ptr_cast<tcHwSMPtr>
// (CurrentGenerator::current().standardModel());
// assert(hwsm);
// vector<AbstractFFVVertexPtr> weakVertex;
// vector<PDPtr> bosons;
// AbstractFFVVertexPtr strongVertex = hwsm->vertexFFG();
// if(lepton1->id()==lepton2->id()) {
// weakVertex.push_back(hwsm->vertexFFZ());
// bosons.push_back(hwsm->getParticleData(ParticleID::Z0));
// weakVertex.push_back(hwsm->vertexFFP());
// bosons.push_back(hwsm->getParticleData(ParticleID::gamma));
// }
// else {
// weakVertex.push_back(hwsm->vertexFFW());
// bosons.push_back(hwsm->getParticleData(ParticleID::Wplus));
// }
// if(!BGF) {
// SpinorWaveFunction l1,q1,qp1;
// SpinorBarWaveFunction l2,q2,qp2;
// VectorWaveFunction gl(p2,gluon,outgoing);
// if(lepton1->id()>0) {
// l1 = SpinorWaveFunction (pl1,lepton1,incoming);
// l2 = SpinorBarWaveFunction(pl2,lepton2,outgoing);
// }
// else {
// l1 = SpinorWaveFunction (pl2,lepton2,outgoing);
// l2 = SpinorBarWaveFunction(pl1,lepton1,incoming);
// }
// if(quark1->id()>0) {
// q1 = SpinorWaveFunction (pq1,quark1,incoming);
// q2 = SpinorBarWaveFunction(pq2,quark2,outgoing);
// qp1 = SpinorWaveFunction (pin,quark1,incoming);
// qp2 = SpinorBarWaveFunction(p1 ,quark2,outgoing);
// }
// else {
// q1 = SpinorWaveFunction (pq2,quark2,outgoing);
// q2 = SpinorBarWaveFunction(pq1,quark1,incoming);
// qp1 = SpinorWaveFunction (p1 ,quark2,outgoing);
// qp2 = SpinorBarWaveFunction(pin,quark1,incoming);
// }
// double lome(0.),realme(0.);
// for(unsigned int lhel1=0;lhel1<2;++lhel1) {
// l1.reset(lhel1);
// for(unsigned int lhel2=0;lhel2<2;++lhel2) {
// l2.reset(lhel2);
// for(unsigned int qhel1=0;qhel1<2;++qhel1) {
// q1.reset(qhel1);
// qp1.reset(qhel1);
// for(unsigned int qhel2=0;qhel2<2;++qhel2) {
// q2.reset(qhel2);
// qp2.reset(qhel2);
// // leading order matrix element
// Complex diagLO(0.);
// for(unsigned int ix=0;ix<weakVertex.size();++ix) {
// VectorWaveFunction inter =
// weakVertex[ix]->evaluate(Q2,3,bosons[ix],l1,l2);
// diagLO += weakVertex[ix]->evaluate(Q2,q1,q2,inter);
// }
// lome += norm(diagLO);
// // real emission matrix element
// for(unsigned int ghel=0;ghel<2;++ghel) {
// gl.reset(2*ghel);
// Complex diagReal(0.);
// for(unsigned int ix=0;ix<weakVertex.size();++ix) {
// VectorWaveFunction inter =
// weakVertex[ix]->evaluate(Q2,3,bosons[ix],l1,l2);
// SpinorWaveFunction off1 =
// strongVertex->evaluate(Q2,5,qp1.particle(),qp1,gl);
// Complex diag1 = weakVertex[ix]->evaluate(Q2,off1,qp2,inter);
// SpinorBarWaveFunction off2 =
// strongVertex->evaluate(Q2,5,qp2.particle(),qp2,gl);
// Complex diag2 = weakVertex[ix]->evaluate(Q2,qp1,off2,inter);
// diagReal += diag1+diag2;
// }
// realme += norm(diagReal);
// }
// }
// }
// }
// }
// double test1 = realme/lome/hwsm->alphaS(Q2)*Q2*UnitRemoval::InvE2;
// double cphi(cos(phi));
// double test2;
// if(normalize) {
// test2 = 8.*Constants::pi/(1.-xp)/(1.-zp)*
// (azicoeff[0]+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi))*
// (1.+sqr(xp)*(sqr(x2)+1.5*sqr(xperp)));
// }
// else {
// test2 = 8.*Constants::pi/(1.-xp)/(1.-zp)*
// (azicoeff[0]+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi));
// }
// cerr << "testing RATIO A " << test1/test2 << "\n";
// }
// else {
// SpinorWaveFunction l1,q1,qp1;
// SpinorBarWaveFunction l2,q2,qp2;
// VectorWaveFunction gl(pin,gluon,incoming);
// if(lepton1->id()>0) {
// l1 = SpinorWaveFunction (pl1,lepton1,incoming);
// l2 = SpinorBarWaveFunction(pl2,lepton2,outgoing);
// }
// else {
// l1 = SpinorWaveFunction (pl2,lepton2,outgoing);
// l2 = SpinorBarWaveFunction(pl1,lepton1,incoming);
// }
// if(quark1->id()>0) {
// q1 = SpinorWaveFunction (pq1,quark1 ,incoming);
// q2 = SpinorBarWaveFunction(pq2,quark2 ,outgoing);
// qp2 = SpinorBarWaveFunction(p1 ,quark2 ,outgoing);
// qp1 = SpinorWaveFunction (p2 ,quark1->CC(),outgoing);
// }
// else {
// q1 = SpinorWaveFunction (pq2,quark2 ,outgoing);
// q2 = SpinorBarWaveFunction(pq1,quark1 ,incoming);
// qp2 = SpinorBarWaveFunction(p2 ,quark1->CC(),outgoing);
// qp1 = SpinorWaveFunction (p1 ,quark2 ,outgoing);
// }
// double lome(0.),realme(0.);
// for(unsigned int lhel1=0;lhel1<2;++lhel1) {
// l1.reset(lhel1);
// for(unsigned int lhel2=0;lhel2<2;++lhel2) {
// l2.reset(lhel2);
// for(unsigned int qhel1=0;qhel1<2;++qhel1) {
// q1.reset(qhel1);
// qp1.reset(qhel1);
// for(unsigned int qhel2=0;qhel2<2;++qhel2) {
// q2.reset(qhel2);
// qp2.reset(qhel2);
// // leading order matrix element
// Complex diagLO(0.);
// for(unsigned int ix=0;ix<weakVertex.size();++ix) {
// VectorWaveFunction inter =
// weakVertex[ix]->evaluate(Q2,3,bosons[ix],l1,l2);
// diagLO += weakVertex[ix]->evaluate(Q2,q1,q2,inter);
// }
// lome += norm(diagLO);
// // real emission matrix element
// for(unsigned int ghel=0;ghel<2;++ghel) {
// gl.reset(2*ghel);
// Complex diagReal(0.);
// for(unsigned int ix=0;ix<weakVertex.size();++ix) {
// VectorWaveFunction inter =
// weakVertex[ix]->evaluate(Q2,3,bosons[ix],l1,l2);
// SpinorWaveFunction off1 =
// strongVertex->evaluate(Q2,5,qp1.particle(),qp1,gl);
// Complex diag1 = weakVertex[ix]->evaluate(Q2,off1,qp2,inter);
// SpinorBarWaveFunction off2 =
// strongVertex->evaluate(Q2,5,qp2.particle(),qp2,gl);
// Complex diag2 = weakVertex[ix]->evaluate(Q2,qp1,off2,inter);
// diagReal += diag1+diag2;
// }
// realme += norm(diagReal);
// }
// }
// }
// }
// }
// double test1 = realme/lome/hwsm->alphaS(Q2)*Q2*UnitRemoval::InvE2;
// double cphi(cos(phi));
// double test2;
// if(normalize) {
// test2 = 8.*Constants::pi/zp/(1.-zp)*
// (azicoeff[0]+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi))*
// sqr(xp)*(sqr(x3)+sqr(x2)+3.*sqr(xperp));
// }
// else {
// test2 = 8.*Constants::pi/zp/(1.-zp)*
// (azicoeff[0]+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi));
// }
// cerr << "testing RATIO B " << test1/test2 << "\n";
// }
// }
//
// }
DISBase::DISBase() : initial_(6.), final_(3.),
procProb_(0.35),
comptonInt_(0.), bgfInt_(0.),
comptonWeight_(50.), BGFWeight_(150.),
pTmin_(0.1*GeV),
scaleOpt_(1), muF_(100.*GeV), scaleFact_(1.),
contrib_(0), power_(0.1)
{}
DISBase::~DISBase() {}
void DISBase::persistentOutput(PersistentOStream & os) const {
os << comptonInt_ << bgfInt_ << procProb_ << initial_ << final_ << alpha_
<< ounit(pTmin_,GeV) << comptonWeight_ << BGFWeight_ << gluon_
<< ounit(muF_,GeV) << scaleFact_ << scaleOpt_ << contrib_<< power_;
}
void DISBase::persistentInput(PersistentIStream & is, int) {
is >> comptonInt_ >> bgfInt_ >> procProb_ >> initial_ >> final_ >> alpha_
>> iunit(pTmin_,GeV) >> comptonWeight_ >> BGFWeight_ >> gluon_
>> iunit(muF_,GeV) >> scaleFact_ >> scaleOpt_ >> contrib_ >> power_;
}
AbstractClassDescription<DISBase> DISBase::initDISBase;
// Definition of the static class description member.
void DISBase::Init() {
static ClassDocumentation<DISBase> documentation
("The DISBase class provides the base class for the "
"implementation of DIS type processes including the "
"hard corrections in either the old-fashioned matrix "
"element correction of POWHEG approaches");
static Parameter<DISBase,double> interfaceProcessProbability
("ProcessProbability",
"The probabilty of the QCD compton process for the process selection",
&DISBase::procProb_, 0.3, 0.0, 1.,
false, false, Interface::limited);
static Reference<DISBase,ShowerAlpha> interfaceCoupling
("Coupling",
"Pointer to the object to calculate the coupling for the correction",
&DISBase::alpha_, false, false, true, false, false);
static Parameter<DISBase,Energy> interfacepTMin
("pTMin",
"The minimum pT",
&DISBase::pTmin_, GeV, 1.*GeV, 0.0*GeV, 10.0*GeV,
false, false, Interface::limited);
static Parameter<DISBase,double> interfaceComptonWeight
("ComptonWeight",
"Weight for the overestimate ofthe compton channel",
&DISBase::comptonWeight_, 50.0, 0.0, 100.0,
false, false, Interface::limited);
static Parameter<DISBase,double> interfaceBGFWeight
("BGFWeight",
"Weight for the overestimate of the BGF channel",
&DISBase::BGFWeight_, 100.0, 0.0, 1000.0,
false, false, Interface::limited);
static Switch<DISBase,unsigned int> interfaceContribution
("Contribution",
"Which contributions to the cross section to include",
&DISBase::contrib_, 0, false, false);
static SwitchOption interfaceContributionLeadingOrder
(interfaceContribution,
"LeadingOrder",
"Just generate the leading order cross section",
0);
static SwitchOption interfaceContributionPositiveNLO
(interfaceContribution,
"PositiveNLO",
"Generate the positive contribution to the full NLO cross section",
1);
static SwitchOption interfaceContributionNegativeNLO
(interfaceContribution,
"NegativeNLO",
"Generate the negative contribution to the full NLO cross section",
2);
static Switch<DISBase,unsigned int> interfaceScaleOption
("ScaleOption",
"Option for the choice of factorization (and renormalization) scale",
&DISBase::scaleOpt_, 1, false, false);
static SwitchOption interfaceDynamic
(interfaceScaleOption,
"Dynamic",
"Dynamic factorization scale equal to the current sqrt(sHat())",
1);
static SwitchOption interfaceFixed
(interfaceScaleOption,
"Fixed",
"Use a fixed factorization scale set with FactorizationScaleValue",
2);
static Parameter<DISBase,Energy> interfaceFactorizationScale
("FactorizationScale",
"Value to use in the event of a fixed factorization scale",
&DISBase::muF_, GeV, 100.0*GeV, 1.0*GeV, 500.0*GeV,
true, false, Interface::limited);
static Parameter<DISBase,double> interfaceScaleFactor
("ScaleFactor",
"The factor used before Q2 if using a running scale",
&DISBase::scaleFact_, 1.0, 0.0, 10.0,
false, false, Interface::limited);
static Parameter<DISBase,double> interfaceSamplingPower
("SamplingPower",
"Power for the sampling of xp",
&DISBase::power_, 0.6, 0.0, 1.,
false, false, Interface::limited);
}
void DISBase::doinit() {
HwMEBase::doinit();
// integrals of me over phase space
double r5=sqrt(5.),darg((r5-1.)/(r5+1.)),ath(0.5*log((1.+1./r5)/(1.-1./r5)));
comptonInt_ = 2.*(-21./20.-6./(5.*r5)*ath+sqr(Constants::pi)/3.
-2.*Math::ReLi2(1.-darg)-2.*Math::ReLi2(1.-1./darg));
bgfInt_ = 121./9.-56./r5*ath;
// extract the gluon ParticleData objects
gluon_ = getParticleData(ParticleID::g);
}
void DISBase::initializeMECorrection(ShowerTreePtr tree, double & initial,
double & final) {
initial = initial_;
final = final_;
// incoming particles
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
if(QuarkMatcher::Check(cit->first->progenitor()->data())) {
partons_[0] = cit->first->progenitor()->dataPtr();
pq_[0] = cit->first->progenitor()->momentum();
}
else if(LeptonMatcher::Check(cit->first->progenitor()->data())) {
leptons_[0] = cit->first->progenitor()->dataPtr();
pl_[0] = cit->first->progenitor()->momentum();
}
}
// outgoing particles
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) {
if(QuarkMatcher::Check(cit->first->progenitor()->data())) {
partons_[1] = cit->first->progenitor()->dataPtr();
pq_[1] = cit->first->progenitor()->momentum();
}
else if(LeptonMatcher::Check(cit->first->progenitor()->data())) {
leptons_[1] = cit->first->progenitor()->dataPtr();
pl_[1] = cit->first->progenitor()->momentum();
}
}
// extract the born variables
q_ =pl_[0]-pl_[1];
q2_ = -q_.m2();
double yB = (q_*pq_[0])/(pl_[0]*pq_[0]);
l_ = 2./yB-1.;
// calculate the A coefficient for the correlations
acoeff_ = A(leptons_[0],leptons_[1],
partons_[0],partons_[1],q2_);
}
void DISBase::applyHardMatrixElementCorrection(ShowerTreePtr tree) {
static const double eps=1e-6;
// find the incoming and outgoing quarks and leptons
ShowerParticlePtr quark[2],lepton[2];
PPtr hadron;
// incoming particles
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
if(QuarkMatcher::Check(cit->first->progenitor()->data())) {
hadron = cit->first->original()->parents()[0];
quark [0] = cit->first->progenitor();
beam_ = cit->first->beam();
}
else if(LeptonMatcher::Check(cit->first->progenitor()->data())) {
lepton[0] = cit->first->progenitor();
}
}
pdf_ = beam_->pdf();
assert(beam_&&pdf_&&quark[0]&&lepton[0]);
// outgoing particles
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) {
if(QuarkMatcher::Check(cit->first->progenitor()->data()))
quark [1] = cit->first->progenitor();
else if(LeptonMatcher::Check(cit->first->progenitor()->data())) {
lepton[1] = cit->first->progenitor();
}
}
// momentum fraction
assert(quark[1]&&lepton[1]);
xB_ = quark[0]->x();
// calculate the matrix element
vector<double> azicoeff;
// select the type of process
bool BGF = UseRandom::rnd()>procProb_;
double xp,zp,wgt,x1,x2,x3,xperp;
// generate a QCD compton process
if(!BGF) {
wgt = generateComptonPoint(xp,zp);
if(xp<eps) return;
// common pieces
Energy2 scale = q2_*((1.-xp)*(1-zp)*zp/xp+1.);
wgt *= 2./3./Constants::pi*alpha_->value(scale)/procProb_;
// PDF piece
wgt *= pdf_->xfx(beam_,quark[0]->dataPtr(),scale,xB_/xp)/
pdf_->xfx(beam_,quark[0]->dataPtr(),q2_ ,xB_);
// other bits
xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp);
x1 = -1./xp;
x2 = 1.-(1.-zp)/xp;
x3 = 2.+x1-x2;
// matrix element pieces
azicoeff = ComptonME(xp,x2,xperp,true);
}
// generate a BGF process
else {
wgt = generateBGFPoint(xp,zp);
if(xp<eps) return;
// common pieces
Energy2 scale = q2_*((1.-xp)*(1-zp)*zp/xp+1);
wgt *= 0.25/Constants::pi*alpha_->value(scale)/(1.-procProb_);
// PDF piece
wgt *= pdf_->xfx(beam_,gluon_ ,scale,xB_/xp)/
pdf_->xfx(beam_,quark[0]->dataPtr(),q2_ ,xB_);
// other bits
xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp);
x1 = -1./xp;
x2 = 1.-(1.-zp)/xp;
x3 = 2.+x1-x2;
// matrix element pieces
azicoeff = BGFME(xp,x2,x3,xperp,true);
}
// compute the azimuthal average of the weight
wgt *= (azicoeff[0]+0.5*azicoeff[2]);
// decide whether or not to accept the weight
if(UseRandom::rnd()>wgt) return;
// if generate generate phi
unsigned int itry(0);
double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.);
double phiwgt,phi;
do {
phi = UseRandom::rnd()*Constants::twopi;
double cphi(cos(phi));
phiwgt = azicoeff[0]+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi);
++itry;
}
while (phimax*UseRandom::rnd() > phiwgt && itry<200);
if(itry==200) throw Exception() << "Too many tries in DISMECorrection"
<< "::applyHardMatrixElementCorrection() to"
<< " generate phi" << Exception::eventerror;
// construct lorentz transform from lab to breit frame
Lorentz5Momentum phadron = hadron->momentum();
phadron.setMass(0.*GeV);
phadron.rescaleEnergy();
Lorentz5Momentum pcmf = phadron+0.5/xB_*q_;
pcmf.rescaleMass();
LorentzRotation rot(-pcmf.boostVector());
Lorentz5Momentum pbeam = rot*phadron;
Axis axis(pbeam.vect().unit());
double sinth(sqrt(sqr(axis.x())+sqr(axis.y())));
rot.rotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.));
Lorentz5Momentum pl = rot*pl_[0];
rot.rotateZ(-atan2(pl.y(),pl.x()));
pl_[0] *= rot;
pl_[1] *= rot;
pq_[0] *= rot;
pq_[1] *= rot;
// compute the new incoming and outgoing momenta
Energy Q(sqrt(q2_));
Lorentz5Momentum p1 = Lorentz5Momentum( 0.5*Q*xperp*cos(phi), 0.5*Q*xperp*sin(phi),
-0.5*Q*x2,0.*GeV,0.*GeV);
p1.rescaleEnergy();
Lorentz5Momentum p2 = Lorentz5Momentum(-0.5*Q*xperp*cos(phi),-0.5*Q*xperp*sin(phi),
-0.5*Q*x3,0.*GeV,0.*GeV);
p2.rescaleEnergy();
Lorentz5Momentum pin(0.*GeV,0.*GeV,-0.5*x1*Q,-0.5*x1*Q,0.*GeV);
// debuggingMatrixElement(BGF,pin,p1,p2,gluon_,pl_[0],pl_[1],pq_[0],pq_[1],
// lepton[0]->dataPtr(),lepton[1]->dataPtr(),
// quark [0]->dataPtr(),quark [1]->dataPtr(),
// q2_,phi,x2,x3,xperp,zp,xp,azicoeff,true);
// we need the Lorentz transform back to the lab
rot.invert();
// transform the momenta to lab frame
pin *= rot;
p1 *= rot;
p2 *= rot;
// test to ensure outgoing particles can be put on-shell
if(!BGF) {
if(p1.e()<quark[1]->dataPtr()->constituentMass()) return;
if(p2.e()<gluon_ ->constituentMass()) return;
}
else {
if(p1.e()<quark[1]->dataPtr() ->constituentMass()) return;
if(p2.e()<quark[0]->dataPtr()->CC()->constituentMass()) return;
}
// create the new particles and add to ShowerTree
bool isquark = quark[0]->colourLine();
if(!BGF) {
PPtr newin = new_ptr(Particle(*quark[0]));
newin->set5Momentum(pin);
PPtr newg = gluon_ ->produceParticle(p2 );
PPtr newout = quark[1]->dataPtr()->produceParticle(p1 );
ColinePtr col=isquark ?
quark[0]->colourLine() : quark[0]->antiColourLine();
ColinePtr newline=new_ptr(ColourLine());
// final-state emission
if(xp>zp) {
col->removeColoured(newout,!isquark);
col->addColoured(newin,!isquark);
col->addColoured(newg,!isquark);
newline->addColoured(newg,isquark);
newline->addColoured(newout,!isquark);
}
// initial-state emission
else {
col->removeColoured(newin ,!isquark);
col->addColoured(newout,!isquark);
col->addColoured(newg,isquark);
newline->addColoured(newg,!isquark);
newline->addColoured(newin,!isquark);
}
PPtr orig;
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
if(cit->first->progenitor()!=quark[0]) continue;
// remove old particles from colour line
col->removeColoured(cit->first->copy(),!isquark);
col->removeColoured(cit->first->progenitor(),!isquark);
// insert new particles
cit->first->copy(newin);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newin,1,false)));
cit->first->progenitor(sp);
tree->incomingLines()[cit->first]=sp;
sp->x(xB_/xp);
cit->first->perturbative(xp>zp);
if(xp<=zp) orig=cit->first->original();
}
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) {
if(cit->first->progenitor()!=quark[1]) continue;
// remove old particles from colour line
col->removeColoured(cit->first->copy(),!isquark);
col->removeColoured(cit->first->progenitor(),!isquark);
// insert new particles
cit->first->copy(newout);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newout,1,true)));
cit->first->progenitor(sp);
tree->outgoingLines()[cit->first]=sp;
cit->first->perturbative(xp<=zp);
if(xp>zp) orig=cit->first->original();
}
assert(orig);
// add the gluon
ShowerParticlePtr sg=new_ptr(ShowerParticle(*newg,1,true));
ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(orig,newg,sg));
gluon->perturbative(false);
tree->outgoingLines().insert(make_pair(gluon,sg));
tree->hardMatrixElementCorrection(true);
}
else {
PPtr newin = gluon_ ->produceParticle(pin);
PPtr newqbar = quark[0]->dataPtr()->CC()->produceParticle(p2 );
PPtr newout = quark[1]->dataPtr() ->produceParticle(p1 );
ColinePtr col=isquark ? quark[0]->colourLine() : quark[0]->antiColourLine();
ColinePtr newline=new_ptr(ColourLine());
col ->addColoured(newin ,!isquark);
newline->addColoured(newin , isquark);
col ->addColoured(newout ,!isquark);
newline->addColoured(newqbar, isquark);
PPtr orig;
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
if(cit->first->progenitor()!=quark[0]) continue;
// remove old particles from colour line
col->removeColoured(cit->first->copy(),!isquark);
col->removeColoured(cit->first->progenitor(),!isquark);
// insert new particles
cit->first->copy(newin);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newin,1,false)));
cit->first->progenitor(sp);
tree->incomingLines()[cit->first]=sp;
sp->x(xB_/xp);
cit->first->perturbative(false);
orig=cit->first->original();
}
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) {
if(cit->first->progenitor()!=quark[1]) continue;
// remove old particles from colour line
col->removeColoured(cit->first->copy(),!isquark);
col->removeColoured(cit->first->progenitor(),!isquark);
// insert new particles
cit->first->copy(newout);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newout,1,true)));
cit->first->progenitor(sp);
tree->outgoingLines()[cit->first]=sp;
cit->first->perturbative(true);
}
assert(orig);
// add the (anti)quark
ShowerParticlePtr sqbar=new_ptr(ShowerParticle(*newqbar,1,true));
ShowerProgenitorPtr qbar=new_ptr(ShowerProgenitor(orig,newqbar,sqbar));
qbar->perturbative(false);
tree->outgoingLines().insert(make_pair(qbar,sqbar));
tree->hardMatrixElementCorrection(true);
}
}
bool DISBase::softMatrixElementVeto(ShowerProgenitorPtr initial,
ShowerParticlePtr parent, Branching br) {
bool veto = !UseRandom::rndbool(parent->isFinalState() ? 1./final_ : 1./initial_);
// check if me correction should be applied
long id[2]={initial->id(),parent->id()};
if(id[0]!=id[1]||id[1]==ParticleID::g) return veto;
// get the pT
Energy pT=br.kinematics->pT();
// check if hardest so far
if(pT<initial->highestpT()) return veto;
double kappa(sqr(br.kinematics->scale())/q2_),z(br.kinematics->z());
double zk((1.-z)*kappa);
// final-state
double wgt(0.);
if(parent->isFinalState()) {
double zp=z,xp=1./(1.+z*zk);
double xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp);
double x2 = 1.-(1.-zp)/xp;
vector<double> azicoeff = ComptonME(xp,x2,xperp,false);
wgt = (azicoeff[0]+0.5*azicoeff[2])*xp/(1.+sqr(z))/final_;
if(wgt<.0||wgt>1.) {
ostringstream wstring;
wstring << "Soft ME correction weight too large or "
<< "negative for FSR in DISBase::"
<< "softMatrixElementVeto() soft weight "
<< " xp = " << xp << " zp = " << zp
<< " weight = " << wgt << "\n";
generator()->logWarning( Exception(wstring.str(),
Exception::warning) );
}
}
else {
double xp = 2.*z/(1.+zk+sqrt(sqr(1.+zk)-4.*z*zk));
double zp = 0.5* (1.-zk+sqrt(sqr(1.+zk)-4.*z*zk));
double xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp);
double x1 = -1./xp, x2 = 1.-(1.-zp)/xp, x3 = 2.+x1-x2;
// compton
if(br.ids[0]!=ParticleID::g) {
vector<double> azicoeff = ComptonME(xp,x2,xperp,false);
wgt = (azicoeff[0]+0.5*azicoeff[2])*xp*(1.-z)/(1.-xp)/(1.+sqr(z))/
(1.-zp+xp-2.*xp*(1.-zp));
}
// BGF
else {
vector<double> azicoeff = BGFME(xp,x2,x3,xperp,true);
wgt = (azicoeff[0]+0.5*azicoeff[2])*xp/(1.-zp+xp-2.*xp*(1.-zp))/(sqr(z)+sqr(1.-z));
}
wgt /=initial_;
if(wgt<.0||wgt>1.) {
ostringstream wstring;
wstring << "Soft ME correction weight too large or "
<< "negative for ISR in DISBase::"
<< "softMatrixElementVeto() soft weight "
<< " xp = " << xp << " zp = " << zp
<< " weight = " << wgt << "\n";
generator()->logWarning( Exception(wstring.str(),
Exception::warning) );
}
}
// if not vetoed
if(UseRandom::rndbool(wgt)) return false;
// otherwise
parent->vetoEmission(br.type,br.kinematics->scale());
return true;
}
double DISBase::generateComptonPoint(double &xp, double & zp) {
static const double maxwgt = 1.;
double wgt;
do {
xp = UseRandom::rnd();
double zpmin = xp, zpmax = 1./(1.+xp*(1.-xp));
zp = 1.-pow((1.-zpmin)/(1.-zpmax),UseRandom::rnd())*(1.-zpmax);
wgt = log((1.-zpmin)/(1.-zpmax))*(1.-zp);
if(UseRandom::rndbool()) swap(xp,zp);
double xperp2 = 4.*(1.-xp)*(1.-zp)*zp/xp,x2=1.-(1.-zp)/xp;
wgt *= 2.*(1.+sqr(xp)*(sqr(x2)+1.5*xperp2))/(1.-xp)/(1.-zp);
if(wgt>maxwgt) {
ostringstream wstring;
wstring << "DISBase::generateComptonPoint "
<< "Weight greater than maximum "
<< "wgt = " << wgt << " maxwgt = 1\n";
generator()->logWarning( Exception(wstring.str(),
Exception::warning) );
}
}
while(wgt<UseRandom::rnd()*maxwgt);
return comptonInt_;
}
double DISBase::generateBGFPoint(double &xp, double & zp) {
static const double maxwgt = 25.;
double wgt;
do {
xp = UseRandom::rnd();
double zpmax = 1./(1.+xp*(1.-xp)), zpmin = 1.-zpmax;
zp = 1.-pow((1.-zpmin)/(1.-zpmax),UseRandom::rnd())*(1.-zpmax);
wgt = log((1.-zpmin)/(1.-zpmax))*(1.-zp);
double x1 = -1./xp;
double x2 = 1.-(1.-zp)/xp;
double x3 = 2.+x1-x2;
double xperp2 = 4.*(1.-xp)*(1.-zp)*zp/xp;
wgt *= sqr(xp)/(1.-zp)*(sqr(x3)+sqr(x2)+3.*xperp2);
if(wgt>maxwgt) {
ostringstream wstring;
wstring << "DISBase::generateBGFPoint "
<< "Weight greater than maximum "
<< "wgt = " << wgt << " maxwgt = 1\n";
generator()->logWarning( Exception(wstring.str(),
Exception::warning) );
}
}
while(wgt<UseRandom::rnd()*maxwgt);
return bgfInt_;
// static const double maxwgt = 2.,npow=0.34,ac=1.0;
// double wgt;
// do {
// double rho = UseRandom::rnd();
// xp = 1.-pow(rho,1./(1.-npow));
// wgt = (sqr(xp)+ac+sqr(1.-xp));
// if(wgt>1.+ac) cerr << "testing violates BGF maxA " << wgt << "\n";
// }
// while(wgt<UseRandom::rnd()*(1.+ac));
// double xpwgt = -((6.-5.*npow+sqr(npow))*ac-3.*npow+sqr(npow)+4)
// /(sqr(npow)*(npow-6.)+11.*npow-6.);
// xpwgt *= pow(1.-xp,npow)/wgt;
// double xp2(sqr(xp)),lxp(log(xp)),xp4(sqr(xp2)),lxp1(log(1.-xp));
// double zpwgt = (2.*xp4*(lxp+lxp1-3.)+4.*xp*xp2*(3.-lxp-lxp1)
// +xp2*(-13.+lxp+lxp1)+xp*(+7.+lxp+lxp1)-lxp-lxp1-1.)/(1.+xp-xp2);
// do {
// double zpmax = 1./(1.+xp*(1.-xp)), zpmin = 1.-zpmax;
// zp = 1.-pow((1.-zpmin)/(1.-zpmax),UseRandom::rnd())*(1.-zpmax);
// wgt = log((1.-zpmin)/(1.-zpmax))*(1.-zp);
// double x1 = -1./xp;
// double x2 = 1.-(1.-zp)/xp;
// double x3 = 2.+x1-x2;
// double xperp2 = 4.*(1.-xp)*(1.-zp)*zp/xp;
// wgt *= sqr(xp)/(1.-zp)*(sqr(x3)+sqr(x2)+3.*xperp2);
// if(wgt>maxwgt*zpwgt) cerr << "testing violates BGF maxB " << wgt/xpwgt << "\n";
// }
// while(wgt<UseRandom::rnd()*maxwgt);
// return zpwgt*xpwgt;
}
vector<double> DISBase::ComptonME(double xp, double x2, double xperp,
bool norm) {
vector<double> output(3,0.);
double cos2 = x2 /sqrt(sqr(x2)+sqr(xperp));
double sin2 = xperp/sqrt(sqr(x2)+sqr(xperp));
double root = sqrt(sqr(l_)-1.);
output[0] = sqr(cos2)+acoeff_*cos2*l_+sqr(l_);
output[1] = -acoeff_*cos2*root*sin2-2.*l_*root*sin2;
output[2] = sqr(root)*sqr(sin2);
double lo(1+acoeff_*l_+sqr(l_));
double denom = norm ? 1.+sqr(xp)*(sqr(x2)+1.5*sqr(xperp)) : 1.;
double fact = sqr(xp)*(sqr(x2)+sqr(xperp))/lo;
for(unsigned int ix=0;ix<output.size();++ix)
output[ix] = ((ix==0 ? 1. : 0.) +fact*output[ix])/denom;
return output;
}
vector<double> DISBase::BGFME(double xp, double x2, double x3,
double xperp, bool norm) {
vector<double> output(3,0.);
double cos2 = x2 /sqrt(sqr(x2)+sqr(xperp));
double sin2 = xperp/sqrt(sqr(x2)+sqr(xperp));
double fact2 = sqr(xp)*(sqr(x2)+sqr(xperp));
double cos3 = x3 /sqrt(sqr(x3)+sqr(xperp));
double sin3 = xperp/sqrt(sqr(x3)+sqr(xperp));
double fact3 = sqr(xp)*(sqr(x3)+sqr(xperp));
double root = sqrt(sqr(l_)-1.);
output[0] = fact2*(sqr(cos2)+acoeff_*cos2*l_+sqr(l_)) +
fact3*(sqr(cos3)-acoeff_*cos3*l_+sqr(l_));
output[1] = - fact2*(acoeff_*cos2*root*sin2+2.*l_*root*sin2)
- fact3*(acoeff_*cos3*root*sin3-2.*l_*root*sin3);
output[2] = fact2*(sqr(root)*sqr(sin2)) +
fact3*(sqr(root)*sqr(sin3));
double lo(1+acoeff_*l_+sqr(l_));
double denom = norm ? sqr(xp)*(sqr(x3)+sqr(x2)+3.*sqr(xperp))*lo : lo;
for(unsigned int ix=0;ix<output.size();++ix) output[ix] /= denom;
return output;
}
HardTreePtr DISBase::generateHardest(ShowerTreePtr tree,
- vector<ShowerInteraction::Type> inter) {
- bool found = false;
+ ShowerInteraction::Type inter) {
// check if generating QCD radiation
- for(unsigned int ix=0;ix<inter.size();++ix) {
- found |= inter[ix]==ShowerInteraction::QCD;
- }
- if(!found) return HardTreePtr();
+ if(inter!=ShowerInteraction::QCD && inter!=ShowerInteraction::QEDQCD &&
+ inter!=ShowerInteraction::ALL)
+ return HardTreePtr();
ShowerParticlePtr quark[2],lepton[2];
PPtr hadron;
// incoming particles
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
if(QuarkMatcher::Check(cit->first->progenitor()->data())) {
hadron = cit->first->original()->parents()[0];
quark [0] = cit->first->progenitor();
beam_ = cit->first->beam();
}
else if(LeptonMatcher::Check(cit->first->progenitor()->data())) {
lepton[0] = cit->first->progenitor();
leptons_[0] = lepton[0]->dataPtr();
}
}
pdf_=beam_->pdf();
assert(beam_&&pdf_&&quark[0]&&lepton[0]);
// outgoing particles
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) {
if(QuarkMatcher::Check(cit->first->progenitor()->data()))
quark [1] = cit->first->progenitor();
else if(LeptonMatcher::Check(cit->first->progenitor()->data())) {
lepton[1] = cit->first->progenitor();
leptons_[1] = lepton[1]->dataPtr();
}
}
assert(quark[1]&&lepton[1]);
// Particle data objects
for(unsigned int ix=0;ix<2;++ix) partons_[ix] = quark[ix]->dataPtr();
// extract the born variables
q_ =lepton[0]->momentum()-lepton[1]->momentum();
q2_ = -q_.m2();
xB_ = quark[0]->x();
double yB =
( q_*quark[0]->momentum())/
(lepton[0]->momentum()*quark[0]->momentum());
l_ = 2./yB-1.;
// construct lorentz transform from lab to breit frame
Lorentz5Momentum phadron = hadron->momentum();
phadron.setMass(0.*GeV);
phadron.rescaleRho();
Lorentz5Momentum pb = quark[0]->momentum();
Axis axis(q_.vect().unit());
double sinth(sqrt(sqr(axis.x())+sqr(axis.y())));
LorentzRotation rot_ = LorentzRotation();
if(axis.perp2()>1e-20) {
rot_.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.));
rot_.rotateX(Constants::pi);
}
if(abs(1.-q_.e()/q_.vect().mag())>1e-6) rot_.boostZ( q_.e()/q_.vect().mag());
pb *= rot_;
if(pb.perp2()/GeV2>1e-20) {
Boost trans = -1./pb.e()*pb.vect();
trans.setZ(0.);
rot_.boost(trans);
}
Lorentz5Momentum pl = rot_*lepton[0]->momentum();
rot_.rotateZ(-atan2(pl.y(),pl.x()));
// momenta of the particles
pl_[0]=rot_*lepton[0]->momentum();
pl_[1]=rot_*lepton[1]->momentum();
pq_[0]=rot_* quark[0]->momentum();
pq_[1]=rot_* quark[1]->momentum();
q_ *= rot_;
// coefficient for the matrix elements
acoeff_ = A(lepton[0]->dataPtr(),lepton[1]->dataPtr(),
quark [0]->dataPtr(),quark [1]->dataPtr(),q2_);
// generate a compton point
generateCompton();
generateBGF();
// no valid emission, return
if(pTCompton_<ZERO&&pTBGF_<ZERO) return HardTreePtr();
// type of emission, pick highest pT
bool isCompton=pTCompton_>pTBGF_;
// // find the sudakov for the branching
// SudakovPtr sudakov;
// // ISR
// if(ComptonISFS_||!isCompton) {
// BranchingList branchings=evolver()->splittingGenerator()->initialStateBranchings();
// long index = abs(partons_[0]->id());
// IdList br(3);
// if(isCompton) {
// br[0] = index;
// br[1] = index;
// br[2] = ParticleID::g;
// }
// else {
// br[0] = ParticleID::g;
// br[1] = abs(partons_[0]->id());
// br[2] = -abs(partons_[0]->id());
// }
// for(BranchingList::const_iterator cit = branchings.lower_bound(index);
// cit != branchings.upper_bound(index); ++cit ) {
// IdList ids = cit->second.second;
// if(ids[0]==br[0]&&ids[1]==br[1]&&ids[2]==br[2]) {
// sudakov=cit->second.first;
// break;
// }
// }
// }
// // FSR
// else {
// BranchingList branchings =
// evolver()->splittingGenerator()->finalStateBranchings();
// long index=abs(partons_[1]->id());
// for(BranchingList::const_iterator cit = branchings.lower_bound(index);
// cit != branchings.upper_bound(index); ++cit ) {
// IdList ids = cit->second.second;
// if(ids[0]==index&&ids[1]==index&&ids[2]==ParticleID::g) {
// sudakov = cit->second.first;
// break;
// }
// }
// }
// if(!sudakov) throw Exception() << "Can't find Sudakov for the hard emission in "
// << "DISBase::generateHardest()"
// << Exception::runerror;
// add the leptons
vector<HardBranchingPtr> spaceBranchings,allBranchings;
spaceBranchings.push_back(new_ptr(HardBranching(lepton[0],SudakovPtr(),
HardBranchingPtr(),
HardBranching::Incoming)));
allBranchings.push_back(spaceBranchings.back());
allBranchings.push_back(new_ptr(HardBranching(lepton[1],SudakovPtr(),
HardBranchingPtr(),
HardBranching::Outgoing)));
// compton hardest
if(isCompton) {
rot_.invert();
for(unsigned int ix=0;ix<ComptonMomenta_.size();++ix) {
ComptonMomenta_[ix].transform(rot_);
}
ShowerParticlePtr newqout (new_ptr(ShowerParticle(partons_[1],true)));
newqout->set5Momentum(ComptonMomenta_[1]);
ShowerParticlePtr newg(new_ptr(ShowerParticle(gluon_,true)));
newg->set5Momentum(ComptonMomenta_[2]);
ShowerParticlePtr newqin (new_ptr(ShowerParticle(partons_[0],false )));
newqin->set5Momentum(ComptonMomenta_[0]);
if(ComptonISFS_) {
ShowerParticlePtr newspace(new_ptr(ShowerParticle(partons_[0],false)));
newspace->set5Momentum(ComptonMomenta_[0]-ComptonMomenta_[2]);
HardBranchingPtr spaceBranch(new_ptr(HardBranching(newqin,SudakovPtr(),
HardBranchingPtr(),
HardBranching::Incoming)));
HardBranchingPtr offBranch(new_ptr(HardBranching(newspace,SudakovPtr(),
spaceBranch,
HardBranching::Incoming)));
spaceBranch->addChild(offBranch);
HardBranchingPtr g(new_ptr(HardBranching(newg,SudakovPtr(),spaceBranch,
HardBranching::Outgoing)));
spaceBranch->addChild(g);
spaceBranch->type(offBranch->branchingParticle()->id()>0 ?
ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine);
HardBranchingPtr outBranch(new_ptr(HardBranching(newqout,SudakovPtr(),
HardBranchingPtr(),
HardBranching::Outgoing)));
spaceBranchings.push_back(spaceBranch);
allBranchings.push_back(offBranch);
allBranchings.push_back(outBranch);
ColinePtr newin(new_ptr(ColourLine())),newout(new_ptr(ColourLine()));
newin ->addColoured(newqin ,partons_[0]->id()<0);
newin ->addColoured(newg ,partons_[0]->id()<0);
newout->addColoured(newspace,partons_[0]->id()<0);
newout->addColoured(newqout ,partons_[1]->id()<0);
newout->addColoured(newg ,partons_[1]->id()>0);
}
else {
ShowerParticlePtr newtime(new_ptr(ShowerParticle(partons_[1],true)));
newtime->set5Momentum(ComptonMomenta_[1]+ComptonMomenta_[2]);
HardBranchingPtr spaceBranch(new_ptr(HardBranching(newqin,SudakovPtr(),
HardBranchingPtr(),
HardBranching::Incoming)));
HardBranchingPtr offBranch(new_ptr(HardBranching(newtime,SudakovPtr(),
HardBranchingPtr(),
HardBranching::Outgoing)));
HardBranchingPtr g(new_ptr(HardBranching(newg,SudakovPtr(),offBranch,
HardBranching::Outgoing)));
HardBranchingPtr outBranch(new_ptr(HardBranching(newqout,SudakovPtr(),offBranch,
HardBranching::Outgoing)));
offBranch->addChild(outBranch);
offBranch->addChild(g);
offBranch->type(offBranch->branchingParticle()->id()>0 ?
ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine);
spaceBranchings.push_back(spaceBranch);
allBranchings.push_back(spaceBranch);
allBranchings.push_back(offBranch);
ColinePtr newin(new_ptr(ColourLine())),newout(new_ptr(ColourLine()));
newin ->addColoured(newqin ,newqin->dataPtr()->iColour()!=PDT::Colour3);
newin ->addColoured(newtime,newqin->dataPtr()->iColour()!=PDT::Colour3);
newin ->addColoured(newg ,newqin->dataPtr()->iColour()!=PDT::Colour3);
newout->addColoured(newg ,newqin->dataPtr()->iColour()==PDT::Colour3);
newout->addColoured(newqout,newqin->dataPtr()->iColour()!=PDT::Colour3);
}
}
// BGF hardest
else {
rot_.invert();
for(unsigned int ix=0;ix<BGFMomenta_.size();++ix) {
BGFMomenta_[ix].transform(rot_);
}
ShowerParticlePtr newq (new_ptr(ShowerParticle(partons_[1],true)));
newq->set5Momentum(BGFMomenta_[1]);
ShowerParticlePtr newqbar(new_ptr(ShowerParticle(partons_[0]->CC(),true)));
newqbar->set5Momentum(BGFMomenta_[2]);
ShowerParticlePtr newg (new_ptr(ShowerParticle(gluon_,false)));
newg->set5Momentum(BGFMomenta_[0]);
ShowerParticlePtr newspace(new_ptr(ShowerParticle(partons_[0],false)));
newspace->set5Momentum(BGFMomenta_[0]-BGFMomenta_[2]);
HardBranchingPtr spaceBranch(new_ptr(HardBranching(newg,SudakovPtr(),HardBranchingPtr(),
HardBranching::Incoming)));
HardBranchingPtr offBranch(new_ptr(HardBranching(newspace,SudakovPtr(),spaceBranch,
HardBranching::Incoming)));
HardBranchingPtr qbar(new_ptr(HardBranching(newqbar,SudakovPtr(),spaceBranch,
HardBranching::Outgoing)));
spaceBranch->addChild(offBranch);
spaceBranch->addChild(qbar);
spaceBranch->type(offBranch->branchingParticle()->id()>0 ?
ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine);
HardBranchingPtr outBranch(new_ptr(HardBranching(newq,SudakovPtr(),
HardBranchingPtr(),
HardBranching::Outgoing)));
spaceBranchings.push_back(spaceBranch);
allBranchings.push_back(offBranch);
allBranchings.push_back(outBranch);
ColinePtr newin(new_ptr(ColourLine())),newout(new_ptr(ColourLine()));
newout->addColoured(newspace,newspace->dataPtr()->iColour()!=PDT::Colour3);
newout->addColoured(newq ,newspace->dataPtr()->iColour()!=PDT::Colour3);
newout->addColoured(newg ,newspace->dataPtr()->iColour()!=PDT::Colour3);
newin ->addColoured(newg ,newspace->dataPtr()->iColour()==PDT::Colour3);
newin ->addColoured(newqbar ,newspace->dataPtr()->iColour()==PDT::Colour3);
}
allBranchings[2]->colourPartner(allBranchings[3]);
allBranchings[3]->colourPartner(allBranchings[2]);
HardTreePtr newTree(new_ptr(HardTree(allBranchings,spaceBranchings,
ShowerInteraction::QCD)));
// Set the maximum pt for all other emissions and connect hard and shower tree
Energy pT = isCompton ? pTCompton_ : pTBGF_;
// incoming particles
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
// set maximum pT
if(QuarkMatcher::Check(cit->first->progenitor()->data()))
cit->first->maximumpT(pT,ShowerInteraction::QCD);
for(set<HardBranchingPtr>::iterator cjt=newTree->branchings().begin();
cjt!=newTree->branchings().end();++cjt) {
if(!(*cjt)->branchingParticle()->isFinalState()&&
(*cjt)->branchingParticle()->id()==cit->first->progenitor()->id()) {
newTree->connect(cit->first->progenitor(),*cjt);
tPPtr beam =cit->first->original();
if(!beam->parents().empty()) beam=beam->parents()[0];
(*cjt)->beam(beam);
HardBranchingPtr parent=(*cjt)->parent();
while(parent) {
parent->beam(beam);
parent=parent->parent();
};
}
}
}
// outgoing particles
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) {
// set maximum pT
if(QuarkMatcher::Check(cit->first->progenitor()->data()))
cit->first->maximumpT(pT,ShowerInteraction::QCD);
for(set<HardBranchingPtr>::iterator cjt=newTree->branchings().begin();
cjt!=newTree->branchings().end();++cjt) {
if((*cjt)->branchingParticle()->isFinalState()&&
(*cjt)->branchingParticle()->id()==cit->first->progenitor()->id()) {
newTree->connect(cit->first->progenitor(),*cjt);
}
}
}
return newTree;
}
void DISBase::generateCompton() {
// maximum value of the xT
double xT = sqrt((1.-xB_)/xB_);
double xTMin = 2.*pTmin_/sqrt(q2_);
double zp;
// prefactor
double a = alpha_->overestimateValue()*comptonWeight_/Constants::twopi;
// loop to generate kinematics
double wgt(0.),xp(0.);
vector<double> azicoeff;
do {
wgt = 0.;
// intergration variables dxT/xT^3
xT *= 1./sqrt(1.-2.*log(UseRandom::rnd())/a*sqr(xT));
// zp
zp = UseRandom::rnd();
xp = 1./(1.+0.25*sqr(xT)/zp/(1.-zp));
// check allowed
if(xp<xB_||xp>1.) continue;
// phase-space piece of the weight
wgt = 8.*(1.-xp)*zp/comptonWeight_;
// PDF piece of the weight
Energy2 scale = q2_*((1.-xp)*(1-zp)*zp/xp+1.);
wgt *= pdf_->xfx(beam_,partons_[0],scale,xB_/xp)/
pdf_->xfx(beam_,partons_[0],q2_ ,xB_);
// me piece of the weight
double x2 = 1.-(1.-zp)/xp;
azicoeff = ComptonME(xp,x2,xT,false);
wgt *= 4./3.*alpha_->ratio(0.25*q2_*sqr(xT))*(azicoeff[0]+0.5*azicoeff[2]);
if(wgt>1.||wgt<0.) {
ostringstream wstring;
wstring << "DISBase::generateCompton() "
<< "Weight greater than one or less than zero"
<< "wgt = " << wgt << "\n";
generator()->logWarning( Exception(wstring.str(),
Exception::warning) );
}
}
while(xT>xTMin&&UseRandom::rnd()>wgt);
if(xT<=xTMin) {
pTCompton_=-GeV;
return;
}
// generate phi
unsigned int itry(0);
double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.);
double phiwgt,phi;
do {
phi = UseRandom::rnd()*Constants::twopi;
double cphi(cos(phi));
phiwgt = azicoeff[0]+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi);
++itry;
}
while (phimax*UseRandom::rnd() > phiwgt && itry<200);
if(itry==200) throw Exception() << "Too many tries in DISMECorrection"
<< "::generateCompton() to"
<< " generate phi" << Exception::eventerror;
// momenta for the configuration
Energy Q(sqrt(q2_));
double x1 = -1./xp;
double x2 = 1.-(1.-zp)/xp;
double x3 = 2.+x1-x2;
Lorentz5Momentum p1( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi),
-0.5*Q*x2, 0.5*Q*sqrt(sqr(xT)+sqr(x2)));
Lorentz5Momentum p2(-0.5*Q*xT*cos(phi), -0.5*Q*xT*sin(phi),
-0.5*Q*x3, 0.5*Q*sqrt(sqr(xT)+sqr(x3)));
Lorentz5Momentum p0(ZERO,ZERO,-0.5*Q*x1,-0.5*Q*x1);
pTCompton_ = 0.5*Q*xT;
ComptonMomenta_.resize(3);
ComptonMomenta_[0] = p0;
ComptonMomenta_[1] = p1;
ComptonMomenta_[2] = p2;
ComptonISFS_ = zp>xp;
// debuggingMatrixElement(false,p0,p1,p2,gluon_,pl_[0],pl_[1],pq_[0],pq_[1],
// leptons_[0],leptons_[1],
// partons_[0],partons_[1],
// q2_,phi,x2,x3,xT,zp,xp,azicoeff,false);
}
void DISBase::generateBGF() {
// maximum value of the xT
double xT = (1.-xB_)/xB_;
double xTMin = 2.*max(pTmin_,pTCompton_)/sqrt(q2_);
double zp;
// prefactor
double a = alpha_->overestimateValue()*BGFWeight_/Constants::twopi;
// loop to generate kinematics
double wgt(0.),xp(0.);
vector<double> azicoeff;
do {
wgt = 0.;
// intergration variables dxT/xT^3
xT *= 1./sqrt(1.-2.*log(UseRandom::rnd())/a*sqr(xT));
// zp
zp = UseRandom::rnd();
xp = 1./(1.+0.25*sqr(xT)/zp/(1.-zp));
// check allowed
if(xp<xB_||xp>1.) continue;
// phase-space piece of the weight
wgt = 8.*sqr(1.-xp)*zp/BGFWeight_;
// PDF piece of the weight
Energy2 scale = q2_*((1.-xp)*(1-zp)*zp/xp+1.);
wgt *= pdf_->xfx(beam_,gluon_ ,scale,xB_/xp)/
pdf_->xfx(beam_,partons_[0],q2_ ,xB_);
// me piece of the weight
double x1 = -1./xp;
double x2 = 1.-(1.-zp)/xp;
double x3 = 2.+x1-x2;
azicoeff = BGFME(xp,x2,x3,xT,false);
wgt *= 0.5*alpha_->ratio(0.25*q2_*sqr(xT))*
(azicoeff[0]+0.5*azicoeff[2]);
if(wgt>1.||wgt<0.) {
ostringstream wstring;
wstring << "DISBase::generateBGF() "
<< "Weight greater than one or less than zero"
<< "wgt = " << wgt << "\n";
generator()->logWarning( Exception(wstring.str(),
Exception::warning) );
}
}
while(xT>xTMin&&UseRandom::rnd()>wgt);
if(xT<=xTMin) {
pTBGF_=-GeV;
return;
}
// generate phi
unsigned int itry(0);
double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.);
double phiwgt,phi;
do {
phi = UseRandom::rnd()*Constants::twopi;
double cphi(cos(phi));
phiwgt = azicoeff[0]+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi);
++itry;
}
while (phimax*UseRandom::rnd() > phiwgt && itry<200);
if(itry==200) throw Exception() << "Too many tries in DISMECorrection"
<< "::generateBGF() to"
<< " generate phi" << Exception::eventerror;
// momenta for the configuration
Energy Q(sqrt(q2_));
double x1 = -1./xp;
double x2 = 1.-(1.-zp)/xp;
double x3 = 2.+x1-x2;
Lorentz5Momentum p1( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi),
-0.5*Q*x2, 0.5*Q*sqrt(sqr(xT)+sqr(x2)));
Lorentz5Momentum p2(-0.5*Q*xT*cos(phi), -0.5*Q*xT*sin(phi),
-0.5*Q*x3, 0.5*Q*sqrt(sqr(xT)+sqr(x3)));
Lorentz5Momentum p0(ZERO,ZERO,-0.5*Q*x1,-0.5*Q*x1);
pTBGF_=0.5*Q*xT;
BGFMomenta_.resize(3);
BGFMomenta_[0]=p0;
BGFMomenta_[1]=p1;
BGFMomenta_[2]=p2;
// debuggingMatrixElement(true,p0,p1,p2,gluon_,pl_[0],pl_[1],pq_[0],pq_[1],
// leptons_[0],leptons_[1],
// partons_[0],partons_[1],
// q2_,phi,x2,x3,xT,zp,xp,azicoeff,false);
}
int DISBase::nDim() const {
return HwMEBase::nDim() + (contrib_>0 ? 1 : 0 );
}
bool DISBase::generateKinematics(const double * r) {
// Born kinematics
if(!HwMEBase::generateKinematics(r)) return false;
if(contrib_!=0) {
// hadron and momentum fraction
if(HadronMatcher::Check(*lastParticles().first->dataPtr())) {
hadron_ = dynamic_ptr_cast<tcBeamPtr>(lastParticles().first->dataPtr());
xB_ = lastX1();
}
else {
hadron_ = dynamic_ptr_cast<tcBeamPtr>(lastParticles().second->dataPtr());
xB_ = lastX2();
}
// Q2
q2_ = -(meMomenta()[0]-meMomenta()[2]).m2();
// xp
int ndim=nDim();
double rhomin = pow(1.-xB_,1.-power_);
double rho = r[ndim-1]*rhomin;
xp_ = 1.-pow(rho,1./(1.-power_));
jac_ = rhomin/(1.-power_)*pow(1.-xp_,power_);
jacobian(jacobian()*jac_);
}
return true;
}
Energy2 DISBase::scale() const {
return scaleOpt_ == 1 ?
-sqr(scaleFact_)*tHat() : sqr(scaleFact_*muF_);
}
CrossSection DISBase::dSigHatDR() const {
return NLOWeight()*HwMEBase::dSigHatDR();
}
double DISBase::NLOWeight() const {
// If only leading order is required return 1:
if(contrib_==0) return 1.;
// scale and prefactors
Energy2 mu2(scale());
double aS = SM().alphaS(mu2);
double CFfact = 4./3.*aS/Constants::twopi;
double TRfact = 1./2.*aS/Constants::twopi;
// LO + dipole subtracted virtual + collinear quark bit with LO pdf
double virt = 1.+CFfact*(-4.5-1./3.*sqr(Constants::pi)+1.5*log(q2_/mu2/(1.-xB_))
+2.*log(1.-xB_)*log(q2_/mu2)+sqr(log(1.-xB_)));
virt /= jac_;
// PDF from leading-order
double loPDF = hadron_->pdf()->xfx(hadron_,mePartonData()[1],mu2,xB_)/xB_;
// NLO gluon PDF
tcPDPtr gluon = getParticleData(ParticleID::g);
double gPDF = hadron_->pdf()->xfx(hadron_,gluon,mu2,xB_/xp_)*xp_/xB_;
// NLO quark PDF
double qPDF = hadron_->pdf()->xfx(hadron_,mePartonData()[1],mu2,xB_/xp_)*xp_/xB_;
// collinear counterterms
// gluon
double collg =
TRfact/xp_*gPDF*(2.*xp_*(1.-xp_)+(sqr(xp_)+sqr(1.-xp_))*log((1.-xp_)*q2_/xp_/mu2));
// quark
double collq =
CFfact/xp_*qPDF*(1-xp_-2./(1.-xp_)*log(xp_)-(1.+xp_)*log((1.-xp_)/xp_*q2_/mu2))+
CFfact/xp_*(qPDF-xp_*loPDF)*(2./(1.-xp_)*log(q2_*(1.-xp_)/mu2)-1.5/(1.-xp_));
// calculate the A coefficient for the real pieces
double a(A(mePartonData()[0],mePartonData()[2],
mePartonData()[1],mePartonData()[3],q2_));
// cacluate lepton kinematic variables
Lorentz5Momentum q = meMomenta()[0]-meMomenta()[2];
double yB = (q*meMomenta()[1])/(meMomenta()[0]*meMomenta()[1]);
double l = 2./yB-1.;
// q -> qg term
double realq = CFfact/xp_/(1.+a*l+sqr(l))*qPDF/loPDF*
(2.+2.*sqr(l)-xp_+3.*xp_*sqr(l)+a*l*(2.*xp_+1.));
// g -> q qbar term
double realg =-TRfact/xp_/(1.+a*l+sqr(l))*gPDF/loPDF*
((1.+sqr(l)+2.*(1.-3.*sqr(l))*xp_*(1.-xp_))
+2.*a*l*(1.-2.*xp_*(1.-xp_)));
// return the full result
double wgt = virt+((collq+collg)/loPDF+realq+realg);
// double f2g = gPDF/xp_*TRfact*((sqr(1-xp_)+sqr(xp_))*log((1-xp_)/xp_)+
// 8*xp_*(1.-xp_)-1.);
// double f2q =
// loPDF/jac_*(1.+CFfact*(-1.5*log(1.-xB_)+sqr(log(1.-xB_))
// -sqr(Constants::pi)/3.-4.5))
// +qPDF *CFfact/xp_*(3.+2.*xp_-(1.+xp_)*log(1.-xp_)
// -(1.+sqr(xp_))/(1.-xp_)*log(xp_))
// +(qPDF-xp_*loPDF)*CFfact/xp_*(2.*log(1.-xp_)/(1.-xp_)-1.5/(1.-xp_));
// double wgt = (f2g+f2q)/loPDF;
return contrib_ == 1 ? max(0.,wgt) : max(0.,-wgt);
}
diff --git a/MatrixElement/DIS/DISBase.h b/MatrixElement/DIS/DISBase.h
--- a/MatrixElement/DIS/DISBase.h
+++ b/MatrixElement/DIS/DISBase.h
@@ -1,468 +1,468 @@
// -*- C++ -*-
#ifndef HERWIG_DISBase_H
#define HERWIG_DISBase_H
//
// This is the declaration of the DISBase class.
//
#include "Herwig/MatrixElement/HwMEBase.h"
#include "Herwig/Shower/Couplings/ShowerAlpha.h"
namespace Herwig {
using namespace ThePEG;
/**
* The DISBase class is the base class for the implementation
* of DIS type processes including corrections in both the old
* fashioned matrix element and POWHEG approaches
*
* @see \ref DISBaseInterfaces "The interfaces"
* defined for DISBase.
*/
class DISBase: public HwMEBase {
public:
/**
* The default constructor.
*/
DISBase();
/**
* The default constructor.
*/
virtual ~DISBase();
/**
* Members for the old-fashioned matrix element correction
*/
//@{
/**
* Has an old fashioned ME correction
*/
virtual bool hasMECorrection() {return true;}
/**
* Initialize the ME correction
*/
virtual void initializeMECorrection(ShowerTreePtr, double &,
double & );
/**
* Apply the hard matrix element correction to a given hard process or decay
*/
virtual void applyHardMatrixElementCorrection(ShowerTreePtr);
/**
* Apply the soft matrix element correction
* @param initial The particle from the hard process which started the
* shower
* @param parent The initial particle in the current branching
* @param br The branching struct
* @return If true the emission should be vetoed
*/
virtual bool softMatrixElementVeto(ShowerProgenitorPtr,
ShowerParticlePtr,Branching);
//@}
/**
* Members for the POWHEG stype correction
*/
//@{
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return Both;}
/**
* Apply the POWHEG style correction
*/
- virtual HardTreePtr generateHardest(ShowerTreePtr,vector<ShowerInteraction::Type>);
+ virtual HardTreePtr generateHardest(ShowerTreePtr,ShowerInteraction::Type);
//@}
public:
/** @name Virtual functions required by the MEBase class. */
//@{
/**
* Return the scale associated with the last set phase space point.
*/
virtual Energy2 scale() const;
/**
* The number of internal degrees of freedom used in the matrix
* element.
*/
virtual int nDim() const;
/**
* Generate internal degrees of freedom given nDim() uniform
* random numbers in the interval \f$ ]0,1[ \f$. To help the phase space
* generator, the dSigHatDR should be a smooth function of these
* numbers, although this is not strictly necessary.
* @param r a pointer to the first of nDim() consecutive random numbers.
* @return true if the generation succeeded, otherwise false.
*/
virtual bool generateKinematics(const double * r);
/**
* Return the matrix element squared differential in the variables
* given by the last call to generateKinematics().
*/
virtual CrossSection dSigHatDR() const;
//@}
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is an abstract class with persistent data.
*/
static AbstractClassDescription<DISBase> initDISBase;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
DISBase & operator=(const DISBase &);
protected:
/**
* The NLO weight
*/
double NLOWeight() const;
/**
* Calculate the coefficient A for the correlations
*/
virtual double A(tcPDPtr lin, tcPDPtr lout, tcPDPtr qin, tcPDPtr qout,
Energy2 scale) const =0;
/**
* Members for the matrix element correction
*/
//@{
/**
* Generate the values of \f$x_p\f$ and \f$z_p\f$
* @param xp The value of xp, output
* @param zp The value of zp, output
*/
double generateComptonPoint(double &xp, double & zp);
/**
* Generate the values of \f$x_p\f$ and \f$z_p\f$
* @param xp The value of xp, output
* @param zp The value of zp, output
*/
double generateBGFPoint(double &xp, double & zp);
/**
* Return the coefficients for the matrix element piece for
* the QCD compton case. The output is the \f$a_i\f$ coefficients to
* give the function as
* \f$a_0+a_1\cos\phi+a_2\sin\phi+a_3\cos^2\phi+a_4\sin^2\phi\f$
* @param xp \f$x_p\f$
* @param x2 \f$x_2\f$
* @param xperp \f$x_\perp\f$
* @param norm Normalise to the large $l$ value of the ME
*/
vector<double> ComptonME(double xp, double x2, double xperp,
bool norm);
/**
* Return the coefficients for the matrix element piece for
* the QCD compton case. The output is the \f$a_i\f$ coefficients to
* give the function as
* \f$a_0+a_1\cos\phi+a_2\sin\phi+a_3\cos^2\phi+a_4\sin^2\phi\f$
* @param xp \f$x_p\f$
* @param x2 \f$x_3\f$
* @param x3 \f$x_2\f$
* @param xperp \f$x_\perp\f$
* @param norm Normalise to the large $l$ value of the ME
*/
vector<double> BGFME(double xp, double x2, double x3, double xperp,
bool norm);
//@}
/**
* Members for the POWHEG correction
*/
//@{
/**
* Generate a Compton process
*/
void generateCompton();
/**
* Generate a BGF process
*/
void generateBGF();
//@}
private:
/**
* Parameters for the matrix element correction
*/
//@{
/**
* Enchancement factor for ISR
*/
double initial_;
/**
* Enchancement factor for FSR
*/
double final_;
/**
* Relative fraction of compton and BGF processes to generate
*/
double procProb_;
/**
* Integral for compton process
*/
double comptonInt_;
/**
* Integral for BGF process
*/
double bgfInt_;
//@}
/**
* Parameters for the POWHEG correction
*/
//@{
/**
* Weight for the compton channel
*/
double comptonWeight_;
/**
* Weight for the BGF channel
*/
double BGFWeight_;
/**
* Minimum value of \f$p_T\f$
*/
Energy pTmin_;
//@}
/**
* Parameters for the point being generated
*/
//@{
/**
* \f$Q^2\f$
*/
Energy2 q2_;
/**
*
*/
double l_;
/**
* Borm momentum fraction
*/
double xB_;
/**
* Beam particle
*/
tcBeamPtr beam_;
/**
* Partons
*/
tcPDPtr partons_[2];
/**
* Leptons
*/
tcPDPtr leptons_[2];
/**
* PDF object
*/
tcPDFPtr pdf_;
/**
* Rotation to the Breit frame
*/
LorentzRotation rot_;
/**
* Lepton momenta
*/
Lorentz5Momentum pl_[2];
/**
* Quark momenta
*/
Lorentz5Momentum pq_[2];
/**
* q
*/
Lorentz5Momentum q_;
/**
* Compton parameters
*/
Energy pTCompton_;
bool ComptonISFS_;
vector<Lorentz5Momentum> ComptonMomenta_;
/**
* BGF parameters
*/
Energy pTBGF_;
vector<Lorentz5Momentum> BGFMomenta_;
//@}
/**
* The coefficient for the correlations
*/
double acoeff_;
/**
* Coupling
*/
ShowerAlphaPtr alpha_;
/**
* Gluon particle data object
*/
PDPtr gluon_;
private:
/**
* The radiative variables
*/
//@{
/**
* The \f$x_p\f$ or \f$z\f$ real integration variable
*/
double xp_;
//@}
/**
* The hadron
*/
tcBeamPtr hadron_;
/**
* Selects a dynamic or fixed factorization scale
*/
unsigned int scaleOpt_;
/**
* The factorization scale
*/
Energy muF_;
/**
* Prefactor if variable scale used
*/
double scaleFact_;
/**
* Whether to generate the positive, negative or leading order contribution
*/
unsigned int contrib_;
/**
* Power for sampling \f$x_p\f$
*/
double power_;
/**
* Jacobian for \f$x_p\f$ integral
*/
double jac_;
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of DISBase. */
template <>
struct BaseClassTrait<Herwig::DISBase,1> {
/** Typedef of the first base class of DISBase. */
typedef Herwig::HwMEBase NthBase;
};
/** This template specialization informs ThePEG about the name of
* the DISBase class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::DISBase>
: public ClassTraitsBase<Herwig::DISBase> {
/** Return a platform-independent class name */
static string className() { return "Herwig::DISBase"; }
/**
* The name of a file containing the dynamic library where the class
* MENeutralCurrentDIS is implemented. It may also include several, space-separated,
* libraries if the class MENeutralCurrentDIS depends on other classes (base classes
* excepted). In this case the listed libraries will be dynamically
* linked in the order they are specified.
*/
static string library() { return "HwMEDIS.so"; }
};
/** @endcond */
}
#endif /* HERWIG_DISBase_H */
diff --git a/MatrixElement/DrellYanBase.cc b/MatrixElement/DrellYanBase.cc
--- a/MatrixElement/DrellYanBase.cc
+++ b/MatrixElement/DrellYanBase.cc
@@ -1,1062 +1,1060 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the DrellYanBase class.
//
#include "DrellYanBase.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "Herwig/Shower/Base/ShowerTree.h"
#include "Herwig/Shower/Base/HardTree.h"
#include "Herwig/Shower/Base/ShowerProgenitor.h"
#include "Herwig/Shower/Base/ShowerParticle.h"
#include "Herwig/Shower/Base/Branching.h"
using namespace Herwig;
DrellYanBase::DrellYanBase()
: _channelwgtA(0.12), _channelwgtB(2.00), _nover(0), _maxwgt(0.),
_power(2.0),_preqqbar(6.5),_preqg(4.0),_pregqbar(4.0),
_min_pt(2.*GeV) {}
void DrellYanBase::persistentOutput(PersistentOStream & os) const {
os << _channelwgtA << _channelwgtB << _channelweights << _alpha
<< _power << _preqqbar << _preqg << _pregqbar << ounit( _min_pt, GeV )
<< _prefactor;
}
void DrellYanBase::persistentInput(PersistentIStream & is, int) {
is >> _channelwgtA >> _channelwgtB >> _channelweights >> _alpha
>> _power >> _preqqbar >> _preqg >> _pregqbar >> iunit( _min_pt, GeV )
>> _prefactor;
}
AbstractClassDescription<DrellYanBase> DrellYanBase::initDrellYanBase;
// Definition of the static class description member.
void DrellYanBase::Init() {
static ClassDocumentation<DrellYanBase> documentation
("The DrellYanBase class provides a base class for the"
" corrections to Drell-Yan type processes");
static Parameter<DrellYanBase,double> interfaceQQbarChannelWeight
("QQbarChannelWeight",
"The relative weights of the q qbar abd q g channels for selection."
" This is a technical parameter for the phase-space generation and "
"should not affect the results only the efficiency and fraction"
" of events with weight > 1.",
&DrellYanBase::_channelwgtA, 0.12, 0.01, 100.,
false, false, Interface::limited);
static Parameter<DrellYanBase,double> interfaceQGChannelWeight
("QGChannelWeight",
"The relative weights of the qg abd qbar g channels for selection."
" This is a technical parameter for the phase-space generation and "
"should not affect the results only the efficiency and fraction",
&DrellYanBase::_channelwgtB, 2., 0.01, 100.,
false, false, Interface::limited);
static Reference<DrellYanBase,ShowerAlpha> interfaceCoupling
("Coupling",
"Pointer to the object to calculate the coupling for the correction",
&DrellYanBase::_alpha, false, false, true, false, false);
static Parameter<DrellYanBase,double> interfacePower
("Power",
"The power for the sampling of the matrix elements",
&DrellYanBase::_power, 2.0, 1.0, 10.0,
false, false, Interface::limited);
static Parameter<DrellYanBase,double> interfacePrefactorqqbar
("Prefactorqqbar",
"The prefactor for the sampling of the q qbar channel",
&DrellYanBase::_preqqbar, 5.0, 0.0, 1000.0,
false, false, Interface::limited);
static Parameter<DrellYanBase,double> interfacePrefactorqg
("Prefactorqg",
"The prefactor for the sampling of the q g channel",
&DrellYanBase::_preqg, 3.0, 0.0, 1000.0,
false, false, Interface::limited);
static Parameter<DrellYanBase,double> interfacePrefactorgqbar
("Prefactorgqbar",
"The prefactor for the sampling of the g qbar channel",
&DrellYanBase::_pregqbar, 3.0, 0.0, 1000.0,
false, false, Interface::limited);
static Parameter<DrellYanBase, Energy> interfacePtMin
("minPt",
"The pt cut on hardest emision generation"
"2*(1-Beta)*exp(-sqr(intrinsicpT/RMS))/sqr(RMS)",
&DrellYanBase::_min_pt, GeV, 2.*GeV, ZERO, 100000.0*GeV,
false, false, Interface::limited);
}
void DrellYanBase::doinit() {
HwMEBase::doinit();
_channelweights.push_back(_channelwgtA/(1.+_channelwgtA));
_channelweights.push_back(_channelweights[0]+1./(1.+_channelwgtA)/(1+_channelwgtB));
_channelweights.push_back(1.0);
_prefactor.push_back(_preqqbar);
_prefactor.push_back(_preqg);
_prefactor.push_back(_pregqbar);
}
void DrellYanBase::dofinish() {
HwMEBase::dofinish();
if(_nover==0) return;
generator()->log() << "DrellYanBase when applying the hard correction "
<< _nover << " weights larger than one were generated of which"
<< " the largest was " << _maxwgt << "\n";
}
void DrellYanBase::applyHardMatrixElementCorrection(ShowerTreePtr tree) {
// get the quark,antiquark and the gauge boson
// get the quarks
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cit;
ShowerParticleVector incoming;
vector<tcBeamPtr> beams;
for(cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
incoming.push_back(cit->first->progenitor());
beams.push_back(cit->first->beam());
}
// ensure that the quark is first
if(incoming[0]->id()<incoming[1]->id()) {
swap(incoming[0],incoming[1]);
swap(beams[0],beams[1]);
}
Lorentz5Momentum pboson;
for( map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt= tree->outgoingLines().begin();
cjt != tree->outgoingLines().end();++cjt ) {
pboson += cjt->first->original()->momentum();
}
pboson.rescaleMass();
// calculate the momenta
unsigned int iemit,itype;
vector<Lorentz5Momentum> pnew;
LorentzRotation trans;
pair<double,double> xnew;
// if not accepted return
if(!applyHard(incoming,beams,pboson,iemit,itype,pnew,trans,xnew)) return;
// if applying ME correction create the new particles
if(itype==0) {
// get the momenta of the new particles
Lorentz5Momentum pquark(pnew[0]),panti(pnew[1]),pgluon(pnew[2]);
if(iemit==2) swap(pquark,panti);
// ensure gluon can be put on shell
Lorentz5Momentum ptest(pgluon);
if(ptest.boost(-(pquark+panti).boostVector()).e() <
getParticleData(ParticleID::g)->constituentMass()) return;
// create the new gluon
PPtr newg= getParticleData(ParticleID::g)->produceParticle(pgluon);
PPtr newq,newa;
ColinePtr col;
// make the new particles
if(iemit==1) {
col=incoming[0]->colourLine();
newq = getParticleData(incoming[0]->id())->produceParticle(pquark);
newa = new_ptr(Particle(*incoming[1]));
col->removeAntiColoured(newa);
newa->set5Momentum(panti);
}
else {
col=incoming[1]->antiColourLine();
newa = getParticleData(incoming[1]->id())->produceParticle(panti);
newq = new_ptr(Particle(*incoming[0]));
col->removeColoured(newq);
newq->set5Momentum(pquark);
}
// set the colour lines
ColinePtr newline=new_ptr(ColourLine());
if(iemit==1) {
newline->addColoured(newq);
newline->addColoured(newg);
col->addAntiColoured(newg);
col->addAntiColoured(newa);
}
else {
newline->addAntiColoured(newa);
newline->addAntiColoured(newg);
col->addColoured(newg);
col->addColoured(newq);
}
// change the existing quark and antiquark
PPtr orig;
for(cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
if(cit->first->progenitor()->id()==newq->id()) {
// remove old particles from colour line
col->removeColoured(cit->first->copy());
col->removeColoured(cit->first->progenitor());
// insert new particles
cit->first->copy(newq);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newq,1,false)));
sp->x(xnew.first);
cit->first->progenitor(sp);
tree->incomingLines()[cit->first]=sp;
cit->first->perturbative(iemit!=1);
if(iemit==1) orig=cit->first->original();
}
else {
// remove old particles from colour line
col->removeAntiColoured(cit->first->copy());
col->removeColoured(cit->first->progenitor());
// insert new particles
cit->first->copy(newa);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newa,1,false)));
sp->x(xnew.second);
cit->first->progenitor(sp);
tree->incomingLines()[cit->first]=sp;
cit->first->perturbative(iemit==1);
if(iemit==2) orig=cit->first->original();
}
}
// fix the momentum of the gauge boson
Boost boostv=pboson.findBoostToCM();
trans *=LorentzRotation(boostv);
for( map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt= tree->outgoingLines().begin();
cjt != tree->outgoingLines().end();++cjt ) {
cjt->first->progenitor()->transform(trans);
cjt->first->copy()->transform(trans);
}
tree->hardMatrixElementCorrection(true);
// add the gluon
ShowerParticlePtr sg=new_ptr(ShowerParticle(*newg,1,true));
ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(orig,newg,sg));
gluon->perturbative(false);
tree->outgoingLines().insert(make_pair(gluon,sg));
}
else if(itype==1) {
Lorentz5Momentum pin(pnew[0]),pout(pnew[1]),pgluon(pnew[2]);
if(iemit==2) swap(pin,pout);
// ensure outgoing quark can be put on-shell
Lorentz5Momentum ptest(pout);
if(ptest.boost(-(pin+pgluon).boostVector()).e() <
incoming[1]->dataPtr()->constituentMass()) return;
// create the new gluon
PPtr newg = getParticleData(ParticleID::g)->produceParticle(pgluon);
// create the new outgoing quark
PPtr newout= getParticleData(-incoming[1]->id())->produceParticle(pout);
// create the new incoming quark
PPtr newin = new_ptr(Particle(*incoming[0]));
newin->set5Momentum(pin);
// colour info
ColinePtr col=incoming[0]->colourLine();
col->removeColoured(newin);
ColinePtr newline=new_ptr(ColourLine());
newline->addColoured(newout);
newline->addColoured(newg);
col->addAntiColoured(newg);
col->addColoured(newin);
// change the existing incoming partons
PPtr orig;
for(cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
if(cit->first->progenitor()->id()==newin->id()) {
// remove old particles from colour line
col->removeColoured(cit->first->copy());
col->removeColoured(cit->first->progenitor());
// insert new particles
cit->first->copy(newin);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newin,1,false)));
sp->x(xnew.first);
cit->first->progenitor(sp);
tree->incomingLines()[cit->first]=sp;
cit->first->perturbative(true);
}
else {
// remove old particles from colour line
col->removeAntiColoured(cit->first->copy());
col->removeColoured(cit->first->progenitor());
// insert new particles
cit->first->copy(newg);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newg,1,false)));
sp->x(xnew.second);
cit->first->progenitor(sp);
tree->incomingLines()[cit->first]=sp;
cit->first->perturbative(false);
orig=cit->first->original();
}
}
// fix the momentum of the gauge boson
Boost boostv=pboson.findBoostToCM();
trans *=LorentzRotation(boostv);
for( map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt= tree->outgoingLines().begin();
cjt != tree->outgoingLines().end();++cjt ) {
cjt->first->progenitor()->transform(trans);
cjt->first->copy()->transform(trans);
}
tree->hardMatrixElementCorrection(true);
// add the outgoing quark
ShowerParticlePtr sout=new_ptr(ShowerParticle(*newout,1,true));
ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(orig,newout,sout));
out->perturbative(false);
tree->outgoingLines().insert(make_pair(out,sout));
}
else if(itype==2) {
Lorentz5Momentum pin(pnew[0]),pout(pnew[1]),pgluon(pnew[2]);
if(iemit==2) swap(pin,pout);
// ensure outgoing antiquark can be put on-shell
Lorentz5Momentum ptest(pout);
if(ptest.boost(-(pin+pgluon).boostVector()).e() <
incoming[0]->dataPtr()->constituentMass()) return;
// create the new gluon
PPtr newg = getParticleData(ParticleID::g)->produceParticle(pgluon);
// create the new outgoing antiquark
PPtr newout= getParticleData(-incoming[0]->id())->produceParticle(pout);
// create the new incoming antiquark
PPtr newin = new_ptr(Particle(*incoming[1]));
newin->set5Momentum(pin);
// colour info
ColinePtr col=incoming[0]->colourLine();
col->removeAntiColoured(newin);
ColinePtr newline=new_ptr(ColourLine());
newline->addAntiColoured(newout);
newline->addAntiColoured(newg);
col->addColoured(newg);
col->addAntiColoured(newin);
// change the existing incoming partons
PPtr orig;
for(cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
if(cit->first->progenitor()->id()==newin->id()) {
// remove old particles from colour line
col->removeAntiColoured(cit->first->copy());
col->removeAntiColoured(cit->first->progenitor());
// insert new particles
cit->first->copy(newin);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newin,1,false)));
sp->x(xnew.second);
cit->first->progenitor(sp);
tree->incomingLines()[cit->first]=sp;
cit->first->perturbative(true);
}
else {
// remove old particles from colour line
col->removeColoured(cit->first->copy());
col->removeColoured(cit->first->progenitor());
// insert new particles
cit->first->copy(newg);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newg,1,false)));
sp->x(xnew.first);
cit->first->progenitor(sp);
tree->incomingLines()[cit->first]=sp;
cit->first->perturbative(false);
orig=cit->first->original();
}
}
// fix the momentum of the gauge boson
Boost boostv=pboson.findBoostToCM();
trans *=LorentzRotation(boostv);
for( map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt= tree->outgoingLines().begin();
cjt != tree->outgoingLines().end();++cjt ) {
cjt->first->progenitor()->transform(trans);
cjt->first->copy()->transform(trans);
}
tree->hardMatrixElementCorrection(true);
// add the outgoing antiquark
ShowerParticlePtr sout=new_ptr(ShowerParticle(*newout,1,true));
ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(orig,newout,sout));
out->perturbative(false);
tree->outgoingLines().insert(make_pair(out,sout));
}
}
bool DrellYanBase::applyHard(ShowerParticleVector quarks,
vector<tcBeamPtr> beams, Lorentz5Momentum boson,
unsigned int & iemit,unsigned int & itype,
vector<Lorentz5Momentum> & pnew,
LorentzRotation & trans,
pair<double,double> & xout) {
// check that quark along +z and qbar along -z
bool quarkplus=quarks[0]->momentum().z()>quarks[1]->momentum().z();
// calculate the limits on s
Energy mb = sqrt(mb2_);
Energy2 smin=mb2_;
Energy2 s=
(generator()->currentEvent()->incoming().first ->momentum()+
generator()->currentEvent()->incoming().second->momentum()).m2();
Energy2 smax(s);
// calculate the rapidity of the boson
double yB=0.5*log((boson.e()+boson.z())/
(boson.e()-boson.z()));
if(!quarkplus) yB=-yB;
// if no phase-space return
if(smax<smin) return false;
// get the evolution scales (this needs improving)
double kappa[2]={1.,1.};
// get the momentum fractions for the leading order process
// and the values of the PDF's
double x[2]={-99.99e99,-99.99e99}, fx[2]={-99.99e99,-99.99e99};
tcPDFPtr pdf[2];
for(unsigned int ix=0;ix<quarks.size();++ix) {
x[ix]=quarks[ix]->x();
assert(beams[ix]);
pdf[ix]=beams[ix]->pdf();
assert(pdf[ix]);
fx[ix]=pdf[ix]->xfx(beams[ix],quarks[ix]->dataPtr(),mb2_,x[ix]);
}
// select the type of process and generate the kinematics
double rn(UseRandom::rnd());
Energy2 shat(ZERO),uhat(ZERO),that(ZERO);
double weight(0.),xnew[2]={1.,1.};
// generate the value of s according to 1/s^2
shat = smax*smin/(smin+UseRandom::rnd()*(smax-smin));
Energy2 jacobian = sqr(shat)*(1./smin-1./smax);
double sbar=shat/mb2_;
// calculate limits on that
Energy2 tmax=mb2_*kappa[0]*(1.-sbar)/(kappa[0]+sbar);
Energy2 tmin=shat*(1.-sbar)/(kappa[1]+sbar);
// calculate the limits on uhat
Energy2 umax(mb2_-shat-tmin),umin(mb2_-shat-tmax);
// check inside phase space
if(tmax<tmin||umax<umin) return false;
// q qbar -> g V
if(rn<_channelweights[0]) {
// generate t and u according to 1/t+1/u
// generate in 1/t
if(UseRandom::rndbool(0.5)) {
that=tmax*pow(tmin/tmax,UseRandom::rnd());
uhat=mb2_-shat-that;
jacobian *=log(tmin/tmax);
}
// generate in 1/u
else {
uhat=umax*pow(umin/umax,UseRandom::rnd());
that=mb2_-shat-uhat;
jacobian *=log(umin/umax);
}
Energy4 jacobian2 = jacobian * 2.*uhat*that/(shat-mb2_);
// new scale (this is mt^2=pt^2+mb^2)
Energy2 scale(uhat*that/shat+mb2_);
// the PDF's with the emitted gluon
double fxnew[2];
xnew[0]=exp(yB)/sqrt(s)*sqrt(shat*(mb2_-uhat)/(mb2_-that));
xnew[1]=shat/(s*xnew[0]);
for(unsigned int ix=0;ix<2;++ix)
{fxnew[ix]=pdf[ix]->xfx(beams[ix],quarks[ix]->dataPtr(),scale,xnew[ix]);}
// jacobian and me parts of the weight
weight=jacobian2*(sqr(mb2_-that)+sqr(mb2_-uhat))/(sqr(shat)*that*uhat);
// pdf part of the weight
weight *=fxnew[0]*fxnew[1]*x[0]*x[1]/(fx[0]*fx[1]*xnew[0]*xnew[1]);
// finally coupling, colour factor and different channel pieces
weight *= 2./3./Constants::pi/_channelweights[0]*_alpha->value(scale);
// select the emiting particle
iemit=1;
if(UseRandom::rnd()<sqr(mb2_-uhat)/(sqr(mb2_-uhat)+sqr(mb2_-that))) iemit=2;
itype=0;
}
// incoming gluon
else {
// generate t
if(rn>_channelweights[1]) {
swap(tmax,tmin);
tmax=mb2_-shat-tmax;
tmin=mb2_-shat-tmin;
}
that=tmax*pow(tmin/tmax,UseRandom::rnd());
uhat=mb2_-shat-that;
Energy4 jacobian2 = jacobian * that*log(tmax/tmin);
// new scale (this is mt^2=pt^2+mb^2)
Energy2 scale(uhat*that/shat+mb2_);
// g qbar -> qbar V
double fxnew[2];
if(rn<_channelweights[1]) {
itype=2;
xnew[0]=exp(yB)/sqrt(s)*sqrt(shat*(mb2_-uhat)/(mb2_-that));
xnew[1]=shat/(s*xnew[0]);
fxnew[0]=pdf[0]->xfx(beams[0],getParticleData(ParticleID::g),scale,xnew[0]);
fxnew[1]=pdf[1]->xfx(beams[1],quarks[1]->dataPtr(),scale,xnew[1]);
jacobian2/=(_channelweights[1]-_channelweights[0]);
}
// q g -> q V
else {
itype=1;
xnew[0]=exp(yB)/sqrt(s)*sqrt(shat*(mb2_-that)/(mb2_-uhat));
xnew[1]=shat/(s*xnew[0]);
fxnew[0]=pdf[0]->xfx(beams[0],quarks[0]->dataPtr(),scale,xnew[0]);
fxnew[1]=pdf[1]->xfx(beams[1],getParticleData(ParticleID::g),scale,xnew[1]);
jacobian2/=(_channelweights[2]-_channelweights[1]);
}
// jacobian and me parts of the weight
weight=-jacobian2*(sqr(mb2_-that)+sqr(mb2_-shat))/(sqr(shat)*shat*that);
// pdf part of the weight
weight *=fxnew[0]*fxnew[1]*x[0]*x[1]/(fx[0]*fx[1]*xnew[0]*xnew[1]);
// finally coupling, colour factor and different channel pieces
weight *= 0.25/Constants::pi*_alpha->value(scale);
// select the emiting particle
iemit=1;
if(UseRandom::rnd()<sqr(mb2_-that)/(sqr(mb2_-that)+sqr(mb2_-shat))) iemit=2;
}
// if me correction should be applied
if(weight>1.) {
++_nover;
_maxwgt=max(_maxwgt,weight);
weight=1.;
}
if(UseRandom::rnd()>weight) return false;
// construct the momenta in the rest frame of the boson
Lorentz5Momentum pb(ZERO,ZERO,ZERO,mb,mb),pspect,pg,pemit;
double cos3 = 0.0;
if(itype==0)
{
pg = Lorentz5Momentum(ZERO,ZERO,ZERO,0.5*(shat-mb2_)/mb,ZERO);
Energy2 tp(that),up(uhat);
double zsign(-1.);
if(iemit==2)
{
tp=uhat;
up=that;
zsign=1.;
}
pspect = Lorentz5Momentum(ZERO,ZERO,zsign*0.5*(mb2_-tp)/mb,
0.5*(mb2_-tp)/mb,ZERO);
Energy eemit=0.5*(mb2_-up)/mb;
cos3 = 0.5/pspect.z()/pg.e()*(sqr(pspect.e())+sqr(pg.e())-sqr(eemit));
}
else
{
pg=Lorentz5Momentum(ZERO,ZERO,ZERO,0.5*(mb2_-uhat)/mb,ZERO);
double zsign(1.);
if(iemit==1)
{
if(itype==1) zsign=-1.;
pspect=Lorentz5Momentum(ZERO,ZERO,0.5*zsign*(shat-mb2_)/mb,
0.5*(shat-mb2_)/mb);
Energy eemit=0.5*(mb2_-that)/mb;
cos3 = 0.5/pspect.z()/pg.e()*(sqr(pspect.e())+sqr(pg.e())-sqr(eemit));
}
else
{
if(itype==2) zsign=-1.;
pspect=Lorentz5Momentum(ZERO,ZERO,0.5*zsign*(mb2_-that)/mb,
0.5*(mb2_-that)/mb);
Energy eemit=0.5*(shat-mb2_)/mb;
cos3 = 0.5/pspect.z()/pg.e()*(-sqr(pspect.e())-sqr(pg.e())+sqr(eemit));
}
}
// rotate the gluon
double sin3(sqrt(1.-sqr(cos3)));
double phi(Constants::twopi*UseRandom::rnd());
pg.setX(pg.e()*sin3*cos(phi));
pg.setY(pg.e()*sin3*sin(phi));
pg.setZ(pg.e()*cos3);
if(itype==0) {
pemit=pb+pg-pspect;
}
else {
if(iemit==1) pemit=pb+pspect-pg;
else pemit=pspect+pg-pb;
}
pemit.rescaleMass();
// find the new CMF
Lorentz5Momentum pp[2];
if(itype==0) {
if(iemit==1) {
pp[0]=pemit;
pp[1]=pspect;
}
else {
pp[0]=pspect;
pp[1]=pemit;
}
}
else if(itype==1) {
pp[1]=pg;
if(iemit==1) pp[0]=pemit;
else pp[0]=pspect;
}
else {
pp[0]=pg;
if(iemit==1) pp[1]=pemit;
else pp[1]=pspect;
}
Lorentz5Momentum pz= quarkplus ? pp[0] : pp[1];
pp[0]/=xnew[0];
pp[1]/=xnew[1];
Lorentz5Momentum plab(pp[0]+pp[1]);
plab.rescaleMass();
// construct the boost to rest frame of plab
trans=LorentzRotation(plab.findBoostToCM());
pz.transform(trans);
// rotate so emitting particle along z axis
// rotate so in x-z plane
trans.rotateZ(-atan2(pz.y(),pz.x()));
// rotate so along
trans.rotateY(-acos(pz.z()/pz.vect().mag()));
// undo azimuthal rotation
trans.rotateZ(atan2(pz.y(),pz.x()));
// perform the transforms
pb .transform(trans);
pspect.transform(trans);
pg .transform(trans);
pemit .transform(trans);
// momenta to be returned
pnew.push_back(pemit);
pnew.push_back(pspect);
pnew.push_back(pg);
pnew.push_back(pb);
xout.first=xnew[0];
xout.second=xnew[1];
return true;
}
bool DrellYanBase::softMatrixElementVeto(ShowerProgenitorPtr initial,
ShowerParticlePtr parent,Branching br) {
if(parent->isFinalState()) return false;
// check if me correction should be applied
long id[2]={initial->id(),parent->id()};
if(id[0]!=id[1]||id[1]==ParticleID::g) return false;
// get the pT
Energy pT=br.kinematics->pT();
// check if hardest so far
if(pT<initial->highestpT()) return false;
// compute the invariants
double kappa(sqr(br.kinematics->scale())/mb2_),z(br.kinematics->z());
Energy2 shat(mb2_/z*(1.+(1.-z)*kappa)),that(-(1.-z)*kappa*mb2_),uhat(-(1.-z)*shat);
// check which type of process
// g qbar
double wgt(1.);
if(id[0]>0&&br.ids[0]==ParticleID::g)
wgt=mb2_/(shat+uhat)*(sqr(mb2_-that)+sqr(mb2_-shat))/(sqr(shat+uhat)+sqr(uhat));
else if(id[0]>0&&br.ids[0]==id[0])
wgt=mb2_/(shat+uhat)*(sqr(mb2_-uhat)+sqr(mb2_-that))/(sqr(shat)+sqr(shat+uhat));
else if(id[0]<0&&br.ids[0]==ParticleID::g)
wgt=mb2_/(shat+uhat)*(sqr(mb2_-that)+sqr(mb2_-shat))/(sqr(shat+uhat)+sqr(uhat));
else if(id[0]<0&&br.ids[0]==-id[0])
wgt=mb2_/(shat+uhat)*(sqr(mb2_-uhat)+sqr(mb2_-that))/(sqr(shat)+sqr(shat+uhat));
else return false;
if(wgt<.0||wgt>1.) generator()->log() << "Soft ME correction weight too large or "
<< "negative in DrellYanBase::"
<< "softMatrixElementVeto()soft weight "
<< " sbar = " << shat/mb2_
<< " tbar = " << that/mb2_
<< "weight = " << wgt << "\n";
// if not vetoed
if(UseRandom::rndbool(wgt)) return false;
// otherwise
parent->vetoEmission(br.type,br.kinematics->scale());
return true;
}
HardTreePtr DrellYanBase::generateHardest(ShowerTreePtr tree,
- vector<ShowerInteraction::Type> inter) {
- bool found = false;
+ ShowerInteraction::Type inter) {
// check if generating QCD radiation
- for(unsigned int ix=0;ix<inter.size();++ix) {
- found |= inter[ix]==ShowerInteraction::QCD;
- }
- if(!found) return HardTreePtr();
+ if(inter!=ShowerInteraction::QCD && inter!=ShowerInteraction::QEDQCD &&
+ inter!=ShowerInteraction::ALL)
+ return HardTreePtr();
useMe();
// get the particles to be showered
_beams.clear();
_partons.clear();
// find the incoming particles
ShowerParticleVector incoming;
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cit;
_quarkplus = true;
vector<ShowerProgenitorPtr> particlesToShower;
//progenitor particles are produced in z direction.
for( cit = tree->incomingLines().begin(); cit != tree->incomingLines().end(); ++cit ) {
incoming.push_back( cit->first->progenitor() );
_beams.push_back( cit->first->beam() );
_partons.push_back( cit->first->progenitor()->dataPtr() );
// check that quark is along +ve z direction
if(cit->first->progenitor()->id() > 0 &&
cit->first->progenitor()->momentum().z() < ZERO )
_quarkplus = false;
particlesToShower.push_back( cit->first );
}
Lorentz5Momentum pboson;
for( map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt= tree->outgoingLines().begin();
cjt != tree->outgoingLines().end();++cjt ) {
pboson += cjt->first->original()->momentum();
}
pboson.rescaleMass();
// calculate the rapidity of the boson
_yb = 0.5 * log((pboson.e()+pboson.z())/(pboson.e()-pboson.z()));
_yb *= _quarkplus ? 1. : -1.;
_mass = pboson.mass();
// we are assuming quark first, swap order to ensure this
// if antiquark first
if(_partons[0]->id()<_partons[1]->id()) {
swap(_partons[0],_partons[1]);
swap(_beams[0],_beams[1]);
}
vector<Lorentz5Momentum> pnew;
int emission_type(-1);
// generate the hard emission and return if no emission
if(!getEvent(pnew,emission_type)) {
for(unsigned int ix=0;ix<particlesToShower.size();++ix)
particlesToShower[ix]->maximumpT(_min_pt,ShowerInteraction::QCD);
return HardTreePtr();
}
// construct the HardTree object needed to perform the showers
ShowerParticleVector newparticles;
// make the particles for the HardTree
tcPDPtr gluon=getParticleData(ParticleID::g);
// create the partons
int iemit;
// q qbar -> g V
ColinePtr newline[2]={new_ptr(ColourLine()),new_ptr(ColourLine())};
if(emission_type==0) {
newparticles.push_back(new_ptr(ShowerParticle(_partons[0] ,false)));
newparticles.push_back(new_ptr(ShowerParticle(_partons[1] ,false)));
newparticles.push_back(new_ptr(ShowerParticle(gluon , true)));
newline[1]->addColoured(newparticles[0]);
newline[1]->addColoured(newparticles[2]);
newline[0]->addAntiColoured(newparticles[1]);
newline[0]->addAntiColoured(newparticles[2]);
iemit = (pnew[0]-pnew[2]).m2()>(pnew[1]-pnew[2]).m2() ? 0 : 1;
}
// q g -> q V
else if(emission_type==1) {
iemit=1;
newparticles.push_back(new_ptr(ShowerParticle(_partons[0] ,false)));
newparticles.push_back(new_ptr(ShowerParticle(gluon ,false)));
newparticles.push_back(new_ptr(ShowerParticle(_partons[1]->CC(), true)));
newline[1]->addColoured(newparticles[0]);
newline[1]->addAntiColoured(newparticles[1]);
newline[0]->addColoured(newparticles[1]);
newline[0]->addColoured(newparticles[2]);
}
// g qbar -> qbar V
else {
iemit=0;
newparticles.push_back(new_ptr(ShowerParticle(gluon ,false)));
newparticles.push_back(new_ptr(ShowerParticle(_partons[1] ,false)));
newparticles.push_back(new_ptr(ShowerParticle(_partons[0]->CC(), true)));
newline[0]->addAntiColoured(newparticles[1]);
newline[0]->addColoured(newparticles[0]);
newline[1]->addAntiColoured(newparticles[0]);
newline[1]->addAntiColoured(newparticles[2]);
}
// set the momenta
for(unsigned int ix=0;ix<3;++ix) newparticles[ix]->set5Momentum(pnew[ix]);
// create the off-shell particle
Lorentz5Momentum poff=pnew[iemit]-pnew[2];
poff.rescaleMass();
newparticles.push_back(new_ptr(ShowerParticle(_partons[iemit],false)));
newparticles.back()->set5Momentum(poff);
if(iemit==0) {
newline[0]->addColoured(newparticles.back());
}
else {
newline[1]->addAntiColoured(newparticles.back());
}
// compute the boost for the bosons
LorentzRotation boost(pboson.findBoostToCM());
boost.boost(pnew[3].boostVector());
for( map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt= tree->outgoingLines().begin();
cjt != tree->outgoingLines().end();++cjt ) {
newparticles.push_back(new_ptr(ShowerParticle(cjt->first->original()->dataPtr(),
true)));
newparticles.back()->set5Momentum(boost*cjt->first->original()->momentum());
}
vector<HardBranchingPtr> inBranch,hardBranch;
// create the branchings for the incoming particles
inBranch.push_back(new_ptr(HardBranching(newparticles[0],SudakovPtr(),
HardBranchingPtr(),HardBranching::Incoming)));
inBranch.push_back(new_ptr(HardBranching(newparticles[1],SudakovPtr(),
HardBranchingPtr(),HardBranching::Incoming)));
// intermediate IS particle
hardBranch.push_back(new_ptr(HardBranching(newparticles[3],SudakovPtr(),
inBranch[iemit],HardBranching::Incoming)));
inBranch[iemit]->addChild(hardBranch.back());
inBranch[iemit]->type(hardBranch.back()->branchingParticle()->id()>0 ?
ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine);
// create the branching for the emitted jet
inBranch[iemit]->addChild(new_ptr(HardBranching(newparticles[2],SudakovPtr(),
inBranch[iemit],HardBranching::Outgoing)));
// set the colour partners
hardBranch.back()->colourPartner(inBranch[iemit==0 ? 1 : 0]);
inBranch[iemit==0 ? 1 : 0]->colourPartner(hardBranch.back());
// add other particle
hardBranch.push_back(inBranch[iemit==0 ? 1 : 0]);
// outgoing particles
for(unsigned int ix=4;ix<newparticles.size();++ix) {
hardBranch.push_back(new_ptr(HardBranching(newparticles[ix],SudakovPtr(),
HardBranchingPtr(),HardBranching::Outgoing)));
}
// make the tree
HardTreePtr hardtree=new_ptr(HardTree(hardBranch,inBranch,ShowerInteraction::QCD));
// connect the ShowerParticles with the branchings
// and set the maximum pt for the radiation
set<HardBranchingPtr> hard=hardtree->branchings();
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
if( _pt < _min_pt ) particlesToShower[ix]->maximumpT(_min_pt,ShowerInteraction::QCD);
else particlesToShower[ix]->maximumpT(_pt,ShowerInteraction::QCD);
for(set<HardBranchingPtr>::const_iterator mit=hard.begin();
mit!=hard.end();++mit) {
if(particlesToShower[ix]->progenitor()->id()==(*mit)->branchingParticle()->id()&&
(( particlesToShower[ix]->progenitor()->isFinalState()&&
(**mit).status()==HardBranching::Outgoing)||
(!particlesToShower[ix]->progenitor()->isFinalState()&&
(**mit).status()==HardBranching::Incoming))) {
hardtree->connect(particlesToShower[ix]->progenitor(),*mit);
if((**mit).status()==HardBranching::Incoming) {
(*mit)->beam(particlesToShower[ix]->original()->parents()[0]);
}
HardBranchingPtr parent=(*mit)->parent();
while(parent) {
parent->beam(particlesToShower[ix]->original()->parents()[0]);
parent=parent->parent();
};
}
}
}
// return the tree
return hardtree;
}
double DrellYanBase::getResult(int emis_type, Energy pt, double yj) {
Energy2 s=sqr(generator()->maximumCMEnergy());
Energy2 m2(sqr(_mass));
Energy2 scale = m2+sqr(pt);
Energy et=sqrt(scale);
// longitudinal real correction fractions
double x = pt*exp( yj)/sqrt(s)+et*exp( _yb)/sqrt(s);
double y = pt*exp(-yj)/sqrt(s)+et*exp(-_yb)/sqrt(s);
// reject if outside region
if(x<0.||x>1.||y<0.||y>1.||x*y<m2/s) return 0.;
// longitudinal born fractions
double x1 = _mass*exp( _yb)/sqrt(s);
double y1 = _mass*exp(-_yb)/sqrt(s);
// mandelstam variables
Energy2 th = -sqrt(s)*x*pt*exp(-yj);
Energy2 uh = -sqrt(s)*y*pt*exp( yj);
Energy2 sh = m2-th-uh;
double res;
// pdf part of the cross section
double pdf[4];
pdf[0]=_beams[0]->pdf()->xfx(_beams[0],_partons[0],m2,x1);
pdf[1]=_beams[1]->pdf()->xfx(_beams[1],_partons[1],m2,y1);
//qqbar2Zg
using Constants::pi;
if(emis_type==0) {
pdf[2]=_beams[0]->pdf()->xfx(_beams[0],_partons[0],scale,x);
pdf[3]=_beams[1]->pdf()->xfx(_beams[1],_partons[1],scale,y);
res = 4./3./pi*(sqr(th-m2)+sqr(uh-m2))*pt/(sh*uh*th)*GeV;
}
//qg2Zq
else if(emis_type==1) {
pdf[2]=_beams[0]->pdf()->xfx(_beams[0],_partons[0],scale,x);
pdf[3]=_beams[1]->pdf()->xfx(_beams[1],getParticleData(ParticleID::g),scale,y);
res = -1./2./pi*(sqr(uh-m2)+sqr(sh-m2))*pt/(sh*sh*uh)*GeV;
}
//qbarg2Zqbar
else {
pdf[2]=_beams[0]->pdf()->xfx(_beams[0],getParticleData(ParticleID::g),scale,x);
pdf[3]=_beams[1]->pdf()->xfx(_beams[1],_partons[1],scale,y);
res =- 1./2./pi*(sqr(th-m2)+sqr(sh-m2))*pt/(sh*sh*th)*GeV;
}
//deals with pdf zero issue at large x
if(pdf[0]<=0.||pdf[1]<=0.||pdf[2]<=0.||pdf[3]<=0.) {
res=0.;
}
else {
res*=pdf[2]*pdf[3]/pdf[0]/pdf[1]*m2/sh;
}
res*=_alpha->ratio(sqr(pt));
return res;
}
bool DrellYanBase::getEvent(vector<Lorentz5Momentum> & pnew,
int & emis_type){
// pt cut-off
// Energy minp = 0.1*GeV;
// maximum pt (half of centre-of-mass energy)
Energy maxp = 0.5*generator()->maximumCMEnergy();
// set pt of emission to zero
_pt=ZERO;
//Working Variables
Energy pt;
double yj;
// limits on the rapidity of the jet
double minyj = -8.0,maxyj = 8.0;
bool reject;
double wgt;
emis_type=-1;
for(int j=0;j<3;j++) {
pt=maxp;
double a = _alpha->overestimateValue()*_prefactor[j]*(maxyj-minyj)/(_power-1.);
do {
// generate next pt
pt=GeV/pow(pow(GeV/pt,_power-1)-log(UseRandom::rnd())/a,1./(_power-1.));
// generate rapidity of the jet
yj=UseRandom::rnd()*(maxyj-minyj)+ minyj;
// calculate rejection weight
wgt=getResult(j,pt,yj);
wgt/= _prefactor[j]*pow(GeV/pt,_power);
reject = UseRandom::rnd()>wgt;
//no emission event if p goes past p min - basically set to outside
//of the histogram bounds (hopefully hist object just ignores it)
if(pt<_min_pt){
pt=ZERO;
reject = false;
}
if(wgt>1.0) {
ostringstream s;
s << "DrellYanBase::getEvent weight for channel " << j
<< "is " << wgt << " which is greater than 1";
generator()->logWarning( Exception(s.str(), Exception::warning) );
}
}
while(reject);
// set pt of emission etc
if(pt>_pt){
emis_type = j;
_pt=pt;
_yj=yj;
}
}
//was this an (overall) no emission event?
if(_pt<_min_pt){
_pt=ZERO;
emis_type = 3;
}
if(emis_type==3) return false;
// generate the momenta of the particles
// hadron-hadron cmf
Energy2 s=sqr(generator()->maximumCMEnergy());
// transverse energy
Energy2 m2(sqr(_mass));
Energy et=sqrt(m2+sqr(_pt));
// first calculate all the kinematic variables
// longitudinal real correction fractions
double x = _pt*exp( _yj)/sqrt(s)+et*exp( _yb)/sqrt(s);
double y = _pt*exp(-_yj)/sqrt(s)+et*exp(-_yb)/sqrt(s);
// that and uhat
Energy2 th = -sqrt(s)*x*_pt*exp(-_yj);
Energy2 uh = -sqrt(s)*y*_pt*exp( _yj);
Energy2 sh = x*y*s;
if(emis_type==1) swap(th,uh);
// decide which was the emitting particle
unsigned int iemit=1;
// from q qbar
if(emis_type==0) {
if(UseRandom::rnd()<sqr(m2-uh)/(sqr(m2-uh)+sqr(m2-th))) iemit=2;
}
else {
if(UseRandom::rnd()<sqr(m2-th)/(sqr(m2-th)+sqr(m2-sh))) iemit=2;
}
// reconstruct the momenta in the rest frame of the gauge boson
Lorentz5Momentum pb(ZERO,ZERO,ZERO,_mass,_mass),pspect,pg,pemit;
double cos3;
if(emis_type==0) {
pg=Lorentz5Momentum(ZERO,ZERO,ZERO,0.5*(sh-m2)/_mass,ZERO);
Energy2 tp(th),up(uh);
double zsign(-1.);
if(iemit==2) {
swap(tp,up);
zsign=1;
}
pspect = Lorentz5Momentum(ZERO,ZERO
,zsign*0.5*(m2-tp)/_mass,0.5*(m2-tp)/_mass,
ZERO);
Energy eemit=0.5*(m2-up)/_mass;
cos3 = 0.5/pspect.z()/pg.e()*(sqr(pspect.e())+sqr(pg.e())-sqr(eemit));
}
else {
pg=Lorentz5Momentum(ZERO,ZERO,ZERO,0.5*(m2-uh)/_mass,ZERO);
double zsign(1.);
if(iemit==1) {
if(emis_type==1) zsign=-1.;
pspect=Lorentz5Momentum(ZERO,ZERO,0.5*zsign*(sh-m2)/_mass,0.5*(sh-m2)/_mass);
Energy eemit=0.5*(m2-th)/_mass;
cos3 = 0.5/pspect.z()/pg.e()*(sqr(pspect.e())+sqr(pg.e())-sqr(eemit));
}
else {
if(emis_type==2) zsign=-1.;
pspect=Lorentz5Momentum(ZERO,ZERO,0.5*zsign*(m2-th)/_mass,0.5*(m2-th)/_mass);
Energy eemit=0.5*(sh-m2)/_mass;
cos3 = 0.5/pspect.z()/pg.e()*(-sqr(pspect.e())-sqr(pg.e())+sqr(eemit));
}
}
// rotate the gluon
double sin3(sqrt(1.-sqr(cos3))),phi(Constants::twopi*UseRandom::rnd());
pg.setX(pg.e()*sin3*cos(phi));
pg.setY(pg.e()*sin3*sin(phi));
pg.setZ(pg.e()*cos3);
if(emis_type==0) {
pemit=pb+pg-pspect;
}
else {
if(iemit==1) pemit=pb+pspect-pg;
else pemit=pspect+pg-pb;
}
pemit .setMass(ZERO);
pg .setMass(ZERO);
pspect.setMass(ZERO);
// find the new CMF
Lorentz5Momentum pp[2];
if(emis_type==0) {
pp[0]=pemit;
pp[1]=pspect;
if(iemit==2) swap(pp[0],pp[1]);
}
else if(emis_type==1) {
pp[1]=pg;
if(iemit==1) pp[0]=pemit;
else pp[0]=pspect;
}
else {
pp[0]=pg;
if(iemit==1) pp[1]=pemit;
else pp[1]=pspect;
}
Lorentz5Momentum pz= _quarkplus ? pp[0] : pp[1];
pp[0]/=x;
pp[1]/=y;
Lorentz5Momentum plab(pp[0]+pp[1]);
plab.rescaleMass();
// construct the boost to rest frame of plab
LorentzRotation trans=LorentzRotation(plab.findBoostToCM());
pz.transform(trans);
// rotate so emitting particle along z axis
// rotate so in x-z plane
trans.rotateZ(-atan2(pz.y(),pz.x()));
// rotate so along
trans.rotateY(-acos(pz.z()/pz.vect().mag()));
// undo azimuthal rotation
trans.rotateZ(atan2(pz.y(),pz.x()));
// perform the transforms
pb .transform(trans);
pspect.transform(trans);
pg .transform(trans);
pemit .transform(trans);
// copy the momenta for the new particles
pnew.resize(4);
if(emis_type==0) {
pnew[0]=pemit;
pnew[1]=pspect;
if(iemit==2) swap(pnew[0],pnew[1]);
pnew[2]=pg;
}
else if(emis_type==1) {
pnew[0]=pemit;
pnew[2]=pspect;
if(iemit==2) swap(pnew[0],pnew[2]);
pnew[1]=pg;
}
else if(emis_type==2) {
pnew[1]=pspect;
pnew[2]=pemit;
if(iemit==1) swap(pnew[1],pnew[2]);
pnew[0]=pg;
}
pnew[3]=pb;
return true;
}
diff --git a/MatrixElement/DrellYanBase.h b/MatrixElement/DrellYanBase.h
--- a/MatrixElement/DrellYanBase.h
+++ b/MatrixElement/DrellYanBase.h
@@ -1,339 +1,338 @@
// -*- C++ -*-
#ifndef HERWIG_DrellYanBase_H
#define HERWIG_DrellYanBase_H
//
// This is the declaration of the DrellYanBase class.
//
#include "HwMEBase.h"
#include "Herwig/Shower/ShowerConfig.h"
#include "Herwig/Shower/Couplings/ShowerAlpha.h"
namespace Herwig {
using namespace ThePEG;
/**
* The DrellYanBase class class provides a base class for the implemented
* of Drell-Yan type processes and provides the matrix element and POWHEG
* style hard corrections
*
* @see \ref DrellYanBaseInterfaces "The interfaces"
* defined for DrellYanBase.
*/
class DrellYanBase: public HwMEBase {
public:
/**
* The default constructor.
*/
DrellYanBase();
/**
* Has a POWHEG style correction
*/
//virtual bool hasPOWHEGCorrection() {return _alpha;}
virtual POWHEGType hasPOWHEGCorrection() {return ISR;}
/**
* Has an old fashioned ME correction
*/
virtual bool hasMECorrection() {return _alpha;}
/**
* Initialize the ME correction
*/
virtual void initializeMECorrection(ShowerTreePtr, double & initial,
double & final) {
final = 1.;
initial = 1.;
}
/**
* Apply the hard matrix element correction to a given hard process or decay
*/
virtual void applyHardMatrixElementCorrection(ShowerTreePtr);
/**
* Apply the soft matrix element correction
* @param initial The particle from the hard process which started the
* shower
* @param parent The initial particle in the current branching
* @param br The branching struct
* @return If true the emission should be vetoed
*/
virtual bool softMatrixElementVeto(ShowerProgenitorPtr initial,
ShowerParticlePtr parent,
Branching br);
/**
* Apply the POWHEG style correction
*/
- virtual HardTreePtr generateHardest(ShowerTreePtr,
- vector<ShowerInteraction::Type>);
+ virtual HardTreePtr generateHardest(ShowerTreePtr, ShowerInteraction::Type);
/**
* Set the typed and momenta of the incoming and outgoing partons to
* be used in subsequent calls to me() and colourGeometries()
* according to the associated XComb object.
*/
virtual void setKinematics() {
HwMEBase::setKinematics();
mb2_ = sHat();
}
protected:
/**
* Return the momenta and type of hard matrix element correction
* @param quarks The original incoming particles.
* @param beams The BeamParticleData objects
* @param boson The momentum of the original outgoing gauge boson
* @param iemit Whether the first (0) or second (1) particle emitted
* the radiation
* @param itype The type of radiated particle (0 is gluon, 1 is quark
* and 2 is antiquark)
* @param pnew The momenta of the new particles
* @param trans The LorentzRotation from the boson rest frame to the new lab
* @param xnew The new values of the momentuym fractions
* @return Whether or not the matrix element correction needs to be applied
*/
bool applyHard(ShowerParticleVector quarks,
vector<tcBeamPtr> beams,
Lorentz5Momentum boson,unsigned int & iemit,
unsigned int & itype,vector<Lorentz5Momentum> & pnew,
LorentzRotation & trans, pair<double,double> & xnew);
/**
* Returns the matrix element for a given type of process,
* rapidity of the jet \f$y_j\f$ and transverse momentum \f$p_T\f$
* @param emis_type the type of emission,
* (0 is \f$q\bar{q}\to Vg\f$, 1 is \f$qg\to Vq\f$ and 2 is \f$g\bar{q}\to V\bar{q}\f$)
* @param pt The transverse momentum of the jet
* @param yj The rapidity of the jet
*/
double getResult(int emis_type, Energy pt, double yj);
/**
* generates the hardest emission (yj,p)
* @param pnew The momenta of the new particles
* @param emissiontype The type of emission, as for getResult
* @return Whether not an emission was generated
*/
bool getEvent(vector<Lorentz5Momentum> & pnew,int & emissiontype);
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
/**
* Finalize this object. Called in the run phase just after a
* run has ended. Used eg. to write out statistics.
*/
virtual void dofinish();
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is an abstract class with persistent data.
*/
static AbstractClassDescription<DrellYanBase> initDrellYanBase;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
DrellYanBase & operator=(const DrellYanBase &);
private:
/**
* Mass squared of the vector boson
*/
Energy2 mb2_;
/**
* Parameters for the old-style ME correction
*/
//@{
/**
* Relative weight for the \f$q\bar{q}\f$ and \f$q/\bar{q}g\f$ channels
*/
double _channelwgtA;
/**
* Relative weight for the \f$qg\f$ and \f$\bar{q}g\f$ channels
*/
double _channelwgtB;
/**
* Weights for the channels as a vector
*/
vector<double> _channelweights;
/**
* Number of weights greater than 1
*/
unsigned int _nover;
/**
* Maximum weight
*/
double _maxwgt;
//@}
/**
* Constants for the sampling. The distribution is assumed to have the
* form \f$\frac{c}{{\rm GeV}}\times\left(\frac{{\rm GeV}}{p_T}\right)^n\f$
*/
//@{
/**
* The power, \f$n\f$, for the sampling
*/
double _power;
/**
* The prefactor, \f$c\f$ for the \f$q\bar{q}\f$ channel
*/
double _preqqbar;
/**
* The prefactor, \f$c\f$ for the \f$qg\f$ channel
*/
double _preqg;
/**
* The prefactor, \f$c\f$ for the \f$g\bar{q}\f$ channel
*/
double _pregqbar;
/**
* The prefactors as a vector for easy use
*/
vector<double> _prefactor;
//@}
/**
* Properties of the incoming particles
*/
//@{
/**
* Pointers to the BeamParticleData objects
*/
vector<tcBeamPtr> _beams;
/**
* Pointers to the ParticleDataObjects for the partons
*/
vector<tcPDPtr> _partons;
//@}
/**
* Properties of the boson and jets
*/
//@{
/**
* The rapidity of the gauge boson
*/
double _yb;
/**
* The mass of the gauge boson
*/
Energy _mass;
/**
* Whether the quark is in the + or - z direction
*/
bool _quarkplus;
/**
* the rapidity of the jet
*/
double _yj;
/**
* The transverse momentum of the jet
*/
Energy _pt;
//@}
/**
* The transverse momentum of the jet
*/
Energy _min_pt;
/**
* Pointer to the object calculating the strong coupling
*/
ShowerAlphaPtr _alpha;
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of DrellYanBase. */
template <>
struct BaseClassTrait<Herwig::DrellYanBase,1> {
/** Typedef of the first base class of DrellYanBase. */
typedef Herwig::HwMEBase NthBase;
};
/** This template specialization informs ThePEG about the name of
* the DrellYanBase class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::DrellYanBase>
: public ClassTraitsBase<Herwig::DrellYanBase> {
/** Return a platform-independent class name */
static string className() { return "Herwig::DrellYanBase"; }
};
/** @endcond */
}
#endif /* HERWIG_DrellYanBase_H */
diff --git a/MatrixElement/Hadron/MEPP2Higgs.cc b/MatrixElement/Hadron/MEPP2Higgs.cc
--- a/MatrixElement/Hadron/MEPP2Higgs.cc
+++ b/MatrixElement/Hadron/MEPP2Higgs.cc
@@ -1,1629 +1,1627 @@
// -*- C++ -*-
//
// MEPP2Higgs.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2Higgs class.
//
#include "MEPP2Higgs.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "ThePEG/Cuts/Cuts.h"
#include "Herwig/MatrixElement/HardVertex.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "Herwig/Utilities/Maths.h"
#include "Herwig/Shower/Base/ShowerProgenitor.h"
#include "Herwig/Shower/Base/ShowerTree.h"
#include "Herwig/Shower/Base/Branching.h"
#include "Herwig/Shower/Base/HardTree.h"
using namespace Herwig;
const complex<Energy2>
MEPP2Higgs::epsi_ = complex<Energy2>(ZERO,-1.e-10*GeV2);
MEPP2Higgs::MEPP2Higgs() : scaleopt_(1), mu_F_(100.*GeV),
shapeOption_(2), processOption_(1),
minFlavour_(4), maxFlavour_(5),
mh_(ZERO), wh_(ZERO),
minLoop_(6),maxLoop_(6),massOption_(0),
mu_R_opt_(1),mu_F_opt_(1),
channelwgtA_(0.45),channelwgtB_(0.15),
ggPow_(1.6), qgPow_(1.6), enhance_(1.1),
nover_(0), ntry_(0), ngen_(0), maxwgt_(0.),
power_(2.0), pregg_(7.), preqg_(3.),
pregqbar_(3.), minpT_(2.*GeV),
spinCorrelations_(true)
{}
ClassDescription<MEPP2Higgs> MEPP2Higgs::initMEPP2Higgs;
// Definition of the static class description member.
void MEPP2Higgs::persistentOutput(PersistentOStream & os) const {
os << HGGVertex_ << HFFVertex_ << shapeOption_ << processOption_
<< minFlavour_ << maxFlavour_ << hmass_ << ounit(mh_,GeV)
<< ounit(wh_,GeV) << minLoop_ << maxLoop_ << massOption_
<< alpha_ << prefactor_ << power_ << pregg_ << preqg_
<< pregqbar_ << ounit( minpT_, GeV ) << ggPow_ << qgPow_
<< enhance_ << channelwgtA_ << channelwgtB_ << channelWeights_
<< mu_R_opt_ << mu_F_opt_ << spinCorrelations_;
}
void MEPP2Higgs::persistentInput(PersistentIStream & is, int) {
is >> HGGVertex_ >> HFFVertex_ >> shapeOption_ >> processOption_
>> minFlavour_ >> maxFlavour_ >> hmass_ >> iunit(mh_,GeV)
>> iunit(wh_,GeV) >> minLoop_ >> maxLoop_ >> massOption_
>> alpha_ >> prefactor_ >> power_ >> pregg_ >> preqg_
>> pregqbar_ >> iunit( minpT_, GeV ) >> ggPow_ >> qgPow_
>> enhance_ >> channelwgtA_ >> channelwgtB_ >> channelWeights_
>> mu_R_opt_ >> mu_F_opt_ >> spinCorrelations_;
}
void MEPP2Higgs::Init() {
static ClassDocumentation<MEPP2Higgs> documentation
("The MEPP2Higgs class implements the matrix elements for"
" Higgs production (with decay H->W-W+) in hadron-hadron collisions"
" including the generation of additional hard QCD radiation in "
"gg to h0 processes in the POWHEG scheme",
"Hard QCD radiation for $gg\\to h^0$ processes in the"
" POWHEG scheme \\cite{Hamilton:2009za}.",
"%\\cite{Hamilton:2009za}\n"
"\\bibitem{Hamilton:2009za}\n"
" K.~Hamilton, P.~Richardson and J.~Tully,\n"
" ``A Positive-Weight Next-to-Leading Order Monte Carlo Simulation for Higgs\n"
" Boson Production,''\n"
" JHEP {\\bf 0904}, 116 (2009)\n"
" [arXiv:0903.4345 [hep-ph]].\n"
" %%CITATION = JHEPA,0904,116;%%\n");
static Switch<MEPP2Higgs,unsigned int> interfaceFactorizationScaleOption
("FactorizationScaleOption",
"Option for the choice of factorization scale",
&MEPP2Higgs::scaleopt_, 1, false, false);
static SwitchOption interfaceDynamic
(interfaceFactorizationScaleOption,
"Dynamic",
"Dynamic factorization scale equal to the current sqrt(sHat())",
1);
static SwitchOption interfaceFixed
(interfaceFactorizationScaleOption,
"Fixed",
"Use a fixed factorization scale set with FactorizationScaleValue",
2);
static Parameter<MEPP2Higgs,Energy> interfaceFactorizationScaleValue
("FactorizationScaleValue",
"Value to use in the event of a fixed factorization scale",
&MEPP2Higgs::mu_F_, GeV, 100.0*GeV, 50.0*GeV, 500.0*GeV,
true, false, Interface::limited);
static Reference<MEPP2Higgs,ShowerAlpha> interfaceCoupling
("Coupling",
"Pointer to the object to calculate the coupling for the correction",
&MEPP2Higgs::alpha_, false, false, true, false, false);
static Switch<MEPP2Higgs,unsigned int> interfaceShapeOption
("ShapeScheme",
"Option for the treatment of the Higgs resonance shape",
&MEPP2Higgs::shapeOption_, 1, false, false);
static SwitchOption interfaceStandardShapeFixed
(interfaceShapeOption,
"FixedBreitWigner",
"Breit-Wigner s-channel resonanse",
1);
static SwitchOption interfaceStandardShapeRunning
(interfaceShapeOption,
"MassGenerator",
"Use the mass generator to give the shape",
2);
static Switch<MEPP2Higgs,unsigned int> interfaceProcess
("Process",
"Which subprocesses to include",
&MEPP2Higgs::processOption_, 1, false, false);
static SwitchOption interfaceProcessAll
(interfaceProcess,
"All",
"Include all subprocesses",
1);
static SwitchOption interfaceProcess1
(interfaceProcess,
"qqbar",
"Only include the incoming q qbar subprocess",
2);
static SwitchOption interfaceProcessgg
(interfaceProcess,
"gg",
"Only include the incoming gg subprocess",
3);
static Parameter<MEPP2Higgs,unsigned int> interfaceMinimumInLoop
("MinimumInLoop",
"The minimum flavour of the quarks to include in the loops",
&MEPP2Higgs::minLoop_, 6, 5, 6,
false, false, Interface::limited);
static Parameter<MEPP2Higgs,unsigned int> interfaceMaximumInLoop
("MaximumInLoop",
"The maximum flavour of the quarks to include in the loops",
&MEPP2Higgs::maxLoop_, 6, 5, 6,
false, false, Interface::limited);
static Switch<MEPP2Higgs,unsigned int> interfaceMassOption
("MassOption",
"Option for the treatment of the masses in the loop diagrams",
&MEPP2Higgs::massOption_, 0, false, false);
static SwitchOption interfaceMassOptionFull
(interfaceMassOption,
"Full",
"Include the full mass dependence",
0);
static SwitchOption interfaceMassOptionLarge
(interfaceMassOption,
"Large",
"Use the heavy mass limit",
1);
static Parameter<MEPP2Higgs,int> interfaceMinimumFlavour
("MinimumFlavour",
"The minimum flavour of the incoming quarks in the hard process",
&MEPP2Higgs::minFlavour_, 4, 3, 5,
false, false, Interface::limited);
static Parameter<MEPP2Higgs,int> interfaceMaximumFlavour
("MaximumFlavour",
"The maximum flavour of the incoming quarks in the hard process",
&MEPP2Higgs::maxFlavour_, 5, 3, 5,
false, false, Interface::limited);
static Parameter<MEPP2Higgs,double> interfaceQGChannelWeight
("QGChannelWeight",
"The relative weights of the g g and q g channels for selection."
" This is a technical parameter for the phase-space generation and "
"should not affect the results only the efficiency and fraction"
" of events with weight > 1.",
&MEPP2Higgs::channelwgtA_, 0.45, 0., 1.e10,
false, false, Interface::limited);
static Parameter<MEPP2Higgs,double> interfaceQbarGChannelWeight
("QbarGChannelWeight",
"The relative weights of the g g abd qbar g channels for selection."
" This is a technical parameter for the phase-space generation and "
"should not affect the results only the efficiency and fraction",
&MEPP2Higgs::channelwgtB_, 0.15, 0., 1.e10,
false, false, Interface::limited);
static Parameter<MEPP2Higgs,double> interfaceGGPower
("GGPower",
"Power for the phase-space sampling of the gg channel",
&MEPP2Higgs::ggPow_, 1.6, 1.0, 3.0,
false, false, Interface::limited);
static Parameter<MEPP2Higgs,double> interfaceQGPower
("QGPower",
"Power for the phase-space sampling of the qg and qbarg channels",
&MEPP2Higgs::qgPow_, 1.6, 1.0, 3.0,
false, false, Interface::limited);
static Parameter<MEPP2Higgs,double> interfaceEnhancementFactor
("InitialEnhancementFactor",
"The enhancement factor for initial-state radiation in the shower to ensure"
" the weight for the matrix element correction is less than one.",
&MEPP2Higgs::enhance_, 1.1, 1.0, 10.0,
false, false, Interface::limited);
static Parameter<MEPP2Higgs,double> interfacePower
("Power",
"The power for the sampling of the matrix elements",
&MEPP2Higgs::power_, 2.0, 1.0, 10.0,
false, false, Interface::limited);
static Parameter<MEPP2Higgs,double> interfacePrefactorgg
("Prefactorgg",
"The prefactor for the sampling of the q qbar channel",
&MEPP2Higgs::pregg_, 7.0, 0.0, 1000.0,
false, false, Interface::limited);
static Parameter<MEPP2Higgs,double> interfacePrefactorqg
("Prefactorqg",
"The prefactor for the sampling of the q g channel",
&MEPP2Higgs::preqg_, 3.0, 0.0, 1000.0,
false, false, Interface::limited);
static Parameter<MEPP2Higgs,double> interfacePrefactorgqbar
("Prefactorgqbar",
"The prefactor for the sampling of the g qbar channel",
&MEPP2Higgs::pregqbar_, 3.0, 0.0, 1000.0,
false, false, Interface::limited);
static Parameter<MEPP2Higgs, Energy> interfacePtMin
("minPt",
"The pt cut on hardest emision generation"
"2*(1-Beta)*exp(-sqr(intrinsicpT/RMS))/sqr(RMS)",
&MEPP2Higgs::minpT_, GeV, 2.*GeV, ZERO, 100000.0*GeV,
false, false, Interface::limited);
static Switch<MEPP2Higgs,unsigned int> interface_mu_R_Option
("mu_R_Option",
"Option to use pT or mT as the scale in alphaS",
&MEPP2Higgs::mu_R_opt_, 1, false, false);
static SwitchOption interface_mu_R_Option_mT
(interface_mu_R_Option,
"mT",
"Use mT as the scale in alpha_S",
0);
static SwitchOption interface_mu_R_Option_pT
(interface_mu_R_Option,
"pT",
"Use pT as the scale in alpha_S",
1);
static Switch<MEPP2Higgs,unsigned int> interface_mu_F_Option
("mu_F_Option",
"Option to use pT or mT as the factorization scale in the PDFs",
&MEPP2Higgs::mu_F_opt_, 1, false, false);
static SwitchOption interface_mu_F_Option_mT
(interface_mu_F_Option,
"mT",
"Use mT as the scale in the PDFs",
0);
static SwitchOption interface_mu_F_Option_pT
(interface_mu_F_Option,
"pT",
"Use pT as the scale in the PDFs",
1);
static Switch<MEPP2Higgs,bool> interfaceSpinCorrelations
("SpinCorrelations",
"Which on/off spin correlations in the hard process",
&MEPP2Higgs::spinCorrelations_, true, false, false);
static SwitchOption interfaceSpinCorrelationsYes
(interfaceSpinCorrelations,
"Yes",
"Switch correlations on",
true);
static SwitchOption interfaceSpinCorrelationsNo
(interfaceSpinCorrelations,
"No",
"Switch correlations off",
false);
}
void MEPP2Higgs::doinit() {
HwMEBase::doinit();
// get the vertex pointers from the SM object
tcHwSMPtr theSM = dynamic_ptr_cast<tcHwSMPtr>(standardModel());
// do the initialisation
if(!theSM) {
throw InitException() << "Wrong type of StandardModel object in MEPP2Higgs::doinit(),"
<< " the Herwig version must be used"
<< Exception::runerror;
}
HGGVertex_ = theSM->vertexHGG();
HFFVertex_ = theSM->vertexFFH();
// get the mass generator for the higgs
PDPtr h0 = getParticleData(ParticleID::h0);
mh_ = h0->mass();
wh_ = h0->generateWidth(mh_);
if(h0->massGenerator()) {
hmass_=dynamic_ptr_cast<GenericMassGeneratorPtr>(h0->massGenerator());
}
if(shapeOption_==2&&!hmass_) throw InitException()
<< "If using the mass generator for the line shape in MEPP2Higgs::doinit()"
<< "the mass generator must be an instance of the GenericMassGenerator class"
<< Exception::runerror;
// stuff for the ME correction
double total = 1.+channelwgtA_+channelwgtB_;
channelWeights_.push_back(1./total);
channelWeights_.push_back(channelWeights_.back()+channelwgtA_/total);
channelWeights_.push_back(channelWeights_.back()+channelwgtB_/total);
// insert the different prefactors in the vector for easy look up
prefactor_.push_back(pregg_);
prefactor_.push_back(preqg_);
prefactor_.push_back(preqg_);
prefactor_.push_back(pregqbar_);
prefactor_.push_back(pregqbar_);
}
void MEPP2Higgs::dofinish() {
HwMEBase::dofinish();
if(ntry_==0) return;
generator()->log() << "MEPP2Higgs when applying the hard correction "
<< "generated " << ntry_ << " trial emissions of which "
<< ngen_ << " were accepted\n";
if(nover_==0) return;
generator()->log() << "MEPP2Higgs when applying the hard correction "
<< nover_ << " weights larger than one were generated of which"
<< " the largest was " << maxwgt_ << "\n";
}
unsigned int MEPP2Higgs::orderInAlphaS() const {
return 2;
}
unsigned int MEPP2Higgs::orderInAlphaEW() const {
return 1;
}
Energy2 MEPP2Higgs::scale() const {
return scaleopt_ == 1 ? sHat() : sqr(mu_F_);
}
int MEPP2Higgs::nDim() const {
return 0;
}
bool MEPP2Higgs::generateKinematics(const double *) {
Lorentz5Momentum pout = meMomenta()[0] + meMomenta()[1];
pout.rescaleMass();
meMomenta()[2].setMass(pout.mass());
meMomenta()[2] = LorentzMomentum(pout.x(),pout.y(),pout.z(),pout.t());
jacobian(1.0);
// check whether it passes all the cuts: returns true if it does
vector<LorentzMomentum> out(1,meMomenta()[2]);
tcPDVector tout(1,mePartonData()[2]);
return lastCuts().passCuts(tout, out, mePartonData()[0], mePartonData()[1]);
}
void MEPP2Higgs::getDiagrams() const {
tcPDPtr h0=getParticleData(ParticleID::h0);
// gg -> H process
if(processOption_==1||processOption_==3) {
tcPDPtr g=getParticleData(ParticleID::g);
add(new_ptr((Tree2toNDiagram(2), g, g, 1, h0, -1)));
}
// q qbar -> H processes
if(processOption_==1||processOption_==2) {
for ( int i = minFlavour_; i <= maxFlavour_; ++i ) {
tcPDPtr q = getParticleData(i);
tcPDPtr qb = q->CC();
add(new_ptr((Tree2toNDiagram(2), q, qb, 1, h0, -2)));
}
}
}
CrossSection MEPP2Higgs::dSigHatDR() const {
using Constants::pi;
InvEnergy2 bwfact;
if(shapeOption_==1) {
bwfact = mePartonData()[2]->generateWidth(sqrt(sHat()))*sqrt(sHat())/pi/
(sqr(sHat()-sqr(mh_))+sqr(mh_*wh_));
}
else {
bwfact = hmass_->BreitWignerWeight(sqrt(sHat()));
}
double cs = me2() * jacobian() * pi * double(UnitRemoval::E4 * bwfact/sHat());
return UnitRemoval::InvE2 * sqr(hbarc) * cs;
}
double MEPP2Higgs::me2() const {
double output(0.0);
ScalarWaveFunction hout(meMomenta()[2],mePartonData()[2],outgoing);
// Safety code to garantee the reliable behaviour of Higgs shape limits
// (important for heavy and broad Higgs resonance).
Energy hmass = meMomenta()[2].m();
tcPDPtr h0 = mePartonData()[2];
Energy mass = h0->mass();
Energy halfmass = .5*mass;
if (.0*GeV > hmass) return 0.0;
// stricly speaking the condition is applicable if
// h0->widthUpCut() == h0->widthLoCut()...
if (h0->widthLoCut() > halfmass) {
if ( mass + h0->widthUpCut() < hmass ||
mass - h0->widthLoCut() > hmass ) return 0.0;
}
else {
if (mass + halfmass < hmass || halfmass > hmass) return 0.0;
}
if (mePartonData()[0]->id() == ParticleID::g &&
mePartonData()[1]->id() == ParticleID::g) {
VectorWaveFunction gin1(meMomenta()[0],mePartonData()[0],incoming);
VectorWaveFunction gin2(meMomenta()[1],mePartonData()[1],incoming);
vector<VectorWaveFunction> g1,g2;
for(unsigned int i = 0; i < 2; ++i) {
gin1.reset(2*i);
g1.push_back(gin1);
gin2.reset(2*i);
g2.push_back(gin2);
}
output = ggME(g1,g2,hout,false);
}
else {
if (mePartonData()[0]->id() == -mePartonData()[1]->id()) {
SpinorWaveFunction qin (meMomenta()[0],mePartonData()[0],incoming);
SpinorBarWaveFunction qbin(meMomenta()[1],mePartonData()[1],incoming);
vector<SpinorWaveFunction> fin;
vector<SpinorBarWaveFunction> ain;
for (unsigned int i = 0; i < 2; ++i) {
qin.reset(i);
fin.push_back(qin);
qbin.reset(i);
ain.push_back(qbin);
}
output = qqME(fin,ain,hout,false);
}
else assert(false);
}
return output;
}
Selector<MEBase::DiagramIndex> MEPP2Higgs::diagrams(const DiagramVector & diags) const {
Selector<DiagramIndex> sel;
for (DiagramIndex i = 0; i < diags.size(); ++i)
sel.insert(1.0, i);
return sel;
}
Selector<const ColourLines *> MEPP2Higgs::colourGeometries(tcDiagPtr diag) const {
// colour lines
static const ColourLines line1("1 -2,2 -1");
static const ColourLines line2("1 -2");
// select the colour flow
Selector<const ColourLines *> sel;
if (diag->id() == -1) {
sel.insert(1.0, &line1);
} else {
sel.insert(1.0, &line2);
}
// return the answer
return sel;
}
void MEPP2Higgs::constructVertex(tSubProPtr sub) {
if(!spinCorrelations_) return;
// extract the particles in the hard process
ParticleVector hard;
hard.push_back(sub->incoming().first);
hard.push_back(sub->incoming().second);
hard.push_back(sub->outgoing()[0]);
if(hard[0]->id() < hard[1]->id()) {
swap(hard[0],hard[1]);
}
// identify the process and calculate the matrix element
if(hard[0]->id() == ParticleID::g && hard[1]->id() == ParticleID::g) {
vector<VectorWaveFunction> g1,g2;
vector<SpinorBarWaveFunction> q;
vector<SpinorWaveFunction> qbar;
VectorWaveFunction (g1,hard[0],incoming,false,true,true);
VectorWaveFunction (g2,hard[1],incoming,false,true,true);
ScalarWaveFunction hout(hard[2],outgoing,true);
g1[1] = g1[2];
g2[1] = g2[2];
ggME(g1,g2,hout,true);
}
else {
vector<SpinorWaveFunction> q1;
vector<SpinorBarWaveFunction> q2;
SpinorWaveFunction (q1,hard[0],incoming,false,true);
SpinorBarWaveFunction (q2,hard[1],incoming,false,true);
ScalarWaveFunction hout(hard[2],outgoing,true);
qqME(q1,q2,hout,true);
}
// construct the vertex
HardVertexPtr hardvertex = new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(me_);
// set the pointers and to and from the vertex
for(unsigned int i = 0; i < 3; ++i)
hard[i]->spinInfo()->productionVertex(hardvertex);
}
double MEPP2Higgs::ggME(vector<VectorWaveFunction> g1,
vector<VectorWaveFunction> g2,
ScalarWaveFunction & in,
bool calc) const {
ProductionMatrixElement newme(PDT::Spin1,PDT::Spin1,PDT::Spin0);
Energy2 s(sHat());
double me2(0.0);
for(int i = 0; i < 2; ++i) {
for(int j = 0; j < 2; ++j) {
Complex diag = HGGVertex_->evaluate(s,g1[i],g2[j],in);
me2 += norm(diag);
if(calc) newme(2*i, 2*j, 0) = diag;
}
}
if(calc) me_.reset(newme);
// initial colour and spin factors: colour -> (8/64) and spin -> (1/4)
return me2/32.;
}
double MEPP2Higgs::qqME(vector<SpinorWaveFunction> & fin,
vector<SpinorBarWaveFunction> & ain,
ScalarWaveFunction & in,
bool calc) const {
ProductionMatrixElement newme(PDT::Spin1Half,PDT::Spin1Half,PDT::Spin0);
Energy2 s(scale());
double me2(0.0);
for(int i = 0; i < 2; ++i) {
for(int j = 0; j < 2; ++j) {
Complex diag = HFFVertex_->evaluate(s,fin[i],ain[j],in);
me2+=norm(diag);
if(calc) newme(i, j, 0) = diag;
}
}
if(calc) me_.reset(newme);
// final colour/spin factors
return me2/12.;
}
void MEPP2Higgs::applyHardMatrixElementCorrection(ShowerTreePtr tree) {
useMe();
assert(tree->outgoingLines().size()==1);
if(tree->incomingLines().begin()->second->id()!=ParticleID::g) return;
// get gluons and Higgs
// get the gluons
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cit;
ShowerParticleVector incoming;
vector<tcBeamPtr> beams;
for(cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
incoming.push_back(cit->first->progenitor());
beams.push_back(cit->first->beam());
}
if(incoming[0]->momentum().z()<ZERO) {
swap(incoming[0],incoming[1]);
swap(beams[0],beams[1]);
}
// get the Higgs
PPtr higgs;
higgs=tree->outgoingLines().begin()->first->copy();
// calculate the momenta
unsigned int iemit,itype;
vector<Lorentz5Momentum> pnew;
pair<double,double> xnew;
// if not accepted return
tPDPtr out;
if(!applyHard(incoming,beams,higgs,iemit,itype,pnew,xnew,out)) return;
// if applying ME correction create the new particles
if(itype==0) {
// ensure gluon can be put on shell
Lorentz5Momentum ptest(pnew[2]);
if(ptest.boost(-(pnew[0]+pnew[1]).boostVector()).e() <
getParticleData(ParticleID::g)->constituentMass()) return;
// create the new gluon
PPtr newg= getParticleData(ParticleID::g)->produceParticle(pnew[2]);
PPtr newg1,newg2;
ColinePtr col;
bool colour = UseRandom::rndbool();
// make the new particles
if(iemit==0) {
newg1 = incoming[0]->dataPtr()->produceParticle(pnew[0]);
if(colour) {
col = incoming[0]->colourLine();
incoming[0]->antiColourLine()->addAntiColoured(newg1);
}
else {
col = incoming[0]->antiColourLine();
incoming[0]->colourLine()->addColoured(newg1);
}
newg2 = new_ptr(Particle(*incoming[1]));
col->removeColoured(newg2,colour);
newg2->set5Momentum(pnew[1]);
}
else {
newg2 = incoming[1]->dataPtr()->produceParticle(pnew[1]);
if(colour) {
col= incoming[1]->antiColourLine();
incoming[1]->colourLine()->addColoured(newg2);
}
else {
col= incoming[1]->colourLine();
incoming[1]->antiColourLine()->addAntiColoured(newg2);
}
newg1 = new_ptr(Particle(*incoming[0]));
col->removeColoured(newg1,!colour);
newg1->set5Momentum(pnew[0]);
}
// set the colour lines
ColinePtr newline=new_ptr(ColourLine());
if(iemit==0) {
newline->addColoured(newg1,!colour);
newline->addColoured(newg ,!colour);
col ->addColoured(newg , colour);
col ->addColoured(newg2, colour);
}
else {
newline->addColoured(newg2, colour);
newline->addColoured(newg , colour);
col ->addColoured(newg ,!colour);
col ->addColoured(newg1,!colour);
}
// change the existing gluons
PPtr orig;
for(cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
// remove old particles from colour line
ColinePtr l1=cit->first->copy()-> colourLine();
ColinePtr l2=cit->first->copy()->antiColourLine();
l1->removeColoured (cit->first->copy() );
l1->removeColoured (cit->first->progenitor());
l2->removeAntiColoured(cit->first->copy() );
l2->removeAntiColoured(cit->first->progenitor());
if(cit->first->progenitor()->momentum().z()/newg1->momentum().z()>0) {
// insert new particles
cit->first->copy(newg1);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newg1,1,false)));
sp->x(xnew.first);
cit->first->progenitor(sp);
tree->incomingLines()[cit->first]=sp;
cit->first->perturbative(iemit!=0);
if(iemit==0) orig=cit->first->original();
}
else {
// insert new particles
cit->first->copy(newg2);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newg2,1,false)));
sp->x(xnew.second);
cit->first->progenitor(sp);
tree->incomingLines()[cit->first]=sp;
cit->first->perturbative(iemit==0);
if(iemit==1) orig=cit->first->original();
}
}
// fix the momentum of the higgs
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt=tree->outgoingLines().begin();
Boost boostv=cjt->first->progenitor()->momentum().findBoostToCM();
LorentzRotation trans(pnew[3].boostVector());
trans *=LorentzRotation(boostv);
cjt->first->progenitor()->transform(trans);
cjt->first->copy()->transform(trans);
tree->hardMatrixElementCorrection(true);
// add the gluon
ShowerParticlePtr sg=new_ptr(ShowerParticle(*newg,1,true));
ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(orig,newg,sg));
gluon->perturbative(false);
tree->outgoingLines().insert(make_pair(gluon,sg));
}
else if(itype==1) {
// ensure outgoing quark can be put on-shell
Lorentz5Momentum ptest(pnew[2]);
if(ptest.boost(-(pnew[0]+pnew[1]).boostVector()).e() <
out->constituentMass()) return;
// create the new particles
PPtr newqout = out->produceParticle(pnew[2]);
PPtr newqin,newg;
if(iemit==0) {
newqin = out ->produceParticle(pnew[0]);
newg = new_ptr(Particle(*incoming[1]));
newg->set5Momentum(pnew[1]);
incoming[0]->colourLine() ->addColoured(newqin);
incoming[0]->antiColourLine()->addColoured(newqout);
}
else {
newg = new_ptr(Particle(*incoming[0]));
newg->set5Momentum(pnew[0]);
newqin = out ->produceParticle(pnew[1]);
incoming[1]->colourLine() ->addColoured(newqin);
incoming[1]->antiColourLine()->addColoured(newqout);
}
// change the existing incoming partons
PPtr orig;
for(cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
// remove old particles from colour line
ColinePtr l1=cit->first->copy()-> colourLine();
ColinePtr l2=cit->first->copy()->antiColourLine();
l1->removeColoured (cit->first->copy() );
l1->removeColoured (cit->first->progenitor());
l2->removeAntiColoured(cit->first->copy() );
l2->removeAntiColoured(cit->first->progenitor());
if(cit->first->progenitor()->momentum().z()/newqin->momentum().z()>0.) {
// insert new particles
cit->first->copy(newqin);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newqin,1,false)));
sp->x(iemit==0 ? xnew.first : xnew.second );
cit->first->progenitor(sp);
tree->incomingLines()[cit->first]=sp;
cit->first->perturbative(false);
orig=cit->first->original();
}
else {
// insert new particles
cit->first->copy(newg);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newg,1,false)));
sp->x(iemit==1 ? xnew.first : xnew.second );
cit->first->progenitor(sp);
tree->incomingLines()[cit->first]=sp;
cit->first->perturbative(true);
}
}
// fix the momentum of the higgs
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt=tree->outgoingLines().begin();
Boost boostv=cjt->first->progenitor()->momentum().findBoostToCM();
LorentzRotation trans(pnew[3].boostVector());
trans *=LorentzRotation(boostv);
cjt->first->progenitor()->transform(trans);
cjt->first->copy()->transform(trans);
tree->hardMatrixElementCorrection(true);
// add the outgoing quark
ShowerParticlePtr sout=new_ptr(ShowerParticle(*newqout,1,true));
ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(orig,newqout,sout));
out->perturbative(false);
tree->outgoingLines().insert(make_pair(out,sout));
}
else if(itype==2) {
// ensure outgoing antiquark can be put on-shell
Lorentz5Momentum ptest(pnew[2]);
if(ptest.boost(-(pnew[0]+pnew[1]).boostVector()).e() <
incoming[0]->dataPtr()->constituentMass()) return;
// create the new particles
PPtr newqout = out->produceParticle(pnew[2]);
PPtr newqin,newg;
if(iemit==0) {
newqin = out ->produceParticle(pnew[0]);
newg = new_ptr(Particle(*incoming[1]));
newg->set5Momentum(pnew[1]);
incoming[0]->colourLine() ->addAntiColoured(newqout);
incoming[0]->antiColourLine()->addAntiColoured(newqin);
}
else {
newg = new_ptr(Particle(*incoming[0]));
newg->set5Momentum(pnew[0]);
newqin = out ->produceParticle(pnew[1]);
incoming[1]->colourLine() ->addAntiColoured(newqout);
incoming[1]->antiColourLine()->addAntiColoured(newqin);
}
// change the existing incoming partons
PPtr orig;
for(cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
// remove old particles from colour line
ColinePtr l1=cit->first->copy()-> colourLine();
ColinePtr l2=cit->first->copy()->antiColourLine();
l1->removeColoured (cit->first->copy() );
l1->removeColoured (cit->first->progenitor());
l2->removeAntiColoured(cit->first->copy() );
l2->removeAntiColoured(cit->first->progenitor());
if(cit->first->progenitor()->momentum().z()/newqin->momentum().z()>0.) {
// insert new particles
cit->first->copy(newqin);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newqin,1,false)));
sp->x(iemit==0 ? xnew.first : xnew.second );
cit->first->progenitor(sp);
tree->incomingLines()[cit->first]=sp;
cit->first->perturbative(false);
orig=cit->first->original();
}
else {
// insert new particles
cit->first->copy(newg);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newg,1,false)));
sp->x(iemit==1 ? xnew.first : xnew.second );
cit->first->progenitor(sp);
tree->incomingLines()[cit->first]=sp;
cit->first->perturbative(true);
}
}
// fix the momentum of the higgs
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt=tree->outgoingLines().begin();
Boost boostv=cjt->first->progenitor()->momentum().findBoostToCM();
LorentzRotation trans(pnew[3].boostVector());
trans *=LorentzRotation(boostv);
cjt->first->progenitor()->transform(trans);
cjt->first->copy()->transform(trans);
tree->hardMatrixElementCorrection(true);
// add the outgoing antiquark
ShowerParticlePtr sout=new_ptr(ShowerParticle(*newqout,1,true));
ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(orig,newqout,sout));
out->perturbative(false);
tree->outgoingLines().insert(make_pair(out,sout));
}
}
bool MEPP2Higgs::softMatrixElementVeto(ShowerProgenitorPtr initial,
ShowerParticlePtr parent,Branching br) {
if(parent->isFinalState()) return false;
// check if me correction should be applied
long id[2]={initial->id(),parent->id()};
// must have started as a gluon
if(id[0]!=ParticleID::g) return false;
// must be a gluon going into the hard process
if(br.ids[1]!=ParticleID::g) return false;
// get the pT
Energy pT=br.kinematics->pT();
// check if hardest so far
if(pT<initial->highestpT()) return false;
// compute the invariants
double kappa(sqr(br.kinematics->scale())/mh2_),z(br.kinematics->z());
Energy2 shat(mh2_/z*(1.+(1.-z)*kappa)),that(-(1.-z)*kappa*mh2_),uhat(-(1.-z)*shat);
// check which type of process
Energy2 me;
// g g
if(br.ids[0]==ParticleID::g&&br.ids[2]==ParticleID::g) {
double split = 6.*(z/(1.-z)+(1.-z)/z+z*(1.-z));
me = ggME(shat,that,uhat)/split;
}
// q g
else if(br.ids[0] >= 1 && br.ids[0] <= 5 && br.ids[2]==br.ids[0]) {
double split = 4./3./z*(1.+sqr(1.-z));
me = qgME(shat,uhat,that)/split;
}
// qbar g
else if(br.ids[0] <= -1 && br.ids[0] >= -5 && br.ids[2]==br.ids[0]) {
double split = 4./3./z*(1.+sqr(1.-z));
me = qbargME(shat,uhat,that)/split;
}
else {
return false;
}
InvEnergy2 pre = 0.125/Constants::pi/loME()*sqr(mh2_)*that/shat/(shat+uhat);
double wgt = -pre*me/enhance_;
if(wgt<.0||wgt>1.) generator()->log() << "Soft ME correction weight too large or "
<< "negative in MEPP2Higgs::"
<< "softMatrixElementVeto()\n soft weight "
<< " sbar = " << shat/mh2_
<< " tbar = " << that/mh2_
<< "weight = " << wgt << " for "
<< br.ids[0] << " " << br.ids[1] << " "
<< br.ids[2] << "\n";
// if not vetoed
if(UseRandom::rndbool(wgt)) return false;
// otherwise
parent->vetoEmission(br.type,br.kinematics->scale());
return true;
}
HardTreePtr MEPP2Higgs::generateHardest(ShowerTreePtr tree,
- vector<ShowerInteraction::Type> inter) {
- bool found = false;
+ ShowerInteraction::Type inter) {
// check if generating QCD radiation
- for(unsigned int ix=0;ix<inter.size();++ix) {
- found |= inter[ix]==ShowerInteraction::QCD;
- }
- if(!found) return HardTreePtr();
+ if(inter!=ShowerInteraction::QCD && inter!=ShowerInteraction::QEDQCD &&
+ inter!=ShowerInteraction::ALL)
+ return HardTreePtr();
if(tree->incomingLines().begin()->second->id()!=ParticleID::g)
return HardTreePtr();
useMe();
// get the particles to be showered
beams_.clear();
partons_.clear();
// find the incoming particles
ShowerParticleVector incoming;
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cit;
vector<ShowerProgenitorPtr> particlesToShower;
for( cit = tree->incomingLines().begin();
cit != tree->incomingLines().end(); ++cit ) {
incoming.push_back( cit->first->progenitor() );
beams_.push_back( cit->first->beam() );
partons_.push_back( cit->first->progenitor()->dataPtr() );
particlesToShower.push_back( cit->first );
}
// find the higgs boson
PPtr higgs;
if(tree->outgoingLines().size() == 1) {
higgs = tree->outgoingLines().begin()->first->copy();
}
else {
higgs = tree->outgoingLines().begin()->first->copy()->parents()[0];
}
// calculate the rapidity of the higgs
yh_ = 0.5 * log((higgs->momentum().e()+higgs->momentum().z())/
(higgs->momentum().e()-higgs->momentum().z()));
mass_=higgs->mass();
mh2_ = sqr(mass_);
vector<Lorentz5Momentum> pnew;
int emission_type(-1);
// generate the hard emission and return if no emission
if(!getEvent(pnew,emission_type)) {
for(unsigned int ix=0;ix<particlesToShower.size();++ix)
particlesToShower[ix]->maximumpT(minpT_,ShowerInteraction::QCD);
return HardTreePtr();
}
// construct the HardTree object needed to perform the showers
ShowerParticleVector newparticles(4);
// create the partons
int iemit=-1;
// g g -> h g
if(emission_type==0) {
newparticles[0] = new_ptr(ShowerParticle(partons_[0] ,false));
newparticles[1] = new_ptr(ShowerParticle(partons_[1] ,false));
iemit = pnew[0].z()/pnew[3].z()>0. ? 0 : 1;
}
// g q -> H q
else if(emission_type==1) {
newparticles[0] = new_ptr(ShowerParticle(partons_[0] ,false));
newparticles[1] = new_ptr(ShowerParticle(out_ ,false));
iemit = 1;
}
// q g -> H q
else if(emission_type==2) {
newparticles[0] = new_ptr(ShowerParticle(out_ ,false));
newparticles[1] = new_ptr(ShowerParticle(partons_[1] ,false));
iemit = 0;
}
// g qbar -> H qbar
else if(emission_type==3) {
newparticles[0] = new_ptr(ShowerParticle(partons_[0] ,false));
newparticles[1] = new_ptr(ShowerParticle(out_ ,false));
iemit = 1;
}
// qbar g -> H qbar
else if(emission_type==4) {
newparticles[0] = new_ptr(ShowerParticle(out_ ,false));
newparticles[1] = new_ptr(ShowerParticle(partons_[1] ,false));
iemit = 0;
}
unsigned int ispect = iemit==0 ? 1 : 0;
// create the jet
newparticles[3] = new_ptr(ShowerParticle(out_ , true));
// create the boson
newparticles[2] = new_ptr(ShowerParticle(higgs->dataPtr(),true));
// set the momenta
for(unsigned int ix=0;ix<4;++ix) newparticles[ix]->set5Momentum(pnew[ix]);
// create the off-shell particle
Lorentz5Momentum poff=pnew[iemit]-pnew[3];
poff.rescaleMass();
newparticles.push_back(new_ptr(ShowerParticle(partons_[iemit],false)));
newparticles.back()->set5Momentum(poff);
vector<HardBranchingPtr> inBranch,hardBranch; // create the branchings for the incoming particles
inBranch.push_back(new_ptr(HardBranching(newparticles[0],SudakovPtr(),
HardBranchingPtr(),HardBranching::Incoming)));
inBranch.push_back(new_ptr(HardBranching(newparticles[1],SudakovPtr(),
HardBranchingPtr(),HardBranching::Incoming)));
// intermediate IS particle
hardBranch.push_back(new_ptr(HardBranching(newparticles[4],SudakovPtr(),
inBranch[iemit],HardBranching::Incoming)));
inBranch[iemit]->addChild(hardBranch.back());
// create the branching for the emitted jet
inBranch[iemit]->addChild(new_ptr(HardBranching(newparticles[3],SudakovPtr(),
inBranch[iemit],HardBranching::Outgoing)));
ColinePtr cline1 = new_ptr(ColourLine());
ColinePtr cline2 = new_ptr(ColourLine());
ColinePtr cline3 = new_ptr(ColourLine());
if(newparticles[3]->id()<0||
(newparticles[3]->id()==ParticleID::g&&UseRandom::rndbool())) {
inBranch[iemit]->type(ShowerPartnerType::QCDColourLine);
cline1->addAntiColoured(newparticles[3]);
cline1->addColoured (newparticles[4]);
cline1->addAntiColoured(newparticles[ispect]);
cline2->addColoured (newparticles[ispect]);
cline2->addAntiColoured(newparticles[4]);
cline2->addAntiColoured(newparticles[iemit]);
if(newparticles[3]->id()==ParticleID::g) {
cline3->addColoured(newparticles[iemit]);
cline3->addColoured(newparticles[3]);
}
}
else {
inBranch[iemit]->type(ShowerPartnerType::QCDAntiColourLine);
cline1->addColoured (newparticles[3]);
cline1->addAntiColoured(newparticles[4]);
cline1->addColoured (newparticles[ispect]);
cline2->addAntiColoured(newparticles[ispect]);
cline2->addColoured (newparticles[4]);
cline2->addColoured (newparticles[iemit]);
if(newparticles[3]->id()==ParticleID::g) {
cline3->addAntiColoured(newparticles[iemit]);
cline3->addAntiColoured(newparticles[3]);
}
}
// set the colour partners
hardBranch.back()->colourPartner(inBranch[iemit==0 ? 1 : 0]);
inBranch[iemit==0 ? 1 : 0]->colourPartner(hardBranch.back());
// add other particle
hardBranch.push_back(inBranch[iemit==0 ? 1 : 0]);
// outgoing Higgs boson
hardBranch.push_back(new_ptr(HardBranching(newparticles[2],SudakovPtr(),
HardBranchingPtr(),HardBranching::Outgoing)));
// make the tree
HardTreePtr hardtree=new_ptr(HardTree(hardBranch,inBranch,ShowerInteraction::QCD));
// connect the ShowerParticles with the branchings
// and set the maximum pt for the radiation
set<HardBranchingPtr> hard=hardtree->branchings();
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
if( pt_ < minpT_ ) particlesToShower[ix]->maximumpT(minpT_,ShowerInteraction::QCD);
else particlesToShower[ix]->maximumpT(pt_,ShowerInteraction::QCD);
for(set<HardBranchingPtr>::const_iterator mit=hard.begin();
mit!=hard.end();++mit) {
if(particlesToShower[ix]->progenitor()->id()==(*mit)->branchingParticle()->id()&&
(( particlesToShower[ix]->progenitor()->isFinalState()&&
(**mit).status()==HardBranching::Outgoing)||
(!particlesToShower[ix]->progenitor()->isFinalState()&&
(**mit).status()==HardBranching::Incoming))) {
if(particlesToShower[ix]->progenitor()->momentum().z()/
(*mit)->branchingParticle()->momentum().z()<0.) continue;
hardtree->connect(particlesToShower[ix]->progenitor(),*mit);
if((**mit).status()==HardBranching::Incoming) {
(*mit)->beam(particlesToShower[ix]->original()->parents()[0]);
}
HardBranchingPtr parent=(*mit)->parent();
while(parent) {
parent->beam(particlesToShower[ix]->original()->parents()[0]);
parent=parent->parent();
};
}
}
}
// return the answer
return hardtree;
}
bool MEPP2Higgs::applyHard(ShowerParticleVector gluons,
vector<tcBeamPtr> beams,PPtr higgs,
unsigned int & iemit, unsigned int & itype,
vector<Lorentz5Momentum> & pnew,
pair<double,double> & xout, tPDPtr & out) {
++ntry_;
// calculate the limits on s
Energy mh(higgs->mass());
mh2_=sqr(mh);
Energy2 smin=mh2_;
Energy2 s=
(generator()->currentEvent()->incoming().first->momentum()+
generator()->currentEvent()->incoming().second->momentum()).m2();
Energy2 smax(s);
// calculate the rapidity of the higgs
double yH = 0.5*log((higgs->momentum().e()+higgs->momentum().z())/
(higgs->momentum().e()-higgs->momentum().z()));
// if no phase-space return
if(smax<smin) return false;
// get the evolution scales (this needs improving)
double kappa[2]={1.,1.};
// get the momentum fractions for the leading order process
// and the values of the PDF's
double x[2]={-99.99e99,-99.99e99},fx[2]={-99.99e99,-99.99e99};
tcPDFPtr pdf[2];
for(unsigned int ix=0;ix<gluons.size();++ix) {
x[ix]=gluons[ix]->x();
assert(beams[ix]);
pdf[ix]=beams[ix]->pdf();
assert(pdf[ix]);
fx[ix]=pdf[ix]->xfx(beams[ix],gluons[ix]->dataPtr(),mh2_,x[ix]);
}
// leading order ME
Energy4 lome = loME();
// select the type of process and generate the kinematics
double rn(UseRandom::rnd());
Energy2 shat(ZERO),uhat(ZERO),that(ZERO);
double weight(0.),xnew[2]={1.,1.};
// gg -> H g
if(rn<channelWeights_[0]) {
// generate the value of s according to 1/s^n
double rhomax(pow(smin/mh2_,1.-ggPow_)),rhomin(pow(smax/mh2_,1.-ggPow_));
double rho = rhomin+UseRandom::rnd()*(rhomax-rhomin);
shat = mh2_*pow(rho,1./(1.-ggPow_));
Energy2 jacobian = mh2_/(ggPow_-1.)*(rhomax-rhomin)*pow(shat/mh2_,ggPow_);
double sbar=shat/mh2_;
// calculate limits on that
Energy2 tmax=mh2_*kappa[0]*(1.-sbar)/(kappa[0]+sbar);
Energy2 tmin=shat*(1.-sbar)/(kappa[1]+sbar);
// calculate the limits on uhat
Energy2 umax(mh2_-shat-tmin),umin(mh2_-shat-tmax);
// check inside phase space
if(tmax<tmin||umax<umin) return false;
// generate t and u according to 1/t+1/u
// generate in 1/t
if(UseRandom::rndbool(0.5)) {
that=tmax*pow(tmin/tmax,UseRandom::rnd());
uhat=mh2_-shat-that;
jacobian *=log(tmin/tmax);
}
// generate in 1/u
else {
uhat=umax*pow(umin/umax,UseRandom::rnd());
that=mh2_-shat-uhat;
jacobian *=log(umin/umax);
}
Energy4 jacobian2 = jacobian * 2.*uhat*that/(shat-mh2_);
// new scale (this is mt^2=pt^2+mh^2)
Energy2 scale(uhat*that/shat+mh2_);
// the PDF's with the emitted gluon
double fxnew[2];
xnew[0]=exp(yH)/sqrt(s)*sqrt(shat*(mh2_-uhat)/(mh2_-that));
xnew[1]=shat/(s*xnew[0]);
if(xnew[0]<=0.||xnew[0]>=1.||xnew[1]<=0.||xnew[1]>=1.) return false;
for(unsigned int ix=0;ix<2;++ix)
fxnew[ix]=pdf[ix]->xfx(beams[ix],gluons[ix]->dataPtr(),scale,xnew[ix]);
// jacobian and me parts of the weight
weight = jacobian2*ggME(shat,uhat,that)/lome*mh2_/sqr(shat);
// pdf part of the weight
weight *=fxnew[0]*fxnew[1]*x[0]*x[1]/(fx[0]*fx[1]*xnew[0]*xnew[1]);
// finally coupling and different channel pieces
weight *= 1./16./sqr(Constants::pi)*alpha_->value(scale)/channelWeights_[0];
itype=0;
iemit = that>uhat ? 0 : 1;
out = getParticleData(ParticleID::g);
}
// incoming quark or antiquark
else {
// generate the value of s according to 1/s^n
double rhomax(pow(smin/mh2_,1.-qgPow_)),rhomin(pow(smax/mh2_,1.-qgPow_));
double rho = rhomin+UseRandom::rnd()*(rhomax-rhomin);
shat = mh2_*pow(rho,1./(1.-qgPow_));
Energy2 jacobian = mh2_/(qgPow_-1.)*(rhomax-rhomin)*pow(shat/mh2_,qgPow_);
double sbar=shat/mh2_;
// calculate limits on that
Energy2 tmax=mh2_*kappa[0]*(1.-sbar)/(kappa[0]+sbar);
Energy2 tmin=shat*(1.-sbar)/(kappa[1]+sbar);
// calculate the limits on uhat
Energy2 umax(mh2_-shat-tmin),umin(mh2_-shat-tmax);
// check inside phase space
if(tmax<tmin||umax<umin) return false;
// generate t
bool order(UseRandom::rndbool());
Energy4 jacobian2;
if(order) {
uhat=umax*pow(umin/umax,UseRandom::rnd());
that=mh2_-shat-uhat;
jacobian2 = jacobian * uhat*log(umax/umin);
}
else {
that=tmax*pow(tmin/tmax,UseRandom::rnd());
uhat=mh2_-shat-that;
jacobian2 = jacobian * that*log(tmax/tmin);
}
InvEnergy4 mewgt;
// new scale (this is mt^2=pt^2+mh^2)
Energy2 scale(uhat*that/shat+mh2_);
double fxnew[2];
xnew[0]=exp(yH)/sqrt(s)*sqrt(shat*(mh2_-uhat)/(mh2_-that));
xnew[1]=shat/(s*xnew[0]);
if(xnew[0]<=0.||xnew[0]>=1.||xnew[1]<=0.||xnew[1]>=1.) return false;
if(rn<channelWeights_[1]) {
itype = 1;
// q g -> H q
if(!order) {
out = quarkFlavour(pdf[0],scale,xnew[0],beams[0],fxnew[0],false);
fxnew[1]=pdf[1]->xfx(beams[1],gluons[1]->dataPtr(),scale,xnew[1]);
iemit = 0;
mewgt = out ? qgME(shat,uhat,that)/lome*mh2_/sqr(shat) : ZERO;
}
// g q -> H q
else {
fxnew[0]=pdf[0]->xfx(beams[0],gluons[0]->dataPtr(),scale,xnew[0]);
out = quarkFlavour(pdf[1],scale,xnew[1],beams[1],fxnew[1],false);
iemit = 1;
mewgt = out ? qgME(shat,that,uhat)/lome*mh2_/sqr(shat) : ZERO;
}
jacobian2 /= (channelWeights_[1]-channelWeights_[0]);
}
else {
itype=2;
// qbar g -> H qbar
if(!order) {
out = quarkFlavour(pdf[0],scale,xnew[0],beams[0],fxnew[0],true);
fxnew[1]=pdf[1]->xfx(beams[1],gluons[1]->dataPtr(),scale,xnew[1]);
iemit = 0;
mewgt = out ? qbargME(shat,uhat,that)/lome*mh2_/sqr(shat) : ZERO;
}
// g qbar -> H qbar
else {
fxnew[0]=pdf[0]->xfx(beams[0],gluons[0]->dataPtr(),scale,xnew[0]);
out = quarkFlavour(pdf[1],scale,xnew[1],beams[1],fxnew[1],true);
iemit = 1;
mewgt = out ? qbargME(shat,that,uhat)/lome*mh2_/sqr(shat) : ZERO;
}
jacobian2/=(channelWeights_[2]-channelWeights_[1]);
}
// weight (factor of 2 as pick q(bar)g or gq(bar)
weight = 2.*jacobian2*mewgt;
// pdf part of the weight
weight *=fxnew[0]*fxnew[1]*x[0]*x[1]/(fx[0]*fx[1]*xnew[0]*xnew[1]);
// finally coupling and different channel pieces
weight *= 1./16./sqr(Constants::pi)*alpha_->value(scale);
}
// if me correction should be applied
if(weight>1.) {
++nover_;
maxwgt_ = max( maxwgt_ , weight);
weight=1.;
}
if(UseRandom::rnd()>weight) return false;
++ngen_;
// construct the momenta
Energy roots = 0.5*sqrt(s);
Energy pt = sqrt(uhat*that/shat);
Energy mt = sqrt(uhat*that/shat+mh2_);
Lorentz5Momentum pin[2]={Lorentz5Momentum(ZERO,ZERO, xnew[0]*roots,xnew[0]*roots),
Lorentz5Momentum(ZERO,ZERO,-xnew[1]*roots,xnew[1]*roots)};
double phi = Constants::twopi*UseRandom::rnd();
Lorentz5Momentum pH(pt*cos(phi),pt*sin(phi),mt*sinh(yH),mt*cosh(yH));
Lorentz5Momentum pJ(pin[0]+pin[1]-pH);
// momenta to be returned
pnew.push_back(pin[0]);
pnew.push_back(pin[1]);
pnew.push_back(pJ);
pnew.push_back(pH);
xout.first = xnew[0];
xout.second = xnew[1];
return true;
}
Energy2 MEPP2Higgs::ggME(Energy2 s, Energy2 t, Energy2 u) {
Energy2 output;
if(massOption_==0) {
complex<Energy> me[2][2][2];
me[1][1][1] = ZERO;
me[1][1][0] = ZERO;
me[0][1][0] = ZERO;
me[0][1][1] = ZERO;
for(unsigned int ix=minLoop_; ix<=maxLoop_; ++ix ) {
Energy2 mf2=sqr(getParticleData(long(ix))->mass());
bi_[1]=B(s,mf2);
bi_[2]=B(u,mf2);
bi_[3]=B(t,mf2);
bi_[4]=B(mh2_,mf2);
bi_[1]=bi_[1]-bi_[4];
bi_[2]=bi_[2]-bi_[4];
bi_[3]=bi_[3]-bi_[4];
ci_[1]=C(s,mf2);
ci_[2]=C(u,mf2);
ci_[3]=C(t,mf2);
ci_[7]=C(mh2_,mf2);
ci_[4]=(s*ci_[1]-mh2_*ci_[7])/(s-mh2_);
ci_[5]=(u*ci_[2]-mh2_*ci_[7])/(u-mh2_);
ci_[6]=(t*ci_[3]-mh2_*ci_[7])/(t-mh2_);
di_[1]=D(t,u,s,mf2);
di_[2]=D(s,t,u,mf2);
di_[3]=D(s,u,t,mf2);
me[1][1][1]+=me1(s,u,t,mf2,1,2,3,4,5,6);
me[1][1][0]+=me2(s,u,t,mf2);
me[0][1][0]+=me1(u,s,t,mf2,2,1,3,5,4,6);
me[0][1][1]+=me1(t,u,s,mf2,3,2,1,6,5,4);
}
me[0][0][0]=-me[1][1][1];
me[0][0][1]=-me[1][1][0];
me[1][0][1]=-me[0][1][0];
me[1][0][0]=-me[0][1][1];
output = real(me[0][0][0]*conj(me[0][0][0])+
me[0][0][1]*conj(me[0][0][1])+
me[0][1][0]*conj(me[0][1][0])+
me[0][1][1]*conj(me[0][1][1])+
me[1][0][0]*conj(me[1][0][0])+
me[1][0][1]*conj(me[1][0][1])+
me[1][1][0]*conj(me[1][1][0])+
me[1][1][1]*conj(me[1][1][1]));
output *= 3./8.;
}
else {
output=32./3.*
(pow<4,1>(s)+pow<4,1>(t)+pow<4,1>(u)+pow<4,1>(mh2_))/s/t/u;
}
// spin and colour factors
return output/4./64.;
}
Energy2 MEPP2Higgs::qgME(Energy2 s, Energy2 t, Energy2 u) {
Energy2 output;
if(massOption_==0) {
complex<Energy2> A(ZERO);
Energy2 si(u-mh2_);
for(unsigned int ix=minLoop_;ix<=maxLoop_;++ix) {
Energy2 mf2=sqr(getParticleData(long(ix))->mass());
A += mf2*(2.+2.*double(u/si)*(B(u,mf2)-B(mh2_,mf2))
+double((4.*mf2-s-t)/si)*Complex(u*C(u,mf2)-mh2_*C(mh2_,mf2)));
}
output =-4.*(sqr(s)+sqr(t))/sqr(si)/u*real(A*conj(A));
}
else{
output =-4.*(sqr(s)+sqr(t))/u/9.;
}
// final colour/spin factors
return output/24.;
}
Energy2 MEPP2Higgs::qbargME(Energy2 s, Energy2 t, Energy2 u) {
Energy2 output;
if(massOption_==0) {
complex<Energy2> A(ZERO);
Energy2 si(u-mh2_);
for(unsigned int ix=minLoop_;ix<=maxLoop_;++ix) {
Energy2 mf2=sqr(getParticleData(long(ix))->mass());
A+=mf2*(2.+2.*double(u/si)*(B(u,mf2)-B(mh2_,mf2))
+double((4.*mf2-s-t)/si)*Complex(u*C(u,mf2)-mh2_*C(mh2_,mf2)));
}
output =-4.*(sqr(s)+sqr(t))/sqr(si)/u*real(A*conj(A));
}
else {
output =-4.*(sqr(s)+sqr(t))/u/9.;
}
// final colour/spin factors
return output/24.;
}
Energy4 MEPP2Higgs::loME() const {
Complex I(0);
if(massOption_==0) {
for(unsigned int ix=minLoop_;ix<=maxLoop_;++ix) {
double x = sqr(getParticleData(long(ix))->mass())/mh2_;
I += 3.*x*(2.+(4.*x-1.)*F(x));
}
}
else {
I = 1.;
}
return sqr(mh2_)/576./Constants::pi*norm(I);
}
tPDPtr MEPP2Higgs::quarkFlavour(tcPDFPtr pdf, Energy2 scale,
double x, tcBeamPtr beam,
double & pdfweight, bool anti) {
vector<double> weights;
vector<tPDPtr> partons;
pdfweight = 0.;
if(!anti) {
for(unsigned int ix=1;ix<=5;++ix) {
partons.push_back(getParticleData(long(ix)));
weights.push_back(max(0.,pdf->xfx(beam,partons.back(),scale,x)));
pdfweight += weights.back();
}
}
else {
for(unsigned int ix=1;ix<=5;++ix) {
partons.push_back(getParticleData(-long(ix)));
weights.push_back(max(0.,pdf->xfx(beam,partons.back(),scale,x)));
pdfweight += weights.back();
}
}
if(pdfweight==0.) return tPDPtr();
double wgt=UseRandom::rnd()*pdfweight;
for(unsigned int ix=0;ix<weights.size();++ix) {
if(wgt<=weights[ix]) return partons[ix];
wgt -= weights[ix];
}
assert(false);
return tPDPtr();
}
Complex MEPP2Higgs::B(Energy2 s,Energy2 mf2) const {
Complex output,pii(0.,Constants::pi);
double rat=s/(4.*mf2);
if(s<ZERO)
output=2.-2.*sqrt(1.-1./rat)*log(sqrt(-rat)+sqrt(1.-rat));
else if(s>=ZERO&&rat<1.)
output=2.-2.*sqrt(1./rat-1.)*asin(sqrt(rat));
else
output=2.-sqrt(1.-1./rat)*(2.*log(sqrt(rat)+sqrt(rat-1.))-pii);
return output;
}
complex<InvEnergy2> MEPP2Higgs::C(Energy2 s,Energy2 mf2) const {
complex<InvEnergy2> output;
Complex pii(0.,Constants::pi);
double rat=s/(4.*mf2);
if(s<ZERO)
output=2.*sqr(log(sqrt(-rat)+sqrt(1.-rat)))/s;
else if(s>=ZERO&&rat<1.)
output=-2.*sqr(asin(sqrt(rat)))/s;
else {
double cosh=log(sqrt(rat)+sqrt(rat-1.));
output=2.*(sqr(cosh)-sqr(Constants::pi)/4.-pii*cosh)/s;
}
return output;
}
Complex MEPP2Higgs::dIntegral(Energy2 a, Energy2 b, double y0) const {
Complex output;
if(b==ZERO) output=0.;
else {
Complex y1=0.5*(1.+sqrt(1.-4.*(a+epsi_)/b));
Complex y2=1.-y1;
Complex z1=y0/(y0-y1);
Complex z2=(y0-1.)/(y0-y1);
Complex z3=y0/(y0-y2);
Complex z4=(y0-1.)/(y0-y2);
output=Math::Li2(z1)-Math::Li2(z2)+Math::Li2(z3)-Math::Li2(z4);
}
return output;
}
complex<InvEnergy4> MEPP2Higgs::D(Energy2 s,Energy2 t, Energy2,
Energy2 mf2) const {
Complex output,pii(0.,Constants::pi);
Energy4 st=s*t;
Energy4 root=sqrt(sqr(st)-4.*st*mf2*(s+t-mh2_));
double xp=0.5*(st+root)/st,xm=1-xp;
output = 2.*(-dIntegral(mf2,s,xp)-dIntegral(mf2,t,xp)
+dIntegral(mf2,mh2_,xp)+log(-xm/xp)
*(log((mf2+epsi_)/GeV2)-log((mf2+epsi_-s*xp*xm)/GeV2)
+log((mf2+epsi_-mh2_*xp*xm)/GeV2)-log((mf2+epsi_-t*xp*xm)/GeV2)));
return output/root;
}
complex<Energy> MEPP2Higgs::me1(Energy2 s,Energy2 t,Energy2 u, Energy2 mf2,
unsigned int i ,unsigned int j ,unsigned int k ,
unsigned int i1,unsigned int j1,unsigned int k1) const {
Energy2 s1(s-mh2_),t1(t-mh2_),u1(u-mh2_);
return mf2*4.*sqrt(2.*s*t*u)*
(-4.*(1./(u*t)+1./(u*u1)+1./(t*t1))
-4.*((2.*s+t)*bi_[k]/sqr(u1)+(2.*s+u)*bi_[j]/sqr(t1))/s
-(s-4.*mf2)*(s1*ci_[i1]+(u-s)*ci_[j1]+(t-s)*ci_[k1])/(s*t*u)
-8.*mf2*(ci_[j1]/(t*t1)+ci_[k1]/(u*u1))
+0.5*(s-4.*mf2)*(s*t*di_[k]+u*s*di_[j]-u*t*di_[i])/(s*t*u)
+4.*mf2*di_[i]/s
-2.*(u*ci_[k]+t*ci_[j]+u1*ci_[k1]+t1*ci_[j1]-u*t*di_[i])/sqr(s));
}
complex<Energy> MEPP2Higgs::me2(Energy2 s,Energy2 t,Energy2 u,
Energy2 mf2) const {
Energy2 s1(s-mh2_),t1(t-mh2_),u1(u-mh2_);
return mf2*4.*sqrt(2.*s*t*u)*(4.*mh2_+(mh2_-4.*mf2)*(s1*ci_[4]+t1*ci_[5]+u1*ci_[6])
-0.5*(mh2_-4.*mf2)*(s*t*di_[3]+u*s*di_[2]+u*t*di_[1]) )/
(s*t*u);
}
Complex MEPP2Higgs::F(double x) const {
if(x<.25) {
double root = sqrt(1.-4.*x);
Complex pii(0.,Constants::pi);
return 0.5*sqr(log((1.+root)/(1.-root))-pii);
}
else {
return -2.*sqr(asin(0.5/sqrt(x)));
}
}
bool MEPP2Higgs::getEvent(vector<Lorentz5Momentum> & pnew,
int & emis_type){
// maximum pt (half of centre-of-mass energy)
Energy maxp = 0.5*generator()->maximumCMEnergy();
// set pt of emission to zero
pt_=ZERO;
//Working Variables
Energy pt;
double yj;
// limits on the rapidity of the jet
double minyj = -8.0,maxyj = 8.0;
bool reject;
double wgt;
emis_type=-1;
tcPDPtr outParton;
for(int j=0;j<5;++j) {
pt = maxp;
do {
double a = alpha_->overestimateValue()*prefactor_[j]*(maxyj-minyj)/(power_-1.);
// generate next pt
pt=GeV/pow(pow(GeV/pt,power_-1)-log(UseRandom::rnd())/a,1./(power_-1.));
// generate rapidity of the jet
yj=UseRandom::rnd()*(maxyj-minyj)+ minyj;
// calculate rejection weight
wgt=getResult(j,pt,yj,outParton);
wgt/= prefactor_[j]*pow(GeV/pt,power_);
reject = UseRandom::rnd()>wgt;
//no emission event if p goes past p min - basically set to outside
//of the histogram bounds (hopefully hist object just ignores it)
if(pt<minpT_){
pt=ZERO;
reject = false;
}
if(wgt>1.0) {
ostringstream s;
s << "MEPP2Higgs::getEvent weight for channel " << j
<< "is " << wgt << " which is greater than 1";
generator()->logWarning( Exception(s.str(), Exception::warning) );
}
}
while(reject);
// set pt of emission etc
if(pt>pt_){
emis_type = j;
pt_=pt;
yj_=yj;
out_ = outParton;
}
}
//was this an (overall) no emission event?
if(pt_<minpT_){
pt_=ZERO;
emis_type = 5;
}
if(emis_type==5) return false;
// generate the momenta of the particles
// hadron-hadron cmf
Energy2 s=sqr(generator()->maximumCMEnergy());
// transverse energy
Energy et=sqrt(mh2_+sqr(pt_));
// first calculate all the kinematic variables
// longitudinal real correction fractions
double x = pt_*exp( yj_)/sqrt(s)+et*exp( yh_)/sqrt(s);
double y = pt_*exp(-yj_)/sqrt(s)+et*exp(-yh_)/sqrt(s);
// that and uhat
// Energy2 th = -sqrt(s)*x*pt_*exp(-yj_);
// Energy2 uh = -sqrt(s)*y*pt_*exp( yj_);
// Energy2 sh = x*y*s;
// reconstruct the momenta
// incoming momenta
pnew.push_back(Lorentz5Momentum(ZERO,ZERO,
x*0.5*sqrt(s), x*0.5*sqrt(s),ZERO));
pnew.push_back(Lorentz5Momentum(ZERO,ZERO,
-y*0.5*sqrt(s), y*0.5*sqrt(s),ZERO));
// outgoing momenta
double phi(Constants::twopi*UseRandom::rnd());
double sphi(sin(phi)),cphi(cos(phi));
pnew.push_back(Lorentz5Momentum( cphi*pt_, sphi*pt_, et*sinh(yh_),
et*cosh(yh_), mass_));
pnew.push_back(Lorentz5Momentum(-cphi*pt_,-sphi*pt_,pt_*sinh(yj_),
pt_*cosh(yj_),ZERO));
return true;
}
double MEPP2Higgs::getResult(int emis_type, Energy pt, double yj,
tcPDPtr & outParton) {
Energy2 s=sqr(generator()->maximumCMEnergy());
Energy2 scale = mh2_+sqr(pt);
Energy et=sqrt(scale);
scale = mu_F_opt_==0 ? mh2_+sqr(pt) : sqr(pt) ;
// longitudinal real correction fractions
double x = pt*exp( yj)/sqrt(s)+et*exp( yh_)/sqrt(s);
double y = pt*exp(-yj)/sqrt(s)+et*exp(-yh_)/sqrt(s);
// reject if outside region
if(x<0.||x>1.||y<0.||y>1.||x*y<mh2_/s) return 0.;
// longitudinal born fractions
double x1 = mass_*exp( yh_)/sqrt(s);
double y1 = mass_*exp(-yh_)/sqrt(s);
// mandelstam variables
Energy2 th = -sqrt(s)*x*pt*exp(-yj);
Energy2 uh = -sqrt(s)*y*pt*exp( yj);
Energy2 sh = mh2_-th-uh;
InvEnergy2 res = InvEnergy2();
// pdf part of the cross section
double pdf[4] = {99.99e99,99.99e99,99.99e99,99.99e99};
if(mu_F_opt_==0) { // As in original version ...
pdf[0]=beams_[0]->pdf()->xfx(beams_[0],partons_[0],mh2_,x1);
pdf[1]=beams_[1]->pdf()->xfx(beams_[1],partons_[1],mh2_,y1);
} else { // As in Nason and Ridolfi paper ...
pdf[0]=beams_[0]->pdf()->xfx(beams_[0],partons_[0],scale,x1);
pdf[1]=beams_[1]->pdf()->xfx(beams_[1],partons_[1],scale,y1);
}
// g g -> H g
if(emis_type==0) {
outParton = partons_[1];
pdf[2]=beams_[0]->pdf()->xfx(beams_[0],partons_[0],scale,x);
pdf[3]=beams_[1]->pdf()->xfx(beams_[1],partons_[1],scale,y);
res = ggME(sh,uh,th)/loME();
}
// q g -> H q
else if(emis_type==1) {
outParton = quarkFlavour(beams_[0]->pdf(),scale,x,beams_[0],pdf[2],false);
pdf[3]=beams_[1]->pdf()->xfx(beams_[1],partons_[1],scale,y);
res = outParton ? qgME(sh,uh,th)/loME() : ZERO;
}
// g q -> H q
else if(emis_type==2) {
pdf[2]=beams_[0]->pdf()->xfx(beams_[0],partons_[0],scale,x);
outParton = quarkFlavour(beams_[1]->pdf(),scale,y,beams_[1],pdf[3],false);
res = outParton ? qgME(sh,th,uh)/loME() : ZERO;
}
// qbar g -> H qbar
else if(emis_type==3) {
outParton = quarkFlavour(beams_[0]->pdf(),scale,x,beams_[0],pdf[2],true);
pdf[3]=beams_[1]->pdf()->xfx(beams_[1],partons_[1],scale,y);
res = outParton ? qbargME(sh,uh,th)/loME() : ZERO;
}
// g qbar -> H qbar
else if(emis_type==4) {
pdf[2]=beams_[0]->pdf()->xfx(beams_[0],partons_[0],scale,x);
outParton = quarkFlavour(beams_[1]->pdf(),scale,y,beams_[1],pdf[3],true);
res = outParton ? qbargME(sh,th,uh)/loME() : ZERO;
}
//deals with pdf zero issue at large x
if(pdf[0]<=0.||pdf[1]<=0.||pdf[2]<=0.||pdf[3]<=0.) {
res = ZERO;
}
else {
res *= pdf[2]*pdf[3]/pdf[0]/pdf[1]*mh2_/sh;
}
scale = mu_R_opt_==0 ? mh2_+sqr(pt) : sqr(pt) ;
return alpha_->ratio(scale)/8./sqr(Constants::pi)*mh2_/sh*GeV*pt*res;
}
void MEPP2Higgs::initializeMECorrection(ShowerTreePtr tree, double & initial,
double & final) {
final = 1.;
initial = tree->incomingLines().begin()->second->id()==ParticleID::g ?
enhance_ : 1.;
}
diff --git a/MatrixElement/Hadron/MEPP2Higgs.h b/MatrixElement/Hadron/MEPP2Higgs.h
--- a/MatrixElement/Hadron/MEPP2Higgs.h
+++ b/MatrixElement/Hadron/MEPP2Higgs.h
@@ -1,742 +1,741 @@
// -*- C++ -*-
//
// MEPP2Higgs.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_MEPP2Higgs_H
#define HERWIG_MEPP2Higgs_H
//
// This is the declaration of the MEPP2Higgs class.
//
#include "Herwig/MatrixElement/HwMEBase.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVSVertex.h"
#include "Herwig/PDT/GenericMassGenerator.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
#include "Herwig/Shower/Couplings/ShowerAlpha.h"
namespace Herwig {
using namespace ThePEG;
using namespace ThePEG::Helicity;
/**
* The MEPP2Higgs class implements the matrix element for the process
* pp->Higgs with different Higgs shape prescriptions (see details in hep-ph/9505211)
* and the NLL corrected Higgs width (see details in the FORTRAN HERWIG manual).
*
* @see \ref MEPP2HiggsInterfaces "The interfaces"
* defined for MEPP2Higgs.
*/
class MEPP2Higgs: public HwMEBase {
public:
/**
* The default constructor.
*/
MEPP2Higgs();
/**
* Return the matrix element for the kinematical configuation
* previously provided by the last call to setKinematics(). Uses
* me().
*/
virtual CrossSection dSigHatDR() const;
/**
* Set the typed and momenta of the incoming and outgoing partons to
* be used in subsequent calls to me() and colourGeometries()
* according to the associated XComb object.
*/
virtual void setKinematics() {
HwMEBase::setKinematics();
mh2_ = sHat();
}
public:
/** @name Member functions for the generation of hard QCD radiation */
//@{
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return ISR;}
/**
* Has an old fashioned ME correction
*/
virtual bool hasMECorrection() {return true;}
/**
* Initialize the ME correction
*/
virtual void initializeMECorrection(ShowerTreePtr tree, double & initial,
double & final);
/**
* Apply the hard matrix element correction to a given hard process or decay
*/
virtual void applyHardMatrixElementCorrection(ShowerTreePtr);
/**
* Apply the soft matrix element correction
* @param initial The particle from the hard process which started the
* shower
* @param parent The initial particle in the current branching
* @param br The branching struct
* @return If true the emission should be vetoed
*/
virtual bool softMatrixElementVeto(ShowerProgenitorPtr initial,
ShowerParticlePtr parent,
Branching br);
/**
* Apply the POWHEG style correction
*/
- virtual HardTreePtr generateHardest(ShowerTreePtr,
- vector<ShowerInteraction::Type>);
+ virtual HardTreePtr generateHardest(ShowerTreePtr,ShowerInteraction::Type);
//@}
public:
/** @name Virtual functions required by the MEBase class. */
//@{
/**
* Return the order in \f$\alpha_S\f$ in which this matrix
* element is given.
*/
virtual unsigned int orderInAlphaS() const;
/**
* Return the order in \f$\alpha_{EW}\f$ in which this matrix
* element is given.
*/
virtual unsigned int orderInAlphaEW() const;
/**
* The matrix element for the kinematical configuration
* previously provided by the last call to setKinematics(), suitably
* scaled by sHat() to give a dimension-less number.
* @return the matrix element scaled with sHat() to give a
* dimensionless number.
*/
virtual double me2() const;
/**
* Generate internal degrees of freedom given nDim() uniform
* random numbers in the interval \f$ ]0,1[ \f$. To help the phase space
* generator, the dSigHatDR should be a smooth function of these
* numbers, although this is not strictly necessary.
* @param r a pointer to the first of nDim() consecutive random numbers.
* @return true if the generation succeeded, otherwise false.
*/
virtual bool generateKinematics(const double * r);
/**
* Return the scale associated with the last set phase space point.
*/
virtual Energy2 scale() const;
/**
* The number of internal degrees of freedom used in the matrix
* element.
*/
virtual int nDim() const;
/**
* Add all possible diagrams with the add() function.
*/
virtual void getDiagrams() const;
/**
* Get diagram selector. With the information previously supplied with the
* setKinematics method, a derived class may optionally
* override this method to weight the given diagrams with their
* (although certainly not physical) relative probabilities.
* @param dv the diagrams to be weighted.
* @return a Selector relating the given diagrams to their weights.
*/
virtual Selector<DiagramIndex> diagrams(const DiagramVector & dv) const;
/**
* Return a Selector with possible colour geometries for the selected
* diagram weighted by their relative probabilities.
* @param diag the diagram chosen.
* @return the possible colour geometries weighted by their
* relative probabilities.
*/
virtual Selector<const ColourLines *> colourGeometries(tcDiagPtr diag) const;
/**
* Construct the vertex of spin correlations.
*/
virtual void constructVertex(tSubProPtr);
//@}
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const { return new_ptr(*this); }
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const { return new_ptr(*this); }
//@}
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
/**
* Finalize this object. Called in the run phase just after a
* run has ended. Used eg. to write out statistics.
*/
virtual void dofinish();
//@}
protected:
/**
* Members to calculate the real emission matrix elements
*/
//@{
/**
* The leading-order matrix element for \f$gg\to H\f$
*/
Energy4 loME() const;
/**
* The matrix element for \f$gg\to H g\f$
*/
Energy2 ggME(Energy2 s, Energy2 t, Energy2 u);
/**
* The matrix element for \f$qg\to H q\f$
*/
Energy2 qgME(Energy2 s, Energy2 t, Energy2 u);
/**
* The matrix element for \f$qbarg\to H qbar\f$
*/
Energy2 qbargME(Energy2 s, Energy2 t, Energy2 u);
//@}
/**
* Members to calculate the functions for the loop diagrams
*/
//@{
/**
* The \f$B(s)\f$ function of NBP339 (1990) 38-66
* @param s The scale
* @param mf2 The fermion mass squared.
*/
Complex B(Energy2 s,Energy2 mf2) const;
/**
* The \f$C(s)\f$ function of NBP339 (1990) 38-66
* @param s The scale
* @param mf2 The fermion mass squared.
*/
complex<InvEnergy2> C(Energy2 s,Energy2 mf2) const;
/**
* The \f$C(s)\f$ function of NBP339 (1990) 38-66
* @param s The \f$s\f$ invariant
* @param t The \f$t\f$ invariant
* @param u The \f$u\f$ invariant
* @param mf2 The fermion mass squared
*/
complex<InvEnergy4> D(Energy2 s,Energy2 t, Energy2 u,Energy2 mf2) const;
/**
* The integral \f$\int\frac{dy}{y-y_0}\log(a-i\epsilon-b y(1-y))\f$
* from NBP339 (1990) 38-66.
* @param a The parameter \f$a\f$.
* @param b The parameter \f$b\f$.
* @param y0 The parameter \f$y_0\f$.
*/
Complex dIntegral(Energy2 a, Energy2 b, double y0) const;
/**
* The \f$M_{+++}\f$ matrix element of NBP339 (1990) 38-66.
* @param s The \f$s\f$ invariant
* @param t The \f$t\f$ invariant
* @param u The \f$u\f$ invariant
* @param mf2 The fermion mass squared.
* @param i Which of the stored values to use for \f$D(u,t)\f$.
* @param j Which of the stored values to use for \f$D(u,s)\f$.
* @param k Which of the stored values to use for \f$D(s,t)\f$.
* @param i1 Which of the stored values to use for \f$C_1(s)\f$.
* @param j1 Which of the stored values to use for \f$C_1(t)\f$.
* @param k1 Which of the stored values to use for \f$C_1(u)\f$.
*/
complex<Energy> me1(Energy2 s,Energy2 t,Energy2 u, Energy2 mf2,
unsigned int i,unsigned int j, unsigned int k,
unsigned int i1,unsigned int j1, unsigned int k1) const;
/**
* The \f$M_{++-}\f$ matrix element of NBP339 (1990) 38-66.
* @param s The \f$s\f$ invariant
* @param t The \f$t\f$ invariant
* @param u The \f$u\f$ invariant
* @param mf2 The fermion mass squared.
*/
complex<Energy> me2(Energy2 s,Energy2 t,Energy2 u, Energy2 mf2) const;
/**
* The \f$F(x)\f$ function for the leading-order result
*/
Complex F(double x) const;
//@}
/**
* Method to extract the PDF weight for quark/antiquark
* initiated processes and select the quark flavour
*/
tPDPtr quarkFlavour(tcPDFPtr pdf, Energy2 scale, double x, tcBeamPtr beam,
double & pdfweight, bool anti);
/**
* Return the momenta and type of hard matrix element correction
* @param gluons The original incoming particles.
* @param beams The BeamParticleData objects
* @param higgs The original outgoing higgs
* @param iemit Whether the first (0) or second (1) particle emitted
* the radiation
* @param itype The type of radiated particle (0 is gluon, 1 is quark
* and 2 is antiquark)
* @param pnew The momenta of the new particles
* @param xnew The new values of the momentuym fractions
* @param out The ParticleData object for the outgoing parton
* @return Whether or not the matrix element correction needs to be applied
*/
bool applyHard(ShowerParticleVector gluons,
vector<tcBeamPtr> beams,
PPtr higgs,unsigned int & iemit,
unsigned int & itype,vector<Lorentz5Momentum> & pnew,
pair<double,double> & xnew,
tPDPtr & out);
/**
* generates the hardest emission (yj,p)
* @param pnew The momenta of the new particles
* @param emissiontype The type of emission, as for getResult
* @return Whether not an emission was generated
*/
bool getEvent(vector<Lorentz5Momentum> & pnew,int & emissiontype);
/**
* Returns the matrix element for a given type of process,
* rapidity of the jet \f$y_j\f$ and transverse momentum \f$p_T\f$
* @param emis_type the type of emission,
* (0 is \f$gg\to h^0g\f$, 1 is \f$qg\to h^0q\f$ and 2 is \f$g\bar{q}\to h^0\bar{q}\f$)
* @param pt The transverse momentum of the jet
* @param yj The rapidity of the jet
* @param outParton the outgoing parton
*/
double getResult(int emis_type, Energy pt, double yj,tcPDPtr & outParton);
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<MEPP2Higgs> initMEPP2Higgs;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEPP2Higgs & operator=(const MEPP2Higgs &);
//@}
/**
* Members to return the matrix elements for the different subprocesses
*/
//@{
/**
* Calculates the matrix element for the process g,g->h (via quark loops)
* @param g1 a vector of wave functions of the first incoming gluon
* @param g2 a vector of wave functions of the second incoming gluon
* @param calc Whether or not to calculate the matrix element for spin correlations
* @return the amlitude value.
*/
double ggME(vector<VectorWaveFunction> g1,
vector<VectorWaveFunction> g2,
ScalarWaveFunction &,
bool calc) const;
/**
* Calculates the matrix element for the process q,qbar->h
* @param fin a vector of quark spinors
* @param ain a vector of anti-quark spinors
* @param calc Whether or not to calculate the matrix element for spin correlations
* @return the amlitude value.
*/
double qqME(vector<SpinorWaveFunction> & fin,
vector<SpinorBarWaveFunction> & ain,
ScalarWaveFunction &,
bool calc) const;
//@}
private:
/**
* Selects a dynamic (sHat) or fixed factorization scale
*/
unsigned int scaleopt_;
/**
* The value associated to the fixed factorization scale option
*/
Energy mu_F_;
/**
* Defines the Higgs resonance shape
*/
unsigned int shapeOption_;
/**
* The processes to be included (GG->H and/or qq->H)
*/
unsigned int processOption_;
/**
* Minimum flavour of incoming quarks
*/
int minFlavour_;
/**
* Maximum flavour of incoming quarks
*/
int maxFlavour_;
/**
* Matrix element for spin correlations
*/
ProductionMatrixElement me_;
/**
* Pointer to the H-> 2 gluon vertex (used in gg->H)
*/
AbstractVVSVertexPtr HGGVertex_;
/**
* Pointer to the fermion-fermion Higgs vertex (used in qq->H)
*/
AbstractFFSVertexPtr HFFVertex_;
/**
* The mass generator for the Higgs
*/
GenericMassGeneratorPtr hmass_;
/**
* On-shell mass for the higgs
*/
Energy mh_;
/**
* On-shell width for the higgs
*/
Energy wh_;
/**
* Stuff for the ME correction
*/
//@{
/**
* Parameters for the evaluation of the loops for the
* matrix elements
*/
//@{
/**
* Minimum flavour of quarks to include in the loops
*/
unsigned int minLoop_;
/**
* Maximum flavour of quarks to include in the loops
*/
unsigned int maxLoop_;
/**
* Option for treatment of the fermion loops
*/
unsigned int massOption_;
/**
* Option for dynamic scale choice in alpha_S (0=mT,>0=pT)
*/
unsigned int mu_R_opt_;
/**
* Option for dynamic scale choice in PDFs (0=mT,>0=pT)
*/
unsigned int mu_F_opt_;
//@}
//@}
/**
* Small complex number to regularize some integrals
*/
static const complex<Energy2> epsi_;
/**
* Storage of the loop functions
*/
//@{
/**
* B functions
*/
mutable Complex bi_[5];
/**
* C functions
*/
mutable complex<InvEnergy2> ci_[8];
/**
* D functions
*/
mutable complex<InvEnergy4> di_[4];
//@}
/**
* Pointer to the object calculating the strong coupling
*/
ShowerAlphaPtr alpha_;
/**
* Mass squared of Higgs
*/
Energy2 mh2_;
/**
* Relative weight of the \f$qg\f$ to the \f$gg\f$ channel
*/
double channelwgtA_;
/**
* Relative weight for the \f$\bar{q}g\f$ to the \f$gg\f$ channel
*/
double channelwgtB_;
/**
* Weights for the channels as a vector
*/
vector<double> channelWeights_;
/**
* Power for the \f$\frac{{\rm d}\hat{s}}{\hat{s}^n}\f$ importance sampling
* of the \f$gg\f$ component
*/
double ggPow_;
/**
* Power for the \f$\frac{{\rm d}\hat{s}}{\hat{s}^n}\f$ importance sampling
* of the \f$qg\f$ and \f$\bar{q}g\f$ components
*/
double qgPow_;
/**
* The enhancement factor for initial-state radiation
*/
double enhance_;
/**
* Number of weights greater than 1
*/
unsigned int nover_;
/**
* Number of attempts
*/
unsigned int ntry_;
/**
* Number which suceed
*/
unsigned int ngen_;
/**
* Maximum weight
*/
double maxwgt_;
//@}
/**
* Constants for the sampling. The distribution is assumed to have the
* form \f$\frac{c}{{\rm GeV}}\times\left(\frac{{\rm GeV}}{p_T}\right)^n\f$
*/
//@{
/**
* The power, \f$n\f$, for the sampling
*/
double power_;
/**
* The prefactor, \f$c\f$ for the \f$gg\f$ channel
*/
double pregg_;
/**
* The prefactor, \f$c\f$ for the \f$qg\f$ channel
*/
double preqg_;
/**
* The prefactor, \f$c\f$ for the \f$g\bar{q}\f$ channel
*/
double pregqbar_;
/**
* The prefactors as a vector for easy use
*/
vector<double> prefactor_;
//@}
/**
* The transverse momentum of the jet
*/
Energy minpT_;
/**
* Properties of the incoming particles
*/
//@{
/**
* Pointers to the BeamParticleData objects
*/
vector<tcBeamPtr> beams_;
/**
* Pointers to the ParticleDataObjects for the partons
*/
vector<tcPDPtr> partons_;
//@}
/**
* Properties of the boson and jets
*/
//@{
/**
* The rapidity of the Higgs boson
*/
double yh_;
/**
* The mass of the Higgs boson
*/
Energy mass_;
/**
* the rapidity of the jet
*/
double yj_;
/**
* The transverse momentum of the jet
*/
Energy pt_;
/**
* The outgoing parton
*/
tcPDPtr out_;
//@}
/**
* Whether of not to construct the vertex for spin correlations
*/
bool spinCorrelations_;
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the base classes of MEPP2Higgs. */
template <>
struct BaseClassTrait<Herwig::MEPP2Higgs,1> {
/** Typedef of the first base class of MEPP2Higgs. */
typedef Herwig::HwMEBase NthBase;
};
/** This template specialization informs ThePEG about the name of
* the MEPP2Higgs class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::MEPP2Higgs>
: public ClassTraitsBase<Herwig::MEPP2Higgs> {
/** Return a platform-independent class name */
static string className() { return "Herwig::MEPP2Higgs"; }
/**
* The name of a file containing the dynamic library where the class
* MEPP2Higgs is implemented. It may also include several, space-separated,
* libraries if the class MEPP2Higgs depends on other classes (base classes
* excepted). In this case the listed libraries will be dynamically
* linked in the order they are specified.
*/
static string library() { return "HwMEHadron.so"; }
};
/** @endcond */
}
#endif /* HERWIG_MEPP2Higgs_H */
diff --git a/MatrixElement/Hadron/MEPP2HiggsVBF.cc b/MatrixElement/Hadron/MEPP2HiggsVBF.cc
--- a/MatrixElement/Hadron/MEPP2HiggsVBF.cc
+++ b/MatrixElement/Hadron/MEPP2HiggsVBF.cc
@@ -1,1634 +1,1632 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2HiggsVBF class.
//
#include "MEPP2HiggsVBF.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "ThePEG/PDT/StandardMatchers.h"
#include <numeric>
#include "Herwig/Utilities/Maths.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/Repository/CurrentGenerator.h"
#include "Herwig/Shower/Base/ShowerProgenitor.h"
#include "Herwig/Shower/Base/ShowerTree.h"
#include "Herwig/Shower/Base/Branching.h"
#include "Herwig/Shower/Base/HardTree.h"
using namespace Herwig;
// namespace {
// using namespace Herwig;
// using namespace ThePEG;
// using namespace ThePEG::Helicity;
// void debuggingMatrixElement(bool BGF,
// tcPDPtr partons1, tcPDPtr partons2,
// tcPDPtr partons3, tcPDPtr partons4,
// const Lorentz5Momentum & psystem0,
// const Lorentz5Momentum & psystem1,
// const Lorentz5Momentum & pother0,
// const Lorentz5Momentum & pother1,
// const Lorentz5Momentum & p0,
// const Lorentz5Momentum & p1,
// const Lorentz5Momentum & p2,
// const Lorentz5Momentum & phiggs,
// Energy2 Q12, Energy2 scale,
// double old) {
// // get the vertex and the boson
// tcHwSMPtr hwsm=ThePEG::dynamic_ptr_cast<tcHwSMPtr>
// (CurrentGenerator::current().standardModel());
// assert(hwsm);
// tcPDPtr boson;
// AbstractFFVVertexPtr weakVertex;
// AbstractFFVVertexPtr strongVertex = hwsm->vertexFFG();
// AbstractVVSVertexPtr higgsVertex = hwsm->vertexWWH();
// if(partons1->id()==partons2->id()) {
// weakVertex = hwsm->vertexFFZ();
// boson = hwsm->getParticleData(ParticleID::Z0);
// }
// else {
// weakVertex = hwsm->vertexFFW();
// boson = hwsm->getParticleData(ParticleID::Wplus);
// }
// tcPDPtr hdata = hwsm->getParticleData(ParticleID::h0);
// tcPDPtr gluon = hwsm->getParticleData(ParticleID::g);
// SpinorWaveFunction q1,q2;
// SpinorBarWaveFunction qbar1,qbar2;
// if(partons1->id()>0) {
// q1 = SpinorWaveFunction (psystem0,partons1,incoming);
// qbar1 = SpinorBarWaveFunction(psystem1,partons2,outgoing);
// }
// else {
// q1 = SpinorWaveFunction (psystem1,partons2,outgoing);
// qbar1 = SpinorBarWaveFunction(psystem0,partons1,incoming);
// }
// if(partons3->id()>0) {
// q2 = SpinorWaveFunction (pother0,partons3,incoming);
// qbar2 = SpinorBarWaveFunction(pother1,partons4,outgoing);
// }
// else {
// q2 = SpinorWaveFunction (pother1,partons4,outgoing);
// qbar2 = SpinorBarWaveFunction(pother0,partons3,incoming);
// }
// ScalarWaveFunction higgs(phiggs,hdata,outgoing);
// if(!BGF) {
// SpinorWaveFunction q1p;
// SpinorBarWaveFunction qbar1p;
// if(partons1->id()>0) {
// q1p = SpinorWaveFunction (p0 ,partons1,incoming);
// qbar1p = SpinorBarWaveFunction(p1 ,partons2,outgoing);
// }
// else {
// q1p = SpinorWaveFunction (p1 ,partons2,outgoing);
// qbar1p = SpinorBarWaveFunction(p0 ,partons1,incoming);
// }
// VectorWaveFunction gl(p2,gluon,outgoing);
// double lome(0.),realme(0.);
// for(unsigned int lhel1=0;lhel1<2;++lhel1) {
// q2.reset(lhel1);
// for(unsigned int lhel2=0;lhel2<2;++lhel2) {
// qbar2.reset(lhel2);
// VectorWaveFunction off1
// = weakVertex->evaluate(scale,3,boson,q2,qbar2);
// VectorWaveFunction off2
// = higgsVertex->evaluate(scale,3,boson,off1,higgs);
// for(unsigned int qhel1=0;qhel1<2;++qhel1) {
// q1.reset(qhel1);
// q1p.reset(qhel1);
// for(unsigned int qhel2=0;qhel2<2;++qhel2) {
// qbar1.reset(qhel2);
// qbar1p.reset(qhel2);
// Complex diag = weakVertex->evaluate(scale,q1,qbar1,off2);
// lome += norm(diag);
// for(unsigned int ghel=0;ghel<2;++ghel) {
// gl.reset(2*ghel);
// SpinorWaveFunction inter1 =
// strongVertex->evaluate(Q12,5,q1p.particle(),q1p,gl);
// Complex diag1 = weakVertex->evaluate(scale,inter1,qbar1p,off2);
// SpinorBarWaveFunction inter2 =
// strongVertex->evaluate(Q12,5,qbar1p.particle(),qbar1p,gl);
// Complex diag2 = weakVertex->evaluate(scale,q1p,inter2,off2);
// realme += norm(diag1+diag2);
// }
// }
// }
// }
// }
// double test1 = realme/lome/hwsm->alphaS(Q12)*Q12*UnitRemoval::InvE2;
// cerr << "testing ratio A " << old/test1 << "\n";
// }
// else {
// SpinorWaveFunction q1p;
// SpinorBarWaveFunction qbar1p;
// if(partons1->id()>0) {
// q1p = SpinorWaveFunction (p2,partons1->CC(),outgoing);
// qbar1p = SpinorBarWaveFunction(p1,partons2 ,outgoing);
// }
// else {
// q1p = SpinorWaveFunction (p1,partons2 ,outgoing);
// qbar1p = SpinorBarWaveFunction(p2,partons1->CC(),outgoing);
// }
// VectorWaveFunction gl(p0,gluon,incoming);
// double lome(0.),realme(0.);
// for(unsigned int lhel1=0;lhel1<2;++lhel1) {
// q2.reset(lhel1);
// for(unsigned int lhel2=0;lhel2<2;++lhel2) {
// qbar2.reset(lhel2);
// VectorWaveFunction off1
// = weakVertex->evaluate(scale,3,boson,q2,qbar2);
// VectorWaveFunction off2
// = higgsVertex->evaluate(scale,3,boson,off1,higgs);
// for(unsigned int qhel1=0;qhel1<2;++qhel1) {
// q1.reset(qhel1);
// q1p.reset(qhel1);
// for(unsigned int qhel2=0;qhel2<2;++qhel2) {
// qbar1.reset(qhel2);
// qbar1p.reset(qhel2);
// Complex diag = weakVertex->evaluate(scale,q1,qbar1,off2);
// lome += norm(diag);
// for(unsigned int ghel=0;ghel<2;++ghel) {
// gl.reset(2*ghel);
// SpinorWaveFunction inter1 =
// strongVertex->evaluate(Q12,5,q1p.particle(),q1p,gl);
// Complex diag1 = weakVertex->evaluate(scale,inter1,qbar1p,off2);
// SpinorBarWaveFunction inter2 =
// strongVertex->evaluate(Q12,5,qbar1p.particle(),qbar1p,gl);
// Complex diag2 = weakVertex->evaluate(scale,q1p,inter2,off2);
// realme += norm(diag1+diag2);
// }
// }
// }
// }
// }
// double test1 = realme/lome/hwsm->alphaS(Q12)*Q12*UnitRemoval::InvE2;
// cerr << "testing ratio B " << old/test1 << "\n";
// }
// }
// }
MEPP2HiggsVBF::MEPP2HiggsVBF() : comptonWeight_(8.), BGFWeight_(30.),
pTmin_(1.*GeV),initial_(10.),final_(8.),
procProb_(0.5), comptonInt_(0.), bgfInt_(0.),
nover_(0),maxwgt_(make_pair(0.,0.))
{}
void MEPP2HiggsVBF::doinit() {
gluon_ = getParticleData(ParticleID::g);
// integrals of me over phase space
double r5=sqrt(5.),darg((r5-1.)/(r5+1.)),ath(0.5*log((1.+1./r5)/(1.-1./r5)));
comptonInt_ = 2.*(-21./20.-6./(5.*r5)*ath+sqr(Constants::pi)/3.
-2.*Math::ReLi2(1.-darg)-2.*Math::ReLi2(1.-1./darg));
bgfInt_ = 121./9.-56./r5*ath;
// get the vertex pointers from the SM object
tcHwSMPtr hwsm= dynamic_ptr_cast<tcHwSMPtr>(standardModel());
if(!hwsm)
throw InitException() << "Wrong type of StandardModel object in "
<< "MEPP2HiggsVBF::doinit() the Herwig"
<< " version must be used"
<< Exception::runerror;
// set the vertex
setWWHVertex(hwsm->vertexWWH());
higgs(getParticleData(ParticleID::h0));
MEfftoffH::doinit();
}
void MEPP2HiggsVBF::dofinish() {
MEfftoffH::dofinish();
if(nover_==0) return;
generator()->log() << "VBFMECorrection when applying the hard correction "
<< nover_ << " weights larger than one were generated of which"
<< " the largest was " << maxwgt_.first << " for the QCD compton"
<< " processes and " << maxwgt_.second << " for the BGF process\n";
}
void MEPP2HiggsVBF::getDiagrams() const {
// get the quark particle data objects as we'll be using them
tcPDPtr q[6],qbar[6];
for ( int ix=0; ix<5; ++ix ) {
q [ix] = getParticleData(ix+1);
qbar[ix] = q[ix]->CC();
}
// WW processes
if(process()==0||process()==1) {
std::vector<pair<tcPDPtr,tcPDPtr> > parentpair;
parentpair.reserve(6);
// don't even think of putting 'break' in here!
switch(maxFlavour()) {
case 5:
if (minFlavour()<=4)
parentpair.push_back(make_pair(getParticleData(ParticleID::b),
getParticleData(ParticleID::c)));
if (minFlavour()<=2)
parentpair.push_back(make_pair(getParticleData(ParticleID::b),
getParticleData(ParticleID::u)));
case 4:
if (minFlavour()<=3)
parentpair.push_back(make_pair(getParticleData(ParticleID::s),
getParticleData(ParticleID::c)));
if (minFlavour()<=1)
parentpair.push_back(make_pair(getParticleData(ParticleID::d),
getParticleData(ParticleID::c)));
case 3:
if (minFlavour()<=2)
parentpair.push_back(make_pair(getParticleData(ParticleID::s),
getParticleData(ParticleID::u)));
case 2:
if (minFlavour()<=1)
parentpair.push_back(make_pair(getParticleData(ParticleID::d),
getParticleData(ParticleID::u)));
default:
;
}
for(unsigned int ix=0;ix<parentpair.size();++ix) {
for(unsigned int iy=0;iy<parentpair.size();++iy) {
// q1 q2 -> q1' q2' h
if(parentpair[ix].first->id()<parentpair[iy].second->id()) {
add(new_ptr((Tree2toNDiagram(4), parentpair[ix].first, WMinus(), WPlus(),
parentpair[iy].second, 1, parentpair[ix].second, 3,
parentpair[iy].first, 2, higgs(),-1)));
}
else {
add(new_ptr((Tree2toNDiagram(4), parentpair[iy].second, WPlus(), WMinus(),
parentpair[ix].first, 1, parentpair[iy].first, 3,
parentpair[ix].second, 2, higgs(),-1)));
}
// q1 qbar2 -> q1' qbar2' h
add(new_ptr((Tree2toNDiagram(4), parentpair[ix].first, WMinus(), WPlus(),
parentpair[iy].first->CC(), 1,
parentpair[ix].second, 3, parentpair[iy].second->CC(),
2, higgs(),-1)));
add(new_ptr((Tree2toNDiagram(4),parentpair[iy].second, WPlus(), WMinus(),
parentpair[ix].second->CC(), 1, parentpair[iy].first,
3, parentpair[ix].first->CC(),
2, higgs(),-1)));
// qbar1 qbar2 -> qbar1' qbar2' h
if(parentpair[ix].first->id()<parentpair[ix].second->id()) {
add(new_ptr((Tree2toNDiagram(4), parentpair[ix].first->CC(), WPlus(), WMinus(),
parentpair[iy].second->CC(), 1,
parentpair[ix].second->CC(), 3, parentpair[iy].first->CC(),
2, higgs(),-1)));
}
else {
add(new_ptr((Tree2toNDiagram(4), parentpair[iy].second->CC(), WMinus(), WPlus(),
parentpair[ix].first->CC(), 1,
parentpair[iy].first->CC(), 3, parentpair[ix].second->CC(),
2, higgs(),-1)));
}
}
}
}
// ZZ processes
if(process()==0||process()==2) {
for(unsigned int ix=minFlavour()-1;ix<maxFlavour();++ix) {
for(unsigned int iy=ix;iy<maxFlavour();++iy) {
// q q -> q q H
add(new_ptr((Tree2toNDiagram(4), q[ix], Z0(), Z0(), q[iy],
1, q[ix], 3, q[iy], 2, higgs(),-2)));
// qbar qbar -> qbar qbar H
add(new_ptr((Tree2toNDiagram(4), qbar[ix], Z0(), Z0(), qbar[iy],
1, qbar[ix], 3, qbar[iy], 2, higgs(),-2)));
}
// q qbar -> q qbar H
for(unsigned int iy=minFlavour()-1;iy<maxFlavour();++iy) {
add(new_ptr((Tree2toNDiagram(4), q[ix], Z0(), Z0(), qbar[iy],
1, q[ix], 3, qbar[iy], 2, higgs(),-2)));
}
}
}
}
void MEPP2HiggsVBF::persistentOutput(PersistentOStream & os) const {
os << initial_ << final_
<< alpha_ << ounit(pTmin_,GeV) << comptonWeight_ << BGFWeight_ << gluon_
<< comptonInt_ << bgfInt_ << procProb_;
}
void MEPP2HiggsVBF::persistentInput(PersistentIStream & is, int) {
is >> initial_ >> final_
>> alpha_ >> iunit(pTmin_,GeV) >> comptonWeight_ >> BGFWeight_ >> gluon_
>> comptonInt_ >> bgfInt_ >> procProb_;
}
ClassDescription<MEPP2HiggsVBF> MEPP2HiggsVBF::initMEPP2HiggsVBF;
// Definition of the static class description member.
void MEPP2HiggsVBF::Init() {
static ClassDocumentation<MEPP2HiggsVBF> documentation
("The MEPP2HiggsVBF class implements Higgs production via vector-boson fusion");
static Reference<MEPP2HiggsVBF,ShowerAlpha> interfaceShowerAlphaQCD
("ShowerAlphaQCD",
"The object calculating the strong coupling constant",
&MEPP2HiggsVBF::alpha_, false, false, true, false, false);
static Parameter<MEPP2HiggsVBF,Energy> interfacepTMin
("pTMin",
"The minimum pT",
&MEPP2HiggsVBF::pTmin_, GeV, 1.*GeV, 0.0*GeV, 10.0*GeV,
false, false, Interface::limited);
static Parameter<MEPP2HiggsVBF,double> interfaceComptonWeight
("ComptonWeight",
"Weight for the overestimate ofthe compton channel",
&MEPP2HiggsVBF::comptonWeight_, 50.0, 0.0, 100.0,
false, false, Interface::limited);
static Parameter<MEPP2HiggsVBF,double> interfaceBGFWeight
("BGFWeight",
"Weight for the overestimate of the BGF channel",
&MEPP2HiggsVBF::BGFWeight_, 100.0, 0.0, 1000.0,
false, false, Interface::limited);
static Parameter<MEPP2HiggsVBF,double> interfaceProcessProbability
("ProcessProbability",
"The probabilty of the QCD compton process for the process selection",
&MEPP2HiggsVBF::procProb_, 0.3, 0.0, 1.,
false, false, Interface::limited);
}
HardTreePtr MEPP2HiggsVBF::generateHardest(ShowerTreePtr tree,
- vector<ShowerInteraction::Type> inter) {
- bool found = false;
+ ShowerInteraction::Type inter) {
// check if generating QCD radiation
- for(unsigned int ix=0;ix<inter.size();++ix) {
- found |= inter[ix]==ShowerInteraction::QCD;
- }
- if(!found) return HardTreePtr();
+ if(inter!=ShowerInteraction::QCD && inter!=ShowerInteraction::QEDQCD &&
+ inter!=ShowerInteraction::ALL)
+ return HardTreePtr();
pair< tShowerParticlePtr, tShowerParticlePtr> first,second;
pair<tcBeamPtr,tcBeamPtr> beams;
pair<tPPtr,tPPtr> hadrons;
// get the incoming particles
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
if(!first.first) {
first.first = cit->first->progenitor();
beams.first = cit->first->beam();
hadrons.first = cit->first->original()->parents()[0];
}
else {
second.first = cit->first->progenitor();
beams.second = cit->first->beam();
hadrons.second = cit->first->original()->parents()[0];
}
}
// and the outgoing
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt=tree->outgoingLines().begin();cjt!=tree->outgoingLines().end();++cjt) {
if(cjt->first->progenitor()->id()==ParticleID::h0) {
higgs_ = cjt->first->progenitor();
}
else {
if(abs(cjt->first->progenitor()->id())>5) continue;
if(cjt->first->progenitor()->colourLine()&&
cjt->first->progenitor()->colourLine()==first.first->colourLine()) {
first.second = cjt->first->progenitor();
continue;
}
if(cjt->first->progenitor()->antiColourLine()&&
cjt->first->progenitor()->antiColourLine()==first.first->antiColourLine()) {
first.second = cjt->first->progenitor();
continue;
}
if(cjt->first->progenitor()->colourLine()&&
cjt->first->progenitor()->colourLine()==second.first->colourLine()) {
second.second = cjt->first->progenitor();
continue;
}
if(cjt->first->progenitor()->antiColourLine()&&
cjt->first->progenitor()->antiColourLine()==second.first->antiColourLine()) {
second.second = cjt->first->progenitor();
continue;
}
}
}
// loop over the two possible emitting systems
q_ [0] = first .second->momentum()-first .first->momentum();
q2_[0] = -q_[0].m2();
q_ [1] = second.second->momentum()-second.first->momentum();
q2_[1] = -q_[1].m2();
for(unsigned int ix=0;ix<2;++ix) {
if(ix==1) {
swap(first,second);
swap(beams.first,beams.second);
}
// check beam, all particles
assert(beams.first && higgs_ &&
first .first && first.second &&
second.first && second.second);
// beam and pdf
beam_[ix] = beams.first;
pdf_ [ix] = beam_[ix]->pdf();
assert(beam_[ix] && pdf_[ix] );
// Particle data objects
partons_[ix][0] = first. first->dataPtr();
partons_[ix][1] = first.second->dataPtr();
partons_[ix][2] = second. first->dataPtr();
partons_[ix][3] = second.second->dataPtr();
// extract the born variables
xB_[ix] = first.first->x();
Lorentz5Momentum pb = first.first->momentum();
Axis axis(q_[ix].vect().unit());
double sinth(sqrt(sqr(axis.x())+sqr(axis.y())));
rot_[ix] = LorentzRotation();
if(axis.perp2()>1e-20) {
rot_[ix].setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.));
rot_[ix].rotateX(Constants::pi);
}
if(abs(1.-q_[ix].e()/q_[ix].vect().mag())>1e-6)
rot_[ix].boostZ( q_[ix].e()/q_[ix].vect().mag());
pb *= rot_[ix];
if(pb.perp2()/GeV2>1e-20) {
Boost trans = -1./pb.e()*pb.vect();
trans.setZ(0.);
rot_[ix].boost(trans);
}
// momenta of the particles
phiggs_ [ix] = rot_[ix]*higgs_->momentum();
pother_ [ix][0] = rot_[ix]*second. first->momentum();
pother_ [ix][1] = rot_[ix]*second.second->momentum();
psystem_[ix][0] = rot_[ix]* first. first->momentum();
psystem_[ix][1] = rot_[ix]* first.second->momentum();
q_[ix] *= rot_[ix];
pTCompton_[ix] = pTBGF_[ix] = ZERO;
// generate a compton point
generateCompton(ix);
// generate a BGF point
generateBGF(ix);
}
// no valid emissions, return
if(pTCompton_[0]<ZERO && pTCompton_[1]<ZERO&&
pTBGF_ [0]<ZERO && pTBGF_ [1]<ZERO) {
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
if(QuarkMatcher::Check(cit->first->progenitor()->data()))
cit->first->maximumpT(pTmin_,ShowerInteraction::QCD);
}
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) {
if(QuarkMatcher::Check(cit->first->progenitor()->data()))
cit->first->maximumpT(pTmin_,ShowerInteraction::QCD);
}
return HardTreePtr();
}
// find the maximum pT emission
unsigned int system = 0;
bool isCompton = false;
Energy pTmax = -GeV;
for(unsigned int ix=0;ix<2;++ix) {
if(pTCompton_[ix]>pTmax) {
pTmax = pTCompton_[ix];
isCompton = true;
system = ix;
}
if(pTBGF_[ix]>pTmax) {
pTmax = pTBGF_[ix];
isCompton = false;
system = ix;
}
}
if(system==0) {
swap(first,second);
swap(beams.first,beams.second);
}
// add the non emitting particles
vector<HardBranchingPtr> spaceBranchings,allBranchings;
spaceBranchings.push_back(new_ptr(HardBranching(second.first,SudakovPtr(),
HardBranchingPtr(),
HardBranching::Incoming)));
allBranchings.push_back(spaceBranchings.back());
allBranchings.push_back(new_ptr(HardBranching(second.second,SudakovPtr(),
HardBranchingPtr(),
HardBranching::Outgoing)));
allBranchings.push_back(new_ptr(HardBranching(higgs_,SudakovPtr(),
HardBranchingPtr(),
HardBranching::Outgoing)));
allBranchings[0]->colourPartner(allBranchings[1]);
allBranchings[1]->colourPartner(allBranchings[0]);
rot_[system].invert();
// compton hardest
if(isCompton) {
for(unsigned int ix=0;ix<ComptonMomenta_[system].size();++ix) {
ComptonMomenta_[system][ix].transform(rot_[system]);
}
ShowerParticlePtr newqout (new_ptr(ShowerParticle(partons_[system][1],true)));
newqout->set5Momentum(ComptonMomenta_[system][1]);
ShowerParticlePtr newg(new_ptr(ShowerParticle(gluon_,true)));
newg->set5Momentum(ComptonMomenta_[system][2]);
ShowerParticlePtr newqin (new_ptr(ShowerParticle(partons_[system][0],false )));
newqin->set5Momentum(ComptonMomenta_[system][0]);
if(ComptonISFS_[system]) {
ShowerParticlePtr newspace(new_ptr(ShowerParticle(partons_[system][0],false)));
newspace->set5Momentum(ComptonMomenta_[system][0]-ComptonMomenta_[system][2]);
HardBranchingPtr spaceBranch(new_ptr(HardBranching(newqin,SudakovPtr(),
HardBranchingPtr(),
HardBranching::Incoming)));
HardBranchingPtr offBranch(new_ptr(HardBranching(newspace,SudakovPtr(),
spaceBranch,
HardBranching::Incoming)));
spaceBranch->addChild(offBranch);
HardBranchingPtr g(new_ptr(HardBranching(newg,SudakovPtr(),spaceBranch,
HardBranching::Outgoing)));
spaceBranch->addChild(g);
spaceBranch->type(offBranch->branchingParticle()->id()>0 ?
ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine);
HardBranchingPtr outBranch(new_ptr(HardBranching(newqout,SudakovPtr(),
HardBranchingPtr(),
HardBranching::Outgoing)));
spaceBranchings.push_back(spaceBranch);
allBranchings.push_back(offBranch);
allBranchings.push_back(outBranch);
ColinePtr newin(new_ptr(ColourLine())),newout(new_ptr(ColourLine()));
newin ->addColoured(newqin ,newspace->dataPtr()->iColour()!=PDT::Colour3);
newin ->addColoured(newg ,newspace->dataPtr()->iColour()!=PDT::Colour3);
newout->addColoured(newspace,newspace->dataPtr()->iColour()!=PDT::Colour3);
newout->addColoured(newqout ,newspace->dataPtr()->iColour()!=PDT::Colour3);
newout->addColoured(newg ,newspace->dataPtr()->iColour()==PDT::Colour3);
}
else {
ShowerParticlePtr newtime(new_ptr(ShowerParticle(partons_[system][1],true)));
newtime->set5Momentum(ComptonMomenta_[system][1]+ComptonMomenta_[system][2]);
HardBranchingPtr spaceBranch(new_ptr(HardBranching(newqin,SudakovPtr(),
HardBranchingPtr(),
HardBranching::Incoming)));
HardBranchingPtr offBranch(new_ptr(HardBranching(newtime,SudakovPtr(),
HardBranchingPtr(),
HardBranching::Outgoing)));
HardBranchingPtr g(new_ptr(HardBranching(newg,SudakovPtr(),offBranch,
HardBranching::Outgoing)));
HardBranchingPtr outBranch(new_ptr(HardBranching(newqout,SudakovPtr(),offBranch,
HardBranching::Outgoing)));
offBranch->addChild(outBranch);
offBranch->addChild(g);
offBranch->type(offBranch->branchingParticle()->id()>0 ?
ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine);
spaceBranchings.push_back(spaceBranch);
allBranchings.push_back(spaceBranch);
allBranchings.push_back(offBranch);
ColinePtr newin(new_ptr(ColourLine())),newout(new_ptr(ColourLine()));
newin ->addColoured(newqin ,newqin->dataPtr()->iColour()!=PDT::Colour3);
newin ->addColoured(newtime ,newqin->dataPtr()->iColour()!=PDT::Colour3);
newin ->addColoured(newg ,newqin->dataPtr()->iColour()!=PDT::Colour3);
newout->addColoured(newg ,newqin->dataPtr()->iColour()==PDT::Colour3);
newout->addColoured(newqout ,newqin->dataPtr()->iColour()!=PDT::Colour3);
}
}
// BGF hardest
else {
for(unsigned int ix=0;ix<BGFMomenta_[system].size();++ix) {
BGFMomenta_[system][ix].transform(rot_[system]);
}
ShowerParticlePtr newq (new_ptr(ShowerParticle(partons_[system][1],true)));
newq->set5Momentum(BGFMomenta_[system][1]);
ShowerParticlePtr newqbar(new_ptr(ShowerParticle(partons_[system][0]->CC(),true)));
newqbar->set5Momentum(BGFMomenta_[system][2]);
ShowerParticlePtr newg (new_ptr(ShowerParticle(gluon_,false)));
newg->set5Momentum(BGFMomenta_[system][0]);
ShowerParticlePtr newspace(new_ptr(ShowerParticle(partons_[system][0],false)));
newspace->set5Momentum(BGFMomenta_[system][0]-BGFMomenta_[system][2]);
HardBranchingPtr spaceBranch(new_ptr(HardBranching(newg,SudakovPtr(),HardBranchingPtr(),
HardBranching::Incoming)));
HardBranchingPtr offBranch(new_ptr(HardBranching(newspace,SudakovPtr(),spaceBranch,
HardBranching::Incoming)));
HardBranchingPtr qbar(new_ptr(HardBranching(newqbar,SudakovPtr(),spaceBranch,
HardBranching::Outgoing)));
spaceBranch->addChild(offBranch);
spaceBranch->addChild(qbar);
spaceBranch->type(offBranch->branchingParticle()->id()>0 ?
ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine);
HardBranchingPtr outBranch(new_ptr(HardBranching(newq,SudakovPtr(),
HardBranchingPtr(),
HardBranching::Outgoing)));
spaceBranchings.push_back(spaceBranch);
allBranchings.push_back(offBranch);
allBranchings.push_back(outBranch);
ColinePtr newin(new_ptr(ColourLine())),newout(new_ptr(ColourLine()));
newout->addColoured(newspace,newspace->dataPtr()->iColour()!=PDT::Colour3);
newout->addColoured(newq ,newspace->dataPtr()->iColour()!=PDT::Colour3);
newout->addColoured(newg ,newspace->dataPtr()->iColour()!=PDT::Colour3);
newin ->addColoured(newg ,newspace->dataPtr()->iColour()==PDT::Colour3);
newin ->addColoured(newqbar ,newspace->dataPtr()->iColour()==PDT::Colour3);
}
allBranchings[3]->colourPartner(allBranchings[4]);
allBranchings[4]->colourPartner(allBranchings[3]);
HardTreePtr newTree(new_ptr(HardTree(allBranchings,spaceBranchings,
ShowerInteraction::QCD)));
// Set the maximum pt for all other emissions and connect hard and shower tree
Energy pT = isCompton ? pTCompton_[system] : pTBGF_[system];
// incoming particles
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
// set maximum pT
if(QuarkMatcher::Check(cit->first->progenitor()->data()))
cit->first->maximumpT(pT,ShowerInteraction::QCD);
set<HardBranchingPtr>::iterator cjt=newTree->branchings().begin();
if(cit->first->progenitor()==first.first) {
++cjt;++cjt;++cjt;
}
newTree->connect(cit->first->progenitor(),*cjt);
tPPtr beam =cit->first->original();
if(!beam->parents().empty()) beam=beam->parents()[0];
(*cjt)->beam(beam);
HardBranchingPtr parent=(*cjt)->parent();
while(parent) {
parent->beam(beam);
parent=parent->parent();
};
}
// outgoing particles
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) {
// set maximum pT
if(QuarkMatcher::Check(cit->first->progenitor()->data()))
cit->first->maximumpT(pT,ShowerInteraction::QCD);
for(set<HardBranchingPtr>::iterator cjt=newTree->branchings().begin();
cjt!=newTree->branchings().end();++cjt) {
if((*cjt)->branchingParticle()->isFinalState()&&
(*cjt)->branchingParticle()->id()==cit->first->progenitor()->id()) {
newTree->connect(cit->first->progenitor(),*cjt);
}
}
}
// set the evolution partners and scales
ShowerParticleVector particles;
for(set<HardBranchingPtr>::iterator cit=newTree->branchings().begin();
cit!=newTree->branchings().end();++cit) {
particles.push_back((*cit)->branchingParticle());
}
for(set<HardBranchingPtr>::iterator cjt=newTree->branchings().begin();
cjt!=newTree->branchings().end();++cjt) {
if(cjt==newTree->branchings().begin()) {
(**cjt).showerMomentum((**cjt).branchingParticle()->momentum());
++cjt;
(**cjt).showerMomentum((**cjt).branchingParticle()->momentum());
++cjt;
(**cjt).showerMomentum((**cjt).branchingParticle()->momentum());
++cjt;
}
}
return newTree;
}
void MEPP2HiggsVBF::generateCompton(unsigned int system) {
// calculate the A coefficient for the correlations
acoeff_ = A(partons_[system][0],partons_[system][1],
partons_[system][2],partons_[system][3]);
// maximum value of the xT
double xT = sqrt((1.-xB_[system])/xB_[system]);
double xTMin = 2.*pTmin_/sqrt(q2_[system]);
double zp;
// prefactor
double a = alpha_->overestimateValue()*comptonWeight_/Constants::twopi;
// loop to generate kinematics
double wgt(0.),xp(0.);
l_ = 2.*pother_[system][0]/sqrt(q2_[system]);
m_ = 2.*pother_[system][1]/sqrt(q2_[system]);
vector<double> azicoeff;
do {
wgt = 0.;
// intergration variables dxT/xT^3
xT *= 1./sqrt(1.-2.*log(UseRandom::rnd())/a*sqr(xT));
// dz
zp = UseRandom::rnd();
xp = 1./(1.+0.25*sqr(xT)/zp/(1.-zp));
// check allowed
if(xp<xB_[system]||xp>1.) continue;
// phase-space piece of the weight
wgt = 8.*(1.-xp)*zp/comptonWeight_;
// PDF piece of the weight
Energy2 mu2 = q2_[system]*((1.-xp)*(1-zp)*zp/xp+1.);
double pdf = pdf_[system]->xfx(beam_[system],partons_[system][0],
mu2 ,xB_[system]/xp)/
pdf_[system]->xfx(beam_[system],partons_[system][0],
scale(),xB_[system] );
wgt *= max(pdf,0.);
// me piece of the weight
// double me = comptonME(system,xT,xp,zp,phi);
double x2 = 1.-(1.-zp)/xp;
azicoeff = ComptonME(xp,x2,xT,l_,m_);
double me = 4./3.*alpha_->ratio(0.25*q2_[system]*sqr(xT))*
(azicoeff[0]+0.5*azicoeff[2]+0.5*azicoeff[4]);
wgt *= me;
if(wgt>1.||wgt<0.) {
ostringstream wstring;
wstring << "MEPP2HiggsVBF::generateCompton() "
<< "Weight greater than one or less than zero"
<< "wgt = " << wgt << "\n";
generator()->logWarning( Exception(wstring.str(),
Exception::warning) );
}
}
while(xT>xTMin&&UseRandom::rnd()>wgt);
if(xT<=xTMin) {
pTCompton_[system]=-GeV;
return;
}
// generate phi
unsigned int itry(0);
double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.);
double phiwgt,phi;
do {
phi = UseRandom::rnd()*Constants::twopi;
double cphi(cos(phi)),sphi(sin(phi));
phiwgt = azicoeff[0]+azicoeff[5]*sphi*cphi
+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi)
+azicoeff[3]*sphi+azicoeff[4]*sqr(sphi);
++itry;
}
while (phimax*UseRandom::rnd() > phiwgt && itry<200);
if(itry==200) throw Exception() << "Too many tries in MEPP2HiggsVBF"
<< "::generateCompton() to"
<< " generate phi" << Exception::eventerror;
// momenta for the configuration
Energy Q(sqrt(q2_[system]));
double x1 = -1./xp;
double x2 = 1.-(1.-zp)/xp;
double x3 = 2.+x1-x2;
Lorentz5Momentum p1( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi),
-0.5*Q*x2, 0.5*Q*sqrt(sqr(xT)+sqr(x2)));
Lorentz5Momentum p2(-0.5*Q*xT*cos(phi), -0.5*Q*xT*sin(phi),
-0.5*Q*x3, 0.5*Q*sqrt(sqr(xT)+sqr(x3)));
Lorentz5Momentum p0(ZERO,ZERO,-0.5*Q*x1,-0.5*Q*x1);
pTCompton_[system] = 0.5*Q*xT;
ComptonMomenta_[system].resize(3);
ComptonMomenta_[system][0] = p0;
ComptonMomenta_[system][1] = p1;
ComptonMomenta_[system][2] = p2;
ComptonISFS_[system] = zp>xp;
}
double MEPP2HiggsVBF::comptonME(unsigned int system, double xT,
double xp, double zp, double phi) {
// scale and prefactors
double CFfact = 4./3.*alpha_->ratio(0.25*q2_[system]*sqr(xT));
Energy Q(sqrt(q2_[system]));
double x1 = -1./xp;
double x2 = 1.-(1.-zp)/xp;
double x3 = 2.+x1-x2;
//set NLO momenta
Lorentz5Momentum p1( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi),
-0.5*Q*x2, 0.5*Q*sqrt(sqr(xT)+sqr(x2)));
Lorentz5Momentum p2(-0.5*Q*xT*cos(phi), -0.5*Q*xT*sin(phi),
-0.5*Q*x3, 0.5*Q*sqrt(sqr(xT)+sqr(x3)));
Lorentz5Momentum p0(ZERO,ZERO,-0.5*Q*x1,-0.5*Q*x1);
Lorentz5Momentum qnlo = p2+p1-p0;
// Breit frame variables
Lorentz5Momentum r1 = -p0/x1;
Lorentz5Momentum r2 = p1/x2;
// electroweak parameters
double c0L,c1L,c0R,c1R;
// W
if(partons_[system][0]->id()!=partons_[system][1]->id()) {
c0L = sqrt(0.5);
c0R = 0;
c1L = sqrt(0.5);
c1R = 0;
}
// Z
else {
if(abs(partons_[system][0]->id())%2==0) {
c0L =
generator()->standardModel()->vu()+
generator()->standardModel()->au();
c0R =
generator()->standardModel()->vu()-
generator()->standardModel()->au();
}
else {
c0L =
generator()->standardModel()->vd()+
generator()->standardModel()->ad();
c0R =
generator()->standardModel()->vd()-
generator()->standardModel()->ad();
}
if(abs(partons_[system][2]->id())%2==0) {
c1L =
generator()->standardModel()->vu()+
generator()->standardModel()->au();
c1R =
generator()->standardModel()->vu()-
generator()->standardModel()->au();
}
else {
c1L =
generator()->standardModel()->vd()+
generator()->standardModel()->ad();
c1R =
generator()->standardModel()->vd()-
generator()->standardModel()->ad();
}
c0L *= 0.25;
c0R *= 0.25;
c1L *= 0.25;
c1R *= 0.25;
}
// Matrix element variables
double G1 = sqr(c0L*c1L)+sqr(c0R*c1R);
double G2 = sqr(c0L*c1R)+sqr(c0R*c1L);
Energy4 term1,term2,loME;
if(partons_[system][0]->id()>0) {
if(partons_[system][2]->id()>0) {
term1 = loMatrixElement(r1 ,pother_[system][0],
qnlo+r1 ,pother_[system][1],G1,G2);
term2 = loMatrixElement(r2-qnlo ,pother_[system][0],
r2 ,pother_[system][1],G1,G2);
loME = loMatrixElement(psystem_[system][0],pother_[system][0],
psystem_[system][1],pother_[system][1],G1,G2);
}
else {
term1 = loMatrixElement(r1 ,pother_[system][1],
qnlo+r1 ,pother_[system][0],G1,G2);
term2 = loMatrixElement(r2-qnlo ,pother_[system][1],
r2 ,pother_[system][0],G1,G2);
loME = loMatrixElement(psystem_[system][0],pother_[system][1],
psystem_[system][1],pother_[system][0],G1,G2);
}
}
else {
if(partons_[system][2]->id()>0) {
term1 = loMatrixElement(qnlo+r1 ,pother_[system][0],
r1 ,pother_[system][1],G1,G2);
term2 = loMatrixElement(r2 ,pother_[system][0],
r2-qnlo ,pother_[system][1],G1,G2);
loME = loMatrixElement(psystem_[system][1],pother_[system][0],
psystem_[system][0],pother_[system][1],G1,G2);
}
else {
term1 = loMatrixElement(qnlo+r1,pother_[system][1],r1 ,
pother_[system][0],G1,G2);
term2 = loMatrixElement(r2 ,pother_[system][1],r2-qnlo,
pother_[system][0],G1,G2);
loME = loMatrixElement(psystem_[system][1],pother_[system][1],
psystem_[system][0],pother_[system][0],G1,G2);
}
}
double R1 = term1/loME;
double R2 = sqr(x2)/(sqr(x2)+sqr(xT))*(term2/loME);
// debuggingMatrixElement(false,
// partons_[system][0],partons_[system][1],
// partons_[system][2],partons_[system][3],
// psystem_[system][0],psystem_[system][1],
// pother_ [system][0],pother_ [system][1],
// p0,p1,p2,phiggs_[system],q2_[system],scale(),
// 8.*Constants::pi/(1.-xp)/(1.-zp)*(R1+sqr(xp)*(sqr(x2)+sqr(xT))*R2));
// cerr << "testing pieces A " << R1 << " " << sqr(xp)*(sqr(x2)+sqr(xT)) << " " << R2 << "\n";
return CFfact*(R1+sqr(xp)*(sqr(x2)+sqr(xT))*R2);
}
void MEPP2HiggsVBF::generateBGF(unsigned int system) {
// maximum value of the xT
double xT = (1.-xB_[system])/xB_[system];
double xTMin = 2.*pTmin_/sqrt(q2_[system]);
double zp;
// prefactor
double a = alpha_->overestimateValue()*BGFWeight_/Constants::twopi;
// loop to generate kinematics
double wgt(0.),xp(0.);
l_ = 2.*pother_[system][0]/sqrt(q2_[system]);
m_ = 2.*pother_[system][1]/sqrt(q2_[system]);
vector<double> azicoeff;
do {
wgt = 0.;
// intergration variables dxT/xT^3
xT *= 1./sqrt(1.-2.*log(UseRandom::rnd())/a*sqr(xT));
// dzp
zp = UseRandom::rnd();
xp = 1./(1.+0.25*sqr(xT)/zp/(1.-zp));
// check allowed
if(xp<xB_[system]||xp>1.) continue;
// phase-space piece of the weight
wgt = 8.*sqr(1.-xp)*zp/BGFWeight_;
// PDF piece of the weight
Energy2 mu2 = q2_[system]*((1.-xp)*(1-zp)*zp/xp+1.);
wgt *= pdf_[system]->xfx(beam_[system],gluon_ ,
mu2 ,xB_[system]/xp)/
pdf_[system]->xfx(beam_[system],partons_[system][0],
scale(),xB_[system]);
// me piece of the weight
//double me = BGFME(system,xT,xp,zp,phi);
double x1 = -1./xp;
double x2 = 1.-(1.-zp)/xp;
double x3 = 2.+x1-x2;
azicoeff = BGFME(xp,x2,x3,xT,l_,m_);
double me = 0.5*alpha_->ratio(0.25*q2_[system]*sqr(xT))*
(azicoeff[0]+0.5*azicoeff[2]+0.5*azicoeff[4]);
wgt *= me;
if(wgt>1.||wgt<0.) {
ostringstream wstring;
wstring << "MEPP2HiggsVBF::generateBGF() "
<< "Weight greater than one or less than zero"
<< "wgt = " << wgt << "\n";
generator()->logWarning( Exception(wstring.str(),
Exception::warning) );
}
}
while(xT>xTMin&&UseRandom::rnd()>wgt);
if(xT<=xTMin) {
pTBGF_[system] = -GeV;
return;
}
// generate phi
unsigned int itry(0);
double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.);
double phiwgt,phi;
do {
phi = UseRandom::rnd()*Constants::twopi;
double cphi(cos(phi)),sphi(sin(phi));
phiwgt = azicoeff[0]+azicoeff[5]*sphi*cphi
+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi)
+azicoeff[3]*sphi+azicoeff[4]*sqr(sphi);
++itry;
}
while (phimax*UseRandom::rnd() > phiwgt && itry<200);
if(itry==200) throw Exception() << "Too many tries in MEPP2HiggsVBF"
<< "::generateBGF() to"
<< " generate phi" << Exception::eventerror;
// momenta for the configuration
Energy Q(sqrt(q2_[system]));
double x1 = -1./xp;
double x2 = 1.-(1.-zp)/xp;
double x3 = 2.+x1-x2;
Lorentz5Momentum p1( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi),
-0.5*Q*x2, 0.5*Q*sqrt(sqr(xT)+sqr(x2)));
Lorentz5Momentum p2(-0.5*Q*xT*cos(phi), -0.5*Q*xT*sin(phi),
-0.5*Q*x3, 0.5*Q*sqrt(sqr(xT)+sqr(x3)));
Lorentz5Momentum p0(ZERO,ZERO,-0.5*Q*x1,-0.5*Q*x1);
pTBGF_[system] = 0.5*Q*xT;
BGFMomenta_[system].resize(3);
BGFMomenta_[system][0] = p0;
BGFMomenta_[system][1] = p1;
BGFMomenta_[system][2] = p2;
}
double MEPP2HiggsVBF::BGFME(unsigned int system, double xT,
double xp, double zp, double phi) {
// scale and prefactors
double TRfact = 0.5*alpha_->ratio(0.25*q2_[system]*sqr(xT));
Energy Q(sqrt(q2_[system]));
double x1 = -1./xp;
double x2 = 1.-(1.-zp)/xp;
double x3 = 2.+x1-x2;
// Set NLO momenta
Lorentz5Momentum p1( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi),
-0.5*Q*x2, 0.5*Q*sqrt(sqr(xT)+sqr(x2)));
Lorentz5Momentum p2(-0.5*Q*xT*cos(phi), -0.5*Q*xT*sin(phi),
-0.5*Q*x3, 0.5*Q*sqrt(sqr(xT)+sqr(x3)));
Lorentz5Momentum p0(ZERO,ZERO,-0.5*Q*x1,-0.5*Q*x1);
Lorentz5Momentum qnlo = p2+p1-p0;
// Breit frame variables
Lorentz5Momentum r2 = p1/x2;
Lorentz5Momentum r3 = -p2/x3;
// electroweak parameters
double c0L,c1L,c0R,c1R;
// W
if(partons_[system][0]->id()!=partons_[system][1]->id()) {
c0L = sqrt(0.5);
c0R = 0;
c1L = sqrt(0.5);
c1R = 0;
}
// Z
else {
if(abs(partons_[system][0]->id())%2==0) {
c0L =
generator()->standardModel()->vu()+
generator()->standardModel()->au();
c0R =
generator()->standardModel()->vu()-
generator()->standardModel()->au();
}
else {
c0L =
generator()->standardModel()->vd()+
generator()->standardModel()->ad();
c0R =
generator()->standardModel()->vd()-
generator()->standardModel()->ad();
}
if(abs(partons_[system][2]->id())%2==0) {
c1L =
generator()->standardModel()->vu()+
generator()->standardModel()->au();
c1R =
generator()->standardModel()->vu()-
generator()->standardModel()->au();
}
else {
c1L =
generator()->standardModel()->vd()+
generator()->standardModel()->ad();
c1R =
generator()->standardModel()->vd()-
generator()->standardModel()->ad();
}
c0L *= 0.25;
c0R *= 0.25;
c1L *= 0.25;
c1R *= 0.25;
}
// Matrix element variables
double G1 = sqr(c0L*c1L)+sqr(c0R*c1R);
double G2 = sqr(c0L*c1R)+sqr(c0R*c1L);
Energy4 term2,term3,loME;
if(partons_[system][0]->id()>0) {
if(partons_[system][2]->id()>0) {
term2 = loMatrixElement(r2-qnlo,pother_[system][0],
r2 ,pother_[system][1],G1,G2);
term3 = loMatrixElement(r3 ,pother_[system][0],
qnlo+r3,pother_[system][1],G1,G2);
loME = loMatrixElement(psystem_[system][0],pother_[system][0],
psystem_[system][1],pother_[system][1],G1,G2);
}
else {
term2 = loMatrixElement(r2-qnlo,pother_[system][1],
r2 ,pother_[system][0],G1,G2);
term3 = loMatrixElement(r3 ,pother_[system][1],
qnlo+r3,pother_[system][0],G1,G2);
loME = loMatrixElement(psystem_[system][0],pother_[system][1],
psystem_[system][1],pother_[system][0],G1,G2);
}
}
else {
if(partons_[system][2]->id()>0) {
term2 = loMatrixElement(r2 ,pother_[system][0],
r2-qnlo,pother_[system][1],G1,G2);
term3 = loMatrixElement(qnlo+r3,pother_[system][0],
r3 ,pother_[system][1],G1,G2);
loME = loMatrixElement(psystem_[system][1],pother_[system][0],
psystem_[system][0],pother_[system][1],G1,G2);
}
else {
term2 = loMatrixElement(r2 ,pother_[system][1],
r2-qnlo,pother_[system][0],G1,G2);
term3 = loMatrixElement(qnlo+r3,pother_[system][1],
r3 ,pother_[system][0],G1,G2);
loME = loMatrixElement(psystem_[system][1],pother_[system][1],
psystem_[system][0],pother_[system][0],G1,G2);
}
}
double R3 = sqr(x3)/(sqr(x3)+sqr(xT))*(term3/loME);
double R2 = sqr(x2)/(sqr(x2)+sqr(xT))*(term2/loME);
// debuggingMatrixElement(true,
// partons_[system][0],partons_[system][1],
// partons_[system][2],partons_[system][3],
// psystem_[system][0],psystem_[system][1],
// pother_ [system][0],pother_ [system][1],
// p0,p1,p2,phiggs_[system],q2_[system],
// 8.*Constants::pi/zp/(1.-zp)*(sqr(xp)*(sqr(x3)+sqr(xT))*R3+
// sqr(xp)*(sqr(x2)+sqr(xT))*R2));
return TRfact*
(sqr(xp)*(sqr(x3)+sqr(xT))*R3+
sqr(xp)*(sqr(x2)+sqr(xT))*R2);
}
Energy4 MEPP2HiggsVBF::loMatrixElement(const Lorentz5Momentum &p1,
const Lorentz5Momentum &p2,
const Lorentz5Momentum &q1,
const Lorentz5Momentum &q2,
double G1, double G2) const {
return G1*(p1*p2)*(q1*q2) + G2*(p1*q2)*(q1*p2);
}
void MEPP2HiggsVBF::initializeMECorrection(ShowerTreePtr tree, double & initial,
double & final) {
systems_.clear();
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
if(QuarkMatcher::Check(cit->first->progenitor()->data())) {
systems_.push_back(tChannelPair());
systems_.back().hadron = cit->first->original()->parents()[0];
systems_.back().beam = cit->first->beam();
systems_.back().incoming = cit->first->progenitor();
systems_.back().pdf = systems_.back().beam->pdf();
}
}
vector<ShowerParticlePtr> outgoing;
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt=tree->outgoingLines().begin();cjt!=tree->outgoingLines().end();++cjt) {
if(cjt->first->progenitor()->id()==ParticleID::h0)
higgs_ = cjt->first->progenitor();
else if(QuarkMatcher::Check(cjt->first->progenitor()->data()))
outgoing.push_back(cjt->first->progenitor());
}
assert(outgoing.size()==2&&higgs_);
// match up the quarks
for(unsigned int ix=0;ix<systems_.size();++ix) {
if(systems_[ix].incoming->colourLine()) {
for(unsigned int iy=0;iy<outgoing.size();++iy) {
if(outgoing[iy]->colourLine()==systems_[ix].incoming->colourLine()) {
systems_[ix].outgoing=outgoing[iy];
break;
}
}
}
else {
for(unsigned int iy=0;iy<outgoing.size();++iy) {
if(outgoing[iy]->antiColourLine()==systems_[ix].incoming->antiColourLine()) {
systems_[ix].outgoing=outgoing[iy];
break;
}
}
}
}
assert(systems_[0].outgoing&&systems_[1].outgoing);
assert(systems_.size()==2);
initial = initial_;
final = final_;
}
void MEPP2HiggsVBF::applyHardMatrixElementCorrection(ShowerTreePtr tree) {
static const double eps = 1e-6;
// select emitting line
if(UseRandom::rndbool()) swap(systems_[0],systems_[1]);
// extract the born variables
q_[0] = systems_[0].outgoing->momentum()-systems_[0].incoming->momentum();
q2_[0] = -q_[0].m2();
Energy Q = sqrt(q2_[0]);
xB_[0] = systems_[0].incoming->x();
// construct lorentz transform from lab to breit frame
Lorentz5Momentum phadron = systems_[0].hadron->momentum();
phadron.setMass(0.*GeV);
phadron.rescaleEnergy();
Lorentz5Momentum pcmf = phadron+0.5/xB_[0]*q_[0];
pcmf.rescaleMass();
LorentzRotation rot(-pcmf.boostVector());
Lorentz5Momentum pbeam = rot*phadron;
Axis axis(pbeam.vect().unit());
double sinth(sqrt(sqr(axis.x())+sqr(axis.y())));
rot.rotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.));
Lorentz5Momentum pout = rot*(systems_[1].outgoing->momentum()+higgs_->momentum());
rot.rotateZ(-atan2(pout.y(),pout.x()));
// calculate the A coefficient for the correlations
acoeff_ = A(systems_[0].incoming->dataPtr(),systems_[0].outgoing->dataPtr(),
systems_[1].incoming->dataPtr(),systems_[1].outgoing->dataPtr());
vector<double> azicoeff;
// select the type of process
bool BGF = UseRandom::rnd()>procProb_;
double wgt,xp,zp,x1,x2,x3,xperp;
l_ = 2.*(rot*systems_[1].incoming->momentum())/Q;
m_ = 2.*(rot*systems_[1].outgoing->momentum())/Q;
// compton process
if(!BGF) {
wgt = generateComptonPoint(xp,zp);
if(xp<eps) return;
// common pieces
Energy2 mu2 = q2_[0]*((1.-xp)*(1-zp)*zp/xp+1);
wgt *= 2./3./Constants::pi*alpha_->value(mu2)/procProb_;
// PDF piece
wgt *= systems_[0].pdf->xfx(systems_[0].beam,
systems_[0].incoming->dataPtr(),mu2 ,xB_[0]/xp)/
systems_[0].pdf->xfx(systems_[0].beam,
systems_[0].incoming->dataPtr(),scale(),xB_[0] );
// numerator factors
wgt /= (1.-xp)*(1.-zp);
// other bits
xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp);
x1 = -1./xp;
x2 = 1.-(1.-zp)/xp;
x3 = 2.+x1-x2;
// matrix element pieces
azicoeff = ComptonME(xp,x2,xperp,l_,m_);
}
else {
wgt = generateBGFPoint(xp,zp);
if(xp<1e-6) return;
// common pieces
Energy2 mu2 = q2_[0]*((1.-xp)*(1-zp)*zp/xp+1);
wgt *= 0.25/Constants::pi*alpha_->value(mu2)/(1.-procProb_);
// PDF piece
wgt *= systems_[0].pdf->xfx(systems_[0].beam,
gluon_ ,mu2 ,xB_[0]/xp)/
systems_[0].pdf->xfx(systems_[0].beam,
systems_[0].incoming->dataPtr(),scale(),xB_[0] );
// numerator factors
wgt /= (1.-zp);
// other bits
xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp);
x1 = -1./xp;
x2 = 1.-(1.-zp)/xp;
x3 = 2.+x1-x2;
// matrix element pieces
azicoeff = BGFME(xp,x2,x3,xperp,l_,m_);
}
// compute the azimuthal average of the weight
wgt *= azicoeff[0]+0.5*(azicoeff[2]+azicoeff[4]);
// finally factor as picked one line
wgt *= 2.;
// decide whether or not to accept the weight
if(UseRandom::rnd()>wgt) return;
// if accepted generate generate phi
unsigned int itry(0);
double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.);
double phiwgt,phi;
do {
phi = UseRandom::rnd()*Constants::twopi;
double cphi(cos(phi)),sphi(sin(phi));
phiwgt = azicoeff[0]+azicoeff[5]*sphi*cphi
+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi)
+azicoeff[3]*sphi+azicoeff[4]*sqr(sphi);
++itry;
}
while (phimax*UseRandom::rnd() > phiwgt && itry<200);
if(itry==200) throw Exception() << "Too many tries in VBFMECorrection"
<< "::applyHardMatrixElementCorrection() to"
<< " generate phi" << Exception::eventerror;
// compute the new incoming and outgoing momenta
Lorentz5Momentum p1 = Lorentz5Momentum( 0.5*Q*xperp*cos(phi), 0.5*Q*xperp*sin(phi),
-0.5*Q*x2,0.*GeV,0.*GeV);
p1.rescaleEnergy();
Lorentz5Momentum p2 = Lorentz5Momentum(-0.5*Q*xperp*cos(phi),-0.5*Q*xperp*sin(phi),
-0.5*Q*x3,0.*GeV,0.*GeV);
p2.rescaleEnergy();
Lorentz5Momentum pin(0.*GeV,0.*GeV,-0.5*x1*Q,-0.5*x1*Q,0.*GeV);
// debugging code to test vs helicity amplitude expression for matrix elements
// double cphi(cos(phi)),sphi(sin(phi));
// double old = (azicoeff[0]+azicoeff[5]*sphi*cphi
// +azicoeff[1]*cphi+azicoeff[2]*sqr(cphi)
// +azicoeff[3]*sphi+azicoeff[4]*sqr(sphi));
// if(!BGF) {
// old *= 8.*Constants::pi/(1.-xp)/(1.-zp);
// }
// else {
// old *= 8.*Constants::pi/zp/(1.-zp);
// }
// debuggingMatrixElement(BGF,
// systems_[0].incoming->dataPtr(),
// systems_[0].outgoing->dataPtr(),
// systems_[1].incoming->dataPtr(),
// systems_[1].outgoing->dataPtr(),
// rot*systems_[0].incoming->momentum(),
// rot*systems_[0].outgoing->momentum(),
// rot*systems_[1].incoming->momentum(),
// rot*systems_[1].outgoing->momentum(),
// pin,p1,p2,rot*higgs_->momentum(),
// q2_[0],scale(),old);
// we need inverse of the rotation, i.e back to lab from breit
rot.invert();
// transform the momenta to lab frame
pin *= rot;
p1 *= rot;
p2 *= rot;
// test to ensure outgoing particles can be put on-shell
if(!BGF) {
if(p1.e()<systems_[0].outgoing->dataPtr()->constituentMass()) return;
if(p2.e()<gluon_ ->constituentMass()) return;
}
else {
if(p1.e()<systems_[0].outgoing->dataPtr() ->constituentMass()) return;
if(p2.e()<systems_[0].incoming->dataPtr()->CC()->constituentMass()) return;
}
// stats for weights > 1
if(wgt>1.) {
++nover_;
if(!BGF) maxwgt_.first = max(maxwgt_.first ,wgt);
else maxwgt_.second = max(maxwgt_.second,wgt);
}
// create the new particles and add to ShowerTree
bool isquark = systems_[0].incoming->colourLine();
if(!BGF) {
PPtr newin = new_ptr(Particle(*systems_[0].incoming));
newin->set5Momentum(pin);
PPtr newg = gluon_ ->produceParticle(p2 );
PPtr newout = systems_[0].outgoing->dataPtr()->produceParticle(p1 );
ColinePtr col=isquark ?
systems_[0].incoming->colourLine() : systems_[0].incoming->antiColourLine();
ColinePtr newline=new_ptr(ColourLine());
// final-state emission
if(xp>zp) {
col->removeColoured(newout,!isquark);
col->addColoured(newin,!isquark);
col->addColoured(newg,!isquark);
newline->addColoured(newg,isquark);
newline->addColoured(newout,!isquark);
}
// initial-state emission
else {
col->removeColoured(newin ,!isquark);
col->addColoured(newout,!isquark);
col->addColoured(newg,isquark);
newline->addColoured(newg,!isquark);
newline->addColoured(newin,!isquark);
}
PPtr orig;
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
if(cit->first->progenitor()!=systems_[0].incoming) continue;
// remove old particles from colour line
col->removeColoured(cit->first->copy(),!isquark);
col->removeColoured(cit->first->progenitor(),!isquark);
// insert new particles
cit->first->copy(newin);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newin,1,false)));
cit->first->progenitor(sp);
tree->incomingLines()[cit->first]=sp;
sp->x(xB_[0]/xp);
cit->first->perturbative(xp>zp);
if(xp<=zp) orig=cit->first->original();
}
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) {
if(cit->first->progenitor()!=systems_[0].outgoing) continue;
// remove old particles from colour line
col->removeColoured(cit->first->copy(),!isquark);
col->removeColoured(cit->first->progenitor(),!isquark);
// insert new particles
cit->first->copy(newout);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newout,1,true)));
cit->first->progenitor(sp);
tree->outgoingLines()[cit->first]=sp;
cit->first->perturbative(xp<=zp);
if(xp>zp) orig=cit->first->original();
}
assert(orig);
// add the gluon
ShowerParticlePtr sg=new_ptr(ShowerParticle(*newg,1,true));
ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(orig,newg,sg));
gluon->perturbative(false);
tree->outgoingLines().insert(make_pair(gluon,sg));
tree->hardMatrixElementCorrection(true);
}
else {
PPtr newin = gluon_ ->produceParticle(pin);
PPtr newqbar = systems_[0].incoming->dataPtr()->CC()->produceParticle(p2 );
PPtr newout = systems_[0].outgoing->dataPtr() ->produceParticle(p1 );
ColinePtr col=isquark ? systems_[0].incoming->colourLine() : systems_[0].incoming->antiColourLine();
ColinePtr newline=new_ptr(ColourLine());
col ->addColoured(newin ,!isquark);
newline->addColoured(newin , isquark);
col ->addColoured(newout ,!isquark);
newline->addColoured(newqbar, isquark);
PPtr orig;
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
if(cit->first->progenitor()!=systems_[0].incoming) continue;
// remove old particles from colour line
col->removeColoured(cit->first->copy(),!isquark);
col->removeColoured(cit->first->progenitor(),!isquark);
// insert new particles
cit->first->copy(newin);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newin,1,false)));
cit->first->progenitor(sp);
tree->incomingLines()[cit->first]=sp;
sp->x(xB_[0]/xp);
cit->first->perturbative(false);
orig=cit->first->original();
}
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) {
if(cit->first->progenitor()!=systems_[0].outgoing) continue;
// remove old particles from colour line
col->removeColoured(cit->first->copy(),!isquark);
col->removeColoured(cit->first->progenitor(),!isquark);
// insert new particles
cit->first->copy(newout);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newout,1,true)));
cit->first->progenitor(sp);
tree->outgoingLines()[cit->first]=sp;
cit->first->perturbative(true);
}
assert(orig);
// add the (anti)quark
ShowerParticlePtr sqbar=new_ptr(ShowerParticle(*newqbar,1,true));
ShowerProgenitorPtr qbar=new_ptr(ShowerProgenitor(orig,newqbar,sqbar));
qbar->perturbative(false);
tree->outgoingLines().insert(make_pair(qbar,sqbar));
tree->hardMatrixElementCorrection(true);
}
}
double MEPP2HiggsVBF::A(tcPDPtr qin1, tcPDPtr qout1,
tcPDPtr qin2, tcPDPtr ) {
double output;
// charged current
if(qin1->id()!=qout1->id()) {
output = 2;
}
// neutral current
else {
double cvl,cal,cvq,caq;
if(abs(qin2->id())%2==0) {
cvl = generator()->standardModel()->vu();
cal = generator()->standardModel()->au();
}
else {
cvl = generator()->standardModel()->vd();
cal = generator()->standardModel()->ad();
}
if(abs(qin1->id())%2==0) {
cvq = generator()->standardModel()->vu();
caq = generator()->standardModel()->au();
}
else {
cvq = generator()->standardModel()->vd();
caq = generator()->standardModel()->ad();
}
output = 8.*cvl*cal*cvq*caq/(sqr(cvl)+sqr(cal))/(sqr(cvq)+sqr(caq));
}
if(qin1->id()<0) output *= -1.;
if(qin2->id()<0) output *= -1;
return output;
}
double MEPP2HiggsVBF::generateComptonPoint(double &xp, double & zp) {
static const double maxwgt = 50.;
double wgt,xperp2,x2;
do {
xp = UseRandom::rnd();
double zpmin = xp, zpmax = 1./(1.+xp*(1.-xp));
zp = 1.-pow((1.-zpmin)/(1.-zpmax),UseRandom::rnd())*(1.-zpmax);
wgt = log((1.-zpmin)/(1.-zpmax))*(1.-zp);
if(UseRandom::rndbool()) swap(xp,zp);
xperp2 = 4.*(1.-xp)*(1.-zp)*zp/xp;
x2 = 1.-(1.-zp)/xp;
wgt *= 2.*(1.+sqr(xp)*(sqr(x2)+1.5*xperp2))/(1.-xp)/(1.-zp);
if(wgt>maxwgt)
if(wgt>maxwgt) {
ostringstream wstring;
wstring << "MEPP2HiggsVBF::generateComptonPoint() "
<< "Weight greater than maximum"
<< "wgt = " << wgt << " maxwgt = " << maxwgt << "\n";
generator()->logWarning( Exception(wstring.str(),
Exception::warning) );
}
}
while(wgt<UseRandom::rnd()*maxwgt);
return comptonInt_/((1.+sqr(xp)*(sqr(x2)+1.5*xperp2))/(1.-xp)/(1.-zp));
}
double MEPP2HiggsVBF::generateBGFPoint(double &xp, double & zp) {
static const double maxwgt = 25.;
double wgt;
double x2,x3,xperp2;
do {
xp = UseRandom::rnd();
double zpmax = 1./(1.+xp*(1.-xp)), zpmin = 1.-zpmax;
zp = 1.-pow((1.-zpmin)/(1.-zpmax),UseRandom::rnd())*(1.-zpmax);
wgt = log((1.-zpmin)/(1.-zpmax))*(1.-zp);
double x1 = -1./xp;
x2 = 1.-(1.-zp)/xp;
x3 = 2.+x1-x2;
xperp2 = 4.*(1.-xp)*(1.-zp)*zp/xp;
wgt *= sqr(xp)/(1.-zp)*(sqr(x3)+sqr(x2)+3.*xperp2);
if(wgt>maxwgt) {
ostringstream wstring;
wstring << "DISBase::generateBGFPoint "
<< "Weight greater than maximum "
<< "wgt = " << wgt << " maxwgt = 1\n";
generator()->logWarning( Exception(wstring.str(),
Exception::warning) );
}
}
while(wgt<UseRandom::rnd()*maxwgt);
return bgfInt_/sqr(xp)*(1.-zp)/(sqr(x3)+sqr(x2)+3.*xperp2);
}
bool MEPP2HiggsVBF::softMatrixElementVeto(ShowerProgenitorPtr initial,
ShowerParticlePtr parent,Branching br) {
bool veto = !UseRandom::rndbool(parent->isFinalState() ? 1./final_ : 1./initial_);
// check if me correction should be applied
long id[2]={initial->id(),parent->id()};
if(id[0]!=id[1]||id[1]==ParticleID::g) return veto;
// if not from the right side
if(initial->progenitor()!=systems_[0].incoming &&
initial->progenitor()!=systems_[0].outgoing) return veto;
// get the pT
Energy pT=br.kinematics->pT();
// check if hardest so far
if(pT<initial->highestpT()) return veto;
double kappa(sqr(br.kinematics->scale())/q2_[0]),z(br.kinematics->z());
double zk((1.-z)*kappa);
// final-state
double wgt(0.);
if(parent->isFinalState()) {
double zp=z,xp=1./(1.+z*zk);
double xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp);
double x2 = 1.-(1.-zp)/xp;
vector<double> azicoeff = ComptonME(xp,x2,xperp,l_,m_);
wgt = (azicoeff[0]+0.5*azicoeff[2]+0.5*azicoeff[4])*
xp/(1.+sqr(z))/final_;
if(wgt<.0||wgt>1.) {
ostringstream wstring;
wstring << "Soft ME correction weight too large or "
<< "negative for FSR in MEPP2HiggsVBF::"
<< "softMatrixElementVeto() soft weight "
<< " xp = " << xp << " zp = " << zp
<< " weight = " << wgt << "\n";
generator()->logWarning( Exception(wstring.str(),
Exception::warning) );
}
}
else {
double xp = 2.*z/(1.+zk+sqrt(sqr(1.+zk)-4.*z*zk));
double zp = 0.5* (1.-zk+sqrt(sqr(1.+zk)-4.*z*zk));
double xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp);
double x1 = -1./xp, x2 = 1.-(1.-zp)/xp, x3 = 2.+x1-x2;
// compton
if(br.ids[0]!=ParticleID::g) {
vector<double> azicoeff = ComptonME(xp,x2,xperp,l_,m_);
wgt = (azicoeff[0]+0.5*azicoeff[2]+0.5*azicoeff[4])*
xp*(1.-z)/(1.-xp)/(1.+sqr(z))/(1.-zp+xp-2.*xp*(1.-zp));
}
// BGF
else {
vector<double> azicoeff = BGFME(xp,x2,x3,xperp,l_,m_);
wgt = (azicoeff[0]+0.5*azicoeff[2]+0.5*azicoeff[4])*
xp/(1.-zp+xp-2.*xp*(1.-zp))/(sqr(z)+sqr(1.-z));
}
wgt /=initial_;
if(wgt<.0||wgt>1.) {
ostringstream wstring;
wstring << "Soft ME correction weight too large or "
<< "negative for ISR in MEPP2HiggsVBF::"
<< "softMatrixElementVeto() soft weight "
<< " xp = " << xp << " zp = " << zp
<< " weight = " << wgt << "\n";
generator()->logWarning( Exception(wstring.str(),
Exception::warning) );
}
}
// if not vetoed
if(UseRandom::rndbool(wgt)) return false;
// otherwise
parent->vetoEmission(br.type,br.kinematics->scale());
return true;
}
vector<double> MEPP2HiggsVBF::ComptonME(double xp, double x2, double xperp,
LorentzVector<double> l,
LorentzVector<double> m) {
vector<double> output(6,0.);
double cos2 = x2 /sqrt(sqr(x2)+sqr(xperp));
double sin2 = xperp/sqrt(sqr(x2)+sqr(xperp));
// no phi dependence
output[0] = l.t()*m.t()-l.z()*m.z()*sqr(cos2)+0.5*acoeff_*cos2*(l.t()*m.z()-l.z()*m.t());
// cos(phi)
output[1] = sin2*(-l.x()*m.t()-l.t()*m.x()
+ 0.5*acoeff_*cos2*(l.z()*m.x()-m.z()*l.x()));
// cos(phi)^2
output[2] = +sqr(sin2)*l.x()*m.x();
// sin(phi)
output[3] = sin2*(-l.t()*m.y()-l.y()*m.t()
+ 0.5*acoeff_*cos2*(l.z()*m.y()-m.z()*l.y()));
// sin(phi)^2
output[4] = +sqr(sin2)*l.y()*m.y();
// sin(phi)cos(phi)
output[5] = +sqr(sin2)*(m.y()*l.x()+m.x()*l.y());
// additional factors
double denom = -l.z()*m.z()+l.t()*m.t()+0.5*acoeff_*(l.t()*m.z()-l.z()*m.t());
double fact = sqr(xp)*(sqr(x2)+sqr(xperp))/denom;
for(unsigned int ix=0;ix<output.size();++ix) output[ix] *=fact;
output[0] += 1.;
return output;
}
vector<double> MEPP2HiggsVBF::BGFME(double xp, double x2, double x3,
double xperp,
LorentzVector<double> l,
LorentzVector<double> m) {
vector<double> output(6,0.);
double denom = -l.z()*m.z()+l.t()*m.t()+0.5*acoeff_*(l.t()*m.z()-l.z()*m.t());
double cos2 = x2 /sqrt(sqr(x2)+sqr(xperp));
double sin2 = xperp/sqrt(sqr(x2)+sqr(xperp));
double fact2 = sqr(xp)*(sqr(x2)+sqr(xperp))/denom;
double cos3 = x3 /sqrt(sqr(x3)+sqr(xperp));
double sin3 = xperp/sqrt(sqr(x3)+sqr(xperp));
double fact3 = sqr(xp)*(sqr(x3)+sqr(xperp))/denom;
// no phi dependence
output[0] =
fact2*(l.t()*m.t()-l.z()*m.z()*sqr(cos2)
+ 0.5*acoeff_*cos2*(l.t()*m.z()-l.z()*m.t())) +
fact3*(l.t()*m.t()-l.z()*m.z()*sqr(cos3)
- 0.5*acoeff_*cos3*(l.t()*m.z()-l.z()*m.t()));
// cos(phi)
output[1] =
fact2*sin2*( - l.x()*m.t()-l.t()*m.x()
+ 0.5*acoeff_*cos2*(l.z()*m.x()-m.z()*l.x())) -
fact3*sin3*( - l.x()*m.t()-l.t()*m.x()
- 0.5*acoeff_*cos3*(l.z()*m.x()-m.z()*l.x())) ;
// cos(phi)^2
output[2] = (fact2*sqr(sin2)+fact3*sqr(sin3))*l.x()*m.x();
// sin(phi)
output[3] =
fact2*sin2*( - l.t()*m.y()-l.y()*m.t()
+ 0.5*acoeff_*cos2*(l.z()*m.y()-m.z()*l.y())) -
fact3*sin3*( - l.t()*m.y()-l.y()*m.t()
- 0.5*acoeff_*cos3*(l.z()*m.y()-m.z()*l.y()));
// sin(phi)^2
output[4] = (fact2*sqr(sin2)+fact3*sqr(sin3))*l.y()*m.y();
// sin(phi)cos(phi)
output[5] = (fact2*sqr(sin2)+fact3*sqr(sin3))*(m.y()*l.x()+m.x()*l.y());
// return the answer
return output;
}
diff --git a/MatrixElement/Hadron/MEPP2HiggsVBF.h b/MatrixElement/Hadron/MEPP2HiggsVBF.h
--- a/MatrixElement/Hadron/MEPP2HiggsVBF.h
+++ b/MatrixElement/Hadron/MEPP2HiggsVBF.h
@@ -1,502 +1,501 @@
// -*- C++ -*-
#ifndef HERWIG_MEPP2HiggsVBF_H
#define HERWIG_MEPP2HiggsVBF_H
//
// This is the declaration of the MEPP2HiggsVBF class.
//
#include "Herwig/MatrixElement/MEfftoffH.h"
#include "Herwig/Shower/Couplings/ShowerAlpha.h"
namespace Herwig {
using namespace ThePEG;
/**
* The MEPP2HiggsVBF class provides the matrix elements for the
* production of the Higgs boson via the vector boson fusion mechanism
* in hadron collisions
*
* @see \ref MEPP2HiggsVBFInterfaces "The interfaces"
* defined for MEPP2HiggsVBF.
*/
class MEPP2HiggsVBF: public MEfftoffH {
/**
* Struct to contain the hadronic system
*/
struct tChannelPair{
/**
* The hadron
*/
PPtr hadron;
/**
* The beam particle data object
*/
tcBeamPtr beam;
/**
* The incoming particle
*/
ShowerParticlePtr incoming;
/**
* The outgoing particle
*/
ShowerParticlePtr outgoing;
/**
* The PDF
*/
tcPDFPtr pdf;
};
public:
/**
* The default constructor.
*/
MEPP2HiggsVBF();
/** @name Virtual functions required by the MEBase class. */
//@{
/**
* Add all possible diagrams with the add() function.
*/
virtual void getDiagrams() const;
//@}
/**
* Virtual members to be overridden by inheriting classes
* which implement hard corrections
*/
//@{
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return Both;}
/**
* Has an old fashioned ME correction
*/
virtual bool hasMECorrection() {return true;}
/**
* Initialize the ME correction
*/
virtual void initializeMECorrection(ShowerTreePtr , double & ,
double & );
/**
* Apply the hard matrix element correction to a given hard process or decay
*/
virtual void applyHardMatrixElementCorrection(ShowerTreePtr);
/**
* Apply the soft matrix element correction
* @param initial The particle from the hard process which started the
* shower
* @param parent The initial particle in the current branching
* @param br The branching struct
* @return If true the emission should be vetoed
*/
virtual bool softMatrixElementVeto(ShowerProgenitorPtr,
ShowerParticlePtr,Branching);
/**
* Apply the POWHEG style correction
*/
- virtual HardTreePtr generateHardest(ShowerTreePtr,
- vector<ShowerInteraction::Type>);
+ virtual HardTreePtr generateHardest(ShowerTreePtr, ShowerInteraction::Type);
//@}
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/**
* Generate the hardest emission in the POWHEG approach
*/
//@{
/**
* Generate a Compton process
*/
void generateCompton(unsigned int system);
/**
* Generate a BGF process
*/
void generateBGF(unsigned int system);
/**
* Matrix element piece for the Compton process
*/
double comptonME(unsigned int system,
double xT,double xp, double zp, double phi);
/**
* Matrix element piece for the Compton process
*/
double BGFME(unsigned int system,
double xT,double xp, double zp, double phi);
/**
* Leading order matrix element
*/
Energy4 loMatrixElement(const Lorentz5Momentum &p1,
const Lorentz5Momentum &p2,
const Lorentz5Momentum &q1,
const Lorentz5Momentum &q2,
double G1, double G2) const;
//@}
/**
* Generate the hard emission in the old-fashioned matrix element correction approach
*/
//@{
/**
* Generate the values of \f$x_p\f$ and \f$z_p\f$
* @param xp The value of xp, output
* @param zp The value of zp, output
*/
double generateComptonPoint(double &xp, double & zp);
/**
* Generate the values of \f$x_p\f$ and \f$z_p\f$
* @param xp The value of xp, output
* @param zp The value of zp, output
*/
double generateBGFPoint(double &xp, double & zp);
/**
* Return the coefficients for the matrix element piece for
* the QCD compton case. The output is the \f$a_i\f$ coefficients to
* give the function as
* \f$a_0+a_1\cos\phi+a_2\sin\phi+a_3\cos^2\phi+a_4\sin^2\phi\f$
* @param xp \f$x_p\f$
* @param x2 \f$x_2\f$
* @param xperp \f$x_\perp\f$
* @param l Scaled momentum of incoming spectator
* @param m Scaled momentum of outgoing spectator
*
*/
vector<double> ComptonME(double xp, double x2, double xperp,
LorentzVector<double> l,
LorentzVector<double> m);
/**
* Return the coefficients for the matrix element piece for
* the QCD compton case. The output is the \f$a_i\f$ coefficients to
* give the function as
* \f$a_0+a_1\cos\phi+a_2\sin\phi+a_3\cos^2\phi+a_4\sin^2\phi\f$
* @param xp \f$x_p\f$
* @param x2 \f$x_3\f$
* @param x3 \f$x_2\f$
* @param xperp \f$x_\perp\f$
* @param l Scaled momentum of incoming spectator
* @param m Scaled momentum of outgoing spectator
*
*/
vector<double> BGFME(double xp, double x2, double x3, double xperp,
LorentzVector<double> l,
LorentzVector<double> m);
/**
* Calculate the coefficient A for the correlations
*/
double A(tcPDPtr qin1, tcPDPtr qout1, tcPDPtr qin2, tcPDPtr qout2);
//@}
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
/**
* Finalize this object. Called in the run phase just after a
* run has ended. Used eg. to write out statistics.
*/
virtual void dofinish();
//@}
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const { return new_ptr(*this); }
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const { return new_ptr(*this); }
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<MEPP2HiggsVBF> initMEPP2HiggsVBF;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEPP2HiggsVBF & operator=(const MEPP2HiggsVBF &);
private:
/**
* Parameters for the hard POWHEG emission
*/
//@{
/**
* Pointer to the object calculating the strong coupling
*/
ShowerAlphaPtr alpha_;
/**
* Weight for the compton channel
*/
double comptonWeight_;
/**
* Weight for the BGF channel
*/
double BGFWeight_;
/**
* Minimum value of \f$p_T\f$
*/
Energy pTmin_;
/**
* Gluon particle data object
*/
PDPtr gluon_;
//@}
/**
* Properties of the emission
*/
//@{
/**
* Beam particle
*/
tcBeamPtr beam_[2];
/**
* PDF object
*/
tcPDFPtr pdf_[2];
/**
* Partons
*/
tcPDPtr partons_[2][4];
/**
* q
*/
Lorentz5Momentum q_[2];
/**
* \f$Q^2\f$
*/
Energy2 q2_[2];
/**
* Coupling factor
*/
double acoeff_;
/**
* Lorentz vectors for the matrix element
*/
LorentzVector<double> l_;
/**
* Lorentz vectors for the matrix element
*/
LorentzVector<double> m_;
/**
* Born momentum fraction
*/
double xB_[2];
/**
* Rotation to the Breit frame
*/
LorentzRotation rot_[2];
/**
* Quark momenta for spectator system
*/
Lorentz5Momentum pother_[2][2];
/**
* Quark momenta for emitting system
*/
Lorentz5Momentum psystem_[2][2];
/**
* Higgs momenta
*/
Lorentz5Momentum phiggs_[2];
/**
* Transverse momenta for the compton emissions
*/
Energy pTCompton_[2];
/**
* Transverse momenta for the BGF emissions
*/
Energy pTBGF_[2];
/**
* Whether the Compton radiation is ISR or FSR
*/
bool ComptonISFS_[2];
/**
* Momenta of the particles for a compton emission
*/
vector<Lorentz5Momentum> ComptonMomenta_[2];
/**
* Momenta of the particles for a BGF emission
*/
vector<Lorentz5Momentum> BGFMomenta_[2];
/**
* the systems
*/
vector<tChannelPair> systems_;
/**
* Higgs boson
*/
ShowerParticlePtr higgs_;
//@}
/**
* Parameters for the matrix element correction
*/
//@{
/**
* Enchancement factor for ISR
*/
double initial_;
/**
* Enchancement factor for FSR
*/
double final_;
/**
* Relative fraction of compton and BGF processes to generate
*/
double procProb_;
/**
* Integral for compton process
*/
double comptonInt_;
/**
* Integral for BGF process
*/
double bgfInt_;
/**
* Number of weights greater than 1
*/
unsigned int nover_;
/**
* Maximum weight
*/
pair<double,double> maxwgt_;
//@}
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of MEPP2HiggsVBF. */
template <>
struct BaseClassTrait<Herwig::MEPP2HiggsVBF,1> {
/** Typedef of the first base class of MEPP2HiggsVBF. */
typedef Herwig::MEfftoffH NthBase;
};
/** This template specialization informs ThePEG about the name of
* the MEPP2HiggsVBF class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::MEPP2HiggsVBF>
: public ClassTraitsBase<Herwig::MEPP2HiggsVBF> {
/** Return a platform-independent class name */
static string className() { return "Herwig::MEPP2HiggsVBF"; }
/**
* The name of a file containing the dynamic library where the class
* MEPP2HiggsVBF is implemented. It may also include several, space-separated,
* libraries if the class MEPP2HiggsVBF depends on other classes (base classes
* excepted). In this case the listed libraries will be dynamically
* linked in the order they are specified.
*/
static string library() { return "HwMEHadron.so"; }
};
/** @endcond */
}
#endif /* HERWIG_MEPP2HiggsVBF_H */
diff --git a/MatrixElement/HwMEBase.cc b/MatrixElement/HwMEBase.cc
--- a/MatrixElement/HwMEBase.cc
+++ b/MatrixElement/HwMEBase.cc
@@ -1,289 +1,289 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the HwMEBase class.
//
#include "HwMEBase.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Utilities/SimplePhaseSpace.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "Herwig/PDT/GenericMassGenerator.h"
#include "ThePEG/Cuts/Cuts.h"
#include "Herwig/Shower/Base/HardTree.h"
#include "Herwig/Shower/Base/Branching.h"
using namespace Herwig;
void HwMEBase::persistentOutput(PersistentOStream & os) const {
os << massOption_ << rescaleOption_;
}
void HwMEBase::persistentInput(PersistentIStream & is, int) {
is >> massOption_ >> rescaleOption_;
}
AbstractClassDescription<HwMEBase> HwMEBase::initHwMEBase;
// Definition of the static class description member.
void HwMEBase::Init() {
static ClassDocumentation<HwMEBase> documentation
("The HwMEBase class is the base class for matrix elements in Herwig"
" and provides the virtual members for hard radiation corrections in the"
" shower.");
}
int HwMEBase::nDim() const {
unsigned ndim = 1;
for(unsigned int ix=0;ix<massOption_.size();++ix)
if(massOption_[ix]==2) ++ndim;
return ndim;
}
CrossSection HwMEBase::dSigHatDR() const {
return me2()*jacobian()/(16.0*sqr(Constants::pi)*sHat())*sqr(hbarc);
}
void HwMEBase::setKinematics() {
MEBase::setKinematics();
lastTHat_ = (meMomenta()[0] - meMomenta()[2]).m2();
lastUHat_ = (meMomenta()[1] - meMomenta()[2]).m2();
lastPhi_ = meMomenta()[2].phi();
}
bool HwMEBase::generateMasses(vector<Energy> & masses, double & mjac,
const double *r) {
assert(massOption_.size()+2==mePartonData().size());
mjac = 1.;
masses.clear();
masses.resize(massOption_.size(),ZERO);
Energy ecm = sqrt(sHat());
Energy emin(ZERO);
int noff(0);
for(unsigned int ix=0;ix<massOption_.size();++ix) {
if(massOption_[ix]==1) {
masses[ix] = mePartonData()[ix+2]->hardProcessMass();
emin += masses[ix];
}
else if (massOption_[ix]==2) {
emin += mePartonData()[ix+2]->massMin();
++noff;
}
}
// check allowed
if(emin>ecm) return false;
// if nothing off-shell return
if(noff==0) return true;
int iloc = nDim()-noff;
emin = ecm - emin;
// generate the masses
for(unsigned int ix=0;ix<massOption_.size();++ix) {
if(massOption_[ix]!=2) continue;
Energy mmin = mePartonData()[ix+2]->massMin();
emin += mmin;
Energy mmax = min(mePartonData()[ix+2]->massMax(),emin);
if(mmin>mmax) return false;
tGenericMassGeneratorPtr gen = mePartonData()[ix+2]->massGenerator() ?
dynamic_ptr_cast<tGenericMassGeneratorPtr>(mePartonData()[ix+2]->massGenerator()) :
tGenericMassGeneratorPtr();
if(gen) {
double jtemp(0.);
masses[ix] = gen->mass(jtemp,*mePartonData()[ix+2],mmin,mmax,r[iloc]);
mjac *= jtemp;
}
else {
Energy mon(mePartonData()[ix+2]->hardProcessMass());
Energy width(mePartonData()[ix+2]->width());
double rhomin = atan2((sqr(mmin)-sqr(mon)), mon*width);
double rhomax = atan2((sqr(mmax)-sqr(mon)), mon*width);
masses[ix] = sqrt(mon*width*tan(rhomin+r[iloc]*(rhomax-rhomin))+sqr(mon));
mjac *= (rhomax-rhomin)/Constants::pi;
}
emin -= masses[ix];
if(emin<ZERO) return false;
++iloc;
}
return true;
}
bool HwMEBase::generateKinematics(const double * r) {
jacobian(1.);
vector<Energy> masses;
double mjac(0.);
if(!generateMasses(masses,mjac,r)) return false;
// set up the momenta
for ( int i = 2, N = meMomenta().size(); i < N; ++i ) {
meMomenta()[i] = Lorentz5Momentum(masses[i-2]);
}
double ctmin = -1.0, ctmax = 1.0;
Energy q = ZERO;
try {
q = SimplePhaseSpace::
getMagnitude(sHat(), meMomenta()[2].mass(), meMomenta()[3].mass());
}
catch ( ImpossibleKinematics ) {
return false;
}
Energy e = sqrt(sHat())/2.0;
Energy2 m22 = meMomenta()[2].mass2();
Energy2 m32 = meMomenta()[3].mass2();
Energy2 e0e2 = 2.0*e*sqrt(sqr(q) + m22);
Energy2 e1e2 = 2.0*e*sqrt(sqr(q) + m22);
Energy2 e0e3 = 2.0*e*sqrt(sqr(q) + m32);
Energy2 e1e3 = 2.0*e*sqrt(sqr(q) + m32);
Energy2 pq = 2.0*e*q;
Energy2 thmin = lastCuts().minTij(mePartonData()[0], mePartonData()[2]);
if ( thmin > ZERO ) ctmax = min(ctmax, (e0e2 - m22 - thmin)/pq);
thmin = lastCuts().minTij(mePartonData()[1], mePartonData()[2]);
if ( thmin > ZERO ) ctmin = max(ctmin, (thmin + m22 - e1e2)/pq);
thmin = lastCuts().minTij(mePartonData()[1], mePartonData()[3]);
if ( thmin > ZERO ) ctmax = min(ctmax, (e1e3 - m32 - thmin)/pq);
thmin = lastCuts().minTij(mePartonData()[0], mePartonData()[3]);
if ( thmin > ZERO ) ctmin = max(ctmin, (thmin + m32 - e0e3)/pq);
Energy ptmin = max(lastCuts().minKT(mePartonData()[2]),
lastCuts().minKT(mePartonData()[3]));
if ( ptmin > ZERO ) {
double ctm = 1.0 - sqr(ptmin/q);
if ( ctm <= 0.0 ) return false;
ctmin = max(ctmin, -sqrt(ctm));
ctmax = min(ctmax, sqrt(ctm));
}
double ymin2 = lastCuts().minYStar(mePartonData()[2]);
double ymax2 = lastCuts().maxYStar(mePartonData()[2]);
double ymin3 = lastCuts().minYStar(mePartonData()[3]);
double ymax3 = lastCuts().maxYStar(mePartonData()[3]);
double ytot = lastCuts().Y() + lastCuts().currentYHat();
if ( ymin2 + ytot > -0.9*Constants::MaxRapidity )
ctmin = max(ctmin, sqrt(sqr(q) + m22)*tanh(ymin2)/q);
if ( ymax2 + ytot < 0.9*Constants::MaxRapidity )
ctmax = min(ctmax, sqrt(sqr(q) + m22)*tanh(ymax2)/q);
if ( ymin3 + ytot > -0.9*Constants::MaxRapidity )
ctmax = min(ctmax, sqrt(sqr(q) + m32)*tanh(-ymin3)/q);
if ( ymax3 + ytot < 0.9*Constants::MaxRapidity )
ctmin = max(ctmin, sqrt(sqr(q) + m32)*tanh(-ymax3)/q);
if ( ctmin >= ctmax ) return false;
double cth = getCosTheta(ctmin, ctmax, r[0]);
Energy pt = q*sqrt(1.0-sqr(cth));
phi(rnd(2.0*Constants::pi));
meMomenta()[2].setVect(Momentum3( pt*sin(phi()), pt*cos(phi()), q*cth));
meMomenta()[3].setVect(Momentum3(-pt*sin(phi()), -pt*cos(phi()), -q*cth));
meMomenta()[2].rescaleEnergy();
meMomenta()[3].rescaleEnergy();
vector<LorentzMomentum> out(2);
out[0] = meMomenta()[2];
out[1] = meMomenta()[3];
tcPDVector tout(2);
tout[0] = mePartonData()[2];
tout[1] = mePartonData()[3];
if ( !lastCuts().passCuts(tout, out, mePartonData()[0], mePartonData()[1]) )
return false;
tHat(pq*cth + m22 - e0e2);
uHat(m22 + m32 - sHat() - tHat());
jacobian((pq/sHat())*Constants::pi*jacobian()*mjac);
// compute the rescaled momenta
return rescaleMomenta(meMomenta(),mePartonData());
}
bool HwMEBase::rescaleMomenta(const vector<Lorentz5Momentum> & momenta,
const cPDVector & data) {
assert(momenta.size()==4&&data.size()==4);
// default just use the ones we generated
rescaledMomenta_=momenta;
if(rescaleOption_==1) return true;
Energy mnew[2] = {0*MeV, ZERO};
if(rescaleOption_==0) {
mnew[0] = ZERO;
mnew[1] = ZERO;
}
else if(rescaleOption_==2) {
mnew[0] = data[2]->hardProcessMass();
mnew[1] = data[3]->hardProcessMass();
}
else if(rescaleOption_==3) {
if(abs(data[2]->id())!=abs(data[3]->id())) return true;
mnew[0] = 0.5*(momenta[2].mass()+momenta[3].mass());
mnew[1] = mnew[0];
}
else {
assert(false);
}
Lorentz5Momentum pcm(momenta[2]+momenta[3]);
Energy m0=pcm.m();
if(m0<mnew[0]+mnew[1]) return false;
Boost bv = pcm.boostVector();
rescaledMomenta_[2].boost(bv);
rescaledMomenta_[2].setMass(mnew[0]);
rescaledMomenta_[2].setE(0.5*(sqr(m0)+sqr(mnew[0])-sqr(mnew[1]))/m0);
if(rescaledMomenta_[2].t()-rescaledMomenta_[2].mass()>1e-10*(rescaledMomenta_[2].t()+rescaledMomenta_[2].mass()))
rescaledMomenta_[2].rescaleRho();
else {
rescaledMomenta_[2].setX(ZERO);
rescaledMomenta_[2].setY(ZERO);
rescaledMomenta_[2].setZ(ZERO);
}
rescaledMomenta_[2].boost(-bv);
rescaledMomenta_[3].boost(bv);
rescaledMomenta_[3].setMass(mnew[1]);
rescaledMomenta_[3].setE(0.5*(sqr(m0)-sqr(mnew[0])+sqr(mnew[1]))/m0);
if(rescaledMomenta_[3].t()-rescaledMomenta_[3].mass()>1e-10*(rescaledMomenta_[3].t()+rescaledMomenta_[3].mass()))
rescaledMomenta_[3].rescaleRho();
else {
rescaledMomenta_[3].setX(ZERO);
rescaledMomenta_[3].setY(ZERO);
rescaledMomenta_[3].setZ(ZERO);
}
rescaledMomenta_[3].boost(-bv);
return true;
}
double HwMEBase::getCosTheta(double ctmin, double ctmax, const double r) {
double cth = 0.0;
static const double eps = 1.0e-6;
if ( 1.0 + ctmin <= eps && 1.0 - ctmax <= eps ) {
jacobian(jacobian()*(ctmax - ctmin));
cth = ctmin + r*(ctmax - ctmin);
} else if ( 1.0 + ctmin <= eps ) {
cth = 1.0 - (1.0 - ctmax)*pow((1.0 - ctmin)/(1.0 - ctmax), r);
jacobian(jacobian()*log((1.0 - ctmin)/(1.0 - ctmax))*(1.0 - cth));
} else if ( 1.0 - ctmax <= eps ) {
cth = -1.0 + (1.0 + ctmin)*pow((1.0 + ctmax)/(1.0 + ctmin), r);
jacobian(jacobian()*log((1.0 + ctmax)/(1.0 + ctmin))*(1.0 + cth));
} else {
double zmin = 0.5*(1.0 - ctmax);
double zmax = 0.5*(1.0 - ctmin);
double A1 = -ctmin/(zmax*(1.0-zmax));
double A0 = -ctmax/(zmin*(1.0-zmin));
double A = r*(A1 - A0) + A0;
double z = A < 2.0? 2.0/(sqrt(sqr(A) + 4.0) + 2 - A):
0.5*(A - 2.0 + sqrt(sqr(A) + 4.0))/A;
cth = 1.0 - 2.0*z;
jacobian(jacobian()*2.0*(A1 - A0)*sqr(z)*sqr(1.0 - z)/(sqr(z) + sqr(1.0 - z)));
}
return cth;
}
bool HwMEBase::softMatrixElementVeto(ShowerProgenitorPtr,
ShowerParticlePtr,Branching) {
return false;
}
-HardTreePtr HwMEBase::generateHardest(ShowerTreePtr,vector<ShowerInteraction::Type>) {
+HardTreePtr HwMEBase::generateHardest(ShowerTreePtr,ShowerInteraction::Type) {
return HardTreePtr();
}
diff --git a/MatrixElement/HwMEBase.h b/MatrixElement/HwMEBase.h
--- a/MatrixElement/HwMEBase.h
+++ b/MatrixElement/HwMEBase.h
@@ -1,319 +1,319 @@
// -*- C++ -*-
#ifndef HERWIG_HwMEBase_H
#define HERWIG_HwMEBase_H
//
// This is the declaration of the HwMEBase class.
//
#include "ThePEG/MatrixElement/MEBase.h"
#include "Herwig/Shower/Base/ShowerParticle.fh"
#include "Herwig/Shower/Base/ShowerProgenitor.fh"
#include "Herwig/Shower/Base/ShowerTree.fh"
#include "Herwig/Shower/Base/HardTree.fh"
#include "Herwig/Shower/ShowerConfig.h"
#include "ThePEG/PDF/BeamParticleData.h"
#include "HwMEBase.fh"
namespace Herwig {
struct Branching;
using namespace ThePEG;
typedef Ptr<BeamParticleData>::transient_const_pointer tcBeamPtr;
/**
* The HwMEBase class serves a number of purposes
* - it implements the phase space for \f$2\to2\f$ scattering processes
* - it provides virtual members for the implementation of hard radiation
* - it gives us greater control over the masses of the outgoing
* particles so that they can be
* - set massless where required by gauge invariance
* - have their off-shell masses generated using the sophisticated approaches
* available in Herwig.
*
* @see \ref HwMEBaseInterfaces "The interfaces"
* defined for HwMEBase.
*/
class HwMEBase: public MEBase {
public:
/**
* Default constructor.
*/
HwMEBase() : lastTHat_(ZERO), lastUHat_(ZERO),
lastPhi_(0.0), rescaleOption_(1)
{}
/** @name Virtual functions required by the MEBase class. */
//@{
/**
* The number of internal degreed of freedom used in the matrix
* element.
*/
virtual int nDim() const;
/**
* Generate internal degrees of freedom given 'nDim()' uniform
* random numbers in the interval ]0,1[. To help the phase space
* generator, the 'dSigHatDR()' should be a smooth function of these
* numbers, although this is not strictly necessary. Return
* false if the chosen points failed the kinematical cuts.
*/
virtual bool generateKinematics(const double * r);
/**
* Return the matrix element for the kinematical configuation
* previously provided by the last call to setKinematics(). Uses
* me().
*/
virtual CrossSection dSigHatDR() const;
/**
* Set the typed and momenta of the incoming and outgoing partons to
* be used in subsequent calls to me() and colourGeometries()
* according to the associated XComb object.
*/
virtual void setKinematics();
//@}
/**
* Virtual members to be overridden by inheriting classes
* which implement hard corrections
*/
//@{
/**
* Type of POWHEG correction
*/
enum POWHEGType {No, ISR, FSR, Both};
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return No;}
/**
* Has an old fashioned ME correction
*/
virtual bool hasMECorrection() {return false;}
/**
* Initialize the ME correction
*/
virtual void initializeMECorrection(ShowerTreePtr , double & ,
double & ) {}
/**
* Apply the hard matrix element correction to a given hard process or decay
*/
virtual void applyHardMatrixElementCorrection(ShowerTreePtr) {}
/**
* Apply the soft matrix element correction
* @param initial The particle from the hard process which started the
* shower
* @param parent The initial particle in the current branching
* @param br The branching struct
* @return If true the emission should be vetoed
*/
virtual bool softMatrixElementVeto(ShowerProgenitorPtr initial,
ShowerParticlePtr parent,
Branching br);
/**
* Apply the POWHEG style correction
*/
- virtual HardTreePtr generateHardest(ShowerTreePtr,vector<ShowerInteraction::Type>);
+ virtual HardTreePtr generateHardest(ShowerTreePtr,ShowerInteraction::Type);
//@}
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Access cached values in of the last set phase space point. */
//@{
/**
* Return the \f$\hat{t}\f$ of the last set phase space point.
*/
Energy2 tHat() const { return lastTHat_; }
/**
* Return the \f$\hat{u}\f$ of the last set phase space point.
*/
Energy2 uHat() const { return lastUHat_; }
/**
* Return the azimuth angle of the last set phase space point.
*/
double phi() const { return lastPhi_; }
//@}
/** @name Set the cached values in of the last set phase space point. */
//@{
/**
* Set the \f$\hat{t}\f$ of the last set phase space point.
*/
void tHat(Energy2 e2) { lastTHat_ = e2; }
/**
* Set the \f$\hat{u}\f$ of the last set phase space point.
*/
void uHat(Energy2 e2) { lastUHat_ = e2; }
/**
* Set the azimuth angle of the last set phase space point.
*/
void phi(double phi) { lastPhi_ = phi; }
//@}
/**
* Set the treatment of the outgoing masses
* @param iopt The option for the treatment of the mass
*/
void massOption(vector<unsigned int> iopt) {
massOption_ = iopt;
}
/**
* Rescaled momenta for the helicity ME
*/
//@{
/**
* Set the treatment of the rescaling of the momenta for
* the matrix element calculation
* @param iopt The rescaling option
*/
void rescalingOption(unsigned int iopt) {
rescaleOption_=iopt;
}
/**
* rescale the momenta for the computation of the helicity matrix element
*/
bool rescaleMomenta(const vector<Lorentz5Momentum> &,
const cPDVector &);
/**
* Access to the rescaled momenta
*/
const vector<Lorentz5Momentum> & rescaledMomenta() const {
return rescaledMomenta_;
}
//@}
/**
* Generate the masses of the particles
*/
bool generateMasses(vector<Energy> & masses, double & mjac,
const double *r);
/**
* Used internally by generateKinematics, after calculating the
* limits on cos(theta).
*/
virtual double getCosTheta(double cthmin, double cthmax, const double r);
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is an abstract class without persistent data.
*/
static AbstractClassDescription<HwMEBase> initHwMEBase;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
HwMEBase & operator=(const HwMEBase &);
private:
/**
* Option for the treatment of the particle masses
*/
vector<unsigned int> massOption_;
/**
* The \f$\hat{t}\f$ of the last set phase space point.
*/
Energy2 lastTHat_;
/**
* The \f$\hat{u}\f$ of the last set phase space point.
*/
Energy2 lastUHat_;
/**
* The azimuth angle of the last set phase space point.
*/
double lastPhi_;
/**
* Produced to produce rescaled momenta
*/
unsigned int rescaleOption_;
/**
* Rescaled momenta for use in ME calculations
*/
vector<Lorentz5Momentum> rescaledMomenta_;
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of HwMEBase. */
template <>
struct BaseClassTrait<Herwig::HwMEBase,1> {
/** Typedef of the first base class of HwMEBase. */
typedef MEBase NthBase;
};
/** This template specialization informs ThePEG about the name of
* the HwMEBase class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::HwMEBase>
: public ClassTraitsBase<Herwig::HwMEBase> {
/** Return a platform-independent class name */
static string className() { return "Herwig::HwMEBase"; }
};
/** @endcond */
}
#endif /* HERWIG_HwMEBase_H */
diff --git a/MatrixElement/Lepton/MEee2gZ2ll.cc b/MatrixElement/Lepton/MEee2gZ2ll.cc
--- a/MatrixElement/Lepton/MEee2gZ2ll.cc
+++ b/MatrixElement/Lepton/MEee2gZ2ll.cc
@@ -1,764 +1,758 @@
// -*- C++ -*-
//
// MEee2gZ2ll.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEee2gZ2ll class.
//
#include "MEee2gZ2ll.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "Herwig/MatrixElement/HardVertex.h"
#include "ThePEG/PDF/PolarizedBeamParticleData.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include <numeric>
#include "Herwig/Shower/Base/ShowerTree.h"
#include "Herwig/Shower/Base/ShowerProgenitor.h"
#include "Herwig/Shower/Base/ShowerParticle.h"
#include "Herwig/Shower/Base/Branching.h"
#include "Herwig/Shower/Base/HardTree.h"
using namespace Herwig;
void MEee2gZ2ll::getDiagrams() const {
// specific the diagrams
tcPDPtr ep = getParticleData(ParticleID::eplus);
tcPDPtr em = getParticleData(ParticleID::eminus);
// setup the processes
for( int i =11;i<=16;++i) {
if(allowed_==0 || (allowed_==1 && i%2==1) || (allowed_==2&&i==11)
|| (allowed_==3&&i==13) || (allowed_==4&&i==15)) {
tcPDPtr lm = getParticleData(i);
tcPDPtr lp = lm->CC();
add(new_ptr((Tree2toNDiagram(2), em, ep, 1, gamma_, 3, lm, 3, lp, -1)));
add(new_ptr((Tree2toNDiagram(2), em, ep, 1, Z0_, 3, lm, 3, lp, -2)));
}
}
}
Energy2 MEee2gZ2ll::scale() const {
return sHat();
}
unsigned int MEee2gZ2ll::orderInAlphaS() const {
return 0;
}
unsigned int MEee2gZ2ll::orderInAlphaEW() const {
return 2;
}
Selector<MEBase::DiagramIndex>
MEee2gZ2ll::diagrams(const DiagramVector & diags) const {
double lastCont(0.5),lastBW(0.5);
if ( lastXCombPtr() ) {
lastCont = meInfo()[0];
lastBW = meInfo()[1];
}
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i ) {
if ( diags[i]->id() == -1 ) sel.insert(lastCont, i);
else if ( diags[i]->id() == -2 ) sel.insert(lastBW, i);
}
return sel;
}
Selector<const ColourLines *>
MEee2gZ2ll::colourGeometries(tcDiagPtr) const {
static ColourLines ctST(" ");
Selector<const ColourLines *> sel;
sel.insert(1.0, &ctST);
return sel;
}
void MEee2gZ2ll::persistentOutput(PersistentOStream & os) const {
os << allowed_ << FFZVertex_ << FFPVertex_ << gamma_ << Z0_
<< alphaQED_ << ounit(pTmin_,GeV) << preFactor_;
}
void MEee2gZ2ll::persistentInput(PersistentIStream & is, int) {
is >> allowed_ >> FFZVertex_ >> FFPVertex_ >> gamma_ >> Z0_
>> alphaQED_ >> iunit(pTmin_,GeV) >> preFactor_;
}
// *** Attention *** The following static variable is needed for the type
// description system in ThePEG. Please check that the template arguments
// are correct (the class and its base class), and that the constructor
// arguments are correct (the class name and the name of the dynamically
// loadable library where the class implementation can be found).
DescribeClass<MEee2gZ2ll,HwMEBase>
describeMEee2gZ2ll("Herwig::MEee2gZ2ll", "HwMELepton.so");
void MEee2gZ2ll::Init() {
static ClassDocumentation<MEee2gZ2ll> documentation
("The MEee2gZ2ll class implements the matrix element for"
"e+e- to leptons via Z and photon exchange using helicity amplitude"
"techniques");
static Switch<MEee2gZ2ll,int> interfaceallowed
("Allowed",
"Allowed outgoing leptons",
&MEee2gZ2ll::allowed_, 0, false, false);
static SwitchOption interfaceallowedAll
(interfaceallowed,
"All",
"Allow all leptons as outgoing particles",
0);
static SwitchOption interfaceallowedCharged
(interfaceallowed,
"Charged",
"Only charged leptons as outgoing particles",
1);
static SwitchOption interfaceallowedElectron
(interfaceallowed,
"Electron",
"Only the electron and positron as outgoing leptons",
2);
static SwitchOption interfaceallowedMuon
(interfaceallowed,
"Muon",
"Only muons as outgoing particles",
3);
static SwitchOption interfaceallowedTau
(interfaceallowed,
"Tau",
"Only taus as outgoing particles",
4);
static Parameter<MEee2gZ2ll,Energy> interfacepTMin
("pTMin",
"Minimum pT for hard radiation",
&MEee2gZ2ll::pTmin_, GeV, 1.0*GeV, 0.001*GeV, 10.0*GeV,
false, false, Interface::limited);
static Parameter<MEee2gZ2ll,double> interfacePrefactor
("Prefactor",
"Prefactor for the overestimate of the emission probability",
&MEee2gZ2ll::preFactor_, 6.0, 1.0, 100.0,
false, false, Interface::limited);
static Reference<MEee2gZ2ll,ShowerAlpha> interfaceEMCoupling
("AlphaQED",
"Pointer to the object to calculate the EM coupling for the correction",
&MEee2gZ2ll::alphaQED_, false, false, true, false, false);
}
double MEee2gZ2ll::me2() const {
return loME(mePartonData(),rescaledMomenta(),true);
}
double MEee2gZ2ll::loME(const vector<cPDPtr> & partons,
const vector<Lorentz5Momentum> & momenta,
bool first) const {
vector<SpinorWaveFunction> fin,aout;
vector<SpinorBarWaveFunction> ain,fout;
SpinorWaveFunction ein (momenta[0],partons[0],incoming);
SpinorBarWaveFunction pin (momenta[1],partons[1],incoming);
SpinorBarWaveFunction ilmout(momenta[2],partons[2],outgoing);
SpinorWaveFunction ilpout(momenta[3],partons[3],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
ein.reset(ix) ;fin.push_back( ein );
pin.reset(ix) ;ain.push_back( pin );
ilmout.reset(ix);fout.push_back(ilmout);
ilpout.reset(ix);aout.push_back(ilpout);
}
// compute the matrix element
double me,lastCont,lastBW;
HelicityME(fin,ain,fout,aout,me,lastCont,lastBW);
// save the components
if(first) {
DVector save;
save.push_back(lastCont);
save.push_back(lastBW);
meInfo(save);
}
// return the answer
return me;
}
ProductionMatrixElement MEee2gZ2ll::HelicityME(vector<SpinorWaveFunction> & fin,
vector<SpinorBarWaveFunction> & ain,
vector<SpinorBarWaveFunction> & fout,
vector<SpinorWaveFunction> & aout,
double & me,double & cont,
double & BW ) const {
// the particles should be in the order
// for the incoming
// 0 incoming fermion (u spinor)
// 1 incoming antifermion (vbar spinor)
// for the outgoing
// 0 outgoing fermion (ubar spinor)
// 1 outgoing antifermion (v spinor)
// me to be returned
ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half);
ProductionMatrixElement gamma (PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half);
ProductionMatrixElement Zboson(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half);
// // wavefunctions for the intermediate particles
VectorWaveFunction interZ,interG;
// temporary storage of the different diagrams
Complex diag1,diag2;
// sum over helicities to get the matrix element
unsigned int inhel1,inhel2,outhel1,outhel2;
double total[3]={0.,0.,0.};
for(inhel1=0;inhel1<2;++inhel1) {
for(inhel2=0;inhel2<2;++inhel2) {
// intermediate Z
interZ = FFZVertex_->evaluate(sHat(),1,Z0_,fin[inhel1],ain[inhel2]);
// intermediate photon
interG = FFPVertex_->evaluate(sHat(),1,gamma_,fin[inhel1],ain[inhel2]);
for(outhel1=0;outhel1<2;++outhel1) {
for(outhel2=0;outhel2<2;++outhel2) {
// first the Z exchange diagram
diag1 = FFZVertex_->evaluate(sHat(),aout[outhel2],fout[outhel1],
interZ);
// then the photon exchange diagram
diag2 = FFPVertex_->evaluate(sHat(),aout[outhel2],fout[outhel1],
interG);
// add up squares of individual terms
total[1] += norm(diag1);
Zboson(inhel1,inhel2,outhel1,outhel2) = diag1;
total[2] += norm(diag2);
gamma (inhel1,inhel2,outhel1,outhel2) = diag2;
// the full thing including interference
diag1 += diag2;
total[0] += norm(diag1);
output(inhel1,inhel2,outhel1,outhel2) = diag1;
}
}
}
}
// results
for(int ix=0;ix<3;++ix) total[ix] *= 0.25;
tcPolarizedBeamPDPtr beam[2] =
{dynamic_ptr_cast<tcPolarizedBeamPDPtr>(mePartonData()[0]),
dynamic_ptr_cast<tcPolarizedBeamPDPtr>(mePartonData()[1])};
if( beam[0] || beam[1] ) {
RhoDMatrix rho[2] = {beam[0] ? beam[0]->rhoMatrix() : RhoDMatrix(mePartonData()[0]->iSpin()),
beam[1] ? beam[1]->rhoMatrix() : RhoDMatrix(mePartonData()[1]->iSpin())};
total[0] = output.average(rho[0],rho[1]);
total[1] = Zboson.average(rho[0],rho[1]);
total[2] = gamma .average(rho[0],rho[1]);
}
cont = total[2];
BW = total[1];
me = total[0];
return output;
}
void MEee2gZ2ll::constructVertex(tSubProPtr sub) {
// extract the particles in the hard process
ParticleVector hard;
hard.push_back(sub->incoming().first);hard.push_back(sub->incoming().second);
hard.push_back(sub->outgoing()[0]);hard.push_back(sub->outgoing()[1]);
if(hard[0]->id()<hard[1]->id()) swap(hard[0],hard[1]);
if(hard[2]->id()<hard[3]->id()) swap(hard[2],hard[3]);
vector<SpinorWaveFunction> fin,aout;
vector<SpinorBarWaveFunction> ain,fout;
SpinorWaveFunction( fin ,hard[0],incoming,false,true);
SpinorBarWaveFunction(ain ,hard[1],incoming,false,true);
SpinorBarWaveFunction(fout,hard[2],outgoing,true ,true);
SpinorWaveFunction( aout,hard[3],outgoing,true ,true);
// calculate the matrix element
double me,cont,BW;
ProductionMatrixElement prodme=HelicityME(fin,ain,fout,aout,me,cont,BW);
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(prodme);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<4;++ix) {
tSpinPtr spin = hard[ix]->spinInfo();
if(ix<2) {
tcPolarizedBeamPDPtr beam =
dynamic_ptr_cast<tcPolarizedBeamPDPtr>(hard[ix]->dataPtr());
if(beam) spin->rhoMatrix() = beam->rhoMatrix();
}
spin->productionVertex(hardvertex);
}
}
void MEee2gZ2ll::doinit() {
HwMEBase::doinit();
// set the particle data objects
Z0_=getParticleData(ThePEG::ParticleID::Z0);
gamma_=getParticleData(ThePEG::ParticleID::gamma);
// cast the SM pointer to the Herwig SM pointer
tcHwSMPtr hwsm= dynamic_ptr_cast<tcHwSMPtr>(standardModel());
// do the initialisation
if(!hwsm) throw InitException() << "Wrong type of StandardModel object in "
<< "MEee2gZ2ll::doinit() the Herwig"
<< " version must be used"
<< Exception::runerror;
FFZVertex_ = hwsm->vertexFFZ();
FFPVertex_ = hwsm->vertexFFP();
}
void MEee2gZ2ll::rebind(const TranslationMap & trans) {
FFZVertex_ = trans.translate(FFZVertex_);
FFPVertex_ = trans.translate(FFPVertex_);
Z0_ = trans.translate(Z0_);
gamma_ = trans.translate(gamma_);
HwMEBase::rebind(trans);
}
IVector MEee2gZ2ll::getReferences() {
IVector ret = HwMEBase::getReferences();
ret.push_back(FFZVertex_);
ret.push_back(FFPVertex_);
ret.push_back(Z0_ );
ret.push_back(gamma_ );
return ret;
}
-HardTreePtr MEee2gZ2ll::generateHardest(ShowerTreePtr tree,
- vector<ShowerInteraction::Type> inter) {
- // check if QED switched on
- bool QEDon=false;
- for(unsigned int ix=0;ix<inter.size();++ix)
- QEDon |= inter[ix] == ShowerInteraction::QED;
- if(!QEDon) return HardTreePtr();
+HardTreePtr MEee2gZ2ll::generateHardest(ShowerTreePtr tree,ShowerInteraction::Type inter) {
+ // check if generating QCD radiation
+ if(inter!=ShowerInteraction::QED && inter!=ShowerInteraction::QEDQCD &&
+ inter!=ShowerInteraction::ALL)
+ return HardTreePtr();
// generate the momenta for the hard emission
vector<Lorentz5Momentum> emmision;
unsigned int iemit,ispect;
Energy pTveto = generateHard(tree,emmision,iemit,ispect,false);
// outgoing progenitors
ShowerProgenitorPtr
qkProgenitor = tree->outgoingLines().begin() ->first,
qbProgenitor = tree->outgoingLines().rbegin()->first;
if(qkProgenitor->id()<0) swap(qkProgenitor,qbProgenitor);
// check if charged
if(!qkProgenitor->progenitor()->dataPtr()->charged())
return HardTreePtr();
// maximum pT of emission
if(pTveto<=ZERO) {
- for(unsigned int ix=0;ix<inter.size();++ix) {
- qkProgenitor->maximumpT(pTmin_,inter[ix]);
- qbProgenitor->maximumpT(pTmin_,inter[ix]);
- }
+ qkProgenitor->maximumpT(pTmin_,ShowerInteraction::QED);
+ qbProgenitor->maximumpT(pTmin_,ShowerInteraction::QED);
return HardTreePtr();
}
else {
- for(unsigned int ix=0;ix<inter.size();++ix) {
- qkProgenitor->maximumpT(pTveto,inter[ix]);
- qbProgenitor->maximumpT(pTveto,inter[ix]);
- }
+ qkProgenitor->maximumpT(pTveto,ShowerInteraction::QED);
+ qbProgenitor->maximumpT(pTveto,ShowerInteraction::QED);
}
// Make the particles for the hard tree
ShowerParticleVector hardParticles;
for(unsigned int ix=0;ix<partons_.size();++ix) {
hardParticles.push_back(new_ptr(ShowerParticle(partons_[ix],ix>=2)));
hardParticles.back()->set5Momentum(emmision[ix]);
}
ShowerParticlePtr parent(new_ptr(ShowerParticle(partons_[iemit],true)));
Lorentz5Momentum parentMomentum(emmision[iemit]+emmision[4]);
parentMomentum.setMass(partons_[iemit]->mass());
parent->set5Momentum(parentMomentum);
// Create the vectors of HardBranchings to create the HardTree:
vector<HardBranchingPtr> spaceBranchings,allBranchings;
// Incoming boson:
for(unsigned int ix=0;ix<2;++ix) {
spaceBranchings.push_back(new_ptr(HardBranching(hardParticles[ix],SudakovPtr(),
HardBranchingPtr(),
HardBranching::Incoming)));
allBranchings.push_back(spaceBranchings.back());
}
// Outgoing particles from hard emission:
HardBranchingPtr spectatorBranch(new_ptr(HardBranching(hardParticles[ispect],
SudakovPtr(),HardBranchingPtr(),
HardBranching::Outgoing)));
HardBranchingPtr emitterBranch(new_ptr(HardBranching(parent,SudakovPtr(),
HardBranchingPtr(),
HardBranching::Outgoing)));
emitterBranch->addChild(new_ptr(HardBranching(hardParticles[iemit],
SudakovPtr(),HardBranchingPtr(),
HardBranching::Outgoing)));
emitterBranch->addChild(new_ptr(HardBranching(hardParticles[4],
SudakovPtr(),HardBranchingPtr(),
HardBranching::Outgoing)));
emitterBranch->type(ShowerPartnerType::QED);
if(iemit==0) {
allBranchings.push_back(emitterBranch);
allBranchings.push_back(spectatorBranch);
}
else {
allBranchings.push_back( spectatorBranch );
allBranchings.push_back( emitterBranch );
}
emitterBranch ->branchingParticle()->partner(spectatorBranch->branchingParticle());
spectatorBranch->branchingParticle()->partner(emitterBranch ->branchingParticle());
spaceBranchings[0]->branchingParticle()->partner(spaceBranchings[1]->branchingParticle());
spaceBranchings[1]->branchingParticle()->partner(spaceBranchings[0]->branchingParticle());
// Make the HardTree from the HardBranching vectors.
HardTreePtr hardtree = new_ptr(HardTree(allBranchings,spaceBranchings,
ShowerInteraction::QED));
hardtree->partnersSet(true);
// Connect the particles with the branchings in the HardTree
hardtree->connect( qkProgenitor->progenitor(), allBranchings[2] );
hardtree->connect( qbProgenitor->progenitor(), allBranchings[3] );
// colour flow
ColinePtr newline=new_ptr(ColourLine());
// Return the HardTree
return hardtree;
}
double MEee2gZ2ll::meRatio(vector<cPDPtr> partons,
vector<Lorentz5Momentum> momenta,
unsigned int iemitter, bool subtract) const {
Lorentz5Momentum q = momenta[2]+momenta[3]+momenta[4];
Energy2 Q2=q.m2();
Energy2 lambda = sqrt((Q2-sqr(momenta[2].mass()+momenta[3].mass()))*
(Q2-sqr(momenta[2].mass()-momenta[3].mass())));
InvEnergy2 D[2];
double lome[2];
for(unsigned int iemit=0;iemit<2;++iemit) {
unsigned int ispect = iemit==0 ? 1 : 0;
Energy2 pipj = momenta[4 ] * momenta[2+iemit ];
Energy2 pipk = momenta[4 ] * momenta[2+ispect];
Energy2 pjpk = momenta[2+iemit] * momenta[2+ispect];
double y = pipj/(pipj+pipk+pjpk);
double z = pipk/( pipk+pjpk);
Energy mij = sqrt(2.*pipj+sqr(momenta[2+iemit].mass()));
Energy2 lamB = sqrt((Q2-sqr(mij+momenta[2+ispect].mass()))*
(Q2-sqr(mij-momenta[2+ispect].mass())));
Energy2 Qpk = q*momenta[2+ispect];
Lorentz5Momentum pkt =
lambda/lamB*(momenta[2+ispect]-Qpk/Q2*q)
+0.5/Q2*(Q2+sqr(momenta[2+ispect].mass())-sqr(momenta[2+ispect].mass()))*q;
Lorentz5Momentum pijt =
q-pkt;
double muj = momenta[2+iemit ].mass()/sqrt(Q2);
double muk = momenta[2+ispect].mass()/sqrt(Q2);
double vt = sqrt((1.-sqr(muj+muk))*(1.-sqr(muj-muk)))/(1.-sqr(muj)-sqr(muk));
double v = sqrt(sqr(2.*sqr(muk)+(1.-sqr(muj)-sqr(muk))*(1.-y))-4.*sqr(muk))
/(1.-y)/(1.-sqr(muj)-sqr(muk));
// dipole term
D[iemit] = 0.5/pipj*(2./(1.-(1.-z)*(1.-y))
-vt/v*(2.-z+sqr(momenta[2+iemit].mass())/pipj));
// matrix element
vector<Lorentz5Momentum> lomom(4);
lomom[0] = momenta[0];
lomom[1] = momenta[1];
if(iemit==0) {
lomom[2] = pijt;
lomom[3] = pkt ;
}
else {
lomom[3] = pijt;
lomom[2] = pkt ;
}
lome[iemit] = loME(partons,lomom,false);
}
InvEnergy2 ratio = realME(partons,momenta)
*abs(D[iemitter])/(abs(D[0]*lome[0])+abs(D[1]*lome[1]));
double output = Q2*ratio;
if(subtract) output -= 2.*Q2*D[iemitter];
return output;
}
InvEnergy2 MEee2gZ2ll::realME(const vector<cPDPtr> & partons,
const vector<Lorentz5Momentum> & momenta) const {
// compute the spinors
vector<SpinorWaveFunction> fin,aout;
vector<SpinorBarWaveFunction> ain,fout;
vector<VectorWaveFunction> gout;
SpinorWaveFunction ein (momenta[0],partons[0],incoming);
SpinorBarWaveFunction pin (momenta[1],partons[1],incoming);
SpinorBarWaveFunction qkout(momenta[2],partons[2],outgoing);
SpinorWaveFunction qbout(momenta[3],partons[3],outgoing);
VectorWaveFunction photon(momenta[4],partons[4],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
ein.reset(ix) ;
fin.push_back( ein );
pin.reset(ix) ;
ain.push_back( pin );
qkout.reset(ix);
fout.push_back(qkout);
qbout.reset(ix);
aout.push_back(qbout);
photon.reset(2*ix);
gout.push_back(photon);
}
vector<Complex> diag(4,0.);
ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1);
double total(0.);
for(unsigned int inhel1=0;inhel1<2;++inhel1) {
for(unsigned int inhel2=0;inhel2<2;++inhel2) {
// intermediate Z
VectorWaveFunction interZ =
FFZVertex_->evaluate(scale(),1,Z0_,fin[inhel1],ain[inhel2]);
// intermediate photon
VectorWaveFunction interG =
FFPVertex_->evaluate(scale(),1,gamma_,fin[inhel1],ain[inhel2]);
for(unsigned int outhel1=0;outhel1<2;++outhel1) {
for(unsigned int outhel2=0;outhel2<2;++outhel2) {
for(unsigned int outhel3=0;outhel3<2;++outhel3) {
SpinorBarWaveFunction off1 =
FFPVertex_->evaluate(scale(),3,partons[2],fout[outhel1],gout[outhel3]);
diag[0] = FFZVertex_->evaluate(scale(),aout[outhel2],off1,interZ);
diag[1] = FFPVertex_->evaluate(scale(),aout[outhel2],off1,interG);
SpinorWaveFunction off2 =
FFPVertex_->evaluate(scale(),3,partons[3],aout[outhel2],gout[outhel3]);
diag[2] = FFZVertex_->evaluate(scale(),off2,fout[outhel1],interZ);
diag[3] = FFPVertex_->evaluate(scale(),off2,fout[outhel1],interG);
// sum of diagrams
Complex sum = std::accumulate(diag.begin(),diag.end(),Complex(0.));
// matrix element
output(inhel1,inhel2,outhel1,outhel2,outhel3)=sum;
// me2
total += norm(sum);
}
}
}
}
}
// spin average
total *= 0.25;
tcPolarizedBeamPDPtr beam[2] =
{dynamic_ptr_cast<tcPolarizedBeamPDPtr>(partons[0]),
dynamic_ptr_cast<tcPolarizedBeamPDPtr>(partons[1])};
if( beam[0] || beam[1] ) {
RhoDMatrix rho[2] =
{beam[0] ? beam[0]->rhoMatrix() : RhoDMatrix(mePartonData()[0]->iSpin()),
beam[1] ? beam[1]->rhoMatrix() : RhoDMatrix(mePartonData()[1]->iSpin())};
total = output.average(rho[0],rho[1]);
}
// divide out the coupling and charge
total /= norm(FFPVertex_->norm())*
sqr(double(mePartonData()[2]->iCharge())/3.);
// return the total
return total*UnitRemoval::InvE2;
}
Energy MEee2gZ2ll::generateHard(ShowerTreePtr tree,
vector<Lorentz5Momentum> & emmision,
unsigned int & iemit, unsigned int & ispect,
bool applyVeto) {
// get the momenta of the incoming and outgoing particles
// incoming
ShowerProgenitorPtr
emProgenitor = tree->incomingLines().begin() ->first,
epProgenitor = tree->incomingLines().rbegin()->first;
// outgoing
ShowerProgenitorPtr
qkProgenitor = tree->outgoingLines().begin() ->first,
qbProgenitor = tree->outgoingLines().rbegin()->first;
// get the order right
if(emProgenitor->id()<0) swap(emProgenitor,epProgenitor);
if(qkProgenitor->id()<0) swap(qkProgenitor,qbProgenitor);
loMomenta_.resize(0);
// extract the momenta
loMomenta_.push_back(emProgenitor->progenitor()->momentum());
loMomenta_.push_back(epProgenitor->progenitor()->momentum());
loMomenta_.push_back(qkProgenitor->progenitor()->momentum());
loMomenta_.push_back(qbProgenitor->progenitor()->momentum());
// and ParticleData objects
partons_.resize(5);
partons_[0]=emProgenitor->progenitor()->dataPtr();
partons_[1]=epProgenitor->progenitor()->dataPtr();
partons_[2]=qkProgenitor->progenitor()->dataPtr();
partons_[3]=qbProgenitor->progenitor()->dataPtr();
partons_[4]=gamma_;
// boost from lab to CMS frame with outgoing particles
// along the z axis
LorentzRotation eventFrame( ( loMomenta_[2] + loMomenta_[3] ).findBoostToCM() );
Lorentz5Momentum spectator = eventFrame*loMomenta_[2];
eventFrame.rotateZ( -spectator.phi() );
eventFrame.rotateY( -spectator.theta() );
eventFrame.invert();
// mass of the final-state system
Energy2 M2 = (loMomenta_[2]+loMomenta_[3]).m2();
Energy M = sqrt(M2);
double mu1 = loMomenta_[2].mass()/M;
double mu2 = loMomenta_[3].mass()/M;
double mu12 = sqr(mu1), mu22 = sqr(mu2);
double lambda = sqrt(1.+sqr(mu12)+sqr(mu22)-2.*mu12-2.*mu22-2.*mu12*mu22);
// max pT
Energy pTmax = 0.5*sqrt(M2)*
(1.-sqr(loMomenta_[2].mass()+loMomenta_[3].mass())/M2);
// max y
double ymax = acosh(pTmax/pTmin_);
double a = alphaQED_->overestimateValue()/Constants::twopi*
2.*ymax*preFactor_*sqr(double(mePartonData()[2]->iCharge())/3.);
// variables for the emission
Energy pT[2];
double y[2],phi[2],x3[2],x1[2][2],x2[2][2];
double contrib[2][2];
// storage of the real emission momenta
vector<Lorentz5Momentum> realMomenta[2][2]=
{{vector<Lorentz5Momentum>(5),vector<Lorentz5Momentum>(5)},
{vector<Lorentz5Momentum>(5),vector<Lorentz5Momentum>(5)}};
for(unsigned int ix=0;ix<2;++ix)
for(unsigned int iy=0;iy<2;++iy)
for(unsigned int iz=0;iz<2;++iz)
realMomenta[ix][iy][iz] = loMomenta_[iz];
// generate the emission
for(unsigned int ix=0;ix<2;++ix) {
if(ix==1) {
swap(mu1 ,mu2 );
swap(mu12,mu22);
}
pT[ix] = pTmax;
y [ix] = 0.;
bool reject = true;
do {
// generate pT
pT[ix] *= pow(UseRandom::rnd(),1./a);
if(pT[ix]<pTmin_) {
pT[ix] = -GeV;
break;
}
// generate y
y[ix] = -ymax+2.*UseRandom::rnd()*ymax;
// generate phi
phi[ix] = UseRandom::rnd()*Constants::twopi;
// calculate x3 and check in allowed region
x3[ix] = 2.*pT[ix]*cosh(y[ix])/M;
if(x3[ix] < 0. || x3[ix] > 1. -sqr( mu1 + mu2 ) ) continue;
// find the possible solutions for x1
double xT2 = sqr(2./M*pT[ix]);
double root = (-sqr(x3[ix])+xT2)*
(xT2*mu22+2.*x3[ix]-sqr(mu12)+2.*mu22+2.*mu12-sqr(x3[ix])-1.
+2.*mu12*mu22-sqr(mu22)-2.*mu22*x3[ix]-2.*mu12*x3[ix]);
double c1=2.*sqr(x3[ix])-4.*mu22-6.*x3[ix]+4.*mu12-xT2*x3[ix]
+2.*xT2-2.*mu12*x3[ix]+2.*mu22*x3[ix]+4.;
if(root<0.) continue;
x1[ix][0] = 1./(4.-4.*x3[ix]+xT2)*(c1-2.*sqrt(root));
x1[ix][1] = 1./(4.-4.*x3[ix]+xT2)*(c1+2.*sqrt(root));
// change sign of y if 2nd particle emits
if(ix==1) y[ix] *=-1.;
// loop over the solutions
for(unsigned int iy=0;iy<2;++iy) {
contrib[ix][iy]=0.;
// check x1 value allowed
if(x1[ix][iy]<2.*mu1||x1[ix][iy]>1.+mu12-mu22) continue;
// calculate x2 value and check allowed
x2[ix][iy] = 2.-x3[ix]-x1[ix][iy];
double root = max(0.,sqr(x1[ix][iy])-4.*mu12);
root = sqrt(root);
double x2min = 1.+mu22-mu12
-0.5*(1.-x1[ix][iy]+mu12-mu22)/(1.-x1[ix][iy]+mu12)*(x1[ix][iy]-2.*mu12+root);
double x2max = 1.+mu22-mu12
-0.5*(1.-x1[ix][iy]+mu12-mu22)/(1.-x1[ix][iy]+mu12)*(x1[ix][iy]-2.*mu12-root);
if(x2[ix][iy]<x2min||x2[ix][iy]>x2max) continue;
// check the z components
double z1 = sqrt(sqr(x1[ix][iy])-4.*mu12-xT2);
double z2 = -sqrt(sqr(x2[ix][iy])-4.*mu22);
double z3 = pT[ix]*sinh(y[ix])*2./M;
if(ix==1) z3 *=-1.;
if(abs(-z1+z2+z3)<1e-9) z1 *= -1.;
if(abs(z1+z2+z3)>1e-5) continue;
// if using as an ME correction the veto
if(applyVeto) {
// double xb = x1[ix][iy], xc = x2[ix][iy];
// double b = mu12, c = mu22;
// double r = 0.5*(1.+b/(1.+c-xc));
// double z1 = r + (xb-(2.-xc)*r)/sqrt(sqr(xc)-4.*c);
// double kt1 = (1.-b+c-xc)/z1/(1.-z1);
// r = 0.5*(1.+c/(1.+b-xb));
// double z2 = r + (xc-(2.-xb)*r)/sqrt(sqr(xb)-4.*b);
// double kt2 = (1.-c+b-xb)/z2/(1.-z2);
// if(ix==1) {
// swap(z1 ,z2);
// swap(kt1,kt2);
// }
// // veto the shower region
// if( kt1 < d_kt1_ || kt2 < d_kt2_ ) continue;
}
// construct the momenta
realMomenta[ix][iy][4] =
Lorentz5Momentum(pT[ix]*cos(phi[ix]),pT[ix]*sin(phi[ix]),
pT[ix]*sinh(y[ix]) ,pT[ix]*cosh(y[ix]),ZERO);
if(ix==0) {
realMomenta[ix][iy][2] =
Lorentz5Momentum(-pT[ix]*cos(phi[ix]),-pT[ix]*sin(phi[ix]),
z1*0.5*M,x1[ix][iy]*0.5*M,M*mu1);
realMomenta[ix][iy][3] =
Lorentz5Momentum(ZERO,ZERO, z2*0.5*M,x2[ix][iy]*0.5*M,M*mu2);
}
else {
realMomenta[ix][iy][2] =
Lorentz5Momentum(ZERO,ZERO,-z2*0.5*M,x2[ix][iy]*0.5*M,M*mu2);
realMomenta[ix][iy][3] =
Lorentz5Momentum(-pT[ix]*cos(phi[ix]),-pT[ix]*sin(phi[ix]),
-z1*0.5*M,x1[ix][iy]*0.5*M,M*mu1);
}
// boost the momenta back to the lab
for(unsigned int iz=2;iz<5;++iz)
realMomenta[ix][iy][iz] *= eventFrame;
// jacobian and prefactors for the weight
Energy J = M/sqrt(xT2)*abs(-x1[ix][iy]*x2[ix][iy]+2.*mu22*x1[ix][iy]
+x2[ix][iy]+x2[ix][iy]*mu12+mu22*x2[ix][iy]
-sqr(x2[ix][iy]))
/pow(sqr(x2[ix][iy])-4.*mu22,1.5);
// prefactors etc
contrib[ix][iy] = 0.5*pT[ix]/J/preFactor_/lambda;
// matrix element piece
contrib[ix][iy] *= meRatio(partons_,realMomenta[ix][iy],ix,false);
// coupling piece
contrib[ix][iy] *= alphaQED_->ratio(sqr(pT[ix]));
}
if(contrib[ix][0]+contrib[ix][1]>1.) {
ostringstream s;
s << "MEee2gZ2qq::generateHardest weight for channel " << ix
<< "is " << contrib[ix][0]+contrib[ix][1]
<< " which is greater than 1";
generator()->logWarning( Exception(s.str(), Exception::warning) );
}
reject = UseRandom::rnd() > contrib[ix][0] + contrib[ix][1];
}
while (reject);
if(pT[ix]<pTmin_)
pT[ix] = -GeV;
}
// now pick the emmision with highest pT
Energy pTemit(ZERO);
// no emission
if(pT[0]<ZERO&&pT[1]<ZERO) return -GeV;
// which one emitted
if(pT[0]>pT[1]) {
iemit = 2;
ispect = 3;
pTemit = pT[0];
if(UseRandom::rnd()<contrib[0][0]/(contrib[0][0]+contrib[0][1]))
emmision = realMomenta[0][0];
else
emmision = realMomenta[0][1];
}
else {
iemit = 3;
ispect = 2;
pTemit = pT[1];
if(UseRandom::rnd()<contrib[1][0]/(contrib[1][0]+contrib[1][1]))
emmision = realMomenta[1][0];
else
emmision = realMomenta[1][1];
}
// return pT of emmision
return pTemit;
}
diff --git a/MatrixElement/Lepton/MEee2gZ2ll.h b/MatrixElement/Lepton/MEee2gZ2ll.h
--- a/MatrixElement/Lepton/MEee2gZ2ll.h
+++ b/MatrixElement/Lepton/MEee2gZ2ll.h
@@ -1,401 +1,400 @@
// -*- C++ -*-
//
// MEee2gZ2ll.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_MEee2gZ2ll_H
#define HERWIG_MEee2gZ2ll_H
//
// This is the declaration of the MEee2gZ2ll class.
//
#include "Herwig/MatrixElement/HwMEBase.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/Shower/Couplings/ShowerAlpha.h"
namespace Herwig {
using namespace ThePEG;
/**
* The MEee2gZ2ll class provides the matrix element for
* \f$e^+e^-\to\ell^+\ell^-\f$. N.B. for the production of \f$e^+e^-\f$
* only the \f$s\f$-channel Z and photon diagrams are included.
*
* @see \ref MEee2gZ2llInterfaces "The interfaces"
* defined for MEee2gZ2ll.
*/
class MEee2gZ2ll: public HwMEBase {
public:
/**
* The default constructor.
*/
MEee2gZ2ll() : allowed_(0), pTmin_(GeV),
preFactor_(6.) {
massOption(vector<unsigned int>(2,1));
}
/**
* Members for hard corrections to the emission of QCD radiation
*/
//@{
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return FSR;}
/**
* Has an old fashioned ME correction
*/
virtual bool hasMECorrection() {return false;}
/**
* Apply the POWHEG style correction
*/
- virtual HardTreePtr generateHardest(ShowerTreePtr,
- vector<ShowerInteraction::Type>);
+ virtual HardTreePtr generateHardest(ShowerTreePtr,ShowerInteraction::Type);
//@}
public:
/** @name Virtual functions required by the MEBase class. */
//@{
/**
* Return the order in \f$\alpha_S\f$ in which this matrix
* element is given.
*/
virtual unsigned int orderInAlphaS() const;
/**
* Return the order in \f$\alpha_{EW}\f$ in which this matrix
* element is given.
*/
virtual unsigned int orderInAlphaEW() const;
/**
* The matrix element for the kinematical configuration
* previously provided by the last call to setKinematics(), suitably
* scaled by sHat() to give a dimension-less number.
* @return the matrix element scaled with sHat() to give a
* dimensionless number.
*/
virtual double me2() const;
/**
* Return the scale associated with the last set phase space point.
*/
virtual Energy2 scale() const;
/**
* Add all possible diagrams with the add() function.
*/
virtual void getDiagrams() const;
/**
* Get diagram selector. With the information previously supplied with the
* setKinematics method, a derived class may optionally
* override this method to weight the given diagrams with their
* (although certainly not physical) relative probabilities.
* @param dv the diagrams to be weighted.
* @return a Selector relating the given diagrams to their weights.
*/
virtual Selector<DiagramIndex> diagrams(const DiagramVector & dv) const;
/**
* Return a Selector with possible colour geometries for the selected
* diagram weighted by their relative probabilities.
* @param diag the diagram chosen.
* @return the possible colour geometries weighted by their
* relative probabilities.
*/
virtual Selector<const ColourLines *>
colourGeometries(tcDiagPtr diag) const;
/**
* Construct the vertex of spin correlations.
*/
virtual void constructVertex(tSubProPtr);
//@}
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const {return new_ptr(*this);}
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const {return new_ptr(*this);}
//@}
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
/**
* Rebind pointer to other Interfaced objects. Called in the setup phase
* after all objects used in an EventGenerator has been cloned so that
* the pointers will refer to the cloned objects afterwards.
* @param trans a TranslationMap relating the original objects to
* their respective clones.
* @throws RebindException if no cloned object was found for a given
* pointer.
*/
virtual void rebind(const TranslationMap & trans)
;
/**
* Return a vector of all pointers to Interfaced objects used in this
* object.
* @return a vector of pointers.
*/
virtual IVector getReferences();
//@}
protected:
/**
* Calculate the matrix element for \f$e^+e^-\to \ell^+ \ell^-\f$.
* @param partons The incoming and outgoing particles
* @param momenta The momenta of the incoming and outgoing particles
*/
double loME(const vector<cPDPtr> & partons,
const vector<Lorentz5Momentum> & momenta,
bool first) const;
/**
* Member to calculate the matrix element
* @param fin Spinors for incoming fermion
* @param ain Spinors for incoming antifermion
* @param fout Spinors for outgoing fermion
* @param aout Spinors for outgong antifermion
* @param me Spin summed Matrix element
* @param cont The continuum piece of the matrix element
* @param BW The Z piece of the matrix element
*/
ProductionMatrixElement HelicityME(vector<SpinorWaveFunction> & fin,
vector<SpinorBarWaveFunction> & ain,
vector<SpinorBarWaveFunction> & fout,
vector<SpinorWaveFunction> & aout,
double & me,
double & cont,
double & BW ) const;
/**
* The ratio of the matrix element for one additional jet over the
* leading order result. In practice
* \[\frac{\hat{s}|\overline{\mathcal{M}}|^2_2|D_{\rm emit}|}{4\pi C_F\alpha_S|\overline{\mathcal{M}}|^2_3\left(|D_{\rm emit}|+|D_{\rm spect}\right)}}\]
* is returned where \f$\|\overline{\mathcal{M}}|^2\f$ is
* the spin and colour summed/averaged matrix element.
* @param partons The incoming and outgoing particles
* @param momenta The momenta of the incoming and outgoing particles
* @param iemitter Whether the quark or antiquark is regardede as the emitter
* @param inter The type of interaction
*/
double meRatio(vector<cPDPtr> partons,
vector<Lorentz5Momentum> momenta,
unsigned int iemittor,
bool subtract=false) const;
/**
* Calculate the matrix element for \f$e^-e^-\to q \bar q g$.
* @param partons The incoming and outgoing particles
* @param momenta The momenta of the incoming and outgoing particles
* @param inter The type of interaction
*/
InvEnergy2 realME(const vector<cPDPtr> & partons,
const vector<Lorentz5Momentum> & momenta) const;
/**
* Generate the momenta for a hard configuration
*/
Energy generateHard(ShowerTreePtr tree,
vector<Lorentz5Momentum> & emission,
unsigned int & iemit, unsigned int & ispect,
bool applyVeto);
protected:
/**
* Pointer to the fermion-antifermion Z vertex
*/
AbstractFFVVertexPtr FFZVertex() const {return FFZVertex_;}
/**
* Pointer to the fermion-antifermion photon vertex
*/
AbstractFFVVertexPtr FFPVertex() const {return FFPVertex_;}
/**
* Pointer to the particle data object for the Z
*/
PDPtr Z0() const {return Z0_;}
/**
* Pointer to the particle data object for the photon
*/
PDPtr gamma() const {return gamma_;}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEee2gZ2ll & operator=(const MEee2gZ2ll &);
private:
/**
* Pointers to the vertices
*/
//@{
/**
* Pointer to the fermion-antifermion Z vertex
*/
AbstractFFVVertexPtr FFZVertex_;
/**
* Pointer to the fermion-antifermion photon vertex
*/
AbstractFFVVertexPtr FFPVertex_;
//@}
/**
* Pointer to the particle data object for the Z
*/
PDPtr Z0_;
/**
* Pointer to the particle data object for the photon
*/
PDPtr gamma_;
/**
* The allowed outgoing
*/
int allowed_;
/**
* The initial kappa-tilde values for radiation from the quark
*/
double d_kt1_;
/**
* Pointer to the EM coupling
*/
ShowerAlphaPtr alphaQED_;
/**
* Variables for the POWHEG style corrections
*/
//@{
/**
* The cut off on pt, assuming massless quarks.
*/
Energy pTmin_;
/**
* Overestimate for the prefactor
*/
double preFactor_;
/**
* ParticleData objects for the partons
*/
vector<cPDPtr> partons_;
/**
* Momenta of the leading-order partons
*/
vector<Lorentz5Momentum> loMomenta_;
//@}
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of MEee2gZ2ll. */
template <>
struct BaseClassTrait<Herwig::MEee2gZ2ll,1> {
/** Typedef of the first base class of MEee2gZ2ll. */
typedef Herwig::HwMEBase NthBase;
};
/** This template specialization informs ThePEG about the name of
* the MEee2gZ2ll class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::MEee2gZ2ll>
: public ClassTraitsBase<Herwig::MEee2gZ2ll> {
/** Return a platform-independent class name */
static string className() { return "Herwig::MEee2gZ2ll"; }
/**
* The name of a file containing the dynamic library where the class
* MEee2gZ2ll is implemented. It may also include several, space-separated,
* libraries if the class MEee2gZ2ll depends on other classes (base classes
* excepted). In this case the listed libraries will be dynamically
* linked in the order they are specified.
*/
static string library() { return "HwMELepton.so"; }
};
/** @endcond */
}
#endif /* HERWIG_MEee2gZ2ll_H */
diff --git a/MatrixElement/Lepton/MEee2gZ2qq.cc b/MatrixElement/Lepton/MEee2gZ2qq.cc
--- a/MatrixElement/Lepton/MEee2gZ2qq.cc
+++ b/MatrixElement/Lepton/MEee2gZ2qq.cc
@@ -1,1151 +1,1169 @@
// -*- C++ -*-
//
// MEee2gZ2qq.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEee2gZ2qq class.
//
#include "MEee2gZ2qq.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "Herwig/MatrixElement/HardVertex.h"
#include "Herwig/Shower/Base/Evolver.h"
#include "Herwig/Shower/Base/KinematicsReconstructor.h"
#include "Herwig/Shower/Base/PartnerFinder.h"
#include "ThePEG/PDF/PolarizedBeamParticleData.h"
#include <numeric>
#include "ThePEG/Utilities/DescribeClass.h"
using namespace Herwig;
const double MEee2gZ2qq::EPS_=0.00000001;
void MEee2gZ2qq::doinit() {
HwMEBase::doinit();
massOption(vector<unsigned int>(2,massopt_));
rescalingOption(3);
if(minflav_>maxflav_)
throw InitException() << "The minimum flavour " << minflav_
<< "must be lower the than maximum flavour " << maxflav_
<< " in MEee2gZ2qq::doinit() "
<< Exception::runerror;
// set the particle data objects
Z0_ = getParticleData(ParticleID::Z0);
gamma_ = getParticleData(ParticleID::gamma);
gluon_ = getParticleData(ParticleID::g);
// cast the SM pointer to the Herwig SM pointer
tcHwSMPtr hwsm= dynamic_ptr_cast<tcHwSMPtr>(standardModel());
// do the initialisation
if(!hwsm) throw InitException()
<< "Wrong type of StandardModel object in "
<< "MEee2gZ2qq::doinit() the Herwig version must be used"
<< Exception::runerror;
FFZVertex_ = hwsm->vertexFFZ();
FFPVertex_ = hwsm->vertexFFP();
FFGVertex_ = hwsm->vertexFFG();
}
void MEee2gZ2qq::getDiagrams() const {
// specific the diagrams
tcPDPtr ep = getParticleData(ParticleID::eplus);
tcPDPtr em = getParticleData(ParticleID::eminus);
tcPDPtr gamma = getParticleData(ParticleID::gamma);
tcPDPtr Z0 = getParticleData(ParticleID::Z0);
// setup the processes
for ( int i =minflav_; i<=maxflav_; ++i ) {
tcPDPtr qk = getParticleData(i);
tcPDPtr qb = qk->CC();
add(new_ptr((Tree2toNDiagram(2), em, ep, 1, gamma, 3, qk, 3, qb, -1)));
add(new_ptr((Tree2toNDiagram(2), em, ep, 1, Z0 , 3, qk, 3, qb, -2)));
}
}
Energy2 MEee2gZ2qq::scale() const {
return sqr(getParticleData(ParticleID::Z0)->mass());
// return sHat();
}
unsigned int MEee2gZ2qq::orderInAlphaS() const {
return 0;
}
unsigned int MEee2gZ2qq::orderInAlphaEW() const {
return 2;
}
Selector<MEBase::DiagramIndex>
MEee2gZ2qq::diagrams(const DiagramVector & diags) const {
double lastCont(0.5),lastBW(0.5);
if ( lastXCombPtr() ) {
lastCont = meInfo()[0];
lastBW = meInfo()[1];
}
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i ) {
if ( diags[i]->id() == -1 ) sel.insert(lastCont, i);
else if ( diags[i]->id() == -2 ) sel.insert(lastBW, i);
}
return sel;
}
Selector<const ColourLines *>
MEee2gZ2qq::colourGeometries(tcDiagPtr ) const {
static const ColourLines c("-5 4");
Selector<const ColourLines *> sel;
sel.insert(1.0, &c);
return sel;
}
void MEee2gZ2qq::persistentOutput(PersistentOStream & os) const {
os << FFZVertex_ << FFPVertex_ << FFGVertex_
<< Z0_ << gamma_ << gluon_ << minflav_
<< maxflav_ << massopt_ << alphaQCD_ << alphaQED_
<< ounit(pTminQED_,GeV) << ounit(pTminQCD_,GeV) << preFactor_
<< spinCorrelations_;
}
void MEee2gZ2qq::persistentInput(PersistentIStream & is, int) {
is >> FFZVertex_ >> FFPVertex_ >> FFGVertex_
>> Z0_ >> gamma_ >> gluon_ >> minflav_
>> maxflav_ >> massopt_ >> alphaQCD_ >> alphaQED_
>> iunit(pTminQED_,GeV) >> iunit(pTminQCD_,GeV) >> preFactor_
>> spinCorrelations_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<MEee2gZ2qq,HwMEBase>
describeMEee2gZ2qq("Herwig::MEee2gZ2qq", "HwMELepton.so");
void MEee2gZ2qq::Init() {
static ClassDocumentation<MEee2gZ2qq> documentation
("The MEee2gZ2qq class implements the matrix element for e+e- -> q qbar");
static Parameter<MEee2gZ2qq,int> interfaceMinimumFlavour
("MinimumFlavour",
"The PDG code of the quark with the lowest PDG code to produce.",
&MEee2gZ2qq::minflav_, 1, 1, 6,
false, false, Interface::limited);
static Parameter<MEee2gZ2qq,int> interfaceMaximumFlavour
("MaximumFlavour",
"The PDG code of the quark with the highest PDG code to produce",
&MEee2gZ2qq::maxflav_, 5, 1, 6,
false, false, Interface::limited);
static Switch<MEee2gZ2qq,unsigned int> interfaceTopMassOption
("TopMassOption",
"Option for the treatment of the top quark mass",
&MEee2gZ2qq::massopt_, 1, false, false);
static SwitchOption interfaceTopMassOptionOnMassShell
(interfaceTopMassOption,
"OnMassShell",
"The top is produced on its mass shell",
1);
static SwitchOption interfaceTopMassOption2
(interfaceTopMassOption,
"OffShell",
"The top is generated off-shell using the mass and width generator.",
2);
static Parameter<MEee2gZ2qq,Energy> interfacepTMinQED
("pTMinQED",
"Minimum pT for hard QED radiation",
&MEee2gZ2qq::pTminQED_, GeV, 1.0*GeV, 0.001*GeV, 10.0*GeV,
false, false, Interface::limited);
static Parameter<MEee2gZ2qq,Energy> interfacepTMinQCD
("pTMinQCD",
"Minimum pT for hard QCD radiation",
&MEee2gZ2qq::pTminQCD_, GeV, 1.0*GeV, 0.001*GeV, 10.0*GeV,
false, false, Interface::limited);
static Parameter<MEee2gZ2qq,double> interfacePrefactor
("Prefactor",
"Prefactor for the overestimate of the emission probability",
&MEee2gZ2qq::preFactor_, 6.0, 1.0, 100.0,
false, false, Interface::limited);
static Reference<MEee2gZ2qq,ShowerAlpha> interfaceQCDCoupling
("AlphaQCD",
"Pointer to the object to calculate the strong coupling for the correction",
&MEee2gZ2qq::alphaQCD_, false, false, true, false, false);
static Reference<MEee2gZ2qq,ShowerAlpha> interfaceEMCoupling
("AlphaQED",
"Pointer to the object to calculate the EM coupling for the correction",
&MEee2gZ2qq::alphaQED_, false, false, true, false, false);
static Switch<MEee2gZ2qq,bool> interfaceSpinCorrelations
("SpinCorrelations",
"Switch the construction of the veretx for spin correlations on/off",
&MEee2gZ2qq::spinCorrelations_, true, false, false);
static SwitchOption interfaceSpinCorrelationsYes
(interfaceSpinCorrelations,
"Yes",
"Swtich On",
true);
static SwitchOption interfaceSpinCorrelationsNo
(interfaceSpinCorrelations,
"No",
"Switch off",
false);
}
double MEee2gZ2qq::me2() const {
return loME(mePartonData(),rescaledMomenta(),true);
}
ProductionMatrixElement MEee2gZ2qq::HelicityME(vector<SpinorWaveFunction> & fin,
vector<SpinorBarWaveFunction> & ain,
vector<SpinorBarWaveFunction> & fout,
vector<SpinorWaveFunction> & aout,
double & me,
double & cont,
double & BW ) const {
// the particles should be in the order
// for the incoming
// 0 incoming fermion (u spinor)
// 1 incoming antifermion (vbar spinor)
// for the outgoing
// 0 outgoing fermion (ubar spinor)
// 1 outgoing antifermion (v spinor)
// me to be returned
ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half);
ProductionMatrixElement gamma (PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half);
ProductionMatrixElement Zboson(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half);
// wavefunctions for the intermediate particles
VectorWaveFunction interZ,interG;
// temporary storage of the different diagrams
Complex diag1,diag2;
// sum over helicities to get the matrix element
unsigned int inhel1,inhel2,outhel1,outhel2;
double total[3]={0.,0.,0.};
for(inhel1=0;inhel1<2;++inhel1) {
for(inhel2=0;inhel2<2;++inhel2) {
// intermediate Z
interZ = FFZVertex_->evaluate(scale(),1,Z0_,fin[inhel1],ain[inhel2]);
// intermediate photon
interG = FFPVertex_->evaluate(scale(),1,gamma_,fin[inhel1],ain[inhel2]);
for(outhel1=0;outhel1<2;++outhel1) {
for(outhel2=0;outhel2<2;++outhel2) {
// first the Z exchange diagram
diag1 = FFZVertex_->evaluate(scale(),aout[outhel2],fout[outhel1],
interZ);
// then the photon exchange diagram
diag2 = FFPVertex_->evaluate(scale(),aout[outhel2],fout[outhel1],
interG);
// add up squares of individual terms
total[1] += norm(diag1);
Zboson(inhel1,inhel2,outhel1,outhel2) = diag1;
total[2] += norm(diag2);
gamma (inhel1,inhel2,outhel1,outhel2) = diag2;
// the full thing including interference
diag1 += diag2;
total[0] += norm(diag1);
output(inhel1,inhel2,outhel1,outhel2)=diag1;
}
}
}
}
for(int ix=0;ix<3;++ix) total[ix] *= 0.25;
tcPolarizedBeamPDPtr beam[2] =
{dynamic_ptr_cast<tcPolarizedBeamPDPtr>(mePartonData()[0]),
dynamic_ptr_cast<tcPolarizedBeamPDPtr>(mePartonData()[1])};
if( beam[0] || beam[1] ) {
RhoDMatrix rho[2] =
{beam[0] ? beam[0]->rhoMatrix() : RhoDMatrix(mePartonData()[0]->iSpin()),
beam[1] ? beam[1]->rhoMatrix() : RhoDMatrix(mePartonData()[1]->iSpin())};
total[0] = output.average(rho[0],rho[1]);
total[1] = Zboson.average(rho[0],rho[1]);
total[2] = gamma .average(rho[0],rho[1]);
}
// results
for(int ix=0;ix<3;++ix) total[ix]*= 3.;
cont = total[2];
BW = total[1];
me = total[0];
return output;
}
void MEee2gZ2qq::constructVertex(tSubProPtr sub) {
if(!spinCorrelations_) return;
// extract the particles in the hard process
ParticleVector hard;
hard.push_back(sub->incoming().first);
hard.push_back(sub->incoming().second);
hard.push_back(sub->outgoing()[0]);
hard.push_back(sub->outgoing()[1]);
if(hard[0]->id()<hard[1]->id()) swap(hard[0],hard[1]);
if(hard[2]->id()<hard[3]->id()) swap(hard[2],hard[3]);
vector<SpinorWaveFunction> fin,aout;
vector<SpinorBarWaveFunction> ain,fout;
// get wave functions for off-shell momenta for later on
SpinorWaveFunction( fin ,hard[0],incoming,false,true);
SpinorBarWaveFunction(ain ,hard[1],incoming,false,true);
SpinorBarWaveFunction(fout,hard[2],outgoing,true ,true);
SpinorWaveFunction( aout,hard[3],outgoing,true ,true);
// now rescale the momenta and compute the matrix element with the
// rescaled momenta for correlations
vector<Lorentz5Momentum> momenta;
cPDVector data;
for(unsigned int ix=0;ix<4;++ix) {
momenta.push_back(hard[ix]->momentum());
data .push_back(hard[ix]->dataPtr());
}
rescaleMomenta(momenta,data);
SpinorWaveFunction ein (rescaledMomenta()[0],data[0],incoming);
SpinorBarWaveFunction pin (rescaledMomenta()[1],data[1],incoming);
SpinorBarWaveFunction qkout(rescaledMomenta()[2],data[2],outgoing);
SpinorWaveFunction qbout(rescaledMomenta()[3],data[3],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
ein.reset(ix) ; fin [ix] = ein ;
pin.reset(ix) ; ain [ix] = pin ;
qkout.reset(ix); fout[ix] = qkout;
qbout.reset(ix); aout[ix] = qbout;
}
// calculate the matrix element
double me,cont,BW;
ProductionMatrixElement prodme=HelicityME(fin,ain,fout,aout,me,cont,BW);
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(prodme);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<4;++ix) {
tSpinPtr spin = hard[ix]->spinInfo();
if(ix<2) {
tcPolarizedBeamPDPtr beam =
dynamic_ptr_cast<tcPolarizedBeamPDPtr>(hard[ix]->dataPtr());
if(beam) spin->rhoMatrix() = beam->rhoMatrix();
}
spin->productionVertex(hardvertex);
}
}
void MEee2gZ2qq::rebind(const TranslationMap & trans) {
FFZVertex_ = trans.translate(FFZVertex_);
FFPVertex_ = trans.translate(FFPVertex_);
FFGVertex_ = trans.translate(FFGVertex_);
Z0_ = trans.translate(Z0_);
gamma_ = trans.translate(gamma_);
gluon_ = trans.translate(gluon_);
HwMEBase::rebind(trans);
}
IVector MEee2gZ2qq::getReferences() {
IVector ret = HwMEBase::getReferences();
ret.push_back(FFZVertex_);
ret.push_back(FFPVertex_);
ret.push_back(FFGVertex_);
ret.push_back(Z0_ );
ret.push_back(gamma_ );
ret.push_back(gluon_ );
return ret;
}
void MEee2gZ2qq::initializeMECorrection(ShowerTreePtr , double & initial,
double & final) {
d_Q_ = sqrt(sHat());
d_m_ = 0.5*(meMomenta()[2].mass()+meMomenta()[3].mass());
// set the other parameters
d_rho_ = sqr(d_m_/d_Q_);
d_v_ = sqrt(1.-4.*d_rho_);
// maximum evolution scale
d_kt1_ = (1. + sqrt(1. - 4.*d_rho_))/2.;
double num = d_rho_ * d_kt1_ + 0.25 * d_v_ *(1.+d_v_)*(1.+d_v_);
double den = d_kt1_ - d_rho_;
d_kt2_ = num/den;
// maximums for reweighting
initial = 1.;
final = 1.;
}
void MEee2gZ2qq::applyHardMatrixElementCorrection(ShowerTreePtr tree) {
vector<Lorentz5Momentum> emission;
unsigned int iemit,ispect;
- generateHard(tree,emission,iemit,ispect,true,
- vector<ShowerInteraction::Type>(1,ShowerInteraction::QCD));
+ generateHard(tree,emission,iemit,ispect,true,ShowerInteraction::QCD);
if(emission.empty()) return;
// get the quark and antiquark
ParticleVector qq;
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cit;
for(cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit)
qq.push_back(cit->first->copy());
// ensure quark first
if(qq[0]->id()<0) swap(qq[0],qq[1]);
// perform final check to ensure energy greater than constituent mass
for (int i=0; i<2; i++) {
if (emission[i+2].e() < qq[i]->data().constituentMass()) return;
}
if (emission[4].e() < gluon_->constituentMass()) return;
// set masses
for (int i=0; i<2; i++) emission[i+2].setMass(qq[i]->mass());
emission[4].setMass(ZERO);
// decide which particle emits
bool firstEmits=
emission[4].vect().perp2(emission[2].vect())<
emission[4].vect().perp2(emission[3].vect());
// create the new quark, antiquark and gluon
PPtr newg = gluon_->produceParticle(emission[4]);
PPtr newq,newa;
if(firstEmits) {
newq = qq[0]->dataPtr()->produceParticle(emission[2]);
newa = new_ptr(Particle(*qq[1]));
qq[1]->antiColourLine()->removeAntiColoured(newa);
newa->set5Momentum(emission[3]);
}
else {
newq = new_ptr(Particle(*qq[0]));
qq[0]->colourLine()->removeColoured(newq);
newq->set5Momentum(emission[2]);
newa = qq[1]->dataPtr()->produceParticle(emission[3]);
}
// get the original colour line
ColinePtr col;
if(qq[0]->id()>0) col=qq[0]->colourLine();
else col=qq[0]->antiColourLine();
// set the colour lines
if(firstEmits) {
col->addColoured(newq);
col->addAntiColoured(newg);
newa->colourNeighbour(newg);
}
else {
col->addAntiColoured(newa);
col->addColoured(newg);
newq->antiColourNeighbour(newg);
}
// change the existing quark and antiquark
PPtr orig;
for(cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) {
map<tShowerTreePtr,pair<tShowerProgenitorPtr,
tShowerParticlePtr> >::const_iterator tit;
for(tit = tree->treelinks().begin();
tit != tree->treelinks().end();++tit) {
if(tit->second.first && tit->second.second==cit->first->progenitor())
break;
}
if(cit->first->progenitor()->id()==newq->id()) {
// remove old particles from colour line
col->removeColoured(cit->first->copy());
col->removeColoured(cit->first->progenitor());
// insert new particles
cit->first->copy(newq);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newq,1,true)));
cit->first->progenitor(sp);
tree->outgoingLines()[cit->first]=sp;
cit->first->perturbative(!firstEmits);
if(firstEmits) orig=cit->first->original();
if(tit!=tree->treelinks().end())
tree->updateLink(tit->first,make_pair(cit->first,sp));
}
else {
// remove old particles from colour line
col->removeAntiColoured(cit->first->copy());
col->removeAntiColoured(cit->first->progenitor());
// insert new particles
cit->first->copy(newa);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newa,1,true)));
cit->first->progenitor(sp);
tree->outgoingLines()[cit->first]=sp;
cit->first->perturbative(firstEmits);
if(!firstEmits) orig=cit->first->original();
if(tit!=tree->treelinks().end())
tree->updateLink(tit->first,make_pair(cit->first,sp));
}
}
// add the gluon
ShowerParticlePtr sg=new_ptr(ShowerParticle(*newg,1,true));
ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(orig,newg,sg));
gluon->perturbative(false);
tree->outgoingLines().insert(make_pair(gluon,sg));
tree->hardMatrixElementCorrection(true);
}
bool MEee2gZ2qq::softMatrixElementVeto(ShowerProgenitorPtr initial,
ShowerParticlePtr parent,Branching br) {
// check we should be applying the veto
if(parent->id()!=initial->progenitor()->id()||
br.ids[0]!=br.ids[1]||
br.ids[2]!=ParticleID::g) return false;
// calculate pt
double d_z = br.kinematics->z();
Energy d_qt = br.kinematics->scale();
Energy2 d_m2 = parent->momentum().m2();
Energy pPerp = (1.-d_z)*sqrt( sqr(d_z*d_qt) - d_m2);
// if not hardest so far don't apply veto
if(pPerp<initial->highestpT()) return false;
// calculate x and xb
double kti = sqr(d_qt/d_Q_);
double w = sqr(d_v_) + kti*(-1. + d_z)*d_z*(2. + kti*(-1. + d_z)*d_z);
if (w < 0) return false;
double x = (1. + sqr(d_v_)*(-1. + d_z) + sqr(kti*(-1. + d_z))*d_z*d_z*d_z
+ d_z*sqrt(w)
- kti*(-1. + d_z)*d_z*(2. + d_z*(-2 + sqrt(w))))/
(1. - kti*(-1. + d_z)*d_z + sqrt(w));
double xb = 1. + kti*(-1. + d_z)*d_z;
// calculate the weight
if(parent->id()<0) swap(x,xb);
// if exceptionally out of phase space, leave this emission, as there
// is no good interpretation for the soft ME correction.
if( x<0 || xb<0) return false;
double xg = 2. - xb - x;
// always return one in the soft gluon region
if(xg < EPS_) return false;
// check it is in the phase space
if((1.-x)*(1.-xb)*(1.-xg) < d_rho_*xg*xg) {
parent->vetoEmission(parent->id()>0 ? ShowerPartnerType::QCDColourLine :
ShowerPartnerType::QCDColourLine,br.kinematics->scale());
return true;
}
double k1 = getKfromX(x, xb);
double k2 = getKfromX(xb, x);
double weight = 1.;
// quark emission
if(parent->id() > 0 && k1 < d_kt1_) {
weight = MEV(x, xb)/PS(x, xb);
// is it also in the anti-quark emission zone?
if(k2 < d_kt2_) weight *= 0.5;
}
// antiquark emission
if(parent->id() < 0 && k2 < d_kt2_) {
weight = MEV(x, xb)/PS(xb, x);
// is it also in the quark emission zone?
if(k1 < d_kt1_) weight *= 0.5;
}
// compute veto from weight
bool veto = !UseRandom::rndbool(weight);
// if not vetoed reset max
// if vetoing reset the scale
if(veto) {
parent->vetoEmission(parent->id()>0 ? ShowerPartnerType::QCDColourLine :
ShowerPartnerType::QCDColourLine,br.kinematics->scale());
}
// return the veto
return veto;
}
double MEee2gZ2qq::getKfromX(double x1, double x2) {
double uval = 0.5*(1. + d_rho_/(1.-x2+d_rho_));
double num = x1 - (2. - x2)*uval;
double den = sqrt(x2*x2 - 4.*d_rho_);
double zval = uval + num/den;
return (1.-x2)/(zval*(1.-zval));
}
double MEee2gZ2qq::MEV(double x1, double x2) {
// Vector part
double num = (x1+2.*d_rho_)*(x1+2.*d_rho_) + (x2+2.*d_rho_)*(x2+2.*d_rho_)
- 8.*d_rho_*(1.+2.*d_rho_);
double den = (1.+2.*d_rho_)*(1.-x1)*(1.-x2);
return (num/den - 2.*d_rho_/((1.-x1)*(1.-x1))
- 2*d_rho_/((1.-x2)*(1.-x2)))/d_v_;
}
double MEee2gZ2qq::PS(double x, double xbar) {
double u = 0.5*(1. + d_rho_ / (1.-xbar+d_rho_));
double z = u + (x - (2.-xbar)*u)/sqrt(xbar*xbar - 4.*d_rho_);
double brack = (1.+z*z)/(1.-z)- 2.*d_rho_/(1-xbar);
// interesting: the splitting function without the subtraction
// term. Actually gives a much worse approximation in the collinear
// limit. double brack = (1.+z*z)/(1.-z);
double den = (1.-xbar)*sqrt(xbar*xbar - 4.*d_rho_);
return brack/den;
}
pair<Energy,ShowerInteraction::Type>
MEee2gZ2qq::generateHard(ShowerTreePtr tree,
vector<Lorentz5Momentum> & emmision,
unsigned int & iemit, unsigned int & ispect,
- bool applyVeto,
- vector<ShowerInteraction::Type> inter) {
+ bool applyVeto,ShowerInteraction::Type type) {
+ vector<ShowerInteraction::Type> inter;
+ if(type==ShowerInteraction::QCD)
+ inter.push_back(ShowerInteraction::QCD);
+ else if(type==ShowerInteraction::QED)
+ inter.push_back(ShowerInteraction::QED);
+ else if(type==ShowerInteraction::QEDQCD ||
+ type==ShowerInteraction::ALL) {
+ inter.push_back(ShowerInteraction::QCD);
+ inter.push_back(ShowerInteraction::QED);
+ }
// get the momenta of the incoming and outgoing partons
// incoming
ShowerProgenitorPtr
emProgenitor = tree->incomingLines().begin() ->first,
epProgenitor = tree->incomingLines().rbegin()->first;
// outgoing
ShowerProgenitorPtr
qkProgenitor = tree->outgoingLines().begin() ->first,
qbProgenitor = tree->outgoingLines().rbegin()->first;
// get the order right
if(emProgenitor->id()<0) swap(emProgenitor,epProgenitor);
if(qkProgenitor->id()<0) swap(qkProgenitor,qbProgenitor);
loMomenta_.clear();
// extract the momenta
loMomenta_.push_back(emProgenitor->progenitor()->momentum());
loMomenta_.push_back(epProgenitor->progenitor()->momentum());
loMomenta_.push_back(qkProgenitor->progenitor()->momentum());
loMomenta_.push_back(qbProgenitor->progenitor()->momentum());
// and ParticleData objects
partons_.resize(5);
partons_[0]=emProgenitor->progenitor()->dataPtr();
partons_[1]=epProgenitor->progenitor()->dataPtr();
partons_[2]=qkProgenitor->progenitor()->dataPtr();
partons_[3]=qbProgenitor->progenitor()->dataPtr();
partons_[4]=cPDPtr();
// boost from lab to CMS frame with outgoing particles
// along the z axis
LorentzRotation eventFrame( ( loMomenta_[2] + loMomenta_[3] ).findBoostToCM() );
Lorentz5Momentum spectator = eventFrame*loMomenta_[2];
eventFrame.rotateZ( -spectator.phi() );
eventFrame.rotateY( -spectator.theta() );
eventFrame.invert();
// mass of the final-state system
Energy2 M2 = (loMomenta_[2]+loMomenta_[3]).m2();
Energy M = sqrt(M2);
double mu1 = loMomenta_[2].mass()/M;
double mu2 = loMomenta_[3].mass()/M;
double mu12 = sqr(mu1), mu22 = sqr(mu2);
double lambda = sqrt(1.+sqr(mu12)+sqr(mu22)-2.*mu12-2.*mu22-2.*mu12*mu22);
// max pT
Energy pTmax = 0.5*sqrt(M2)*
(1.-sqr(loMomenta_[2].mass()+loMomenta_[3].mass())/M2);
// max y
if ( pTmax < pTminQED_ && pTmax < pTminQCD_ ) return make_pair(ZERO,ShowerInteraction::QCD);
vector<Energy> pTemit;
vector<vector<Lorentz5Momentum> > emittedMomenta;;
vector<unsigned int> iemitter,ispectater;
for(unsigned int iinter=0;iinter<inter.size();++iinter) {
Energy pTmin(ZERO);
double a,ymax;
if(inter[iinter]==ShowerInteraction::QCD) {
pTmin = pTminQCD_;
ymax = acosh(pTmax/pTmin);
partons_[4] = gluon_;
// prefactor for the overestimate of the Sudakov
a = 4./3.*alphaQCD_->overestimateValue()/Constants::twopi*
2.*ymax*preFactor_;
}
else {
pTmin = pTminQED_;
ymax = acosh(pTmax/pTmin);
partons_[4] = gamma_;
a = alphaQED_->overestimateValue()/Constants::twopi*
2.*ymax*preFactor_*sqr(double(mePartonData()[2]->iCharge())/3.);
}
// variables for the emission
Energy pT[2];
double y[2],phi[2],x3[2],x1[2][2],x2[2][2];
double contrib[2][2];
// storage of the real emission momenta
vector<Lorentz5Momentum> realMomenta[2][2]=
{{vector<Lorentz5Momentum>(5),vector<Lorentz5Momentum>(5)},
{vector<Lorentz5Momentum>(5),vector<Lorentz5Momentum>(5)}};
for(unsigned int ix=0;ix<2;++ix)
for(unsigned int iy=0;iy<2;++iy)
for(unsigned int iz=0;iz<2;++iz)
realMomenta[ix][iy][iz] = loMomenta_[iz];
// generate the emission
for(unsigned int ix=0;ix<2;++ix) {
if(ix==1) {
swap(mu1 ,mu2 );
swap(mu12,mu22);
}
pT[ix] = pTmax;
y [ix] = 0.;
bool reject = true;
do {
// generate pT
pT[ix] *= pow(UseRandom::rnd(),1./a);
if(pT[ix]<pTmin) {
pT[ix] = -GeV;
break;
}
// generate y
y[ix] = -ymax+2.*UseRandom::rnd()*ymax;
// generate phi
phi[ix] = UseRandom::rnd()*Constants::twopi;
// calculate x3 and check in allowed region
x3[ix] = 2.*pT[ix]*cosh(y[ix])/M;
if(x3[ix] < 0. || x3[ix] > 1. -sqr( mu1 + mu2 ) ) continue;
// find the possible solutions for x1
double xT2 = sqr(2./M*pT[ix]);
double root = (-sqr(x3[ix])+xT2)*
(xT2*mu22+2.*x3[ix]-sqr(mu12)+2.*mu22+2.*mu12-sqr(x3[ix])-1.
+2.*mu12*mu22-sqr(mu22)-2.*mu22*x3[ix]-2.*mu12*x3[ix]);
double c1=2.*sqr(x3[ix])-4.*mu22-6.*x3[ix]+4.*mu12-xT2*x3[ix]
+2.*xT2-2.*mu12*x3[ix]+2.*mu22*x3[ix]+4.;
if(root<0.) continue;
x1[ix][0] = 1./(4.-4.*x3[ix]+xT2)*(c1-2.*sqrt(root));
x1[ix][1] = 1./(4.-4.*x3[ix]+xT2)*(c1+2.*sqrt(root));
// change sign of y if 2nd particle emits
if(ix==1) y[ix] *=-1.;
// loop over the solutions
for(unsigned int iy=0;iy<2;++iy) {
contrib[ix][iy]=0.;
// check x1 value allowed
if(x1[ix][iy]<2.*mu1||x1[ix][iy]>1.+mu12-mu22) continue;
// calculate x2 value and check allowed
x2[ix][iy] = 2.-x3[ix]-x1[ix][iy];
double root = max(0.,sqr(x1[ix][iy])-4.*mu12);
root = sqrt(root);
double x2min = 1.+mu22-mu12
-0.5*(1.-x1[ix][iy]+mu12-mu22)/(1.-x1[ix][iy]+mu12)*(x1[ix][iy]-2.*mu12+root);
double x2max = 1.+mu22-mu12
-0.5*(1.-x1[ix][iy]+mu12-mu22)/(1.-x1[ix][iy]+mu12)*(x1[ix][iy]-2.*mu12-root);
if(x2[ix][iy]<x2min||x2[ix][iy]>x2max) continue;
// check the z components
double z1 = sqrt(sqr(x1[ix][iy])-4.*mu12-xT2);
double z2 = -sqrt(sqr(x2[ix][iy])-4.*mu22);
double z3 = pT[ix]*sinh(y[ix])*2./M;
if(ix==1) z3 *=-1.;
if(abs(-z1+z2+z3)<1e-9) z1 *= -1.;
if(abs(z1+z2+z3)>1e-5) continue;
// if using as an ME correction the veto
if(applyVeto) {
double xb = x1[ix][iy], xc = x2[ix][iy];
double b = mu12, c = mu22;
double r = 0.5*(1.+b/(1.+c-xc));
double z1 = r + (xb-(2.-xc)*r)/sqrt(sqr(xc)-4.*c);
double kt1 = (1.-b+c-xc)/z1/(1.-z1);
r = 0.5*(1.+c/(1.+b-xb));
double z2 = r + (xc-(2.-xb)*r)/sqrt(sqr(xb)-4.*b);
double kt2 = (1.-c+b-xb)/z2/(1.-z2);
if(ix==1) {
swap(z1 ,z2);
swap(kt1,kt2);
}
// veto the shower region
if( kt1 < d_kt1_ || kt2 < d_kt2_ ) continue;
}
// construct the momenta
realMomenta[ix][iy][4] =
Lorentz5Momentum(pT[ix]*cos(phi[ix]),pT[ix]*sin(phi[ix]),
pT[ix]*sinh(y[ix]) ,pT[ix]*cosh(y[ix]),ZERO);
if(ix==0) {
realMomenta[ix][iy][2] =
Lorentz5Momentum(-pT[ix]*cos(phi[ix]),-pT[ix]*sin(phi[ix]),
z1*0.5*M,x1[ix][iy]*0.5*M,M*mu1);
realMomenta[ix][iy][3] =
Lorentz5Momentum(ZERO,ZERO, z2*0.5*M,x2[ix][iy]*0.5*M,M*mu2);
}
else {
realMomenta[ix][iy][2] =
Lorentz5Momentum(ZERO,ZERO,-z2*0.5*M,x2[ix][iy]*0.5*M,M*mu2);
realMomenta[ix][iy][3] =
Lorentz5Momentum(-pT[ix]*cos(phi[ix]),-pT[ix]*sin(phi[ix]),
-z1*0.5*M,x1[ix][iy]*0.5*M,M*mu1);
}
// boost the momenta back to the lab
for(unsigned int iz=2;iz<5;++iz)
realMomenta[ix][iy][iz] *= eventFrame;
// jacobian and prefactors for the weight
Energy J = M/sqrt(xT2)*abs(-x1[ix][iy]*x2[ix][iy]+2.*mu22*x1[ix][iy]
+x2[ix][iy]+x2[ix][iy]*mu12+mu22*x2[ix][iy]
-sqr(x2[ix][iy]))
/pow(sqr(x2[ix][iy])-4.*mu22,1.5);
// prefactors etc
contrib[ix][iy] = 0.5*pT[ix]/J/preFactor_/lambda;
// matrix element piece
contrib[ix][iy] *= meRatio(partons_,realMomenta[ix][iy],
ix,inter[iinter],false);
// coupling piece
if(inter[iinter]==ShowerInteraction::QCD)
contrib[ix][iy] *= alphaQCD_->ratio(sqr(pT[ix]));
else
contrib[ix][iy] *= alphaQED_->ratio(sqr(pT[ix]));
}
if(contrib[ix][0]+contrib[ix][1]>1.) {
ostringstream s;
s << "MEee2gZ2qq::generateHardest weight for channel " << ix
<< "is " << contrib[ix][0]+contrib[ix][1]
<< " which is greater than 1";
generator()->logWarning( Exception(s.str(), Exception::warning) );
}
reject = UseRandom::rnd() > contrib[ix][0] + contrib[ix][1];
}
while (reject);
if(pT[ix]<pTmin)
pT[ix] = -GeV;
}
// pt of emission
if(pT[0]<ZERO && pT[1]<ZERO) {
pTemit.push_back(-GeV);
emittedMomenta.push_back(vector<Lorentz5Momentum>());
iemitter .push_back(0);
ispectater.push_back(0);
continue;
}
// now pick the emission with highest pT
vector<Lorentz5Momentum> emission;
if(pT[0]>pT[1]) {
iemitter .push_back(2);
ispectater.push_back(3);
pTemit.push_back(pT[0]);
if(UseRandom::rnd()<contrib[0][0]/(contrib[0][0]+contrib[0][1]))
emission = realMomenta[0][0];
else
emission = realMomenta[0][1];
}
else {
iemitter .push_back(3);
ispectater.push_back(2);
pTemit.push_back(pT[1]);
if(UseRandom::rnd()<contrib[1][0]/(contrib[1][0]+contrib[1][1]))
emission = realMomenta[1][0];
else
emission = realMomenta[1][1];
}
emittedMomenta.push_back(emission);
}
// select the type of emission
int iselect=-1;
pTmax = ZERO;
for(unsigned int ix=0;ix<inter.size();++ix) {
if(pTemit[ix]>pTmax) {
iselect = ix;
pTmax = pTemit[ix];
}
}
// no emission return
if(iselect<0) {
return make_pair(ZERO,ShowerInteraction::QCD);
}
partons_[4] = inter[iselect]==ShowerInteraction::QCD ? gluon_ : gamma_;
iemit = iemitter[iselect];
ispect = ispectater[iselect];
emmision = emittedMomenta[iselect];
// return pT of emission
return make_pair(pTmax,inter[iselect]);
}
HardTreePtr MEee2gZ2qq::generateHardest(ShowerTreePtr tree,
- vector<ShowerInteraction::Type> inter) {
+ ShowerInteraction::Type inter) {
// generate the momenta for the hard emission
vector<Lorentz5Momentum> emmision;
unsigned int iemit,ispect;
pair<Energy,ShowerInteraction::Type> output
= generateHard(tree,emmision,iemit,ispect,false,inter);
Energy pTveto = output.first;
ShowerInteraction::Type force = output.second;
// incoming progenitors
ShowerProgenitorPtr
ePProgenitor = tree->incomingLines().begin() ->first,
eMProgenitor = tree->incomingLines().rbegin()->first;
if(eMProgenitor->id()<0) swap(eMProgenitor,ePProgenitor);
// outgoing progenitors
ShowerProgenitorPtr
qkProgenitor = tree->outgoingLines().begin() ->first,
qbProgenitor = tree->outgoingLines().rbegin()->first;
if(qkProgenitor->id()<0) swap(qkProgenitor,qbProgenitor);
// maximum pT of emission
if(emmision.empty()) {
- for(unsigned int ix=0;ix<inter.size();++ix) {
- if(inter[ix]==ShowerInteraction::QCD) {
- qkProgenitor->maximumpT(pTminQCD_,inter[ix]);
- qbProgenitor->maximumpT(pTminQCD_,inter[ix]);
- }
- else {
- qkProgenitor->maximumpT(pTminQED_,inter[ix]);
- qbProgenitor->maximumpT(pTminQED_,inter[ix]);
- }
+ if(inter==ShowerInteraction::QCD ||
+ inter==ShowerInteraction::QEDQCD ||
+ inter==ShowerInteraction::ALL) {
+ qkProgenitor->maximumpT(pTminQCD_,ShowerInteraction::QCD);
+ qbProgenitor->maximumpT(pTminQCD_,ShowerInteraction::QCD);
+ }
+ if(inter==ShowerInteraction::QED ||
+ inter==ShowerInteraction::QEDQCD ||
+ inter==ShowerInteraction::ALL) {
+ qkProgenitor->maximumpT(pTminQED_,ShowerInteraction::QED);
+ qbProgenitor->maximumpT(pTminQED_,ShowerInteraction::QED);
}
return HardTreePtr();
}
else {
- for(unsigned int ix=0;ix<inter.size();++ix) {
- qkProgenitor->maximumpT(pTveto,inter[ix]);
- qbProgenitor->maximumpT(pTveto,inter[ix]);
+ if(inter==ShowerInteraction::QCD ||
+ inter==ShowerInteraction::QEDQCD ||
+ inter==ShowerInteraction::ALL) {
+ qkProgenitor->maximumpT(pTveto,ShowerInteraction::QCD);
+ qbProgenitor->maximumpT(pTveto,ShowerInteraction::QCD);
+ }
+ if(inter==ShowerInteraction::QED ||
+ inter==ShowerInteraction::QEDQCD ||
+ inter==ShowerInteraction::ALL) {
+ qkProgenitor->maximumpT(pTveto,ShowerInteraction::QED);
+ qbProgenitor->maximumpT(pTveto,ShowerInteraction::QED);
}
}
// perform final check to ensure energy greater than constituent mass
if (emmision[2].e() < qkProgenitor->progenitor()->data().constituentMass()) return HardTreePtr();
if (emmision[3].e() < qbProgenitor->progenitor()->data().constituentMass()) return HardTreePtr();
if(force!=ShowerInteraction::QED &&
emmision[4].e() < gluon_->constituentMass()) return HardTreePtr();
// Make the particles for the hard tree
ShowerParticleVector hardParticles;
for(unsigned int ix=0;ix<partons_.size();++ix) {
hardParticles.push_back(new_ptr(ShowerParticle(partons_[ix],ix>=2)));
hardParticles.back()->set5Momentum(emmision[ix]);
}
ShowerParticlePtr parent(new_ptr(ShowerParticle(partons_[iemit],true)));
Lorentz5Momentum parentMomentum(emmision[iemit]+emmision[4]);
parentMomentum.setMass(partons_[iemit]->mass());
parent->set5Momentum(parentMomentum);
// Create the vectors of HardBranchings to create the HardTree:
vector<HardBranchingPtr> spaceBranchings,allBranchings;
// Incoming boson:
for(unsigned int ix=0;ix<2;++ix) {
spaceBranchings.push_back(new_ptr(HardBranching(hardParticles[ix],SudakovPtr(),
HardBranchingPtr(),
HardBranching::Incoming)));
allBranchings.push_back(spaceBranchings.back());
}
// Outgoing particles from hard emission:
HardBranchingPtr spectatorBranch(new_ptr(HardBranching(hardParticles[ispect],
SudakovPtr(),HardBranchingPtr(),
HardBranching::Outgoing)));
HardBranchingPtr emitterBranch(new_ptr(HardBranching(parent,SudakovPtr(),
HardBranchingPtr(),
HardBranching::Outgoing)));
if(force==ShowerInteraction::QED) {
emitterBranch->type(ShowerPartnerType::QED);
}
else {
emitterBranch->type(emitterBranch->branchingParticle()->id()>0 ?
ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine);
}
emitterBranch->addChild(new_ptr(HardBranching(hardParticles[iemit],
SudakovPtr(),HardBranchingPtr(),
HardBranching::Outgoing)));
emitterBranch->addChild(new_ptr(HardBranching(hardParticles[4],
SudakovPtr(),HardBranchingPtr(),
HardBranching::Outgoing)));
if(iemit==0) {
allBranchings.push_back(emitterBranch);
allBranchings.push_back(spectatorBranch);
}
else {
allBranchings.push_back( spectatorBranch );
allBranchings.push_back( emitterBranch );
}
emitterBranch ->branchingParticle()->partner(spectatorBranch->branchingParticle());
spectatorBranch->branchingParticle()->partner(emitterBranch ->branchingParticle());
if(force==ShowerInteraction::QED) {
spaceBranchings[0]->branchingParticle()->partner(spaceBranchings[1]->branchingParticle());
spaceBranchings[1]->branchingParticle()->partner(spaceBranchings[0]->branchingParticle());
}
// Make the HardTree from the HardBranching vectors.
HardTreePtr hardtree = new_ptr(HardTree(allBranchings,spaceBranchings,
force));
hardtree->partnersSet(true);
// Connect the particles with the branchings in the HardTree
hardtree->connect( eMProgenitor->progenitor(), allBranchings[0] );
tPPtr beam = eMProgenitor->original();
if(!beam->parents().empty()) beam = beam->parents()[0];
allBranchings[0]->beam(beam);
hardtree->connect( ePProgenitor->progenitor(), allBranchings[1] );
beam = ePProgenitor->original();
if(!beam->parents().empty()) beam = beam->parents()[0];
allBranchings[1]->beam(beam);
hardtree->connect( qkProgenitor->progenitor(), allBranchings[2] );
hardtree->connect( qbProgenitor->progenitor(), allBranchings[3] );
// colour flow
ColinePtr newline=new_ptr(ColourLine());
for(set<HardBranchingPtr>::const_iterator cit=hardtree->branchings().begin();
cit!=hardtree->branchings().end();++cit) {
if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3)
newline->addColoured((**cit).branchingParticle());
else if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3bar)
newline->addAntiColoured((**cit).branchingParticle());
}
allBranchings[2]->colourPartner(allBranchings[3]);
allBranchings[3]->colourPartner(allBranchings[2]);
if(hardParticles[4]->dataPtr()->iColour()==PDT::Colour8) {
ColinePtr newLine2=new_ptr(ColourLine());
if(emitterBranch->branchingParticle()->dataPtr()->iColour()==PDT::Colour3) {
emitterBranch->branchingParticle()->colourLine()->addColoured(hardParticles[4]);
newLine2->addColoured(hardParticles[iemit]);
newLine2->addAntiColoured(hardParticles[4]);
}
else {
emitterBranch->branchingParticle()->antiColourLine()->addAntiColoured(hardParticles[4]);
newLine2->addAntiColoured(hardParticles[iemit]);
newLine2->addColoured(hardParticles[4]);
}
}
else {
if(emitterBranch->branchingParticle()->dataPtr()->iColour()==PDT::Colour3) {
emitterBranch->branchingParticle()->colourLine()->addColoured(hardParticles[iemit]);
}
else {
emitterBranch->branchingParticle()->antiColourLine()->addAntiColoured(hardParticles[iemit]);
}
}
// Return the HardTree
return hardtree;
}
double MEee2gZ2qq::meRatio(vector<cPDPtr> partons,
vector<Lorentz5Momentum> momenta,
unsigned int iemitter,
ShowerInteraction::Type inter,
bool subtract) const {
Lorentz5Momentum q = momenta[2]+momenta[3]+momenta[4];
Energy2 Q2=q.m2();
Energy2 lambda = sqrt((Q2-sqr(momenta[2].mass()+momenta[3].mass()))*
(Q2-sqr(momenta[2].mass()-momenta[3].mass())));
InvEnergy2 D[2];
double lome[2];
for(unsigned int iemit=0;iemit<2;++iemit) {
unsigned int ispect = iemit==0 ? 1 : 0;
Energy2 pipj = momenta[4 ] * momenta[2+iemit ];
Energy2 pipk = momenta[4 ] * momenta[2+ispect];
Energy2 pjpk = momenta[2+iemit] * momenta[2+ispect];
double y = pipj/(pipj+pipk+pjpk);
double z = pipk/( pipk+pjpk);
Energy mij = sqrt(2.*pipj+sqr(momenta[2+iemit].mass()));
Energy2 lamB = sqrt((Q2-sqr(mij+momenta[2+ispect].mass()))*
(Q2-sqr(mij-momenta[2+ispect].mass())));
Energy2 Qpk = q*momenta[2+ispect];
Lorentz5Momentum pkt =
lambda/lamB*(momenta[2+ispect]-Qpk/Q2*q)
+0.5/Q2*(Q2+sqr(momenta[2+ispect].mass())-sqr(momenta[2+ispect].mass()))*q;
Lorentz5Momentum pijt =
q-pkt;
double muj = momenta[2+iemit ].mass()/sqrt(Q2);
double muk = momenta[2+ispect].mass()/sqrt(Q2);
double vt = sqrt((1.-sqr(muj+muk))*(1.-sqr(muj-muk)))/(1.-sqr(muj)-sqr(muk));
double v = sqr(2.*sqr(muk)+(1.-sqr(muj)-sqr(muk))*(1.-y))-4.*sqr(muk);
if(v<=0.) return 0.;
v = sqrt(v)/(1.-y)/(1.-sqr(muj)-sqr(muk));
// dipole term
D[iemit] = 0.5/pipj*(2./(1.-(1.-z)*(1.-y))
-vt/v*(2.-z+sqr(momenta[2+iemit].mass())/pipj));
// matrix element
vector<Lorentz5Momentum> lomom(4);
lomom[0] = momenta[0];
lomom[1] = momenta[1];
if(iemit==0) {
lomom[2] = pijt;
lomom[3] = pkt ;
}
else {
lomom[3] = pijt;
lomom[2] = pkt ;
}
lome[iemit] = loME(partons,lomom,false)/3.;
}
InvEnergy2 ratio = realME(partons,momenta,inter)
*abs(D[iemitter])/(abs(D[0]*lome[0])+abs(D[1]*lome[1]));
double output = Q2*ratio;
if(subtract) output -= 2.*Q2*D[iemitter];
return output;
}
double MEee2gZ2qq::loME(const vector<cPDPtr> & partons,
const vector<Lorentz5Momentum> & momenta,
bool first) const {
// compute the spinors
vector<SpinorWaveFunction> fin,aout;
vector<SpinorBarWaveFunction> ain,fout;
SpinorWaveFunction ein (momenta[0],partons[0],incoming);
SpinorBarWaveFunction pin (momenta[1],partons[1],incoming);
SpinorBarWaveFunction qkout(momenta[2],partons[2],outgoing);
SpinorWaveFunction qbout(momenta[3],partons[3],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
ein.reset(ix) ;
fin.push_back( ein );
pin.reset(ix) ;
ain.push_back( pin );
qkout.reset(ix);
fout.push_back(qkout);
qbout.reset(ix);
aout.push_back(qbout);
}
// compute the matrix element
double me,lastCont,lastBW;
HelicityME(fin,ain,fout,aout,me,lastCont,lastBW);
// save the components
if(first) {
DVector save;
save.push_back(lastCont);
save.push_back(lastBW);
meInfo(save);
}
// return the answer
return me;
}
InvEnergy2 MEee2gZ2qq::realME(const vector<cPDPtr> & partons,
const vector<Lorentz5Momentum> & momenta,
ShowerInteraction::Type inter) const {
// compute the spinors
vector<SpinorWaveFunction> fin,aout;
vector<SpinorBarWaveFunction> ain,fout;
vector<VectorWaveFunction> gout;
SpinorWaveFunction ein (momenta[0],partons[0],incoming);
SpinorBarWaveFunction pin (momenta[1],partons[1],incoming);
SpinorBarWaveFunction qkout(momenta[2],partons[2],outgoing);
SpinorWaveFunction qbout(momenta[3],partons[3],outgoing);
VectorWaveFunction gluon(momenta[4],partons[4],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
ein.reset(ix) ;
fin.push_back( ein );
pin.reset(ix) ;
ain.push_back( pin );
qkout.reset(ix);
fout.push_back(qkout);
qbout.reset(ix);
aout.push_back(qbout);
gluon.reset(2*ix);
gout.push_back(gluon);
}
AbstractFFVVertexPtr vertex = inter == ShowerInteraction::QCD ?
FFGVertex_ : FFPVertex_;
vector<Complex> diag(4,0.);
ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1);
double total(0.);
for(unsigned int inhel1=0;inhel1<2;++inhel1) {
for(unsigned int inhel2=0;inhel2<2;++inhel2) {
// intermediate Z
VectorWaveFunction interZ =
FFZVertex_->evaluate(scale(),1,Z0_,fin[inhel1],ain[inhel2]);
// intermediate photon
VectorWaveFunction interG =
FFPVertex_->evaluate(scale(),1,gamma_,fin[inhel1],ain[inhel2]);
for(unsigned int outhel1=0;outhel1<2;++outhel1) {
for(unsigned int outhel2=0;outhel2<2;++outhel2) {
for(unsigned int outhel3=0;outhel3<2;++outhel3) {
SpinorBarWaveFunction off1 =
vertex->evaluate(scale(),3,partons[2],fout[outhel1],gout[outhel3]);
diag[0] = FFZVertex_->evaluate(scale(),aout[outhel2],off1,interZ);
diag[1] = FFPVertex_->evaluate(scale(),aout[outhel2],off1,interG);
SpinorWaveFunction off2 =
vertex->evaluate(scale(),3,partons[3],aout[outhel2],gout[outhel3]);
diag[2] = FFZVertex_->evaluate(scale(),off2,fout[outhel1],interZ);
diag[3] = FFPVertex_->evaluate(scale(),off2,fout[outhel1],interG);
// sum of diagrams
Complex sum = std::accumulate(diag.begin(),diag.end(),Complex(0.));
// matrix element
output(inhel1,inhel2,outhel1,outhel2,outhel3)=sum;
// me2
total += norm(sum);
}
}
}
}
}
// spin average
total *= 0.25;
tcPolarizedBeamPDPtr beam[2] =
{dynamic_ptr_cast<tcPolarizedBeamPDPtr>(partons[0]),
dynamic_ptr_cast<tcPolarizedBeamPDPtr>(partons[1])};
if( beam[0] || beam[1] ) {
RhoDMatrix rho[2] =
{beam[0] ? beam[0]->rhoMatrix() : RhoDMatrix(mePartonData()[0]->iSpin()),
beam[1] ? beam[1]->rhoMatrix() : RhoDMatrix(mePartonData()[1]->iSpin())};
total = output.average(rho[0],rho[1]);
}
// divide out the coupling
total /= norm(vertex->norm());
// and charge (if needed)
if(inter==ShowerInteraction::QED)
total /= sqr(double(mePartonData()[2]->iCharge())/3.);
// return the total
return total*UnitRemoval::InvE2;
}
diff --git a/MatrixElement/Lepton/MEee2gZ2qq.h b/MatrixElement/Lepton/MEee2gZ2qq.h
--- a/MatrixElement/Lepton/MEee2gZ2qq.h
+++ b/MatrixElement/Lepton/MEee2gZ2qq.h
@@ -1,503 +1,501 @@
// -*- C++ -*-
//
// MEee2gZ2qq.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_MEee2gZ2qq_H
#define HERWIG_MEee2gZ2qq_H
//
// This is the declaration of the MEee2gZ2qq class.
//
#include "Herwig/MatrixElement/HwMEBase.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Utilities/Rebinder.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/Shower/Couplings/ShowerAlpha.h"
namespace Herwig {
using namespace ThePEG;
/**
* The MEee2gZ2qq class implements the matrix element
* for \f$e^+e^-\to Z/\gamma \to q\bar{q}\f$ including spin correlations.
* The class includes greater control over the type of quark produced than is available
* in the corresponding matrix element from ThePEG, in addition to spin correlations.
*
* @see \ref MEee2gZ2qqInterfaces "The interfaces"
* defined for MEee2gZ2qq.
*/
class MEee2gZ2qq: public HwMEBase {
public:
/**
* The default constructor.
*/
MEee2gZ2qq() : minflav_(1), maxflav_(5), massopt_(1),
spinCorrelations_(true),
pTminQED_(GeV), pTminQCD_(GeV),
preFactor_(6.)
{}
/**
* Members for hard corrections to the emission of QCD radiation
*/
//@{
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return FSR;}
/**
* Has an old fashioned ME correction
*/
virtual bool hasMECorrection() {return true;}
/**
* Initialize the ME correction
*/
virtual void initializeMECorrection(ShowerTreePtr, double &,
double & );
/**
* Apply the hard matrix element correction to a given hard process or decay
*/
virtual void applyHardMatrixElementCorrection(ShowerTreePtr);
/**
* Apply the soft matrix element correction
* @param initial The particle from the hard process which started the
* shower
* @param parent The initial particle in the current branching
* @param br The branching struct
* @return If true the emission should be vetoed
*/
virtual bool softMatrixElementVeto(ShowerProgenitorPtr initial,
ShowerParticlePtr parent,
Branching br);
/**
* Apply the POWHEG style correction
*/
- virtual HardTreePtr generateHardest(ShowerTreePtr,
- vector<ShowerInteraction::Type>);
+ virtual HardTreePtr generateHardest(ShowerTreePtr,ShowerInteraction::Type);
//@}
/** @name Virtual functions required by the MEBase class. */
//@{
/**
* Return the order in \f$\alpha_S\f$ in which this matrix
* element is given.
*/
virtual unsigned int orderInAlphaS() const;
/**
* Return the order in \f$\alpha_{EW}\f$ in which this matrix
* element is given.
*/
virtual unsigned int orderInAlphaEW() const;
/**
* The matrix element for the kinematical configuration
* previously provided by the last call to setKinematics(), suitably
* scaled by sHat() to give a dimension-less number.
* @return the matrix element scaled with sHat() to give a
* dimensionless number.
*/
virtual double me2() const;
/**
* Return the scale associated with the last set phase space point.
*/
virtual Energy2 scale() const;
/**
* Add all possible diagrams with the add() function.
*/
virtual void getDiagrams() const;
/**
* Get diagram selector. With the information previously supplied with the
* setKinematics method, a derived class may optionally
* override this method to weight the given diagrams with their
* (although certainly not physical) relative probabilities.
* @param dv the diagrams to be weighted.
* @return a Selector relating the given diagrams to their weights.
*/
virtual Selector<DiagramIndex> diagrams(const DiagramVector & dv) const;
/**
* Return a Selector with possible colour geometries for the selected
* diagram weighted by their relative probabilities.
* @param diag the diagram chosen.
* @return the possible colour geometries weighted by their
* relative probabilities.
*/
virtual Selector<const ColourLines *>
colourGeometries(tcDiagPtr diag) const;
/**
* Construct the vertex of spin correlations.
*/
virtual void constructVertex(tSubProPtr);
//@}
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const {return new_ptr(*this);}
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const {return new_ptr(*this);}
//@}
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
/**
* Rebind pointer to other Interfaced objects. Called in the setup phase
* after all objects used in an EventGenerator has been cloned so that
* the pointers will refer to the cloned objects afterwards.
* @param trans a TranslationMap relating the original objects to
* their respective clones.
* @throws RebindException if no cloned object was found for a given
* pointer.
*/
virtual void rebind(const TranslationMap & trans)
;
/**
* Return a vector of all pointers to Interfaced objects used in this
* object.
* @return a vector of pointers.
*/
virtual IVector getReferences();
//@}
protected:
/**
* Calculate the matrix element for \f$e^+e^-\to q \bar{q}\f$.
* @param partons The incoming and outgoing particles
* @param momenta The momenta of the incoming and outgoing particles
* @param first Whether or not to calculate the spin correlations
*/
double loME(const vector<cPDPtr> & partons,
const vector<Lorentz5Momentum> & momenta,
bool first) const;
/**
* Member to calculate the matrix element
* @param fin Spinors for incoming fermion
* @param ain Spinors for incoming antifermion
* @param fout Spinors for outgoing fermion
* @param aout Spinors for outgong antifermion
* @param me Spin summed Matrix element
* @param cont The continuum piece of the matrix element
* @param BW The Z piece of the matrix element
*/
ProductionMatrixElement HelicityME(vector<SpinorWaveFunction> & fin,
vector<SpinorBarWaveFunction> & ain,
vector<SpinorBarWaveFunction> & fout,
vector<SpinorWaveFunction> & aout,
double & me,
double & cont,
double & BW ) const;
/**
* The ratio of the matrix element for one additional jet over the
* leading order result. In practice
* \f[\frac{\hat{s}|\overline{\mathcal{M}}|^2_2|D_{\rm emit}|}{4\pi C_F\alpha_S|\overline{\mathcal{M}}|^2_3\left(|D_{\rm emit}|+|D_{\rm spect}|\right)}\f]
* is returned where \f$\|\overline{\mathcal{M}}|^2\f$ is
* the spin and colour summed/averaged matrix element.
* @param partons The incoming and outgoing particles
* @param momenta The momenta of the incoming and outgoing particles
* @param iemitter Whether the quark or antiquark is regardede as the emitter
* @param inter The type of interaction
* @param subtract Whether or not to subtract the relevant dipole term
*/
double meRatio(vector<cPDPtr> partons,
vector<Lorentz5Momentum> momenta,
unsigned int iemitter,
ShowerInteraction::Type inter,
bool subtract =false) const;
/**
* Calculate the matrix element for \f$e^-e^-\to q \bar q g\f$.
* @param partons The incoming and outgoing particles
* @param momenta The momenta of the incoming and outgoing particles
* @param inter The type of interaction
*/
InvEnergy2 realME(const vector<cPDPtr> & partons,
const vector<Lorentz5Momentum> & momenta,
ShowerInteraction::Type inter) const;
private:
/**
* Generate the momenta for a hard configuration
*/
pair<Energy,ShowerInteraction::Type>
generateHard(ShowerTreePtr tree,
vector<Lorentz5Momentum> & emission,
unsigned int & iemit, unsigned int & ispect,
- bool applyVeto,
- vector<ShowerInteraction::Type>);
+ bool applyVeto,ShowerInteraction::Type);
/**
* Calculate \f$\tilde{\kappa}\f$.
*/
double getKfromX(double, double);
/**
* Vector and axial vector parts of the matrix element
*/
//@{
/**
* Vector part of the matrix element
*/
double MEV(double, double);
/**
* The matrix element, given \f$x_1\f$, \f$x_2\f$.
* @param x1 \f$x_1\f$
* @param x2 \f$x_2\f$
*/
double PS(double x1, double x2);
//@}
protected:
/**
* Pointer to the fermion-antifermion Z vertex
*/
AbstractFFVVertexPtr FFZVertex() const {return FFZVertex_;}
/**
* Pointer to the fermion-antifermion photon vertex
*/
AbstractFFVVertexPtr FFPVertex() const {return FFPVertex_;}
/**
* Pointer to the particle data object for the Z
*/
PDPtr Z0() const {return Z0_;}
/**
* Pointer to the particle data object for the photon
*/
PDPtr gamma() const {return gamma_;}
/**
* Pointer to the particle data object for the gluon
*/
PDPtr gluon() const {return gluon_;}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEee2gZ2qq & operator=(const MEee2gZ2qq &);
private:
/**
* Parameters controlling the leading-order process
*/
//@{
/**
* The minimum PDG of the quarks to be produced
*/
int minflav_;
/**
* The maximum PDG of the quarks to be produced
*/
int maxflav_;
/**
* Option for the treatment of the top quark mass
*/
unsigned int massopt_;
//@}
/**
* Pointers to the vertices
*/
//@{
/**
* Pointer to the fermion-antifermion Z vertex
*/
AbstractFFVVertexPtr FFZVertex_;
/**
* Pointer to the fermion-antifermion photon vertex
*/
AbstractFFVVertexPtr FFPVertex_;
/**
* Pointer to the fermion-antifermion photon vertex
*/
AbstractFFVVertexPtr FFGVertex_;
//@}
/**
* Switch on/off the helivity vertex construction
*/
bool spinCorrelations_;
/**
* Pointer to the ParticleData objects
*/
//@{
/**
* Pointer to the particle data object for the Z
*/
PDPtr Z0_;
/**
* Pointer to the particle data object for the photon
*/
PDPtr gamma_;
/**
* Pointer to the particle data object for the gluon
*/
PDPtr gluon_;
//@}
/**
* CM energy
*/
Energy d_Q_;
/**
* Quark mass
*/
Energy d_m_;
/**
* The rho parameter
*/
double d_rho_;
/**
* The v parameter
*/
double d_v_;
/**
* The initial kappa-tilde values for radiation from the quark
*/
double d_kt1_;
/**
* The initial kappa-tilde values for radiation from the antiquark
*/
double d_kt2_;
/**
* Cut-off parameter
*/
static const double EPS_;
/**
* Pointer to the strong coupling
*/
ShowerAlphaPtr alphaQCD_;
/**
* Pointer to the EM coupling
*/
ShowerAlphaPtr alphaQED_;
private:
/**
* Variables for the POWHEG style corrections
*/
//@{
/**
* The cut off on pt for QED, assuming massless quarks.
*/
Energy pTminQED_;
/**
* The cut off on pt for QCD, assuming massless quarks.
*/
Energy pTminQCD_;
/**
* Overestimate for the prefactor
*/
double preFactor_;
/**
* ParticleData objects for the partons
*/
vector<cPDPtr> partons_;
/**
* Momenta of the leading-order partons
*/
vector<Lorentz5Momentum> loMomenta_;
//@}
};
}
#endif /* HERWIG_MEee2gZ2qq_H */
diff --git a/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc b/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc
--- a/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc
+++ b/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc
@@ -1,2201 +1,2198 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2GammaGammaPowheg class.
//
#include "MEPP2GammaGammaPowheg.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "ThePEG/Cuts/Cuts.h"
#include "ThePEG/Utilities/SimplePhaseSpace.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "Herwig/Utilities/Maths.h"
#include "Herwig/Shower/Base/ShowerTree.h"
#include "Herwig/Shower/Base/ShowerProgenitor.h"
#include "Herwig/Shower/Base/ShowerParticle.h"
#include "Herwig/Shower/Base/Branching.h"
#include "Herwig/Shower/Base/HardTree.h"
#include "ThePEG/Utilities/DescribeClass.h"
using namespace Herwig;
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<MEPP2GammaGammaPowheg,Herwig::HwMEBase>
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<LorentzMomentum> 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<double,double> x = make_pair(lastX1(),lastX2());
// partons
pair<tcPDPtr,tcPDPtr> 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<MeV) return false;
double rapidity;
Energy rs=sqrt(lastS());
Lorentz5Momentum pcmf;
// emission from first beam
if(dipole_<=2) {
rapidity = -log(x.second*sqrt(lastS())/pT*vt);
pcmf = Lorentz5Momentum(ZERO,ZERO,
0.5*rs*(x.first*z-x.second),
0.5*rs*(x.first*z+x.second));
}
// emission from second beam
else {
rapidity = log(x.first *sqrt(lastS())/pT*vt);
pcmf = Lorentz5Momentum(ZERO,ZERO,
0.5*rs*(x.first-x.second*z),
0.5*rs*(x.first+x.second*z));
}
pcmf.rescaleMass();
Boost blab(pcmf.boostVector());
// emission from the quark radiation
vector<Lorentz5Momentum> 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;ix<pnew.size();++ix)
pnew[ix].boost(-blab);
// phase-space prefactors
jacobian(jacobian()*vJac);
if(dipole_%2!=0) swap(pnew[3],pnew[4]);
for(unsigned int ix=2;ix<meMomenta().size();++ix)
meMomenta()[ix] = pnew[ix];
}
else if(dipole_<=8) {
double x = shat/sHat();
double z = vTilde_;
double x1 = -1./x;
double x3 = 1.-z/x;
double x2 = 2.+x1-x3;
double xT = sqrt(4.*(1-x)*(1-z)*z/x);
// rotate the momenta into the Breit-frame
Lorentz5Momentum pin,pcmf;
if(dipole_<=6) {
pin = x*meMomenta()[0];
pcmf = pin+meMomenta()[1];
}
else {
pin = x*meMomenta()[1];
pcmf = pin+meMomenta()[0];
}
Boost bv = pcmf.boostVector();
meMomenta()[2].boost(bv);
meMomenta()[3].boost(bv);
Lorentz5Momentum q = meMomenta()[3]-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());
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<LorentzMomentum> 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<MEBase::DiagramIndex>
MEPP2GammaGammaPowheg::diagrams(const DiagramVector & diags) const {
if(mePartonData().size()==4) {
if(mePartonData()[3]->id()==ParticleID::gamma) {
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i ){
sel.insert(meInfo()[abs(diags[i]->id())], i);
}
return sel;
}
else {
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i ){
sel.insert(meInfo()[abs(diags[i]->id())%2], i);
}
return sel;
}
}
else {
Selector<DiagramIndex> 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<const ColourLines *>
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<const ColourLines *> 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<MEPP2GammaGammaPowheg> documentation
("TheMEPP2GammaGammaPowheg class implements gamma gamma production at NLO");
static Switch<MEPP2GammaGammaPowheg,unsigned int> 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<MEPP2GammaGammaPowheg,unsigned int> 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<MEPP2GammaGammaPowheg,unsigned int> 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<MEPP2GammaGammaPowheg,int> interfaceMaximumFlavour
("MaximumFlavour",
"The maximum flavour allowed for the incoming quarks",
&MEPP2GammaGammaPowheg::maxflavour_, 5, 1, 5,
false, false, Interface::limited);
static Parameter<MEPP2GammaGammaPowheg,double> 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<MEPP2GammaGammaPowheg,bool> 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<MEPP2GammaGammaPowheg,unsigned int> 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<MEPP2GammaGammaPowheg,Energy> 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<MEPP2GammaGammaPowheg,unsigned int> 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<MEPP2GammaGammaPowheg,ShowerAlpha> interfaceShowerAlphaQCD
("ShowerAlphaQCD",
"Reference to the object calculating the QCD coupling for the shower",
&MEPP2GammaGammaPowheg::alphaQCD_, false, false, true, false, false);
static Reference<MEPP2GammaGammaPowheg,ShowerAlpha> interfaceShowerAlphaQED
("ShowerAlphaQED",
"Reference to the object calculating the QED coupling for the shower",
&MEPP2GammaGammaPowheg::alphaQED_, false, false, true, false, false);
static Parameter<MEPP2GammaGammaPowheg,double> 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<MEPP2GammaGammaPowheg,double> 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<MEPP2GammaGammaPowheg,unsigned int> 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<MEPP2GammaGammaPowheg,double> 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<tcBeamPtr,tcBeamPtr> hadrons=
make_pair(dynamic_ptr_cast<tcBeamPtr>(lastParticles().first->dataPtr() ),
dynamic_ptr_cast<tcBeamPtr>(lastParticles().second->dataPtr()));
// momentum fractions
pair<double,double> x = make_pair(lastX1(),lastX2());
// partons
pair<tcPDPtr,tcPDPtr> 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<double,double> z;
pair<double,double> 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<double,double> 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<double,double> 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<double,double> 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<Lorentz5Momentum> & 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<SpinorWaveFunction> f1;
vector<SpinorBarWaveFunction> a1;
vector<VectorWaveFunction> 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<double> me(4,0.0);
me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1,PDT::Spin1));
vector<Complex> diag(2,0.0);
SpinorWaveFunction inter;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
inter = FFPvertex_->evaluate(ZERO,5,f1[ihel1].particle(),
f1[ihel1],v1[ohel1]);
diag[0] = FFPvertex_->evaluate(ZERO,inter,a1[ihel2],v2[ohel2]);
inter = FFPvertex_->evaluate(ZERO,5,f1[ihel1].particle(),
f1[ihel1] ,v2[ohel2]);
diag[1] = FFPvertex_->evaluate(ZERO,inter,a1[ihel2],v1[ohel1]);
// individual diagrams
for (size_t ii=0; ii<2; ++ii) me[ii] += std::norm(diag[ii]);
// full matrix element
diag[0] += diag[1];
output += std::norm(diag[0]);
// storage of the matrix element for spin correlations
me_(ihel1,ihel2,2*ohel1,2*ohel2) = diag[0];
}
}
}
}
// store diagram info, etc.
DVector save(3);
for (size_t i = 0; i < 3; ++i) save[i] = 0.25 * me[i];
meInfo(save);
// spin and colour factors
output *= 0.125/3./norm(FFPvertex_->norm());
}
return output;
}
double MEPP2GammaGammaPowheg::loGammaqME(const cPDVector & particles,
const vector<Lorentz5Momentum> & 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<SpinorWaveFunction> fin;
vector<VectorWaveFunction> gin;
vector<SpinorBarWaveFunction> fout;
vector<VectorWaveFunction> vout;
SpinorWaveFunction qin (momenta[0],particles[0],incoming);
VectorWaveFunction glin(momenta[1],particles[1],incoming);
VectorWaveFunction wout(momenta[2],particles[2],outgoing);
SpinorBarWaveFunction qout(momenta[3],particles[3],outgoing);
// polarization states for the particles
for(unsigned int ix=0;ix<2;++ix) {
qin.reset(ix) ;
fin.push_back(qin);
qout.reset(ix);
fout.push_back(qout);
glin.reset(2*ix);
gin.push_back(glin);
wout.reset(2*ix);
vout.push_back(wout);
}
me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1,
PDT::Spin1,PDT::Spin1Half));
// compute the matrix elements
double me[3]={0.,0.,0.};
Complex diag[2];
SpinorWaveFunction inters;
SpinorBarWaveFunction interb;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
// intermediates for the diagrams
interb= FFGvertex_->evaluate(scale(),5,particles[3],
fout[ohel1],gin[ihel2]);
inters= FFGvertex_->evaluate(scale(),5,particles[0],
fin[ihel1],gin[ihel2]);
for(unsigned int vhel=0;vhel<2;++vhel) {
diag[0] = FFPvertex_->evaluate(ZERO,fin[ihel1],interb,vout[vhel]);
diag[1] = FFPvertex_->evaluate(ZERO,inters,fout[ohel1],vout[vhel]);
// diagram contributions
me[1] += norm(diag[0]);
me[2] += norm(diag[1]);
// total
diag[0] += diag[1];
me[0] += norm(diag[0]);
me_(ihel1,2*ihel2,2*vhel,ohel1) = diag[0];
}
}
}
}
// results
// initial state spin and colour average
double colspin = 1./24./4.;
// and C_F N_c from matrix element
colspin *= 4.;
DVector save;
for(unsigned int ix=0;ix<3;++ix) {
me[ix] *= colspin;
if(ix>0) save.push_back(me[ix]);
}
meInfo(save);
output = me[0]/norm(FFGvertex_->norm());
}
return output;
}
double MEPP2GammaGammaPowheg::loGammaqbarME(const cPDVector & particles,
const vector<Lorentz5Momentum> & 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<SpinorBarWaveFunction> ain;
vector<VectorWaveFunction> gin;
vector<SpinorWaveFunction> aout;
vector<VectorWaveFunction> vout;
VectorWaveFunction glin (momenta[0],particles[0],incoming);
SpinorBarWaveFunction qbin (momenta[1],particles[1],incoming);
VectorWaveFunction wout (momenta[2],particles[2],outgoing);
SpinorWaveFunction qbout(momenta[3],particles[3],outgoing);
// polarization states for the particles
for(unsigned int ix=0;ix<2;++ix) {
qbin .reset(ix );
ain .push_back(qbin );
qbout.reset(ix );
aout.push_back(qbout);
glin.reset(2*ix);
gin.push_back(glin);
wout.reset(2*ix);
vout.push_back(wout);
}
// if calculation spin corrections construct the me
me_.reset(ProductionMatrixElement(PDT::Spin1,PDT::Spin1Half,
PDT::Spin1,PDT::Spin1Half));
// compute the matrix elements
double me[3]={0.,0.,0.};
Complex diag[2];
SpinorWaveFunction inters;
SpinorBarWaveFunction interb;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
// intermediates for the diagrams
inters= FFGvertex_->evaluate(scale(),5,particles[3],
aout[ohel1],gin[ihel1]);
interb= FFGvertex_->evaluate(scale(),5,particles[1],
ain[ihel2],gin[ihel1]);
for(unsigned int vhel=0;vhel<2;++vhel) {
diag[0]= FFPvertex_->evaluate(ZERO,inters,ain[ihel2],vout[vhel]);
diag[1]= FFPvertex_->evaluate(ZERO,aout[ohel1],interb,vout[vhel]);
// diagram contributions
me[1] += norm(diag[0]);
me[2] += norm(diag[1]);
// total
diag[0] += diag[1];
me[0] += norm(diag[0]);
me_(2*ihel1,ihel2,2*vhel,ohel1) = diag[0];
}
}
}
}
// results
// initial state spin and colour average
double colspin = 1./24./4.;
// and C_F N_c from matrix element
colspin *= 4.;
DVector save;
for(unsigned int ix=0;ix<3;++ix) {
me[ix] *= colspin;
if(ix>0) save.push_back(me[ix]);
}
meInfo(save);
output = me[0]/norm(FFGvertex_->norm());
}
return output;
}
double MEPP2GammaGammaPowheg::loGammagME(const cPDVector & particles,
const vector<Lorentz5Momentum> & 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<SpinorWaveFunction> fin;
vector<SpinorBarWaveFunction> ain;
vector<VectorWaveFunction> gout;
vector<VectorWaveFunction> 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<Lorentz5Momentum> & 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<double,double> 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<Lorentz5Momentum> 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<Lorentz5Momentum> & 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<Lorentz5Momentum> 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<Lorentz5Momentum> 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<double,double> 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<Lorentz5Momentum> & 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<Lorentz5Momentum> 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<Lorentz5Momentum> 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<double,double> 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<Lorentz5Momentum> & momenta) const {
vector<SpinorWaveFunction> qin;
vector<SpinorBarWaveFunction> qbarin;
vector<VectorWaveFunction> 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<Complex> diag(6 , 0.);
Energy2 mu2 = scale();
double sum(0.);
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
for(unsigned int whel=0;whel<2;++whel) {
for(unsigned int phel=0;phel<2;++phel) {
for(unsigned int ghel=0;ghel<2;++ghel) {
// first diagram
SpinorWaveFunction inters1 =
FFPvertex_->evaluate(ZERO,5,qin[ihel1].particle(),qin[ihel1],pout[phel]);
SpinorBarWaveFunction inters2 =
FFPvertex_->evaluate(ZERO,5,qin[ihel1].particle()->CC(),
qbarin[ihel2],wout[whel]);
diag[0] = FFGvertex_->evaluate(mu2,inters1,inters2,gout[ghel]);
// second diagram
SpinorWaveFunction inters3 =
FFGvertex_->evaluate(mu2,5,qin[ihel1].particle(),qin[ihel1],gout[ghel]);
SpinorBarWaveFunction inters4 =
FFPvertex_->evaluate(ZERO,5,qbarin[ihel2].particle(),
qbarin[ihel2],pout[phel]);
diag[1] = FFPvertex_->evaluate(ZERO,inters3,inters4,wout[whel]);
// fourth diagram
diag[2] = FFPvertex_->evaluate(ZERO,inters3,inters2,pout[phel]);
// fifth diagram
SpinorBarWaveFunction inters5 =
FFGvertex_->evaluate(mu2,5,qbarin[ihel2].particle(),
qbarin[ihel2],gout[ghel]);
diag[3] =
FFPvertex_->evaluate(ZERO,inters1,inters5,wout[whel]);
// sixth diagram
SpinorWaveFunction inters6 =
FFPvertex_->evaluate(ZERO,5,qbarin[ihel2].particle()->CC(),
qin[ihel1],wout[whel]);
diag[4] = FFGvertex_->evaluate(mu2,inters6,inters4,gout[ghel]);
// eighth diagram
diag[5] = FFPvertex_->evaluate(ZERO,inters6,inters5,pout[phel]);
// sum
Complex dsum = std::accumulate(diag.begin(),diag.end(),Complex(0.));
sum += norm(dsum);
}
}
}
}
}
// divide out the em and strong couplings
sum /= norm(FFGvertex_->norm()*FFPvertex_->norm());
// final spin and colour factors spin = 1/4 colour = 4/9
if(particles[4]->id()==ParticleID::g) sum /= 9.;
// final spin and colour factors spin = 1/4 colour = 4/(3*8)
else sum /= 24.;
// finally identical particle factor
return 0.5*sum;
}
double MEPP2GammaGammaPowheg::subtractedVirtual() const {
double v = 1+tHat()/sHat();
double born = (1-v)/v+v/(1-v);
double finite_term = born*
(2./3.*sqr(Constants::pi)-3.+sqr(log(v))+sqr(log(1-v))+3.*log(1-v))+
2.+2.*log(v)+2.*log(1-v)+3.*(1-v)/v*(log(v)-log(1-v))+
(2.+v/(1-v))*sqr(log(v))+(2.+(1-v)/v)*sqr(log(1-v));
double virt = ((6.-(2./3.)*sqr(Constants::pi))*
born-2.+finite_term);
return virt/born;
}
double MEPP2GammaGammaPowheg::subtractedReal(pair<double,double> 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<Lorentz5Momentum> 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<double> 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<unsigned int> 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<tcHwSMPtr>(standardModel());
if (!hwsm) throw InitException() << "hwsm pointer is null in"
<< " MEPP2GammaGamma::doinit()"
<< Exception::abortnow;
// get pointers to all required Vertex objects
FFPvertex_ = hwsm->vertexFFP();
FFGvertex_ = hwsm->vertexFFG();
gluon_ = getParticleData(ParticleID::g);
// sampling factors
prefactor_.push_back(preQCDqqbarq_);
prefactor_.push_back(preQCDqqbarqbar_);
prefactor_.push_back(preQCDqg_);
prefactor_.push_back(preQCDgqbar_);
prefactor_.push_back(preQEDqqbarq_);
prefactor_.push_back(preQEDqqbarqbar_);
prefactor_.push_back(preQEDqgq_);
prefactor_.push_back(preQEDgqbarqbar_);
}
HardTreePtr MEPP2GammaGammaPowheg::
-generateHardest(ShowerTreePtr tree,
- vector<ShowerInteraction::Type> interactions) {
+generateHardest(ShowerTreePtr tree,ShowerInteraction::Type inter) {
beams_.clear();
partons_.clear();
bool QCDAllowed(false),QEDAllowed(false);
- for(unsigned int ix=0;ix<interactions.size();++ix) {
- if(interactions[ix]==ShowerInteraction::QED)
- QEDAllowed = true;
- else if(interactions[ix]==ShowerInteraction::QCD)
- QCDAllowed = true;
- else if(interactions[ix]==ShowerInteraction::QEDQCD ||
- interactions[ix]==ShowerInteraction::ALL ) {
- QEDAllowed = true;
- QCDAllowed = true;
- }
+ if(inter==ShowerInteraction::QCD)
+ QCDAllowed = true;
+ else if(inter==ShowerInteraction::QED)
+ QEDAllowed = true;
+ else if(inter==ShowerInteraction::QEDQCD ||
+ inter==ShowerInteraction::ALL) {
+ QEDAllowed = true;
+ QCDAllowed = true;
}
// find the incoming particles
ShowerParticleVector incoming;
// get the particles to be showered
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cit;
vector<ShowerProgenitorPtr> particlesToShower;
//progenitor particles are produced in z direction.
for( cit = tree->incomingLines().begin();
cit != tree->incomingLines().end(); ++cit ) {
incoming.push_back( cit->first->progenitor() );
beams_.push_back( cit->first->beam() );
partons_.push_back( cit->first->progenitor()->dataPtr() );
particlesToShower.push_back( cit->first );
}
// find the parton which should be first
if( ( particlesToShower[1]->progenitor()->id() > 0 &&
particlesToShower[0]->progenitor()->id() < 0 ) ||
( particlesToShower[0]->progenitor()->id() == ParticleID::g &&
particlesToShower[1]->progenitor()->id() < 6 &&
particlesToShower[1]->progenitor()->id() > 0 ) )
swap(particlesToShower[0],particlesToShower[1]);
// check that quark is along +ve z direction
quarkplus_ = particlesToShower[0]->progenitor()->momentum().z() > ZERO;
if( partons_[0]->id() < 0 ||
(partons_[0]->id()==ParticleID::g && partons_[1]->id()>0)) {
swap(partons_[0],partons_[1]);
swap(beams_ [0],beams_ [1]);
}
// outgoing partons
for( map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt= tree->outgoingLines().begin();
cjt != tree->outgoingLines().end();++cjt ) {
particlesToShower.push_back( cjt->first );
}
if(particlesToShower.size()!=4) return HardTreePtr();
if(particlesToShower[2]->id()!=ParticleID::gamma)
swap(particlesToShower[2],particlesToShower[3]);
if(particlesToShower[3]->progenitor()->id()==ParticleID::gamma) {
if(QCDAllowed) return hardQCDEmission(particlesToShower);
}
else {
if(QEDAllowed) return hardQEDEmission(particlesToShower);
}
return HardTreePtr();
}
HardTreePtr MEPP2GammaGammaPowheg::
hardQCDEmission(vector<ShowerProgenitorPtr> particlesToShower) {
Energy rootS = sqrt(lastS());
// limits on the rapidity of the jet
double minyj = -8.0,maxyj = 8.0;
// generate the hard emission
pair<double,double> x = make_pair(particlesToShower[0]->progenitor()->x(),
particlesToShower[1]->progenitor()->x());
vector<Energy> pT;
Energy pTmax(-GeV);
cPDVector selectedParticles;
vector<Lorentz5Momentum> 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;iy<particlesToShower.size();++iy)
particles.push_back(particlesToShower[iy]->progenitor()->dataPtr());
if(ix<2) particles.push_back(gluon_);
else if(ix==2) {
particles.push_back(particles[0]->CC());
particles[0] = gluon_;
}
else {
particles.push_back(particles[1]->CC());
particles[1] = gluon_;
}
vector<Lorentz5Momentum> 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.||z<x.first) continue;
}
else {
vt = pT[ix]*exp( y)/rootS/x.first ;
z = (1.-pT[ix]*exp( y)/rootS/x.first )/(1.+pT[ix]*exp(-y)/rootS/x.second );
if(z>1.||z<x.second) continue;
}
if(vt>1.-z || vt<0.) continue;
if(ix%2==0) {
momenta[0] = particlesToShower[0]->progenitor()->momentum()/z;
momenta[1] = particlesToShower[1]->progenitor()->momentum();
}
else {
momenta[0] = particlesToShower[0]->progenitor()->momentum();
momenta[1] = particlesToShower[1]->progenitor()->momentum()/z;
}
double phi = Constants::twopi*UseRandom::rnd();
momenta[2] = particlesToShower[2]->progenitor()->momentum();
momenta[3] = particlesToShower[3]->progenitor()->momentum();
if(!quarkplus_) y *= -1.;
momenta[4] = Lorentz5Momentum(pT[ix]*cos(phi),pT[ix]*sin(phi),
pT[ix]*sinh(y),pT[ix]*cosh(y), ZERO);
Lorentz5Momentum K = momenta[0] + momenta[1] - momenta[4];
Lorentz5Momentum Kt = momenta[2]+momenta[3];
Lorentz5Momentum Ksum = K+Kt;
Energy2 K2 = K.m2(), Ksum2 = Ksum.m2();
for(unsigned int iy=2;iy<4;++iy) {
momenta [iy] = momenta [iy] - 2.*Ksum*(Ksum*momenta [iy])/Ksum2
+2*K*(Kt*momenta [iy])/K2;
}
// matrix element piece
double wgt = alphaQCD_->ratio(sqr(pT[ix]))*z/(1.-vt)/prefactor_[ix]/loME_;
if(ix==0)
wgt *= sqr(pT[ix])*realGammaGammagME(particles,momenta,IIQCD1,Shower,false);
else if(ix==1)
wgt *= sqr(pT[ix])*realGammaGammagME(particles,momenta,IIQCD2,Shower,false);
else if(ix==2)
wgt *= sqr(pT[ix])*realGammaGammaqbarME(particles,momenta,IIQCD1,Shower,false);
else if(ix==3)
wgt *= sqr(pT[ix])*realGammaGammaqME(particles,momenta,IIQCD2,Shower,false);
wgt *= 4.*Constants::pi/alphaS_;
// pdf piece
double pdf[2];
if(ix%2==0) {
pdf[0] = beams_[0]->pdf()->xfx(beams_[0],partons_ [0],
scale(), x.first ) /x.first;
pdf[1] = beams_[0]->pdf()->xfx(beams_[0],particles[0],
scale()+sqr(pT[ix]),x.first /z)*z/x.first;
}
else {
pdf[0] = beams_[1]->pdf()->xfx(beams_[1],partons_ [1],
scale() ,x.second ) /x.second;
pdf[1] = beams_[1]->pdf()->xfx(beams_[1],particles[1],
scale()+sqr(pT[ix]),x.second/z)*z/x.second;
}
if(pdf[0]<=0.||pdf[1]<=0.) continue;
wgt *= pdf[1]/pdf[0];
if(wgt>1.) generator()->log() << "Weight greater than one in "
<< "MEPP2GammaGammaPowheg::hardQCDEmission() "
<< "for channel " << ix
<< " Weight = " << wgt << "\n";
if(UseRandom::rnd()<wgt) break;
}
while(pT[ix]>minpT_);
if(pT[ix]>minpT_ && pT[ix]>pTmax) {
pTmax = pT[ix];
selectedParticles = particles;
selectedMomenta = momenta;
iemit=ix;
}
}
// if no emission
if(pTmax<ZERO) {
for(unsigned int ix=0;ix<particlesToShower.size();++ix)
particlesToShower[ix]->maximumpT(minpT_,ShowerInteraction::QCD);
return HardTreePtr();
}
// construct the HardTree object needed to perform the showers
// create the partons
ShowerParticleVector newparticles;
newparticles.push_back(new_ptr(ShowerParticle(selectedParticles[0],false)));
newparticles.push_back(new_ptr(ShowerParticle(selectedParticles[1],false)));
newparticles.push_back(new_ptr(ShowerParticle(selectedParticles[4], true)));
// set the momenta
for(unsigned int ix=0;ix<2;++ix)
newparticles[ix]->set5Momentum(selectedMomenta[ix]);
newparticles[2]->set5Momentum(selectedMomenta[4]);
// create the off-shell particle
Lorentz5Momentum poff = selectedMomenta[iemit%2] - selectedMomenta[4];
poff.rescaleMass();
newparticles.push_back(new_ptr(ShowerParticle(partons_[iemit%2],false)));
newparticles.back()->set5Momentum(poff);
for(unsigned int ix=2;ix<particlesToShower.size();++ix) {
newparticles.push_back(new_ptr(ShowerParticle(particlesToShower[ix]->
progenitor()->dataPtr(),true)));
newparticles.back()->set5Momentum(selectedMomenta[ix]);
}
vector<HardBranchingPtr> inBranch,hardBranch;
// create the branchings for the incoming particles
inBranch.push_back(new_ptr(HardBranching(newparticles[0],SudakovPtr(),
HardBranchingPtr(),HardBranching::Incoming)));
inBranch.push_back(new_ptr(HardBranching(newparticles[1],SudakovPtr(),
HardBranchingPtr(),HardBranching::Incoming)));
// intermediate IS particle
hardBranch.push_back(new_ptr(HardBranching(newparticles[3],SudakovPtr(),
inBranch[iemit%2],HardBranching::Incoming)));
inBranch[iemit%2]->addChild(hardBranch.back());
if(newparticles[3]->id()>0)
inBranch[iemit%2]->type(ShowerPartnerType::QCDColourLine );
else
inBranch[iemit%2]->type(ShowerPartnerType::QCDAntiColourLine);
// create the branching for the emitted jet
inBranch[iemit%2]->addChild(new_ptr(HardBranching(newparticles[2],SudakovPtr(),
inBranch[iemit%2],
HardBranching::Outgoing)));
// set the colour partners
hardBranch.back()->colourPartner(inBranch[iemit%2==0 ? 1 : 0]);
inBranch[iemit%2==0 ? 1 : 0]->colourPartner(hardBranch.back());
// add other particle
hardBranch.push_back(inBranch[iemit%2==0 ? 1 : 0]);
// outgoing particles
for(unsigned int ix=4;ix<newparticles.size();++ix) {
hardBranch.push_back(new_ptr(HardBranching(newparticles[ix],SudakovPtr(),
HardBranchingPtr(),
HardBranching::Outgoing)));
}
// make the tree
HardTreePtr hardtree=new_ptr(HardTree(hardBranch,inBranch,ShowerInteraction::QCD));
// connect the ShowerParticles with the branchings
// and set the maximum pt for the radiation
set<HardBranchingPtr> hard=hardtree->branchings();
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
particlesToShower[ix]->maximumpT(pTmax,ShowerInteraction::QCD);
for(set<HardBranchingPtr>::const_iterator mit=hard.begin();
mit!=hard.end();++mit) {
if(particlesToShower[ix]->progenitor()->id()==(*mit)->branchingParticle()->id()&&
(( particlesToShower[ix]->progenitor()->isFinalState()&&
(**mit).status()==HardBranching::Outgoing)||
(!particlesToShower[ix]->progenitor()->isFinalState()&&
(**mit).status()==HardBranching::Incoming))) {
hardtree->connect(particlesToShower[ix]->progenitor(),*mit);
if((**mit).status()==HardBranching::Incoming) {
(*mit)->beam(particlesToShower[ix]->original()->parents()[0]);
}
HardBranchingPtr parent=(*mit)->parent();
while(parent) {
parent->beam(particlesToShower[ix]->original()->parents()[0]);
parent=parent->parent();
};
}
}
}
ColinePtr newline=new_ptr(ColourLine());
for(set<HardBranchingPtr>::const_iterator cit=hardtree->branchings().begin();
cit!=hardtree->branchings().end();++cit) {
if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3)
newline->addColoured((**cit).branchingParticle());
else if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3bar)
newline->addAntiColoured((**cit).branchingParticle());
}
// return the tree
return hardtree;
}
HardTreePtr MEPP2GammaGammaPowheg::
hardQEDEmission(vector<ShowerProgenitorPtr> particlesToShower) {
// return if not emission from quark
if(particlesToShower[0]->progenitor()->id()!=ParticleID::g &&
particlesToShower[1]->progenitor()->id()!=ParticleID::g )
return HardTreePtr();
// generate the hard emission
pair<double,double> x = make_pair(particlesToShower[0]->progenitor()->x(),
particlesToShower[1]->progenitor()->x());
vector<Energy> pT;
Energy pTmax(-GeV);
cPDVector selectedParticles;
vector<Lorentz5Momentum> selectedMomenta;
int iemit(-1);
pair<double,double> mewgt(make_pair(0.,0.));
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
selectedParticles.push_back(particlesToShower[ix]->progenitor()->dataPtr());
selectedMomenta.push_back(particlesToShower[ix]->progenitor()->momentum());
}
selectedParticles.push_back(getParticleData(ParticleID::gamma));
swap(selectedParticles[3],selectedParticles[4]);
selectedMomenta.push_back(Lorentz5Momentum());
swap(selectedMomenta[3],selectedMomenta[4]);
Lorentz5Momentum pin,pout;
double xB;
unsigned int iloc;
if(particlesToShower[0]->progenitor()->dataPtr()->charged()) {
pin = particlesToShower[0]->progenitor()->momentum();
xB = x.first;
iloc = 6;
}
else {
pin = particlesToShower[1]->progenitor()->momentum();
xB = x.second;
iloc = 7;
}
pout = particlesToShower[3]->progenitor()->momentum();
Lorentz5Momentum q = pout-pin;
Axis axis(q.vect().unit());
LorentzRotation rot;
double sinth(sqrt(sqr(axis.x())+sqr(axis.y())));
rot = LorentzRotation();
if(axis.perp2()>1e-20) {
rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.));
rot.rotateX(Constants::pi);
}
if(abs(1.-q.e()/q.vect().mag())>1e-6)
rot.boostZ(q.e()/q.vect().mag());
Lorentz5Momentum ptemp = rot*pin;
if(ptemp.perp2()/GeV2>1e-20) {
Boost trans = -1./ptemp.e()*ptemp.vect();
trans.setZ(0.);
rot.boost(trans);
}
rot.invert();
Energy Q = sqrt(-q.m2());
double xT = sqrt((1.-xB)/xB);
double xTMin = 2.*minpT_/Q;
double wgt(0.);
double a = alphaQED_->overestimateValue()*prefactor_[iloc]/Constants::twopi;
Lorentz5Momentum p1,p2,p3;
do {
wgt = 0.;
// intergration variables dxT/xT^3
xT *= 1./sqrt(1.-2.*log(UseRandom::rnd())/a*sqr(xT));
// dz
double zp = UseRandom::rnd();
double xp = 1./(1.+0.25*sqr(xT)/zp/(1.-zp));
if(xT<xTMin) break;
// check allowed
if(xp<xB||xp>1.) 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(xT<xTMin) {
for(unsigned int ix=0;ix<particlesToShower.size();++ix)
particlesToShower[ix]->maximumpT(minpT_,ShowerInteraction::QED);
return HardTreePtr();
}
pTmax = 0.5*xT*Q;
iemit = mewgt.first>mewgt.second ? 2 : 3;
// construct the HardTree object needed to perform the showers
// create the partons
ShowerParticleVector newparticles;
newparticles.push_back(new_ptr(ShowerParticle(selectedParticles[0],false)));
newparticles.push_back(new_ptr(ShowerParticle(selectedParticles[1],false)));
newparticles.push_back(new_ptr(ShowerParticle(selectedParticles[3], true)));
// set the momenta
for(unsigned int ix=0;ix<2;++ix)
newparticles[ix]->set5Momentum(selectedMomenta[ix]);
newparticles[2]->set5Momentum(selectedMomenta[3]);
// create the off-shell particle
if(iemit==2) {
if(particlesToShower[0]->progenitor()->dataPtr()->charged()) {
Lorentz5Momentum poff = selectedMomenta[0] - selectedMomenta[3];
poff.rescaleMass();
newparticles.push_back(new_ptr(ShowerParticle(partons_[0],false)));
newparticles.back()->set5Momentum(poff);
}
else {
Lorentz5Momentum poff = selectedMomenta[1] - selectedMomenta[3];
poff.rescaleMass();
newparticles.push_back(new_ptr(ShowerParticle(partons_[1],false)));
newparticles.back()->set5Momentum(poff);
}
}
else if(iemit==3) {
Lorentz5Momentum poff = selectedMomenta[3]+selectedMomenta[4];
poff.rescaleMass();
newparticles.push_back(new_ptr(ShowerParticle(particlesToShower[3]
->progenitor()->dataPtr(),true)));
newparticles.back()->set5Momentum(poff);
}
else
assert(false);
for(unsigned int ix=2;ix<particlesToShower.size();++ix) {
newparticles.push_back(new_ptr(ShowerParticle(particlesToShower[ix]->
progenitor()->dataPtr(),true)));
newparticles.back()->set5Momentum(selectedMomenta[ix==2 ? 2 : 4 ]);
}
vector<HardBranchingPtr> inBranch,hardBranch;
// create the branchings for the incoming particles
inBranch.push_back(new_ptr(HardBranching(newparticles[0],SudakovPtr(),
HardBranchingPtr(),HardBranching::Incoming)));
inBranch.push_back(new_ptr(HardBranching(newparticles[1],SudakovPtr(),
HardBranchingPtr(),HardBranching::Incoming)));
if(iemit<3) {
int icharged = iemit;
if(icharged==2) icharged = particlesToShower[0]->progenitor()->
dataPtr()->charged() ? 0 : 1;
// intermediate IS particle
hardBranch.push_back(new_ptr(HardBranching(newparticles[3],SudakovPtr(),
inBranch[icharged],HardBranching::Incoming)));
inBranch[icharged]->addChild(hardBranch.back());
inBranch[icharged]->type(ShowerPartnerType::QED);
// create the branching for the emitted jet
inBranch[icharged]->addChild(new_ptr(HardBranching(newparticles[2],SudakovPtr(),
inBranch[icharged],
HardBranching::Outgoing)));
// set the colour partners
if(iemit<2) {
hardBranch.back()->colourPartner(inBranch[icharged==0 ? 1 : 0]);
inBranch[icharged==0 ? 1 : 0]->colourPartner(hardBranch.back());
}
// add other particle
hardBranch.push_back(inBranch[icharged == 0 ? 1 : 0]);
// outgoing particles
for(unsigned int ix=4;ix<newparticles.size();++ix) {
hardBranch.push_back(new_ptr(HardBranching(newparticles[ix],SudakovPtr(),
HardBranchingPtr(),
HardBranching::Outgoing)));
}
if(iemit==2) {
hardBranch.back()->colourPartner(hardBranch[0]);
hardBranch[0]->colourPartner(hardBranch.back());
}
}
else {
for(unsigned int ix=0;ix<2;++ix)
hardBranch.push_back(inBranch[ix]);
hardBranch.push_back(new_ptr(HardBranching(newparticles[4],SudakovPtr(),
HardBranchingPtr(),
HardBranching::Outgoing)));
hardBranch.push_back(new_ptr(HardBranching(newparticles[3],SudakovPtr(),
HardBranchingPtr(),
HardBranching::Outgoing)));
hardBranch.back()->type(ShowerPartnerType::QED);
hardBranch.back()->addChild(new_ptr(HardBranching(newparticles[5],SudakovPtr(),
HardBranchingPtr(),
HardBranching::Outgoing)));
hardBranch.back()->addChild(new_ptr(HardBranching(newparticles[2],SudakovPtr(),
HardBranchingPtr(),
HardBranching::Outgoing)));
if(hardBranch[0]->branchingParticle()->dataPtr()->charged()) {
hardBranch.back()->colourPartner(hardBranch[0]);
hardBranch[0]->colourPartner(hardBranch.back());
}
else {
hardBranch.back()->colourPartner(hardBranch[1]);
hardBranch[1]->colourPartner(hardBranch.back());
}
}
// make the tree
HardTreePtr hardtree=new_ptr(HardTree(hardBranch,inBranch,ShowerInteraction::QED));
// connect the ShowerParticles with the branchings
// and set the maximum pt for the radiation
set<HardBranchingPtr> hard=hardtree->branchings();
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
particlesToShower[ix]->maximumpT(pTmax,ShowerInteraction::QED);
for(set<HardBranchingPtr>::const_iterator mit=hard.begin();
mit!=hard.end();++mit) {
if(particlesToShower[ix]->progenitor()->id()==(*mit)->branchingParticle()->id()&&
(( particlesToShower[ix]->progenitor()->isFinalState()&&
(**mit).status()==HardBranching::Outgoing)||
(!particlesToShower[ix]->progenitor()->isFinalState()&&
(**mit).status()==HardBranching::Incoming))) {
hardtree->connect(particlesToShower[ix]->progenitor(),*mit);
if((**mit).status()==HardBranching::Incoming) {
(*mit)->beam(particlesToShower[ix]->original()->parents()[0]);
}
HardBranchingPtr parent=(*mit)->parent();
while(parent) {
parent->beam(particlesToShower[ix]->original()->parents()[0]);
parent=parent->parent();
};
}
}
}
ColinePtr newline1 = new_ptr(ColourLine());
ColinePtr newline2 = new_ptr(ColourLine());
HardBranchingPtr gluon,quark,antiQuark;
for(set<HardBranchingPtr>::const_iterator cit=hardtree->branchings().begin();
cit!=hardtree->branchings().end();++cit) {
if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour8) {
gluon = *cit;
if((**cit).status()==HardBranching::Incoming) {
newline1->addColoured ((**cit).branchingParticle());
newline2->addAntiColoured((**cit).branchingParticle());
}
else {
newline2->addColoured ((**cit).branchingParticle());
newline1->addAntiColoured((**cit).branchingParticle());
}
}
else if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3) {
if((**cit).status()==HardBranching::Incoming) {
antiQuark = *cit;
newline2->addColoured((**cit).branchingParticle());
}
else {
quark = *cit;
newline1->addColoured((**cit).branchingParticle());
}
}
else if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3bar) {
if((**cit).status()==HardBranching::Incoming) {
quark = *cit;
newline1->addAntiColoured((**cit).branchingParticle());
}
else {
antiQuark = *cit;
newline2->addAntiColoured((**cit).branchingParticle());
}
}
}
assert(quark&&antiQuark&&gluon);
gluon->colourPartner(UseRandom::rndbool() ? quark : antiQuark);
// return the tree
return hardtree;
}
diff --git a/MatrixElement/Powheg/MEPP2GammaGammaPowheg.h b/MatrixElement/Powheg/MEPP2GammaGammaPowheg.h
--- a/MatrixElement/Powheg/MEPP2GammaGammaPowheg.h
+++ b/MatrixElement/Powheg/MEPP2GammaGammaPowheg.h
@@ -1,538 +1,537 @@
// -*- C++ -*-
#ifndef HERWIG_MEPP2GammaGammaPowheg_H
#define HERWIG_MEPP2GammaGammaPowheg_H
//
// This is the declaration of the MEPP2GammaGammaPowheg class.
//
#include "Herwig/MatrixElement/HwMEBase.h"
#include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
#include "Herwig/Shower/Couplings/ShowerAlpha.h"
namespace Herwig {
using namespace ThePEG;
/**
* Here is the documentation of the MEPP2GammaGammaPowheg class.
*
* @see \ref MEPP2GammaGammaPowhegInterfaces "The interfaces"
* defined for MEPP2GammaGammaPowheg.
*/
class MEPP2GammaGammaPowheg: public HwMEBase {
enum DipoleType { IIQCD1=2, IIQCD2=4,
IFQED1=5, FIQED1=6, IFQED2=7, FIQED2=8 };
enum RadiationType {Subtraction,Hard,Shower};
public:
/** @name Standard constructors and destructors. */
//@{
/**
* The default constructor.
*/
MEPP2GammaGammaPowheg();
//@}
/** @name Member functions for the generation of hard QCD radiation */
//@{
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return ISR;}
/**
* Apply the POWHEG style correction
*/
- virtual HardTreePtr generateHardest(ShowerTreePtr,
- vector<ShowerInteraction::Type>);
+ virtual HardTreePtr generateHardest(ShowerTreePtr,ShowerInteraction::Type);
//@}
public:
/** @name Virtual functions required by the MEBase class. */
//@{
/**
* Return the order in \f$\alpha_S\f$ in which this matrix
* element is given.
*/
virtual unsigned int orderInAlphaS() const;
/**
* Return the order in \f$\alpha_{EW}\f$ in which this matrix
* element is given.
*/
virtual unsigned int orderInAlphaEW() const;
/**
* The matrix element for the kinematical configuration
* previously provided by the last call to setKinematics(), suitably
* scaled by sHat() to give a dimension-less number.
* @return the matrix element scaled with sHat() to give a
* dimensionless number.
*/
virtual double me2() const;
/**
* Return the scale associated with the last set phase space point.
*/
virtual Energy2 scale() const;
/**
* The number of internal degrees of freedom used in the matrix
* element.
*/
virtual int nDim() const;
/**
* Generate internal degrees of freedom given nDim() uniform
* random numbers in the interval \f$ ]0,1[ \f$. To help the phase space
* generator, the dSigHatDR should be a smooth function of these
* numbers, although this is not strictly necessary.
* @param r a pointer to the first of nDim() consecutive random numbers.
* @return true if the generation succeeded, otherwise false.
*/
virtual bool generateKinematics(const double * r);
/**
* Return the matrix element squared differential in the variables
* given by the last call to generateKinematics().
*/
virtual CrossSection dSigHatDR() const;
/**
* Add all possible diagrams with the add() function.
*/
virtual void getDiagrams() const;
/**
* Get diagram selector. With the information previously supplied with the
* setKinematics method, a derived class may optionally
* override this method to weight the given diagrams with their
* (although certainly not physical) relative probabilities.
* @param dv the diagrams to be weighted.
* @return a Selector relating the given diagrams to their weights.
*/
virtual Selector<DiagramIndex> diagrams(const DiagramVector & dv) const;
/**
* Return a Selector with possible colour geometries for the selected
* diagram weighted by their relative probabilities.
* @param diag the diagram chosen.
* @return the possible colour geometries weighted by their
* relative probabilities.
*/
virtual Selector<const ColourLines *>
colourGeometries(tcDiagPtr diag) const;
//@}
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/**
* Calculate of the full next-to-leading order weight
*/
virtual double NLOWeight() const;
/**
* Leading-order matrix element for \f$q\bar q\to \gamma\gamma\f$
*/
double loGammaGammaME(const cPDVector & particles,
const vector<Lorentz5Momentum> & momenta,
bool first=false) const;
/**
* Leading-order matrix element for \f$qg\to \gamma q\f$
*/
double loGammaqME(const cPDVector & particles,
const vector<Lorentz5Momentum> & momenta,
bool first=false) const;
/**
* Leading-order matrix element for \f$g\bar q\to \gamma \bar q\f$
*/
double loGammaqbarME(const cPDVector & particles,
const vector<Lorentz5Momentum> & momenta,
bool first=false) const;
/**
* Leading-order matrix element for \f$q\bar q\to \gamma g\f$
*/
double loGammagME(const cPDVector & particles,
const vector<Lorentz5Momentum> & momenta,
bool first=false) const;
/**
* Real emission matrix element for \f$q\bar q\to \gamma \gamma g\f$
*/
InvEnergy2 realGammaGammagME(const cPDVector & particles,
const vector<Lorentz5Momentum> & momenta,
DipoleType dipole, RadiationType rad,
bool first=false) const;
/**
* Real emission matrix element for \f$qg\to \gamma \gamma q\f$
*/
InvEnergy2 realGammaGammaqME(const cPDVector & particles,
const vector<Lorentz5Momentum> & momenta,
DipoleType dipole, RadiationType rad,
bool first=false) const;
/**
* Real emission matrix element for \f$g\bar q\to \gamma \gamma \bar q\f$
*/
InvEnergy2 realGammaGammaqbarME(const cPDVector & particles,
const vector<Lorentz5Momentum> & momenta,
DipoleType dipole, RadiationType rad,
bool first=false) const;
/**
* The dipole subtractedvirtual contribution
*/
double subtractedVirtual() const;
/**
* Subtracted real contribution
*/
double subtractedReal(pair<double,double> x, double z,
double zJac, double oldqPDF, double newqPDF,
double newgPDF,bool order) const;
/**
* Calculate of the collinear counterterms
*/
//@{
/**
* Quark collinear counter term
*/
double collinearQuark(double x, Energy2 mu2, double jac, double z,
double oldPDF, double newPDF) const;
/**
* Gluon collinear counter term
*/
double collinearGluon(Energy2 mu2, double jac, double z,
double oldPDF, double newPDF) const;
//@}
/**
* The real matrix element divided by \f$2 g_S^2\f$, to be implemented in the
* inheriting classes.
* @param particles The ParticleData objects of the particles
* @param momenta The momenta of the particles
*/
double realME(const cPDVector & particles,
const vector<Lorentz5Momentum> & momenta) const;
/**
* Generate hard QCD emission
*/
HardTreePtr hardQCDEmission(vector<ShowerProgenitorPtr>);
/**
* Generate hard QED emission
*/
HardTreePtr hardQEDEmission(vector<ShowerProgenitorPtr>);
/**
* The supression function
*/
pair<double,double> supressionFunction(Energy pT,Energy scale) const {
if(supressionScale_==0) scale = lambda_;
Energy2 scale2 = sqr(scale), pT2 = sqr(pT);
switch( supressionFunction_ ) {
case 0:
return make_pair(1.,0.);
case 1:
if(pT < scale ) return make_pair(1.,0.);
else return make_pair(0.,1.);
case 2:
return make_pair(scale2/(pT2+scale2),pT2/(pT2+scale2));
default:
assert(false);
}
}
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEPP2GammaGammaPowheg & operator=(const MEPP2GammaGammaPowheg &);
private:
/**
* Vertices
*/
//@{
/**
* FFPVertex
*/
AbstractFFVVertexPtr FFPvertex_;
/**
* FFGVertex
*/
AbstractFFVVertexPtr FFGvertex_;
//@}
/**
* Kinematic variables for the real radiation
*/
//@{
/**
* First variable
*/
mutable double zTilde_;
/**
* Second variable
*/
mutable double vTilde_;
/**
* Azimuthal angle
*/
mutable double phi_;
//@}
/**
* Whether to generate the positive, negative or leading order contribution
*/
unsigned int contrib_;
/**
* Power for sampling \f$x_p\f$
*/
double power_;
/**
* Pointer to the gluon ParticleData object
*/
tcPDPtr gluon_;
/**
* Processes
*/
unsigned int process_;
/**
* Processes
*/
unsigned int threeBodyProcess_;
/**
* Allowed flavours of the incoming quarks
*/
int maxflavour_;
/**
* Factor for \f$C_F\f$ dependent pieces
*/
mutable double CFfact_;
/**
* Factor for \f$T_R\f$ dependent pieces
*/
mutable double TRfact_;
/**
* Strong coupling
*/
mutable double alphaS_;
/**
* Use a fixed value of \f$\alpha_S\f$
*/
bool fixedAlphaS_;
/**
* Electromagnetic coupling
*/
mutable double alphaEM_;
/**
* Leading-order matrix element
*/
mutable double loME_;
/**
* The matrix element
*/
mutable ProductionMatrixElement me_;
/**
* the selected dipole
*/
mutable DipoleType dipole_;
/**
* Supression Function
*/
//@{
/**
* Choice of the supression function
*/
unsigned int supressionFunction_;
/**
* Choice for the scale in the supression function
*/
unsigned int supressionScale_;
/**
* Scalar for the supression function
*/
Energy lambda_;
//@}
/**
* Hard emission stuff
*/
//@{
/**
* Whether the quark is in the + or - z direction
*/
bool quarkplus_;
//@}
/**
* Properties of the incoming particles
*/
//@{
/**
* Pointers to the BeamParticleData objects
*/
vector<tcBeamPtr> beams_;
/**
* Pointers to the ParticleDataObjects for the partons
*/
vector<tcPDPtr> partons_;
//@}
/**
* Constants for the sampling. The distribution is assumed to have the
* form \f$\frac{c}{{\rm GeV}}\times\left(\frac{{\rm GeV}}{p_T}\right)^n\f$
*/
//@{
/**
* The prefactor, \f$c\f$ for the \f$q\bar{q}\f$ channel
*/
double preQCDqqbarq_;
/**
* The prefactor, \f$c\f$ for the \f$q\bar{q}\f$ channel
*/
double preQCDqqbarqbar_;
/**
* The prefactor, \f$c\f$ for the \f$qg\f$ channel
*/
double preQCDqg_;
/**
* The prefactor, \f$c\f$ for the \f$g\bar{q}\f$ channel
*/
double preQCDgqbar_;
double preQEDqqbarq_;
double preQEDqqbarqbar_;
double preQEDqgq_;
double preQEDgqbarqbar_;
/**
* The prefactors as a vector for easy use
*/
vector<double> prefactor_;
//@}
/**
* The transverse momentum of the jet
*/
Energy minpT_;
/**
* Pointer to the object calculating the strong coupling
*/
ShowerAlphaPtr alphaQCD_;
/**
* Pointer to the object calculating the EM
*/
ShowerAlphaPtr alphaQED_;
/**
* Scale choice
*/
unsigned int scaleChoice_;
/**
* Scale factor
*/
double scalePreFactor_;
};
}
#endif /* HERWIG_MEPP2GammaGammaPowheg_H */
diff --git a/MatrixElement/Powheg/MEPP2VVPowheg.cc b/MatrixElement/Powheg/MEPP2VVPowheg.cc
--- a/MatrixElement/Powheg/MEPP2VVPowheg.cc
+++ b/MatrixElement/Powheg/MEPP2VVPowheg.cc
@@ -1,5411 +1,5410 @@
// -*- C++ -*-
//
// MEPP2VVPowheg.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2VVPowheg class.
//
#include "MEPP2VVPowheg.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "Herwig/MatrixElement/HardVertex.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
#include "Herwig/Shower/Base/ShowerProgenitor.h"
#include "Herwig/Shower/Base/ShowerTree.h"
#include "Herwig/Shower/Base/Branching.h"
#include "Herwig/Shower/Base/HardTree.h"
using namespace Herwig;
MEPP2VVPowheg::MEPP2VVPowheg() :
tiny(1.e-10), CF_(4./3.), TR_(0.5), NC_(3.),
contrib_(1), channels_(0), nlo_alphaS_opt_(0) , fixed_alphaS_(0.1180346226),
removebr_(1), scaleopt_(1), mu_F_(100.*GeV), mu_UV_(100.*GeV),
ckm_(3,vector<Complex>(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<unsigned int>(2,1));
}
void MEPP2VVPowheg::persistentOutput(PersistentOStream & os) const {
os << contrib_ << channels_ << nlo_alphaS_opt_ << fixed_alphaS_
<< removebr_ << scaleopt_ << ounit(mu_F_,GeV) << ounit(mu_UV_,GeV)
<< ckm_ << helicityConservation_
<< FFPvertex_ << FFWvertex_ << FFZvertex_ << WWWvertex_ << FFGvertex_
<< realMESpinCorrelations_
<< showerAlphaS_ << power_
<< preqqbar_ << preqg_ << pregqbar_ << prefactor_
<< b0_ << ounit(LambdaQCD_,GeV)
<< ounit( min_pT_,GeV );
}
void MEPP2VVPowheg::persistentInput(PersistentIStream & is, int) {
is >> contrib_ >> channels_ >> nlo_alphaS_opt_ >> fixed_alphaS_
>> removebr_ >> scaleopt_ >> iunit(mu_F_,GeV) >> iunit(mu_UV_,GeV)
>> ckm_ >> helicityConservation_
>> FFPvertex_ >> FFWvertex_ >> FFZvertex_ >> WWWvertex_ >> FFGvertex_
>> realMESpinCorrelations_
>> showerAlphaS_ >> power_
>> preqqbar_ >> preqg_ >> pregqbar_ >> prefactor_
>> b0_ >> iunit(LambdaQCD_,GeV)
>> iunit( min_pT_, GeV );
}
ClassDescription<MEPP2VVPowheg> MEPP2VVPowheg::initMEPP2VVPowheg;
// Definition of the static class description member.
void MEPP2VVPowheg::Init() {
static ClassDocumentation<MEPP2VVPowheg> 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<MEPP2VVPowheg,unsigned int> 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<MEPP2VVPowheg,unsigned int> 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<MEPP2VVPowheg,unsigned int> 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<MEPP2VVPowheg,double> 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<MEPP2VVPowheg,unsigned int> interfaceremovebr
("removebr",
"Whether to multiply the event weights by the MCFM branching ratios",
&MEPP2VVPowheg::removebr_, 1, false, false);
static SwitchOption interfaceProductionCrossSection
(interfaceremovebr,
"true",
"Do not multiply in the branching ratios (default running)",
1);
static SwitchOption interfaceIncludeBRs
(interfaceremovebr,
"false",
"Multiply by MCFM branching ratios for comparison/debugging purposes",
0);
static Switch<MEPP2VVPowheg,unsigned int> 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<MEPP2VVPowheg,Energy> 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<MEPP2VVPowheg,Energy> 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<MEPP2VVPowheg,bool> 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<MEPP2VVPowheg,ShowerAlpha> interfaceCoupling
("Coupling",
"The object calculating the strong coupling constant",
&MEPP2VVPowheg::showerAlphaS_, false, false, true, false, false);
static Parameter<MEPP2VVPowheg,double> 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<MEPP2VVPowheg,double> 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<MEPP2VVPowheg,double> 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<MEPP2VVPowheg,double> 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<MEPP2VVPowheg, Energy> 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<tcHwSMPtr>(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<StandardCKM>::pointer
theCKM=dynamic_ptr_cast<Ptr<StandardCKM>::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<Complex > > 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<Ptr<BeamParticleData>::transient_const_pointer>
(lastParticles().first->dataPtr());
// The -z hadron in the lab:
hadron_B_=dynamic_ptr_cast<Ptr<BeamParticleData>::transient_const_pointer>
(lastParticles().second->dataPtr());
// Leading order momentum fractions:
double xa(lastX1()); // The +z momentum fraction in the lab.
double xb(lastX2()); // The -z momentum fraction in the lab.
// Particle data for incoming +z & -z QCD particles respectively:
ab_ = lastPartons().first ->dataPtr(); // The +z momentum parton in the lab.
bb_ = lastPartons().second->dataPtr(); // The -z momentum parton in the lab.
// We checked TVT & LHC for all VV channels with 10K events:
// lastParticles().first ->momentum().z() is always positive
// lastParticles().second->momentum().z() is always negative
// lastParticles().first ->momentum().z()*xa=lastPartons().first ->momentum().z() 1 in 10^6
// lastParticles().second->momentum().z()*xb=lastPartons().second->momentum().z() 1 in 10^6
// Set the quark and antiquark data pointers.
quark_ = mePartonData()[0];
antiquark_ = mePartonData()[1];
if(quark_->id()<0) swap(quark_,antiquark_);
// Now in _our_ calculation we basically define the +z axis as being
// given by the direction of the incoming quark for q+qb & q+g processes
// and the incoming gluon for g+qbar processes. So now we might need to
// flip the values of hadron_A_, hadron_B_, ab_, bb_, xa, xb accordingly:
if(ab_->id()!=quark_->id()) {
swap(hadron_A_,hadron_B_);
swap(ab_,bb_);
swap(xa,xb);
}
// So hadron_A_ is the thing containing a quark (ab_) with momentum frac xa,
// hadron_B_ is the thing containing an antiquark (bb_) with momentum frac xb.
// Now get the partonic flux for the Born process:
lo_lumi_ = hadron_A_->pdf()->xfx(hadron_A_,ab_,scale(),xa)/xa
* hadron_B_->pdf()->xfx(hadron_B_,bb_,scale(),xb)/xb;
// For W+W- events make sure k1 corresponds to the W+ momentum:
if(MEPP2VV::process()==1&&wminus_first) swap(meMomenta()[2],meMomenta()[3]);
// Create the object containing all 2->2 __kinematic__ information:
B_ = bornVVKinematics(meMomenta(),xa,xb);
// We checked that meMomenta()[0] (quark) is in the +z direction and meMomenta()[1]
// is in the -z direction (antiquark).
// Revert momentum swap in case meMomenta and mePartonData correlation
// needs preserving for other things.
if(MEPP2VV::process()==1&&wminus_first) swap(meMomenta()[2],meMomenta()[3]);
// Check the Born kinematics objects is internally consistent:
// B_.sanityCheck();
// If we are going beyond leading order then lets calculate all of
// the necessary real emission kinematics.
if(contrib_>0) {
// Soft limit of the 2->3 real emission kinematics:
S_ = realVVKinematics(B_, 1., y, theta2);
// Soft-collinear limit of the 2->3 kinematics (emission in +z direction):
SCp_ = realVVKinematics(B_, 1., 1., theta2);
// Soft-collinear limit of the 2->3 kinematics (emission in -z direction):
SCm_ = realVVKinematics(B_, 1.,-1., theta2);
// Collinear limit of the 2->3 kinematics (emission in +z direction):
Cp_ = realVVKinematics(B_, xt, 1., theta2);
// Collinear limit of the 2->3 kinematics (emission in -z direction):
Cm_ = realVVKinematics(B_, xt,-1., theta2);
// The resolved 2->3 real emission kinematics:
H_ = realVVKinematics(B_, xt, y, theta2);
// Borrowed from VVhardGenerator (lab momenta of k1,k2):
Energy pT(sqrt(H_.pT2_in_lab()));
LorentzRotation yzRotation;
yzRotation.setRotateX(-atan2(pT/GeV,sqrt(B_.sb())/GeV));
LorentzRotation boostFrompTisZero;
boostFrompTisZero.setBoostY(-pT/sqrt(B_.sb()+pT*pT));
LorentzRotation boostFromYisZero;
boostFromYisZero.setBoostZ(tanh(B_.Yb()));
k1r_perp2_lab_ = (boostFromYisZero*boostFrompTisZero*yzRotation*(H_.k1r())).perp2();
k2r_perp2_lab_ = (boostFromYisZero*boostFrompTisZero*yzRotation*(H_.k2r())).perp2();
// Check all the real kinematics objects are internally consistent:
// S_.sanityCheck();
// SCp_.sanityCheck();
// SCm_.sanityCheck();
// Cp_.sanityCheck();
// Cm_.sanityCheck();
// H_.sanityCheck();
}
return;
}
double MEPP2VVPowheg::NLOweight() const {
// If only leading order is required return 1:
if(contrib_==0) return lo_me()/lo_me2_;
// Calculate alpha_S and alpha_S/(2*pi).
alphaS_ = nlo_alphaS_opt_==1 ? fixed_alphaS_ : SM().alphaS(mu_UV2());
double alsOn2pi(alphaS_/2./pi);
// Particle data objects for the new plus and minus colliding partons.
tcPDPtr gluon;
gluon = getParticleData(ParticleID::g);
// Get the all couplings.
gW_ = sqrt(4.0*pi*SM().alphaEM(scale())/SM().sin2ThetaW());
sin2ThetaW_ = SM().sin2ThetaW();
double cosThetaW(sqrt(1.-sin2ThetaW_));
guL_ = gW_/2./cosThetaW*( 1.-4./3.*sin2ThetaW_);
gdL_ = gW_/2./cosThetaW*(-1.+2./3.*sin2ThetaW_);
guR_ = gW_/2./cosThetaW*( -4./3.*sin2ThetaW_);
gdR_ = gW_/2./cosThetaW*( +2./3.*sin2ThetaW_);
eZ_ = gW_*cosThetaW;
eZ2_ = sqr(eZ_);
// MCFM has gwsq = 0.4389585130009 -> gw = 0.662539442600115
// Here we have gW_ = 0.662888
// MCFM has xw = 0.22224653300000 -> sqrt(xw) = 0.471430306
// Here we have 0.222247
// MCFM has esq = 0.097557007645279 -> e = 0.31234117187024679
// Here we have 4.0*pi*SM().alphaEM(sqr(100.*GeV)) = 0.0976596
// If the process is W-Z instead of W+Z we must transform these
// couplings as follows, according to NPB 383(1992)3-44 Eq.3.23
if(mePartonData()[2]->id()==-24&&mePartonData()[3]->id()==23) {
swap(guL_,gdL_);
eZ_ *= -1.;
}
// Get the CKM entry. Note that this code was debugged
// considerably; the call to CKM(particle,particle)
// did not appear to work, so we extract the elements
// as follows below. The right numbers now appear to
// to be associated with the right quarks.
double Kij(-999.);
// W+Z / W-Z
if(abs(mePartonData()[2]->id())==24&&mePartonData()[3]->id()==23) {
int up_id(-999),dn_id(-999);
if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==1) {
up_id = abs(quark_->id());
dn_id = abs(antiquark_->id());
}
else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==0) {
up_id = abs(antiquark_->id());
dn_id = abs(quark_->id());
}
else {
cout << "MEPP2VVPowheg:" << endl;
cout << "WZ needs an up and a down type quark as incoming!" << endl;
}
up_id /= 2;
up_id -= 1;
dn_id -= 1;
dn_id /= 2;
Kij = sqrt(SM().CKM(up_id,dn_id));
}
// W+W-
else if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) {
if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) {
int up_ida(abs(quark_->id())/2-1);
int up_idb(abs(antiquark_->id())/2-1);
Kij = sqrt(std::norm( CKM(up_ida,0)*CKM(up_idb,0)
+ CKM(up_ida,1)*CKM(up_idb,1)
+ CKM(up_ida,2)*CKM(up_idb,2)));
}
else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) {
int dn_ida((abs(quark_->id())-1)/2);
int dn_idb((abs(antiquark_->id())-1)/2);
Kij = sqrt(std::norm( CKM(0,dn_ida)*CKM(0,dn_idb)
+ CKM(1,dn_ida)*CKM(1,dn_idb)
+ CKM(2,dn_ida)*CKM(2,dn_idb)));
}
else {
cout << "MEPP2VVPowheg:" << endl;
cout << "WW needs 2 down-type / 2 up-type!" << endl;
}
}
// ZZ
else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) {
Kij = 2.*sqrt(2.)/gW_;
}
else {
cout << "MEPP2VVPowheg: incompatible final state particles!" << endl;
}
Fij2_ = sqr(gW_/2./sqrt(2.)*Kij);
// Get the leading order matrix element (this is necessary!)
M_Born_ = M_Born_WZ(B_);
// // Get the regular part of the virtual correction (only needed for sanityCheck()!)
// M_V_regular_ = M_V_regular(S_);
// // Get the q + qbar real emission matrix element (only needed for sanityCheck()!)
// t_u_M_R_qqb_ = t_u_M_R_qqb(H_);
// Calculate the integrand
double wgt(0.);
double wqqb(0.);
double wgqb(0.);
double wqg(0.);
double wqqbvirt(0.);
double wqqbcollin(0.);
double wqqbreal(0.);
double wqgcollin(0.);
double wqgreal(0.);
double wgqbcollin(0.);
double wgqbreal(0.);
if(channels_==0||channels_==1) {
// q+qb
wqqbvirt = Vtilde_universal(S_) + M_V_regular(S_)/lo_me2_;
wqqbcollin = alsOn2pi*( Ctilde_Ltilde_qq_on_x(quark_,antiquark_,Cp_)
+ Ctilde_Ltilde_qq_on_x(quark_,antiquark_,Cm_) );
wqqbreal = alsOn2pi*Rtilde_Ltilde_qqb_on_x(quark_,antiquark_);
wqqb = wqqbvirt + wqqbcollin + wqqbreal;
}
if(channels_==0||channels_==2) {
// q+g
wqgcollin = alsOn2pi*Ctilde_Ltilde_gq_on_x(quark_,gluon,Cm_);
wqgreal = alsOn2pi*Rtilde_Ltilde_qg_on_x(quark_,gluon);
wqg = wqgreal + wqgcollin;
// g+qb
wgqbcollin = alsOn2pi*Ctilde_Ltilde_gq_on_x(gluon,antiquark_,Cp_);
wgqbreal = alsOn2pi*Rtilde_Ltilde_gqb_on_x(gluon,antiquark_);
wgqb = wgqbreal+wgqbcollin;
}
// total contribution
wgt = 1.+(wqqb+wgqb+wqg);
// If restricting to qg, gqb channels then subtract the LO contribution:
if(channels_==2) wgt -= 1.;
if(isnan(wgt)||isinf(wgt)) {
cout << "MEPP2VVPowheg:: NLO weight "
<< "is bad: wgt = " << wgt << endl;
cout << "MEPP2VVPowheg sanityCheck invoked!" << endl;
cout << ab_->PDGName() << ", "
<< bb_->PDGName() << ", "
<< mePartonData()[2]->PDGName() << ", "
<< mePartonData()[3]->PDGName() << endl;
cout << "lo_me2_ - M_Born_ (rel) = "
<< lo_me2_-M_Born_ << " ("
<< (lo_me2_-M_Born_)/M_Born_ << ")\n";
cout << "lo_me2_, M_Born_ " << lo_me2_ << ", " << M_Born_ << endl;
cout << "xr = " << H_.xr() << " 1-xr = " << 1.-H_.xr() << " y = " << H_.y() << endl;
cout << "tkr = " << H_.tkr()/GeV2 << " ukr = " << H_.ukr()/GeV2 << endl;
cout << "root(sb) = " << sqrt(B_.sb())/GeV << endl;
cout << "sb+tb+ub = "
<< B_.sb()/GeV2 << " + "
<< B_.tb()/GeV2 << " + " << B_.ub()/GeV2 << endl;
cout << "sqrt(k12) " << sqrt(H_.k12r())/GeV << endl;
cout << "sqrt(k22) " << sqrt(H_.k22r())/GeV << endl;
cout << "sqr(Kij) " << Kij*Kij << endl;
cout << "wqqbvirt " << wqqbvirt << endl;
cout << "wqqbcollin " << wqqbcollin << endl;
cout << "wqqbreal " << wqqbreal << endl;
cout << "wqqb " << wqqb << endl;
cout << "wqgcollin " << wqgcollin << endl;
cout << "wqgreal " << wqgreal << endl;
cout << "wqg " << wqg << endl;
cout << "wgqbcollin " << wgqbcollin << endl;
cout << "wgqbreal " << wgqbreal << endl;
cout << "wgqb " << wgqb << endl;
cout << "wgt " << wgt << endl;
throw Exception() << "MEPP2VVPowheg:: NLO weight "
<< "is bad: " << wgt
<< Exception::eventerror;
}
return contrib_==1 ? max(0.,wgt) : max(0.,-wgt);
}
double MEPP2VVPowheg::Lhat_ab(tcPDPtr a, tcPDPtr b,
realVVKinematics Kinematics) const {
if(!(abs(a->id())<=6||a->id()==21)||!(abs(b->id())<=6||b->id()==21))
cout << "MEPP2VVPowheg::Lhat_ab: Error,"
<< "particle a = " << a->PDGName() << ", "
<< "particle b = " << b->PDGName() << endl;
double nlo_lumi(-999.);
double x1(Kinematics.x1r()),x2(Kinematics.x2r());
nlo_lumi = (hadron_A_->pdf()->xfx(hadron_A_,a,mu_F2(),x1)/x1)
* (hadron_B_->pdf()->xfx(hadron_B_,b,mu_F2(),x2)/x2);
return nlo_lumi / lo_lumi_;
}
double MEPP2VVPowheg::Vtilde_universal(realVVKinematics S) const {
double xbar_y = S.xbar();
double y = S.y();
double eta1b(S.bornVariables().eta1b());
double eta2b(S.bornVariables().eta2b());
Energy2 sb(S.s2r());
return alphaS_/2./pi*CF_
* ( log(sb/mu_F2())
* (3. + 4.*log(eta1b)+4.*log(eta2b))
+ 8.*sqr(log(eta1b)) +8.*sqr(log(eta2b))
- 2.*sqr(pi)/3.
)
+ alphaS_/2./pi*CF_
* ( 8./(1.+y)*log(sqrt(1.-xbar_y)/eta2b)
+ 8./(1.-y)*log(sqrt(1.-xbar_y)/eta1b)
);
}
double MEPP2VVPowheg::Ctilde_Ltilde_qq_on_x(tcPDPtr a, tcPDPtr b,
realVVKinematics C) const {
if(C.y()!= 1.&&C.y()!=-1.)
cout << "\nCtilde_qq::y value not allowed.";
if(C.y()== 1.&&!(abs(a->id())>0&&abs(a->id())<7))
cout << "\nCtilde_qq::for Cqq^plus a must be a quark! id = "
<< a->id() << "\n";
if(C.y()==-1.&&!(abs(b->id())>0&&abs(b->id())<7))
cout << "\nCtilde_qq::for Cqq^minus b must be a quark! id = "
<< b->id() << "\n";
double xt = C.xt();
double x = C.xr();
double etab = C.y() == 1. ? C.bornVariables().eta1b()
: C.bornVariables().eta2b() ;
Energy2 sb(C.s2r());
if(fabs(1.-xt)<=tiny||fabs(1.-H_.xr())<=tiny) return 0.;
return ( ( (1./(1.-xt))*log(sb/mu_F2()/x)+4.*log(etab)/(1.-xt)
+ 2.*log(1.-xt)/(1.-xt)
)*CF_*(1.+sqr(x))
+ sqr(etab)*CF_*(1.-x)
)*Lhat_ab(a,b,C) / x
- ( ( (1./(1.-xt))*log(sb/mu_F2() )+4.*log(etab)/(1.-xt)
+ 2.*log(1.-xt)/(1.-xt)
)*CF_*2.
)*Lhat_ab(a,b,S_);
}
double MEPP2VVPowheg::Ctilde_Ltilde_gq_on_x(tcPDPtr a, tcPDPtr b,
realVVKinematics C) const {
if(C.y()!= 1.&&C.y()!=-1.)
cout << "\nCtilde_gq::y value not allowed.";
if(C.y()== 1.&&a->id()!=21)
cout << "\nCtilde_gq::for Cgq^plus a must be a gluon! id = "
<< a->id() << "\n";
if(C.y()==-1.&&b->id()!=21)
cout << "\nCtilde_gq::for Cgq^minus b must be a gluon! id = "
<< b->id() << "\n";
double xt = C.xt();
double x = C.xr();
double etab = C.y() == 1. ? C.bornVariables().eta1b()
: C.bornVariables().eta2b() ;
Energy2 sb(C.s2r());
return ( ( (1./(1.-xt))*log(sb/mu_F2()/x)+4.*log(etab)/(1.-xt)
+ 2.*log(1.-xt)/(1.-xt)
)*(1.-x)*TR_*(sqr(x)+sqr(1.-x))
+ sqr(etab)*TR_*2.*x*(1.-x)
)*Lhat_ab(a,b,C) / x;
}
double MEPP2VVPowheg::Rtilde_Ltilde_qqb_on_x(tcPDPtr a , tcPDPtr b) const {
if(!(abs(a->id())<=6||a->id()==21)||!(abs(b->id())<=6||b->id()==21))
cout << "MEPP2VVPowheg::Rtilde_Ltilde_qqb_on_x: Error,"
<< "particle a = " << a->PDGName() << ", "
<< "particle b = " << b->PDGName() << endl;
double xt(H_.xt());
double y(H_.y());
Energy2 s(H_.sr());
Energy2 sCp(Cp_.sr());
Energy2 sCm(Cm_.sr());
Energy2 t_u_M_R_qqb_H (t_u_M_R_qqb(H_ ));
Energy2 t_u_M_R_qqb_Cp(t_u_M_R_qqb(Cp_));
Energy2 t_u_M_R_qqb_Cm(t_u_M_R_qqb(Cm_));
// Energy2 t_u_M_R_qqb_H (t_u_M_R_qqb_hel_amp(H_));
// Energy2 t_u_M_R_qqb_Cp(8.*pi*alphaS_*Cp_.sr()/Cp_.xr()
// *CF_*(1.+sqr(Cp_.xr()))*lo_me2_);
// Energy2 t_u_M_R_qqb_Cm(8.*pi*alphaS_*Cm_.sr()/Cm_.xr()
// *CF_*(1.+sqr(Cm_.xr()))*lo_me2_);
int config(0);
if(fabs(1.-xt)<=tiny||fabs(1.-H_.xr())<=tiny) return 0.;
if(fabs(1.-y )<=tiny) { t_u_M_R_qqb_H = t_u_M_R_qqb_Cp ; config = 1; }
if(fabs(1.+y )<=tiny) { t_u_M_R_qqb_H = t_u_M_R_qqb_Cm ; config = -1; }
if(fabs(H_.tkr()/s)<=tiny) { t_u_M_R_qqb_H = t_u_M_R_qqb_Cp ; config = 1; }
if(fabs(H_.ukr()/s)<=tiny) { t_u_M_R_qqb_H = t_u_M_R_qqb_Cm ; config = -1; }
if(config== 0)
return
( ( (t_u_M_R_qqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qqb_Cp*Lhat_ab(a,b,Cp_)/sCp)
)*2./(1.-y)/(1.-xt)
+ ( (t_u_M_R_qqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qqb_Cm*Lhat_ab(a,b,Cm_)/sCm)
)*2./(1.+y)/(1.-xt)
) / lo_me2_ / 8. / pi / alphaS_;
else if(config== 1)
return
( (t_u_M_R_qqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qqb_Cm*Lhat_ab(a,b,Cm_)/sCm)
)*2./(1.+y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_;
else if(config==-1)
return
( (t_u_M_R_qqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qqb_Cp*Lhat_ab(a,b,Cp_)/sCp)
)*2./(1.-y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_;
else
throw Exception()
<< "MEPP2VVPowheg::Rtilde_Ltilde_qqb_on_x\n"
<< "The configuration is not identified as hard / soft / fwd collinear or bwd collinear."
<< "config = " << config << "\n"
<< "xt = " << xt << " 1.-xt = " << 1.-xt << "\n"
<< "y = " << y << " 1.-y = " << 1.-y << "\n"
<< Exception::eventerror;
}
double MEPP2VVPowheg::Rtilde_Ltilde_gqb_on_x(tcPDPtr a , tcPDPtr b) const {
if(!(abs(a->id())<=6||a->id()==21)||!(abs(b->id())<=6||b->id()==21))
cout << "MEPP2VVPowheg::Rtilde_Ltilde_gqb_on_x: Error,"
<< "particle a = " << a->PDGName() << ", "
<< "particle b = " << b->PDGName() << endl;
double xt(H_.xt());
double y(H_.y());
Energy2 s(H_.sr());
Energy2 sCp(Cp_.sr());
Energy2 sCm(Cm_.sr());
Energy2 t_u_M_R_gqb_H (t_u_M_R_gqb(H_ ));
Energy2 t_u_M_R_gqb_Cp(t_u_M_R_gqb(Cp_));
Energy2 t_u_M_R_gqb_Cm(t_u_M_R_gqb(Cm_));
// Energy2 t_u_M_R_gqb_H (t_u_M_R_gqb_hel_amp(H_));
// Energy2 t_u_M_R_gqb_Cp(8.*pi*alphaS_*Cp_.sr()/Cp_.xr()*(1.-Cp_.xr())
// *TR_*(sqr(Cp_.xr())+sqr(1.-Cp_.xr()))*lo_me2_);
// Energy2 t_u_M_R_gqb_Cm(t_u_M_R_gqb(Cm_));
// // Energy2 t_u_M_R_gqb_Cm(t_u_M_R_gqb_hel_amp(Cm_));
int config(0);
if(fabs(1.-xt)<=tiny||fabs(1.-H_.xr())<=tiny) return 0.;
if(fabs(1.-y )<=tiny) { t_u_M_R_gqb_H = t_u_M_R_gqb_Cp ; config = 1; }
if(fabs(1.+y )<=tiny) { t_u_M_R_gqb_H = t_u_M_R_gqb_Cm ; config = -1; }
if(fabs(H_.tkr()/s)<=tiny) { t_u_M_R_gqb_H = t_u_M_R_gqb_Cp ; config = 1; }
if(fabs(H_.ukr()/s)<=tiny) { t_u_M_R_gqb_H = t_u_M_R_gqb_Cm ; config = -1; }
if(config== 0)
return
( ( (t_u_M_R_gqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_gqb_Cp*Lhat_ab(a,b,Cp_)/sCp)
)*2./(1.-y)/(1.-xt)
+ ( (t_u_M_R_gqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_gqb_Cm*Lhat_ab(a,b,Cm_)/sCm)
)*2./(1.+y)/(1.-xt)
) / lo_me2_ / 8. / pi / alphaS_;
else if(config== 1)
return
( (t_u_M_R_gqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_gqb_Cm*Lhat_ab(a,b,Cm_)/sCm)
)*2./(1.+y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_;
else if(config==-1)
return
( (t_u_M_R_gqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_gqb_Cp*Lhat_ab(a,b,Cp_)/sCp)
)*2./(1.-y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_;
else
throw Exception()
<< "MEPP2VVPowheg::Rtilde_Ltilde_gqb_on_x\n"
<< "The configuration is not identified as hard / soft / fwd collinear or bwd collinear."
<< "config = " << config << "\n"
<< "xt = " << xt << " 1.-xt = " << 1.-xt << "\n"
<< "y = " << y << " 1.-y = " << 1.-y << "\n"
<< Exception::eventerror;
}
double MEPP2VVPowheg::Rtilde_Ltilde_qg_on_x(tcPDPtr a , tcPDPtr b) const {
if(!(abs(a->id())<=6||a->id()==21)||!(abs(b->id())<=6||b->id()==21))
cout << "MEPP2VVPowheg::Rtilde_Ltilde_qg_on_x: Error,"
<< "particle a = " << a->PDGName() << ", "
<< "particle b = " << b->PDGName() << endl;
double xt(H_.xt());
double y(H_.y());
Energy2 s(H_.sr());
Energy2 sCp(Cp_.sr());
Energy2 sCm(Cm_.sr());
Energy2 t_u_M_R_qg_H (t_u_M_R_qg(H_ ));
Energy2 t_u_M_R_qg_Cp(t_u_M_R_qg(Cp_));
Energy2 t_u_M_R_qg_Cm(t_u_M_R_qg(Cm_));
// Energy2 t_u_M_R_qg_H (t_u_M_R_qg_hel_amp(H_));
// Energy2 t_u_M_R_qg_Cp(t_u_M_R_qg(Cp_));
// // Energy2 t_u_M_R_qg_Cp(t_u_M_R_qg_hel_amp(Cp_));
// Energy2 t_u_M_R_qg_Cm(8.*pi*alphaS_*Cm_.sr()/Cm_.xr()*(1.-Cm_.xr())
// *TR_*(sqr(Cm_.xr())+sqr(1.-Cm_.xr()))*lo_me2_);
int config(0);
if(fabs(1.-xt)<=tiny||fabs(1.-H_.xr())<=tiny) return 0.;
if(fabs(1.-y )<=tiny) { t_u_M_R_qg_H = t_u_M_R_qg_Cp ; config = 1; }
if(fabs(1.+y )<=tiny) { t_u_M_R_qg_H = t_u_M_R_qg_Cm ; config = -1; }
if(fabs(H_.tkr()/s)<=tiny) { t_u_M_R_qg_H = t_u_M_R_qg_Cp ; config = 1; }
if(fabs(H_.ukr()/s)<=tiny) { t_u_M_R_qg_H = t_u_M_R_qg_Cm ; config = -1; }
if(config== 0)
return
( ( (t_u_M_R_qg_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qg_Cp*Lhat_ab(a,b,Cp_)/sCp)
)*2./(1.-y)/(1.-xt)
+ ( (t_u_M_R_qg_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qg_Cm*Lhat_ab(a,b,Cm_)/sCm)
)*2./(1.+y)/(1.-xt)
) / lo_me2_ / 8. / pi / alphaS_;
else if(config== 1)
return
( (t_u_M_R_qg_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qg_Cm*Lhat_ab(a,b,Cm_)/sCm)
)*2./(1.+y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_;
else if(config==-1)
return
( (t_u_M_R_qg_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qg_Cp*Lhat_ab(a,b,Cp_)/sCp)
)*2./(1.-y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_;
else
throw Exception()
<< "MEPP2VVPowheg::Rtilde_Ltilde_qg_on_x\n"
<< "The configuration is not identified as hard / soft / fwd collinear or bwd collinear."
<< "config = " << config << "\n"
<< "xt = " << xt << " 1.-xt = " << 1.-xt << "\n"
<< "y = " << y << " 1.-y = " << 1.-y << "\n"
<< Exception::eventerror;
}
/***************************************************************************/
// The following three functions are identically \tilde{I}_{4,t},
// \tilde{I}_{3,WZ} and \tilde{I}_{3,W} given in Eqs. B.8,B.9,B.10
// of NPB 383(1992)3-44, respectively. They are related to / derived
// from the loop integrals in Eqs. A.3, A.5 and A.8 of the same paper.
InvEnergy4 TildeI4t(Energy2 s, Energy2 t, Energy2 mW2, Energy2 mZ2);
InvEnergy2 TildeI3WZ(Energy2 s, Energy2 mW2, Energy2 mZ2, double beta);
InvEnergy2 TildeI3W(Energy2 s, Energy2 t, Energy2 mW2);
/***************************************************************************/
// The following six functions are identically I_{dd}^{(1)}, I_{ud}^{(1)},
// I_{uu}^{(1)}, F_{u}^{(1)}, F_{d}^{(1)}, H^{(1)} from Eqs. B.4, B.5, B.3,
// B.3, B.6, B.7 of NPB 383(1992)3-44, respectively. They make up the
// one-loop matrix element. Ixx functions correspond to the graphs
// with no TGC, Fx functions are due to non-TGC graphs interfering
// with TGC graphs, while the H function is due purely to TGC graphs.
double Idd1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta);
double Iud1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta);
double Iuu1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta);
Energy2 Fu1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta);
Energy2 Fd1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta);
Energy4 H1 (Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2);
/***************************************************************************/
// M_V_Regular is the regular part of the one-loop matrix element
// exactly as defined in Eqs. B.1 and B.2 of of NPB 383(1992)3-44.
double MEPP2VVPowheg::M_V_regular(realVVKinematics S) const {
Energy2 s(S.bornVariables().sb());
Energy2 t(S.bornVariables().tb());
Energy2 u(S.bornVariables().ub());
Energy2 mW2(S.k12r()); // N.B. the diboson masses are preserved in getting
Energy2 mZ2(S.k22r()); // the 2->2 from the 2->3 kinematics.
double beta(S.betaxr()); // N.B. for x=1 \beta_x=\beta in NPB 383(1992)3-44.
double cosThetaW(sqrt(1.-sin2ThetaW_));
double eZ2(eZ2_);
double eZ(eZ_);
double gdL(gdL_);
double guL(guL_);
double gdR(gdR_);
double guR(guR_);
// W+W-
if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) {
double e2(sqr(gW_)*sin2ThetaW_);
if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) {
// N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set!
if(quark_->id()==-antiquark_->id()) {
eZ2 = 1./2.*sqr(s-mW2)/Fij2_
* (e2*e2/s/s*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s/(s-mW2/sqr(cosThetaW)))
+sqr( eZ*(guL-guR)/2./e2*s/(s-mW2/sqr(cosThetaW))))
);
eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s-mW2)
* (gW_*gW_*e2/4./s *( 2./3.+2.*eZ*guL/2./e2*s/(s-mW2/sqr(cosThetaW))));
} else {
eZ2 =0.;
eZ =0.;
}
gdL = gW_/sqrt(2.);
guL = 0.;
}
else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) {
// N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set!
if(quark_->id()==-antiquark_->id()) {
eZ2 = 1./2.*sqr(s-mW2)/Fij2_
* (e2*e2/s/s*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s/(s-mW2/sqr(cosThetaW)))
+sqr( eZ*(gdL-gdR)/2./e2*s/(s-mW2/sqr(cosThetaW))))
);
eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s-mW2)
* (gW_*gW_*e2/4./s *(-1./3.+2.*eZ*gdL/2./e2*s/(s-mW2/sqr(cosThetaW))));
} else {
eZ2 =0.;
eZ =0.;
}
guL = gW_/sqrt(2.);
gdL = 0.;
}
}
// ZZ
else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) {
eZ = 0.;
eZ2 = 0.;
double gV2,gA2;
gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_);
gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_);
guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.;
gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_);
gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_);
gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.;
if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL;
else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL;
else {
cout << "MEPP2VVPowheg:" << endl;
cout << "ZZ needs 2 down-type / 2 up-type!" << endl;
}
}
return 4.*pi*alphaS_*Fij2_*CF_*(1./sqr(4.*pi))/NC_
* ( gdL*gdL*Idd1(s,t,u,mW2,mZ2,beta)
+ gdL*guL*Iud1(s,t,u,mW2,mZ2,beta)
+ guL*guL*Iuu1(s,t,u,mW2,mZ2,beta)
- eZ/(s-mW2) * ( gdL*Fd1(s,t,u,mW2,mZ2,beta)
- guL*Fu1(s,t,u,mW2,mZ2,beta)
)
+ eZ2/sqr(s-mW2) * H1(s,t,u,mW2,mZ2)
);
}
/***************************************************************************/
InvEnergy4 TildeI4t(Energy2 s, Energy2 t, Energy2 mW2, Energy2 mZ2) {
double sqrBrackets;
sqrBrackets = ( sqr(log(-t/mW2))/2.+log(-t/mW2)*log(-t/mZ2)/2.
- 2.*log(-t/mW2)*log((mW2-t)/mW2)-2.*ReLi2(t/mW2)
);
swap(mW2,mZ2);
sqrBrackets+= ( sqr(log(-t/mW2))/2.+log(-t/mW2)*log(-t/mZ2)/2.
- 2.*log(-t/mW2)*log((mW2-t)/mW2)-2.*ReLi2(t/mW2)
);
swap(mW2,mZ2);
return sqrBrackets/s/t;
}
InvEnergy2 TildeI3WZ(Energy2 s, Energy2 mW2, Energy2 mZ2, double beta) {
Energy2 sig(mZ2+mW2);
Energy2 del(mZ2-mW2);
double sqrBrackets ;
sqrBrackets = ( ReLi2(2.*mW2/(sig-del*(del/s+beta)))
+ ReLi2((1.-del/s+beta)/2.)
+ sqr(log((1.-del/s+beta)/2.))/2.
+ log((1.-del/s-beta)/2.)*log((1.+del/s-beta)/2.)
);
beta *= -1;
sqrBrackets -= ( ReLi2(2.*mW2/(sig-del*(del/s+beta)))
+ ReLi2((1.-del/s+beta)/2.)
+ sqr(log((1.-del/s+beta)/2.))/2.
+ log((1.-del/s-beta)/2.)*log((1.+del/s-beta)/2.)
);
beta *= -1;
swap(mW2,mZ2);
del *= -1.;
sqrBrackets += ( ReLi2(2.*mW2/(sig-del*(del/s+beta)))
+ ReLi2((1.-del/s+beta)/2.)
+ sqr(log((1.-del/s+beta)/2.))/2.
+ log((1.-del/s-beta)/2.)*log((1.+del/s-beta)/2.)
);
swap(mW2,mZ2);
del *= -1.;
beta *= -1;
swap(mW2,mZ2);
del *= -1.;
sqrBrackets -= ( ReLi2(2.*mW2/(sig-del*(del/s+beta)))
+ ReLi2((1.-del/s+beta)/2.)
+ sqr(log((1.-del/s+beta)/2.))/2.
+ log((1.-del/s-beta)/2.)*log((1.+del/s-beta)/2.)
);
beta *= -1;
swap(mW2,mZ2);
del *= -1.;
return sqrBrackets/s/beta;
}
InvEnergy2 TildeI3W(Energy2 s, Energy2 t, Energy2 mW2) {
return
1./(mW2-t)*(sqr(log(mW2/s))/2.-sqr(log(-t/s))/2.-sqr(pi)/2.);
}
/***************************************************************************/
double Idd1(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) {
Energy2 sig(mZ2+mW2);
Energy2 del(mZ2-mW2);
double Val(0.);
Val += 2.*(22.*t*t+t*(19.*s-18.*sig)+18.*mW2*mZ2)/t/t
- 8.*(u*t+2*s*sig)/mW2/mZ2
- 2.*sqr(t-u)/t/s/sqr(beta);
Val += +( 2.*(8.*t*t+4.*t*(s-3.*sig)+4*sqr(sig)-5.*s*sig+s*s)/t/s/sqr(beta)
+ 4.*(t*(3.*u+s)-3.*mW2*mZ2)/t/t
+ 6.*(t+u)*sqr(t-u)/t/s/s/sqr(sqr(beta))
)*log(-t/s);
Val += +( ( 8.*t*t*(-2.*s+del)+8.*t*(-s*s+3.*s*sig-2.*del*sig)
- 2.*(s-sig)*(s*s-4.*s*sig+3.*del*sig)
)/t/s/s/beta/beta
+ 16.*s*(t-mZ2)/(t*(u+s)-mW2*mZ2)
+ 2.*(4.*t*t+t*(10.*s-3.*mZ2-9.*mW2)+12.*mW2*mZ2)/t/t
-6.*(s-del)*(t+u)*sqr(t-u)/t/s/s/s/sqr(sqr(beta))
)*log(-t/mW2);
Val += ( - ( 4.*t*t*(2.*sig-3.*s)
- 4.*t*(s-sig)*(2.*s-3.*sig)
- 2.*(s-2.*sig)*sqr(s-sig)
)/t/s/beta/beta
+ ( 4.*sig*t-3.*s*s+4.*s*sig
- 4.*(mW2*mW2+mZ2*mZ2)
)/t
- 3.*sqr(t*t-u*u)/t/s/s/sqr(sqr(beta))
)*TildeI3WZ(s,mW2,mZ2,beta);
Val += +( 4.*(t*u+2.*s*sig)/3./mW2/mZ2 - 4.*(t-2.*u)/3./t
)*pi*pi;
Val += -( 4.*s*(t*u-2.*mW2*mZ2)/t
)*TildeI4t(s,t,mW2,mZ2);
Val += ( 8.*(t-mW2)*(u*t-2.*mW2*mZ2)/t/t
)*TildeI3W(s,t,mW2);
swap(mW2,mZ2);
del *= -1;
Val += 2.*(22.*t*t+t*(19.*s-18.*sig)+18.*mW2*mZ2)/t/t
- 8.*(u*t+2*s*sig)/mW2/mZ2
- 2.*sqr(t-u)/t/s/sqr(beta);
Val += +( 2.*(8.*t*t+4.*t*(s-3.*sig)+4*sqr(sig)-5.*s*sig+s*s)/t/s/sqr(beta)
+ 4.*(t*(3.*u+s)-3.*mW2*mZ2)/t/t
+ 6.*(t+u)*sqr(t-u)/t/s/s/sqr(sqr(beta))
)*log(-t/s);
Val += +( ( 8.*t*t*(-2.*s+del)+8.*t*(-s*s+3.*s*sig-2.*del*sig)
- 2.*(s-sig)*(s*s-4.*s*sig+3.*del*sig)
)/t/s/s/beta/beta
+ 16.*s*(t-mZ2)/(t*(u+s)-mW2*mZ2)
+ 2.*(4.*t*t+t*(10.*s-3.*mZ2-9.*mW2)+12.*mW2*mZ2)/t/t
-6.*(s-del)*(t+u)*sqr(t-u)/t/s/s/s/sqr(sqr(beta))
)*log(-t/mW2);
Val += ( - ( 4.*t*t*(2.*sig-3.*s)
- 4.*t*(s-sig)*(2.*s-3.*sig)
- 2.*(s-2.*sig)*sqr(s-sig)
)/t/s/beta/beta
+ ( 4.*sig*t-3.*s*s+4.*s*sig
- 4.*(mW2*mW2+mZ2*mZ2)
)/t
- 3.*sqr(t*t-u*u)/t/s/s/sqr(sqr(beta))
)*TildeI3WZ(s,mW2,mZ2,beta);
Val += +( 4.*(t*u+2.*s*sig)/3./mW2/mZ2 - 4.*(t-2.*u)/3./t
)*pi*pi;
Val += -( 4.*s*(t*u-2.*mW2*mZ2)/t
)*TildeI4t(s,t,mW2,mZ2);
Val += ( 8.*(t-mW2)*(u*t-2.*mW2*mZ2)/t/t
)*TildeI3W(s,t,mW2);
swap(mW2,mZ2);
del *= -1;
return Val;
}
/***************************************************************************/
double Iud1(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) {
Energy2 sig(mZ2+mW2);
Energy2 del(mZ2-mW2);
double Val(0.);
Val += 2.*(4.*t*t+t*(9.*s-4.*sig)-18.*s*sig)/t/u
+ 8.*(t*u+2.*s*sig)/mW2/mZ2
+ 4.*s*s*(2.*t-sig)/u/(mW2*mZ2-t*(u+s))
- 2.*sqr(t-u)/u/s/sqr(beta);
Val += ( 2.*(8.*t*t-4.*t*(s+3.*sig)-(s-sig)*(3.*s+4.*sig))/u/s/sqr(beta)
+ 6.*(t+u)*sqr(t-u)/u/s/s/sqr(sqr(beta))
- 12.*s*(t-sig)/t/u
)*log(-t/s);
Val += ( (2./u/s/s/sqr(beta))*( 4.*t*t*(-2.*s+del)
+ 4.*t*(s*s+s*(mZ2+5.*mW2)-2.*sig*del)
+ (s-sig)*(3.*s*s+8.*mW2*s-3.*sig*del)
)
+ (2.*t*(18.*s+3.*mW2+mZ2)-24.*s*sig)/t/u
- 8.*s*(2.*t*t-t*(3.*s+4.*mZ2+2.*mW2)+2.*mZ2*(s+sig))
/u/(mW2*mZ2-t*(u+s))
- 8.*s*s*t*(2.*t-sig)*(t-mZ2)/u/sqr(mW2*mZ2-t*(u+s))
+ 6.*(s-del)*(s-sig)*sqr(t-u)/u/s/s/s/sqr(sqr(beta))
)*log(-t/mW2);
Val += ( -2.*(2.*t*t*(2.*sig-3.*s)+6.*sig*t*(s-sig)+sqr(s-sig)*(s+2.*sig))
/u/s/sqr(beta)
+3.*s*(4.*t-4.*sig-s)/u
-3.*sqr(s-sig)*sqr(t-u)/u/s/s/sqr(sqr(beta))
)*TildeI3WZ(s,mW2,mZ2,beta);
Val += ( 4.*(u+4.*s)/3./u - 4.*(u*t+2.*s*sig)/3./mW2/mZ2
)*pi*pi;
Val += -( 16.*s*(t-sig)*(t-mW2)/t/u
)*TildeI3W(s,t,mW2);
Val += ( 8.*s*s*(t-sig)/u
)*TildeI4t(s,t,mW2,mZ2);
swap(t,u);
Val += 2.*(4.*t*t+t*(9.*s-4.*sig)-18.*s*sig)/t/u
+ 8.*(t*u+2.*s*sig)/mW2/mZ2
+ 4.*s*s*(2.*t-sig)/u/(mW2*mZ2-t*(u+s))
- 2.*sqr(t-u)/u/s/sqr(beta);
Val += ( 2.*(8.*t*t-4.*t*(s+3.*sig)-(s-sig)*(3.*s+4.*sig))/u/s/sqr(beta)
+ 6.*(t+u)*sqr(t-u)/u/s/s/sqr(sqr(beta))
- 12.*s*(t-sig)/t/u
)*log(-t/s);
Val += ( (2./u/s/s/sqr(beta))*( 4.*t*t*(-2.*s+del)
+ 4.*t*(s*s+s*(mZ2+5.*mW2)-2.*sig*del)
+ (s-sig)*(3.*s*s+8.*mW2*s-3.*sig*del)
)
+ (2.*t*(18.*s+3.*mW2+mZ2)-24.*s*sig)/t/u
- 8.*s*(2.*t*t-t*(3.*s+4.*mZ2+2.*mW2)+2.*mZ2*(s+sig))
/u/(mW2*mZ2-t*(u+s))
- 8.*s*s*t*(2.*t-sig)*(t-mZ2)/u/sqr(mW2*mZ2-t*(u+s))
+ 6.*(s-del)*(s-sig)*sqr(t-u)/u/s/s/s/sqr(sqr(beta))
)*log(-t/mW2);
Val += ( -2.*(2.*t*t*(2.*sig-3.*s)+6.*sig*t*(s-sig)+sqr(s-sig)*(s+2.*sig))
/u/s/sqr(beta)
+3.*s*(4.*t-4.*sig-s)/u
-3.*sqr(s-sig)*sqr(t-u)/u/s/s/sqr(sqr(beta))
)*TildeI3WZ(s,mW2,mZ2,beta);
Val += ( 4.*(u+4.*s)/3./u - 4.*(u*t+2.*s*sig)/3./mW2/mZ2
)*pi*pi;
Val += -( 16.*s*(t-sig)*(t-mW2)/t/u
)*TildeI3W(s,t,mW2);
Val += ( 8.*s*s*(t-sig)/u
)*TildeI4t(s,t,mW2,mZ2);
swap(t,u);
swap(mW2,mZ2);
del *= -1;
Val += 2.*(4.*t*t+t*(9.*s-4.*sig)-18.*s*sig)/t/u
+ 8.*(t*u+2.*s*sig)/mW2/mZ2
+ 4.*s*s*(2.*t-sig)/u/(mW2*mZ2-t*(u+s))
- 2.*sqr(t-u)/u/s/sqr(beta);
Val += ( 2.*(8.*t*t-4.*t*(s+3.*sig)-(s-sig)*(3.*s+4.*sig))/u/s/sqr(beta)
+ 6.*(t+u)*sqr(t-u)/u/s/s/sqr(sqr(beta))
- 12.*s*(t-sig)/t/u
)*log(-t/s);
Val += ( (2./u/s/s/sqr(beta))*( 4.*t*t*(-2.*s+del)
+ 4.*t*(s*s+s*(mZ2+5.*mW2)-2.*sig*del)
+ (s-sig)*(3.*s*s+8.*mW2*s-3.*sig*del)
)
+ (2.*t*(18.*s+3.*mW2+mZ2)-24.*s*sig)/t/u
- 8.*s*(2.*t*t-t*(3.*s+4.*mZ2+2.*mW2)+2.*mZ2*(s+sig))
/u/(mW2*mZ2-t*(u+s))
- 8.*s*s*t*(2.*t-sig)*(t-mZ2)/u/sqr(mW2*mZ2-t*(u+s))
+ 6.*(s-del)*(s-sig)*sqr(t-u)/u/s/s/s/sqr(sqr(beta))
)*log(-t/mW2);
Val += ( -2.*(2.*t*t*(2.*sig-3.*s)+6.*sig*t*(s-sig)+sqr(s-sig)*(s+2.*sig))
/u/s/sqr(beta)
+3.*s*(4.*t-4.*sig-s)/u
-3.*sqr(s-sig)*sqr(t-u)/u/s/s/sqr(sqr(beta))
)*TildeI3WZ(s,mW2,mZ2,beta);
Val += ( 4.*(u+4.*s)/3./u - 4.*(u*t+2.*s*sig)/3./mW2/mZ2
)*pi*pi;
Val += -( 16.*s*(t-sig)*(t-mW2)/t/u
)*TildeI3W(s,t,mW2);
Val += ( 8.*s*s*(t-sig)/u
)*TildeI4t(s,t,mW2,mZ2);
swap(mW2,mZ2);
del *= -1;
swap(t,u);
swap(mW2,mZ2);
del *= -1;
Val += 2.*(4.*t*t+t*(9.*s-4.*sig)-18.*s*sig)/t/u
+ 8.*(t*u+2.*s*sig)/mW2/mZ2
+ 4.*s*s*(2.*t-sig)/u/(mW2*mZ2-t*(u+s))
- 2.*sqr(t-u)/u/s/sqr(beta);
Val += ( 2.*(8.*t*t-4.*t*(s+3.*sig)-(s-sig)*(3.*s+4.*sig))/u/s/sqr(beta)
+ 6.*(t+u)*sqr(t-u)/u/s/s/sqr(sqr(beta))
- 12.*s*(t-sig)/t/u
)*log(-t/s);
Val += ( (2./u/s/s/sqr(beta))*( 4.*t*t*(-2.*s+del)
+ 4.*t*(s*s+s*(mZ2+5.*mW2)-2.*sig*del)
+ (s-sig)*(3.*s*s+8.*mW2*s-3.*sig*del)
)
+ (2.*t*(18.*s+3.*mW2+mZ2)-24.*s*sig)/t/u
- 8.*s*(2.*t*t-t*(3.*s+4.*mZ2+2.*mW2)+2.*mZ2*(s+sig))
/u/(mW2*mZ2-t*(u+s))
- 8.*s*s*t*(2.*t-sig)*(t-mZ2)/u/sqr(mW2*mZ2-t*(u+s))
+ 6.*(s-del)*(s-sig)*sqr(t-u)/u/s/s/s/sqr(sqr(beta))
)*log(-t/mW2);
Val += ( -2.*(2.*t*t*(2.*sig-3.*s)+6.*sig*t*(s-sig)+sqr(s-sig)*(s+2.*sig))
/u/s/sqr(beta)
+3.*s*(4.*t-4.*sig-s)/u
-3.*sqr(s-sig)*sqr(t-u)/u/s/s/sqr(sqr(beta))
)*TildeI3WZ(s,mW2,mZ2,beta);
Val += ( 4.*(u+4.*s)/3./u - 4.*(u*t+2.*s*sig)/3./mW2/mZ2
)*pi*pi;
Val += -( 16.*s*(t-sig)*(t-mW2)/t/u
)*TildeI3W(s,t,mW2);
Val += ( 8.*s*s*(t-sig)/u
)*TildeI4t(s,t,mW2,mZ2);
swap(t,u);
swap(mW2,mZ2);
del *= -1;
return Val;
}
/***************************************************************************/
double Iuu1(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) {
double Val(Idd1(s,u,t,mW2,mZ2,beta));
return Val;
}
/***************************************************************************/
Energy2 Fd1 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) {
Energy2 sig(mZ2+mW2);
Energy2 del(mZ2-mW2);
Energy2 Val(0.*GeV2);
Val += 4.*(17.*t*t+t*(11.*s-13.*sig)+17.*(s*sig+mW2*mZ2))/t
+ 16.*(s-sig)*(t*u+2.*s*sig)/mW2/mZ2
+ 4*s*s*(2.*t-sig)/(t*(u+s)-mW2*mZ2);
Val += ( 8.*(t-u)/sqr(beta)
- 4.*(3.*t*t-t*(s+3.*sig)+3.*(s*sig+mW2*mZ2))/t
)*log(-t/s);
Val += ( 8.*(t*t-t*(2.*s+3.*mW2+mZ2)+3.*(s*sig+mW2*mZ2))/t
+ 8.*s*(t*(3.*s+2.*sig)-2.*mZ2*(s+sig))/(t*(u+s)-mW2*mZ2)
+ 8.*s*s*t*(2.*t-sig)*(t-mZ2)/sqr(t*(u+s)-mW2*mZ2)
- 8.*(s-del)*(t-u)/s/sqr(beta)
)*log(-t/mW2);
Val += ( 4.*(s-sig)*(t-u)/sqr(beta)
+ 4.*(sig-3.*s)*t
+ 4.*(4.*s*sig-mZ2*mZ2-mW2*mW2)
)*TildeI3WZ(s,mW2,mZ2,beta);
Val += -( 8.*(3.*t*t+2.*t*(2.*s-sig)+2.*(s*sig+mW2*mZ2))/3./t
+ 8.*(s-sig)*(t*u+2.*s*sig)/3./mW2/mZ2
)*pi*pi;
Val += ( 4.*(s*t*t-s*(s+sig)*t+2.*s*(s*sig+mW2*mZ2))
)*TildeI4t(s,t,mW2,mZ2);
Val += -( 8.*(t-mW2)*(t*t-t*(s+sig)+2.*(s*sig+mW2*mZ2))/t
)*TildeI3W(s,t,mW2);
swap(mW2,mZ2);
del *= -1;
Val += 4.*(17.*t*t+t*(11.*s-13.*sig)+17.*(s*sig+mW2*mZ2))/t
+ 16.*(s-sig)*(t*u+2.*s*sig)/mW2/mZ2
+ 4*s*s*(2.*t-sig)/(t*(u+s)-mW2*mZ2);
Val += ( 8.*(t-u)/sqr(beta)
- 4.*(3.*t*t-t*(s+3.*sig)+3.*(s*sig+mW2*mZ2))/t
)*log(-t/s);
Val += ( 8.*(t*t-t*(2.*s+3.*mW2+mZ2)+3.*(s*sig+mW2*mZ2))/t
+ 8.*s*(t*(3.*s+2.*sig)-2.*mZ2*(s+sig))/(t*(u+s)-mW2*mZ2)
+ 8.*s*s*t*(2.*t-sig)*(t-mZ2)/sqr(t*(u+s)-mW2*mZ2)
- 8.*(s-del)*(t-u)/s/sqr(beta)
)*log(-t/mW2);
Val += ( 4.*(s-sig)*(t-u)/sqr(beta)
+ 4.*(sig-3.*s)*t
+ 4.*(4.*s*sig-mZ2*mZ2-mW2*mW2)
)*TildeI3WZ(s,mW2,mZ2,beta);
Val += -( 8.*(3.*t*t+2.*t*(2.*s-sig)+2.*(s*sig+mW2*mZ2))/3./t
+ 8.*(s-sig)*(t*u+2.*s*sig)/3./mW2/mZ2
)*pi*pi;
Val += ( 4.*(s*t*t-s*(s+sig)*t+2.*s*(s*sig+mW2*mZ2))
)*TildeI4t(s,t,mW2,mZ2);
Val += -( 8.*(t-mW2)*(t*t-t*(s+sig)+2.*(s*sig+mW2*mZ2))/t
)*TildeI3W(s,t,mW2);
swap(mW2,mZ2);
del *= -1;
return Val;
}
/***************************************************************************/
Energy2 Fu1 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) {
Energy2 Val(Fd1(s,u,t,mW2,mZ2,beta));
return Val;
}
/***************************************************************************/
Energy4 H1 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) {
Energy2 sig(mZ2+mW2);
Energy4 Val(0.*GeV2*GeV2);
Val = 8.*t*t+8.*t*(s-sig)+s*s+6.*s*sig+mZ2*mZ2+10.*mW2*mZ2+mW2*mW2
- sqr(s-sig)*(t*u+2.*s*sig)/mW2/mZ2;
Val *= ( 16.-8.*pi*pi/3.);
return Val;
}
Energy2 t_u_Rdd(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1 , Energy2 q2,
Energy2 mW2, Energy2 mZ2);
Energy2 t_u_Rud(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1 , Energy2 q2,
Energy2 q1h, Energy2 q2h, Energy2 mW2, Energy2 mZ2);
Energy2 t_u_Ruu(Energy2 s , Energy2 tk , Energy2 uk, Energy2 q1h, Energy2 q2h,
Energy2 mW2, Energy2 mZ2);
Energy4 t_u_RZds(Energy2 s ,Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2,
Energy2 s2,Energy2 mW2, Energy2 mZ2);
Energy4 t_u_RZda(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2,
Energy2 s2, Energy2 mW2, Energy2 mZ2);
Energy4 t_u_RZd(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1 , Energy2 q2 ,
Energy2 s2 , Energy2 mW2, Energy2 mZ2);
Energy4 t_u_RZu(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1h, Energy2 q2h,
Energy2 s2 , Energy2 mW2, Energy2 mZ2);
Energy6 t_u_RZs(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2,
Energy2 s2, Energy2 mW2, Energy2 mZ2);
Energy6 t_u_RZa(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2,
Energy2 s2, Energy2 mW2, Energy2 mZ2);
Energy6 t_u_RZ(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2,
Energy2 s2 , Energy2 mW2, Energy2 mZ2);
/***************************************************************************/
// t_u_M_R_qqb is the real emission q + qb -> n + g matrix element
// exactly as defined in Eqs. C.1 of NPB 383(1992)3-44, multiplied by
// tk * uk!
Energy2 MEPP2VVPowheg::t_u_M_R_qqb(realVVKinematics R) const {
// First the Born variables:
Energy2 s2(R.s2r());
Energy2 mW2(R.k12r());
Energy2 mZ2(R.k22r());
// Then the rest:
Energy2 s(R.sr());
Energy2 tk(R.tkr());
Energy2 uk(R.ukr());
Energy2 q1(R.q1r());
Energy2 q2(R.q2r());
Energy2 q1h(R.q1hatr());
Energy2 q2h(R.q2hatr());
double cosThetaW(sqrt(1.-sin2ThetaW_));
double eZ2(eZ2_);
double eZ(eZ_);
double gdL(gdL_);
double guL(guL_);
double gdR(gdR_);
double guR(guR_);
// W+W-
if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) {
double e2(sqr(gW_)*sin2ThetaW_);
if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) {
// N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set!
if(quark_->id()==-antiquark_->id()) {
eZ2 = 1./2.*sqr(s2-mW2)/Fij2_
* (e2*e2/s2/s2*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))
+sqr( eZ*(guL-guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))))
);
eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2)
* (gW_*gW_*e2/4./s2 *( 2./3.+2.*eZ*guL/2./e2*s2/(s2-mW2/sqr(cosThetaW))));
} else {
eZ2 =0.;
eZ =0.;
}
gdL = gW_/sqrt(2.);
guL = 0.;
}
else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) {
// N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set!
if(quark_->id()==-antiquark_->id()) {
eZ2 = 1./2.*sqr(s2-mW2)/Fij2_
* (e2*e2/s2/s2*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))
+sqr( eZ*(gdL-gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))))
);
eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2)
* (gW_*gW_*e2/4./s2 *(-1./3.+2.*eZ*gdL/2./e2*s2/(s2-mW2/sqr(cosThetaW))));
} else {
eZ2 =0.;
eZ =0.;
}
guL = gW_/sqrt(2.);
gdL = 0.;
}
}
// ZZ
else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) {
eZ = 0.;
eZ2 = 0.;
double gV2,gA2;
gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_);
gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_);
guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.;
gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_);
gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_);
gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.;
if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL;
else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL;
else {
cout << "MEPP2VVPowheg:" << endl;
cout << "ZZ needs 2 down-type / 2 up-type!" << endl;
}
}
return -2.*pi*alphaS_*Fij2_*CF_/NC_
* ( gdL*gdL*t_u_Rdd(s,tk,uk,q1,q2,mW2,mZ2)
+ 2.*gdL*guL*t_u_Rud(s,tk,uk,q1,q2,q1h,q2h,mW2,mZ2)
+ guL*guL*t_u_Ruu(s,tk,uk,q1h,q2h,mW2,mZ2)
- 2.*eZ/(s2-mW2) * ( gdL
* t_u_RZd(s,tk,uk,q1 ,q2 ,s2,mW2,mZ2)
- guL
* t_u_RZu(s,tk,uk,q1h,q2h,s2,mW2,mZ2)
)
+ eZ2/sqr(s2-mW2) *t_u_RZ(s,tk,uk,q1,q2,s2,mW2,mZ2)
);
}
Energy2 t_u_Rdd(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1,Energy2 q2,
Energy2 mW2, Energy2 mZ2) {
Energy2 Val(0.*GeV2);
Val += 4.*(q2*(uk+2.*s+q2)+q1*(s+q1))/mW2/mZ2*uk
+ 16.*(uk+s)/q2*uk
- 4.*(2.*uk+4.*s+q2)/mW2*uk
- 4.*(2.*uk+5.*s+q2+2.*q1-mW2)/mZ2*uk
+ 4.*q1*s*(s+q1)/mW2/mZ2
+ 16.*s*(s+q2-mZ2-mW2)/q1
- 4.*s*(4.*s+q2+q1)/mW2
+ 16.*mW2*mZ2*s/q1/q2
+ 4.*s
+ 16.*mZ2*(tk-2.*mW2)/q1/q2/q2*tk*uk
+ 16.*(2.*mZ2+mW2-tk)/q1/q2*tk*uk
+ 16.*mW2*(s-mZ2-mW2)/q1/q2*uk
+ 16.*mZ2*(q1-2.*mW2)/q2/q2*uk
+ 32.*mW2*mW2*mZ2/q1/q2/q2*uk
+ 16.*mW2/q1*uk
+ 4.*uk
+ 8./q2*tk*uk
+ 4.*q1/mW2/mZ2*tk*uk
- 24./q1*tk*uk
- 4./mW2*tk*uk;
swap(mW2,mZ2);
swap(q1,q2);
swap(tk,uk);
Val += 4.*(q2*(uk+2.*s+q2)+q1*(s+q1))/mW2/mZ2*uk
+ 16.*(uk+s)/q2*uk
- 4.*(2.*uk+4.*s+q2)/mW2*uk
- 4.*(2.*uk+5.*s+q2+2.*q1-mW2)/mZ2*uk
+ 4.*q1*s*(s+q1)/mW2/mZ2
+ 16.*s*(s+q2-mZ2-mW2)/q1
- 4.*s*(4.*s+q2+q1)/mW2
+ 16.*mW2*mZ2*s/q1/q2
+ 4.*s
+ 16.*mZ2*(tk-2.*mW2)/q1/q2/q2*tk*uk
+ 16.*(2.*mZ2+mW2-tk)/q1/q2*tk*uk
+ 16.*mW2*(s-mZ2-mW2)/q1/q2*uk
+ 16.*mZ2*(q1-2.*mW2)/q2/q2*uk
+ 32.*mW2*mW2*mZ2/q1/q2/q2*uk
+ 16.*mW2/q1*uk
+ 4.*uk
+ 8./q2*tk*uk
+ 4.*q1/mW2/mZ2*tk*uk
- 24./q1*tk*uk
- 4./mW2*tk*uk;
swap(mW2,mZ2);
swap(q1,q2);
swap(tk,uk);
return Val;
}
Energy2 t_u_Rud(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1,Energy2 q2,
Energy2 q1h,Energy2 q2h,Energy2 mW2, Energy2 mZ2) {
Energy2 Val(0.*GeV2);
Val += (uk*s*(uk+3.*s+q1h)+s*s*(s+mZ2)-(s+uk)*(2.*mZ2*s+3.*mW2*s+mW2*q1h)
) * 8./q1/q2h/q2*uk
- (uk*(uk+3.*s+q1h-mW2)-(q2+s)*(q2-s)+s*(q2-mW2)+q1h*(q2-mW2)+mW2*q2
) * 4.*s/mZ2/q1/q2h*uk
- 4.*((s+uk+q2h-2.*mZ2)*(s+q1h-mZ2)-mZ2*q1)/mW2/q2*uk
+ 4.*(2.*s*uk+2.*mW2*uk+5.*s*s+2.*q1h*s-2.*mZ2*s)/q1/q2h*uk
+ 4.*(2.*s*uk-s*s-2.*q1h*s+2.*mW2*s+2.*mW2*q1h)/q1/q2h/q2*tk*uk
+ ((2.*uk+s)*(s+q1h)+s*(q2+q2h)+2.*q2*(s+q2h)-q1*s+q1*q2+q1h*q2h
) /mW2/mZ2*uk
+ 8.*s*(uk-q1h+mZ2)/q1/q2*uk
+ 4.*s*(-uk+s-q2+q1+q1h)/mZ2/q2h*uk
+ 4.*s*(-uk-q2+q1h)/mZ2/q1*uk
+ 8.*(mZ2*uk-s*s+mW2*s-2.*mZ2*q1-2.*mZ2*q1h)/q2h/q2*uk
+ 2.*(-uk-9.*s-4.*q2-5.*q2h-3.*q1-4.*q1h+8.*mZ2)/mW2*uk
+ 2.*(-4.*uk+3.*s+5.*q1+4.*q1h)/q2h*uk
+ 2.*(s*tk+q2*tk+s*s-q2*q2+q1h*q2)/mW2/mZ2*tk
- 8.*s*(tk+s+q1h)/mW2/q2*tk
+ 2.*(-tk+3.*s+q2-q1h)/mW2*tk
- 8.*s*s*s/q1h/q2
- 2.*s*q2*(s+q2)/mW2/mZ2
+ 2.*s*(2.*s+q2)/mZ2
+ 2.*s*(2.*s+q2)/mW2
- 16.*s*s/q1h
- 2.*s
- 16.*s*s/q1h/q2*tk
- 8.*s/q2*tk
- 16.*s/q1h*tk
+ 6.*s/mZ2*tk
+ 4.*s/q1*uk
+ 4.*s/mZ2*uk
+ 12.*uk
+ 4.*s*(tk+q1h-mW2)/mZ2/q1/q2h*tk*uk
+ 2.*(s+4.*q1+5.*q1h-4.*mZ2)/q2*uk
- 4.*s*s*s/q1h/q1/q2h/q2*tk*uk
- 4.*s*s/q1h/q2h/q2*tk*uk
- 4.*s*s/q1h/q1/q2*tk*uk
+ 8.*s*s/mW2/q1h/q2*tk*uk
- 4.*s*s/q1h/q1/q2h*tk*uk
+ 4.*(s+mZ2)/mW2/q2*tk*uk
- 4.*s/q1h/q2h*tk*uk
- 4.*s/q1h/q1*tk*uk
+ 12.*s/mW2/q1h*tk*uk
- (s+4.*q2)/mW2/mZ2*tk*uk
- 4.*(s+2.*mZ2)/q2h/q2*tk*uk
- 4.*(3.*s+2.*q1h)/q1/q2*tk*uk
- 8.*mW2/q1/q2h*tk*uk
+ 8./q2h*tk*uk
+ 8./q1*tk*uk;
swap(mW2,mZ2);
swap(q1,q2);
swap(tk,uk);
swap(q1h,q2h); // Note this swap is done in accordance with MC@NLO.
// It is not in NPB 383(1992)3-44 Eq.C.4!
Val += (uk*s*(uk+3.*s+q1h)+s*s*(s+mZ2)-(s+uk)*(2.*mZ2*s+3.*mW2*s+mW2*q1h)
) * 8./q1/q2h/q2*uk
- (uk*(uk+3.*s+q1h-mW2)-(q2+s)*(q2-s)+s*(q2-mW2)+q1h*(q2-mW2)+mW2*q2
) * 4.*s/mZ2/q1/q2h*uk
- 4.*((s+uk+q2h-2.*mZ2)*(s+q1h-mZ2)-mZ2*q1)/mW2/q2*uk
+ 4.*(2.*s*uk+2.*mW2*uk+5.*s*s+2.*q1h*s-2.*mZ2*s)/q1/q2h*uk
+ 4.*(2.*s*uk-s*s-2.*q1h*s+2.*mW2*s+2.*mW2*q1h)/q1/q2h/q2*tk*uk
+ ((2.*uk+s)*(s+q1h)+s*(q2+q2h)+2.*q2*(s+q2h)-q1*s+q1*q2+q1h*q2h
) /mW2/mZ2*uk
+ 8.*s*(uk-q1h+mZ2)/q1/q2*uk
+ 4.*s*(-uk+s-q2+q1+q1h)/mZ2/q2h*uk
+ 4.*s*(-uk-q2+q1h)/mZ2/q1*uk
+ 8.*(mZ2*uk-s*s+mW2*s-2.*mZ2*q1-2.*mZ2*q1h)/q2h/q2*uk
+ 2.*(-uk-9.*s-4.*q2-5.*q2h-3.*q1-4.*q1h+8.*mZ2)/mW2*uk
+ 2.*(-4.*uk+3.*s+5.*q1+4.*q1h)/q2h*uk
+ 2.*(s*tk+q2*tk+s*s-q2*q2+q1h*q2)/mW2/mZ2*tk
- 8.*s*(tk+s+q1h)/mW2/q2*tk
+ 2.*(-tk+3.*s+q2-q1h)/mW2*tk
- 8.*s*s*s/q1h/q2
- 2.*s*q2*(s+q2)/mW2/mZ2
+ 2.*s*(2.*s+q2)/mZ2
+ 2.*s*(2.*s+q2)/mW2
- 16.*s*s/q1h
- 2.*s
- 16.*s*s/q1h/q2*tk
- 8.*s/q2*tk
- 16.*s/q1h*tk
+ 6.*s/mZ2*tk
+ 4.*s/q1*uk
+ 4.*s/mZ2*uk
+ 12.*uk
+ 4.*s*(tk+q1h-mW2)/mZ2/q1/q2h*tk*uk
+ 2.*(s+4.*q1+5.*q1h-4.*mZ2)/q2*uk
- 4.*s*s*s/q1h/q1/q2h/q2*tk*uk
- 4.*s*s/q1h/q2h/q2*tk*uk
- 4.*s*s/q1h/q1/q2*tk*uk
+ 8.*s*s/mW2/q1h/q2*tk*uk
- 4.*s*s/q1h/q1/q2h*tk*uk
+ 4.*(s+mZ2)/mW2/q2*tk*uk
- 4.*s/q1h/q2h*tk*uk
- 4.*s/q1h/q1*tk*uk
+ 12.*s/mW2/q1h*tk*uk
- (s+4.*q2)/mW2/mZ2*tk*uk
- 4.*(s+2.*mZ2)/q2h/q2*tk*uk
- 4.*(3.*s+2.*q1h)/q1/q2*tk*uk
- 8.*mW2/q1/q2h*tk*uk
+ 8./q2h*tk*uk
+ 8./q1*tk*uk;
swap(mW2,mZ2);
swap(q1,q2);
swap(tk,uk);
swap(q1h,q2h); // Note this swap is done in accordance with MC@NLO.
// It is not in NPB 383(1992)3-44 Eq.C.4!
swap(tk,uk);
swap(q1,q2h);
swap(q2,q1h);
Val += (uk*s*(uk+3.*s+q1h)+s*s*(s+mZ2)-(s+uk)*(2.*mZ2*s+3.*mW2*s+mW2*q1h)
) * 8./q1/q2h/q2*uk
- (uk*(uk+3.*s+q1h-mW2)-(q2+s)*(q2-s)+s*(q2-mW2)+q1h*(q2-mW2)+mW2*q2
) * 4.*s/mZ2/q1/q2h*uk
- 4.*((s+uk+q2h-2.*mZ2)*(s+q1h-mZ2)-mZ2*q1)/mW2/q2*uk
+ 4.*(2.*s*uk+2.*mW2*uk+5.*s*s+2.*q1h*s-2.*mZ2*s)/q1/q2h*uk
+ 4.*(2.*s*uk-s*s-2.*q1h*s+2.*mW2*s+2.*mW2*q1h)/q1/q2h/q2*tk*uk
+ ((2.*uk+s)*(s+q1h)+s*(q2+q2h)+2.*q2*(s+q2h)-q1*s+q1*q2+q1h*q2h
) /mW2/mZ2*uk
+ 8.*s*(uk-q1h+mZ2)/q1/q2*uk
+ 4.*s*(-uk+s-q2+q1+q1h)/mZ2/q2h*uk
+ 4.*s*(-uk-q2+q1h)/mZ2/q1*uk
+ 8.*(mZ2*uk-s*s+mW2*s-2.*mZ2*q1-2.*mZ2*q1h)/q2h/q2*uk
+ 2.*(-uk-9.*s-4.*q2-5.*q2h-3.*q1-4.*q1h+8.*mZ2)/mW2*uk
+ 2.*(-4.*uk+3.*s+5.*q1+4.*q1h)/q2h*uk
+ 2.*(s*tk+q2*tk+s*s-q2*q2+q1h*q2)/mW2/mZ2*tk
- 8.*s*(tk+s+q1h)/mW2/q2*tk
+ 2.*(-tk+3.*s+q2-q1h)/mW2*tk
- 8.*s*s*s/q1h/q2
- 2.*s*q2*(s+q2)/mW2/mZ2
+ 2.*s*(2.*s+q2)/mZ2
+ 2.*s*(2.*s+q2)/mW2
- 16.*s*s/q1h
- 2.*s
- 16.*s*s/q1h/q2*tk
- 8.*s/q2*tk
- 16.*s/q1h*tk
+ 6.*s/mZ2*tk
+ 4.*s/q1*uk
+ 4.*s/mZ2*uk
+ 12.*uk
+ 4.*s*(tk+q1h-mW2)/mZ2/q1/q2h*tk*uk
+ 2.*(s+4.*q1+5.*q1h-4.*mZ2)/q2*uk
- 4.*s*s*s/q1h/q1/q2h/q2*tk*uk
- 4.*s*s/q1h/q2h/q2*tk*uk
- 4.*s*s/q1h/q1/q2*tk*uk
+ 8.*s*s/mW2/q1h/q2*tk*uk
- 4.*s*s/q1h/q1/q2h*tk*uk
+ 4.*(s+mZ2)/mW2/q2*tk*uk
- 4.*s/q1h/q2h*tk*uk
- 4.*s/q1h/q1*tk*uk
+ 12.*s/mW2/q1h*tk*uk
- (s+4.*q2)/mW2/mZ2*tk*uk
- 4.*(s+2.*mZ2)/q2h/q2*tk*uk
- 4.*(3.*s+2.*q1h)/q1/q2*tk*uk
- 8.*mW2/q1/q2h*tk*uk
+ 8./q2h*tk*uk
+ 8./q1*tk*uk;
swap(tk,uk);
swap(q1,q2h);
swap(q2,q1h);
swap(mW2,mZ2);
swap(q1,q1h);
swap(q2,q2h);
Val += (uk*s*(uk+3.*s+q1h)+s*s*(s+mZ2)-(s+uk)*(2.*mZ2*s+3.*mW2*s+mW2*q1h)
) * 8./q1/q2h/q2*uk
- (uk*(uk+3.*s+q1h-mW2)-(q2+s)*(q2-s)+s*(q2-mW2)+q1h*(q2-mW2)+mW2*q2
) * 4.*s/mZ2/q1/q2h*uk
- 4.*((s+uk+q2h-2.*mZ2)*(s+q1h-mZ2)-mZ2*q1)/mW2/q2*uk
+ 4.*(2.*s*uk+2.*mW2*uk+5.*s*s+2.*q1h*s-2.*mZ2*s)/q1/q2h*uk
+ 4.*(2.*s*uk-s*s-2.*q1h*s+2.*mW2*s+2.*mW2*q1h)/q1/q2h/q2*tk*uk
+ ((2.*uk+s)*(s+q1h)+s*(q2+q2h)+2.*q2*(s+q2h)-q1*s+q1*q2+q1h*q2h
) /mW2/mZ2*uk
+ 8.*s*(uk-q1h+mZ2)/q1/q2*uk
+ 4.*s*(-uk+s-q2+q1+q1h)/mZ2/q2h*uk
+ 4.*s*(-uk-q2+q1h)/mZ2/q1*uk
+ 8.*(mZ2*uk-s*s+mW2*s-2.*mZ2*q1-2.*mZ2*q1h)/q2h/q2*uk
+ 2.*(-uk-9.*s-4.*q2-5.*q2h-3.*q1-4.*q1h+8.*mZ2)/mW2*uk
+ 2.*(-4.*uk+3.*s+5.*q1+4.*q1h)/q2h*uk
+ 2.*(s*tk+q2*tk+s*s-q2*q2+q1h*q2)/mW2/mZ2*tk
- 8.*s*(tk+s+q1h)/mW2/q2*tk
+ 2.*(-tk+3.*s+q2-q1h)/mW2*tk
- 8.*s*s*s/q1h/q2
- 2.*s*q2*(s+q2)/mW2/mZ2
+ 2.*s*(2.*s+q2)/mZ2
+ 2.*s*(2.*s+q2)/mW2
- 16.*s*s/q1h
- 2.*s
- 16.*s*s/q1h/q2*tk
- 8.*s/q2*tk
- 16.*s/q1h*tk
+ 6.*s/mZ2*tk
+ 4.*s/q1*uk
+ 4.*s/mZ2*uk
+ 12.*uk
+ 4.*s*(tk+q1h-mW2)/mZ2/q1/q2h*tk*uk
+ 2.*(s+4.*q1+5.*q1h-4.*mZ2)/q2*uk
- 4.*s*s*s/q1h/q1/q2h/q2*tk*uk
- 4.*s*s/q1h/q2h/q2*tk*uk
- 4.*s*s/q1h/q1/q2*tk*uk
+ 8.*s*s/mW2/q1h/q2*tk*uk
- 4.*s*s/q1h/q1/q2h*tk*uk
+ 4.*(s+mZ2)/mW2/q2*tk*uk
- 4.*s/q1h/q2h*tk*uk
- 4.*s/q1h/q1*tk*uk
+ 12.*s/mW2/q1h*tk*uk
- (s+4.*q2)/mW2/mZ2*tk*uk
- 4.*(s+2.*mZ2)/q2h/q2*tk*uk
- 4.*(3.*s+2.*q1h)/q1/q2*tk*uk
- 8.*mW2/q1/q2h*tk*uk
+ 8./q2h*tk*uk
+ 8./q1*tk*uk;
swap(mW2,mZ2);
swap(q1,q1h);
swap(q2,q2h);
return Val;
}
Energy2 t_u_Ruu(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1h,Energy2 q2h,
Energy2 mW2, Energy2 mZ2) {
return t_u_Rdd(s,tk,uk,q1h,q2h,mZ2,mW2);
}
Energy4 t_u_RZds(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1,Energy2 q2,
Energy2 s2, Energy2 mW2, Energy2 mZ2) {
Energy4 Val(0.*GeV2*GeV2);
Energy2 sig(mZ2+mW2);
Val += ( q1*q2*(5./2.*s*s+5.*s*tk+3.*tk*tk)+(tk*uk*uk+q1*q1*q2)*(tk+s)
+ q1*(tk*tk*uk+s*uk*uk-s*s*tk+s*s*uk)+q1*q1*q1*(uk+s)-q1*q1*s*s2
) * 8./q1/q2
- ( tk*tk*(4.*uk+s+q1-2.*q2)+tk*(sqr(q1+q2)-q1*s-3.*q2*s-2.*q1*q1)
- q1*s*(4.*s-2.*q1-q2)+tk*uk*(q1+3.*s)
) * 4.*sig/q1/q2
- 4.*sig*sig*(s*(2.*s+q1)+tk*(uk+5./2.*tk+5.*s+q1+q2)
)/mW2/mZ2
+ 2.*sig*s2*(4.*sqr(s+tk)+tk*(uk+s+4.*q1+2.*q2)+2.*q1*(2.*s+q1)
)/mW2/mZ2
+ 4.*sig*sig*(s2+s-q1+q2)/q1/q2*tk
- 16.*mW2*mZ2*(tk*uk/2.+q2*tk-q1*s)/q1/q2
- 4.*s2*s2*q1*(tk+s+q1)/mW2/mZ2
+ sig*sig*sig*(uk+tk)/mW2/mZ2
+ 4.*mW2*mZ2*sig*(uk+tk)/q1/q2;
swap(mW2,mZ2);
swap(q1,q2);
swap(tk,uk);
Val += ( q1*q2*(5./2.*s*s+5.*s*tk+3.*tk*tk)+(tk*uk*uk+q1*q1*q2)*(tk+s)
+ q1*(tk*tk*uk+s*uk*uk-s*s*tk+s*s*uk)+q1*q1*q1*(uk+s)-q1*q1*s*s2
) * 8./q1/q2
- ( tk*tk*(4.*uk+s+q1-2.*q2)+tk*(sqr(q1+q2)-q1*s-3.*q2*s-2.*q1*q1)
- q1*s*(4.*s-2.*q1-q2)+tk*uk*(q1+3.*s)
) * 4.*sig/q1/q2
- 4.*sig*sig*(s*(2.*s+q1)+tk*(uk+5./2.*tk+5.*s+q1+q2)
)/mW2/mZ2
+ 2.*sig*s2*(4.*sqr(s+tk)+tk*(uk+s+4.*q1+2.*q2)+2.*q1*(2.*s+q1)
)/mW2/mZ2
+ 4.*sig*sig*(s2+s-q1+q2)/q1/q2*tk
- 16.*mW2*mZ2*(tk*uk/2.+q2*tk-q1*s)/q1/q2
- 4.*s2*s2*q1*(tk+s+q1)/mW2/mZ2
+ sig*sig*sig*(uk+tk)/mW2/mZ2
+ 4.*mW2*mZ2*sig*(uk+tk)/q1/q2;
swap(mW2,mZ2);
swap(q1,q2);
swap(tk,uk);
return Val;
}
Energy4 t_u_RZda(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1,Energy2 q2,
Energy2 s2, Energy2 mW2, Energy2 mZ2) {
Energy4 Val(0.*GeV2*GeV2);
Val += 4.*mZ2*(2.*uk*uk-s*tk+q1*(uk-tk-s+q1+0.5*q2)+q2*(s-3.*q2)
) /q1/q2*tk
- 4.*mZ2*mZ2*(q1-tk-2.*s-q2)/q1/q2*tk
- 2.*mZ2*(tk+2.*s+2.*q2)/mW2*tk
- 2.*s2*(s+2.*q2)/mZ2*tk
+ 8.*mW2*mZ2*mZ2/q1/q2*tk
+ 2.*mZ2*mZ2/mW2*tk;
swap(mW2,mZ2); // N.B. Here we subtract!
Val -= 4.*mZ2*(2.*uk*uk-s*tk+q1*(uk-tk-s+q1+0.5*q2)+q2*(s-3.*q2)
) /q1/q2*tk
- 4.*mZ2*mZ2*(q1-tk-2.*s-q2)/q1/q2*tk
- 2.*mZ2*(tk+2.*s+2.*q2)/mW2*tk
- 2.*s2*(s+2.*q2)/mZ2*tk
+ 8.*mW2*mZ2*mZ2/q1/q2*tk
+ 2.*mZ2*mZ2/mW2*tk;
swap(mW2,mZ2);
swap(q1,q2); // N.B. Here we subtract!
swap(tk,uk);
Val -= 4.*mZ2*(2.*uk*uk-s*tk+q1*(uk-tk-s+q1+0.5*q2)+q2*(s-3.*q2)
) /q1/q2*tk
- 4.*mZ2*mZ2*(q1-tk-2.*s-q2)/q1/q2*tk
- 2.*mZ2*(tk+2.*s+2.*q2)/mW2*tk
- 2.*s2*(s+2.*q2)/mZ2*tk
+ 8.*mW2*mZ2*mZ2/q1/q2*tk
+ 2.*mZ2*mZ2/mW2*tk;
swap(q1,q2);
swap(tk,uk);
swap(mW2,mZ2); // N.B. Here we add!
swap(q1,q2);
swap(tk,uk);
Val += 4.*mZ2*(2.*uk*uk-s*tk+q1*(uk-tk-s+q1+0.5*q2)+q2*(s-3.*q2)
) /q1/q2*tk
- 4.*mZ2*mZ2*(q1-tk-2.*s-q2)/q1/q2*tk
- 2.*mZ2*(tk+2.*s+2.*q2)/mW2*tk
- 2.*s2*(s+2.*q2)/mZ2*tk
+ 8.*mW2*mZ2*mZ2/q1/q2*tk
+ 2.*mZ2*mZ2/mW2*tk;
swap(mW2,mZ2);
swap(q1,q2);
swap(tk,uk);
return Val;
}
Energy4 t_u_RZd(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1 , Energy2 q2 ,
Energy2 s2, Energy2 mW2, Energy2 mZ2) {
Energy4 Val(0.*GeV2*GeV2);
Val = t_u_RZds(s,tk,uk,q1,q2,s2,mW2,mZ2)
+ t_u_RZda(s,tk,uk,q1,q2,s2,mW2,mZ2);
return Val;
}
Energy4 t_u_RZu(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1h, Energy2 q2h,
Energy2 s2, Energy2 mW2, Energy2 mZ2) {
Energy4 Val(0.*GeV2*GeV2);
Val = t_u_RZd(s,tk,uk,q1h,q2h,s2,mZ2,mW2);
return Val;
}
Energy6 t_u_RZs(Energy2 s,Energy2 tk,Energy2 uk,Energy2 q1,Energy2 q2,
Energy2 s2,Energy2 mW2,Energy2 mZ2) {
Energy6 Val(0.*GeV2*GeV2*GeV2);
Energy2 sig(mZ2+mW2);
Val += 2.*sig*sig*s2*( tk*(3.*uk+9.*tk+19.*s+6.*q1+4.*q2)+8.*s*s+6.*q1*s
+ 2.*q1*q1
)/mW2/mZ2
- 2.*sig*sig*sig*(tk*(3.*uk+6.*tk+11.*s+2.*q1+2.*q2)+2.*s*(2.*s+q1))
/ mW2/mZ2
- 2.*sig*s2*s2*(tk*(uk+4.*tk+9.*s+6.*q1+2.*q2)+4.*sqr(s+q1)-2.*q1*s)
/mW2/mZ2
- 16.*sig*(2.*tk*(uk/2.-tk-s+q1+q2)-s*(3.*s/2.-2.*q1))
+ 8.*s2*(s*(s/2.+tk)+4.*q1*(tk+s+q1))
+ 4.*s2*s2*s2*q1*(tk+s+q1)/mW2/mZ2
+ 8.*sig*sig*(2.*tk+s/2.)
+ 2.*sig*sig*sig*sig*tk/mW2/mZ2
+ 32.*mW2*mZ2*s;
swap(mW2,mZ2);
swap(q1,q2);
swap(tk,uk);
Val += 2.*sig*sig*s2*( tk*(3.*uk+9.*tk+19.*s+6.*q1+4.*q2)+8.*s*s+6.*q1*s
+ 2.*q1*q1
)/mW2/mZ2
- 2.*sig*sig*sig*(tk*(3.*uk+6.*tk+11.*s+2.*q1+2.*q2)+2.*s*(2.*s+q1))
/ mW2/mZ2
- 2.*sig*s2*s2*(tk*(uk+4.*tk+9.*s+6.*q1+2.*q2)+4.*sqr(s+q1)-2.*q1*s)
/mW2/mZ2
- 16.*sig*(2.*tk*(uk/2.-tk-s+q1+q2)-s*(3.*s/2.-2.*q1))
+ 8.*s2*(s*(s/2.+tk)+4.*q1*(tk+s+q1))
+ 4.*s2*s2*s2*q1*(tk+s+q1)/mW2/mZ2
+ 8.*sig*sig*(2.*tk+s/2.)
+ 2.*sig*sig*sig*sig*tk/mW2/mZ2
+ 32.*mW2*mZ2*s;
swap(mW2,mZ2);
swap(q1,q2);
swap(tk,uk);
return Val;
}
Energy6 t_u_RZa(Energy2 s,Energy2 tk,Energy2 uk,Energy2 q1,Energy2 q2,
Energy2 s2,Energy2 mW2,Energy2 mZ2) {
Energy6 Val(0.*GeV2*GeV2*GeV2);
Val += - 2.*mZ2*(2.*tk+11.*s+18.*q2)*tk
- 2.*mZ2*mZ2*(2.*tk+3.*s+2.*q2)/mW2*tk
+ 2.*mZ2*s2*(tk+3.*s+4.*q2)/mW2*tk
- 2.*s2*s2*(s+2.*q2)/mW2*tk
+ 2.*mZ2*mZ2*mZ2/mW2*tk
+ 20.*mZ2*mZ2*tk;
swap(mW2,mZ2);
Val -= - 2.*mZ2*(2.*tk+11.*s+18.*q2)*tk
- 2.*mZ2*mZ2*(2.*tk+3.*s+2.*q2)/mW2*tk
+ 2.*mZ2*s2*(tk+3.*s+4.*q2)/mW2*tk
- 2.*s2*s2*(s+2.*q2)/mW2*tk
+ 2.*mZ2*mZ2*mZ2/mW2*tk
+ 20.*mZ2*mZ2*tk;
swap(mW2,mZ2);
swap(q1,q2);
swap(tk,uk);
Val -= - 2.*mZ2*(2.*tk+11.*s+18.*q2)*tk
- 2.*mZ2*mZ2*(2.*tk+3.*s+2.*q2)/mW2*tk
+ 2.*mZ2*s2*(tk+3.*s+4.*q2)/mW2*tk
- 2.*s2*s2*(s+2.*q2)/mW2*tk
+ 2.*mZ2*mZ2*mZ2/mW2*tk
+ 20.*mZ2*mZ2*tk;
swap(q1,q2);
swap(tk,uk);
swap(mW2,mZ2);
swap(q1,q2);
swap(tk,uk);
Val += - 2.*mZ2*(2.*tk+11.*s+18.*q2)*tk
- 2.*mZ2*mZ2*(2.*tk+3.*s+2.*q2)/mW2*tk
+ 2.*mZ2*s2*(tk+3.*s+4.*q2)/mW2*tk
- 2.*s2*s2*(s+2.*q2)/mW2*tk
+ 2.*mZ2*mZ2*mZ2/mW2*tk
+ 20.*mZ2*mZ2*tk;
swap(mW2,mZ2);
swap(q1,q2);
swap(tk,uk);
return Val;
}
Energy6 t_u_RZ(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2,
Energy2 s2, Energy2 mW2, Energy2 mZ2) {
Energy6 Val(0.*GeV2*GeV2*GeV2);
Val = t_u_RZs(s,tk,uk,q1,q2,s2,mW2,mZ2)
+ t_u_RZa(s,tk,uk,q1,q2,s2,mW2,mZ2);
return Val;
}
/***************************************************************************/
// t_u_M_R_qg is the real emission q + qb -> n + g matrix element
// exactly as defined in Eqs. C.9 of NPB 383(1992)3-44, multiplied by
// tk * uk!
Energy2 MEPP2VVPowheg::t_u_M_R_qg(realVVKinematics R) const {
// First the Born variables:
Energy2 s2(R.s2r());
Energy2 mW2(R.k12r());
Energy2 mZ2(R.k22r());
// Then the rest:
Energy2 s(R.sr());
Energy2 tk(R.tkr());
Energy2 uk(R.ukr());
Energy2 q1(R.q1r());
Energy2 q2(R.q2r());
Energy2 q1h(R.q1hatr());
Energy2 q2h(R.q2hatr());
Energy2 w1(R.w1r());
Energy2 w2(R.w2r());
double cosThetaW(sqrt(1.-sin2ThetaW_));
double eZ2(eZ2_);
double eZ(eZ_);
double gdL(gdL_);
double guL(guL_);
double gdR(gdR_);
double guR(guR_);
// W+W-
if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) {
double e2(sqr(gW_)*sin2ThetaW_);
if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) {
// N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set!
if(quark_->id()==-antiquark_->id()) {
eZ2 = 1./2.*sqr(s2-mW2)/Fij2_
* (e2*e2/s2/s2*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))
+sqr( eZ*(guL-guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))))
);
eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2)
* (gW_*gW_*e2/4./s2 *( 2./3.+2.*eZ*guL/2./e2*s2/(s2-mW2/sqr(cosThetaW))));
} else {
eZ2 =0.;
eZ =0.;
}
gdL = gW_/sqrt(2.);
guL = 0.;
}
else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) {
// N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set!
if(quark_->id()==-antiquark_->id()) {
eZ2 = 1./2.*sqr(s2-mW2)/Fij2_
* (e2*e2/s2/s2*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))
+sqr( eZ*(gdL-gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))))
);
eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2)
* (gW_*gW_*e2/4./s2 *(-1./3.+2.*eZ*gdL/2./e2*s2/(s2-mW2/sqr(cosThetaW))));
} else {
eZ2 =0.;
eZ =0.;
}
guL = gW_/sqrt(2.);
gdL = 0.;
}
}
// ZZ
else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) {
eZ = 0.;
eZ2 = 0.;
double gV2,gA2;
gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_);
gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_);
guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.;
gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_);
gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_);
gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.;
if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL;
else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL;
else {
cout << "MEPP2VVPowheg:" << endl;
cout << "ZZ needs 2 down-type / 2 up-type!" << endl;
}
}
Energy2 Val(0.*GeV2);
swap(s,tk);
swap(q2,w2);
swap(q2h,w1);
Val = -2.*pi*alphaS_*Fij2_*CF_/NC_
* ( gdL*gdL*t_u_Rdd(s,tk,uk,q1,q2,mW2,mZ2)
+ 2.*gdL*guL*t_u_Rud(s,tk,uk,q1,q2,q1h,q2h,mW2,mZ2)
+ guL*guL*t_u_Ruu(s,tk,uk,q1h,q2h,mW2,mZ2)
- 2.*eZ/(s2-mW2) * ( gdL
* t_u_RZd(s,tk,uk,q1 ,q2 ,s2,mW2,mZ2)
- guL
* t_u_RZu(s,tk,uk,q1h,q2h,s2,mW2,mZ2)
)
+ eZ2/sqr(s2-mW2) *t_u_RZ(s,tk,uk,q1,q2,s2,mW2,mZ2)
);
swap(s,tk);
swap(q2,w2);
swap(q2h,w1);
Val *= -tk/s * TR_/CF_;
return Val;
}
/***************************************************************************/
// t_u_M_R_gqb is the real emission g + qb -> n + q matrix element
// exactly as defined in Eqs. C.9 of NPB 383(1992)3-44, multiplied by
// tk * uk!
Energy2 MEPP2VVPowheg::t_u_M_R_gqb(realVVKinematics R) const {
// First the Born variables:
Energy2 s2(R.s2r());
Energy2 mW2(R.k12r());
Energy2 mZ2(R.k22r());
// Then the rest:
Energy2 s(R.sr());
Energy2 tk(R.tkr());
Energy2 uk(R.ukr());
Energy2 q1(R.q1r());
Energy2 q2(R.q2r());
Energy2 q1h(R.q1hatr());
Energy2 q2h(R.q2hatr());
Energy2 w1(R.w1r());
Energy2 w2(R.w2r());
double cosThetaW(sqrt(1.-sin2ThetaW_));
double eZ2(eZ2_);
double eZ(eZ_);
double gdL(gdL_);
double guL(guL_);
double gdR(gdR_);
double guR(guR_);
// W+W-
if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) {
double e2(sqr(gW_)*sin2ThetaW_);
if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) {
// N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set!
if(quark_->id()==-antiquark_->id()) {
eZ2 = 1./2.*sqr(s2-mW2)/Fij2_
* (e2*e2/s2/s2*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))
+sqr( eZ*(guL-guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))))
);
eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2)
* (gW_*gW_*e2/4./s2 *( 2./3.+2.*eZ*guL/2./e2*s2/(s2-mW2/sqr(cosThetaW))));
} else {
eZ2 =0.;
eZ =0.;
}
gdL = gW_/sqrt(2.);
guL = 0.;
}
else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) {
// N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set!
if(quark_->id()==-antiquark_->id()) {
eZ2 = 1./2.*sqr(s2-mW2)/Fij2_
* (e2*e2/s2/s2*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))
+sqr( eZ*(gdL-gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))))
);
eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2)
* (gW_*gW_*e2/4./s2 *(-1./3.+2.*eZ*gdL/2./e2*s2/(s2-mW2/sqr(cosThetaW))));
} else {
eZ2 =0.;
eZ =0.;
}
guL = gW_/sqrt(2.);
gdL = 0.;
}
}
// ZZ
else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) {
eZ = 0.;
eZ2 = 0.;
double gV2,gA2;
gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_);
gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_);
guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.;
gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_);
gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_);
gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.;
if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL;
else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL;
else {
cout << "MEPP2VVPowheg:" << endl;
cout << "ZZ needs 2 down-type / 2 up-type!" << endl;
}
}
Energy2 Val(0.*GeV2);
swap(s,uk);
swap(q1,w1);
swap(q1h,w2);
Val = -2.*pi*alphaS_*Fij2_*CF_/NC_
* ( gdL*gdL*t_u_Rdd(s,tk,uk,q1,q2,mW2,mZ2)
+ 2.*gdL*guL*t_u_Rud(s,tk,uk,q1,q2,q1h,q2h,mW2,mZ2)
+ guL*guL*t_u_Ruu(s,tk,uk,q1h,q2h,mW2,mZ2)
- 2.*eZ/(s2-mW2) * ( gdL
* t_u_RZd(s,tk,uk,q1 ,q2 ,s2,mW2,mZ2)
- guL
* t_u_RZu(s,tk,uk,q1h,q2h,s2,mW2,mZ2)
)
+ eZ2/sqr(s2-mW2) *t_u_RZ(s,tk,uk,q1,q2,s2,mW2,mZ2)
);
swap(s,uk);
swap(q1,w1);
swap(q1h,w2);
Val *= -uk/s * TR_/CF_;
return Val;
}
/***************************************************************************/
// The following six functions are I_{dd}^{(0)}, I_{ud}^{(0)},
// I_{uu}^{(0)}, F_{u}^{(0)}, F_{d}^{(0)}, H^{(0)} from Eqs. 3.9 - 3.14
// They make up the Born matrix element. Ixx functions correspond to the
// graphs with no TGC, Fx functions are due to non-TGC graphs interfering
// with TGC graphs, while the H function is due purely to TGC graphs.
double Idd0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2);
double Iud0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2);
double Iuu0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2);
Energy2 Fu0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2);
Energy2 Fd0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2);
Energy4 H0 (Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2);
/***************************************************************************/
// M_Born_WZ is the Born matrix element exactly as defined in Eqs. 3.3-3.14
// of of NPB 383(1992)3-44 (with a spin*colour averaging factor 1./4./NC_/NC_).
double MEPP2VVPowheg::M_Born_WZ(bornVVKinematics B) const {
Energy2 s(B.sb());
Energy2 t(B.tb());
Energy2 u(B.ub());
Energy2 mW2(B.k12b()); // N.B. the diboson masses are preserved in getting
Energy2 mZ2(B.k22b()); // the 2->2 from the 2->3 kinematics.
double cosThetaW(sqrt(1.-sin2ThetaW_));
double eZ2(eZ2_);
double eZ(eZ_);
double gdL(gdL_);
double guL(guL_);
double gdR(gdR_);
double guR(guR_);
// W+W-
if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) {
double e2(sqr(gW_)*sin2ThetaW_);
if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) {
// N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set!
if(quark_->id()==-antiquark_->id()) {
eZ2 = 1./2.*sqr(s-mW2)/Fij2_
* (e2*e2/s/s*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s/(s-mW2/sqr(cosThetaW)))
+sqr( eZ*(guL-guR)/2./e2*s/(s-mW2/sqr(cosThetaW))))
);
eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s-mW2)
* (gW_*gW_*e2/4./s *( 2./3.+2.*eZ*guL/2./e2*s/(s-mW2/sqr(cosThetaW))));
} else {
eZ2 =0.;
eZ =0.;
}
gdL = gW_/sqrt(2.);
guL = 0.;
}
else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) {
// N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set!
if(quark_->id()==-antiquark_->id()) {
eZ2 = 1./2.*sqr(s-mW2)/Fij2_
* (e2*e2/s/s*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s/(s-mW2/sqr(cosThetaW)))
+sqr( eZ*(gdL-gdR)/2./e2*s/(s-mW2/sqr(cosThetaW))))
);
eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s-mW2)
* (gW_*gW_*e2/4./s *(-1./3.+2.*eZ*gdL/2./e2*s/(s-mW2/sqr(cosThetaW))));
} else {
eZ2 =0.;
eZ =0.;
}
guL = gW_/sqrt(2.);
gdL = 0.;
}
}
// ZZ
else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) {
eZ = 0.;
eZ2 = 0.;
double gV2,gA2;
gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_);
gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_);
guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.;
gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_);
gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_);
gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.;
if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL;
else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL;
else {
cout << "MEPP2VVPowheg:" << endl;
cout << "ZZ needs 2 down-type / 2 up-type!" << endl;
}
}
return Fij2_/2./NC_
* (
gdL*gdL*Idd0(s,t,u,mW2,mZ2)
+ 2.*gdL*guL*Iud0(s,t,u,mW2,mZ2)
+ guL*guL*Iuu0(s,t,u,mW2,mZ2)
- 2.*eZ/(s-mW2) * ( gdL*Fd0(s,t,u,mW2,mZ2)
- guL*Fu0(s,t,u,mW2,mZ2)
)
+ eZ2/sqr(s-mW2) * H0(s,t,u,mW2,mZ2)
);
}
/***************************************************************************/
double Idd0(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) {
return 8.*((u*t/mW2/mZ2-1.)/4.+s/2.*(mW2+mZ2)/mW2/mZ2)
+ 8.*(u/t-mW2*mZ2/t/t);
}
/***************************************************************************/
double Iud0(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) {
return - 8.*((u*t/mW2/mZ2-1.)/4.+s/2.*(mW2+mZ2)/mW2/mZ2)
+ 8.*s/t/u*(mW2+mZ2);
}
/***************************************************************************/
double Iuu0(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) {
return Idd0(s,u,t,mW2,mZ2);
}
/***************************************************************************/
Energy2 Fd0 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) {
return - 8.*s*( (u*t/mW2/mZ2-1.)*(1.-(mW2+mZ2)/s-4.*mW2*mZ2/s/t)/4.
+ (mW2+mZ2)/2./mW2/mZ2*(s-mW2-mZ2+2.*mW2*mZ2/t)
);
}
/***************************************************************************/
Energy2 Fu0 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) {
return Fd0(s,u,t,mW2,mZ2);
}
/***************************************************************************/
Energy4 H0 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) {
return 8.*s*s*(u*t/mW2/mZ2-1.)*( 1./4.-(mW2+mZ2)/2./s
+ (sqr(mW2+mZ2)+8.*mW2*mZ2)/4./s/s
)
+ 8.*s*s*(mW2+mZ2)/mW2/mZ2*(s/2.-mW2-mZ2+sqr(mW2-mZ2)/2./s);
}
/***************************************************************************/
bool MEPP2VVPowheg::sanityCheck() const {
bool alarm(false);
Energy2 prefacs(8.*pi*alphaS_*S_.sr() /S_.xr() );
Energy2 prefacsp(8.*pi*alphaS_*SCp_.sr() /SCp_.xr() );
Energy2 prefacsm(8.*pi*alphaS_*SCm_.sr() /SCm_.xr() );
Energy2 prefacp(8.*pi*alphaS_*Cp_.sr()/Cp_.xr());
Energy2 prefacm(8.*pi*alphaS_*Cm_.sr()/Cm_.xr());
double xp(Cp_.xr());
double xm(Cm_.xr());
double M_B_WW(M_Born_WW(B_));
double M_B_ZZ(M_Born_ZZ(B_));
double M_V_reg_WW(M_V_regular_WW(S_));
double M_V_reg_ZZ(M_V_regular_ZZ(S_));
Energy2 t_u_qqb_WW(t_u_M_R_qqb_WW(H_));
Energy2 t_u_qqb_ZZ(t_u_M_R_qqb_ZZ(H_));
// Check that the native leading order Herwig matrix
// element is equivalent to the WZ leading order matrix
// element in NPB 383 (1992) 3-44, with the relevant WZ->WW
// WZ->ZZ transformation applied (M_Born_).
// if(fabs((lo_me2_ - M_Born_)/M_Born_)>1.e-2) {
// alarm=true;
// cout << "lo_me2_ - M_Born_ (%) = "
// << lo_me2_ - M_Born_ << " ("
// << (lo_me2_ - M_Born_)/M_Born_*100. << ")\n";
// }
// Check that the transformation from NPB 383 (1992) 3-44 WZ
// matrix elements to WW matrix elements actually works, by
// comparing them to the explicit WW matrix elements in
// NPB 410 (1993) 280-324.
if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) {
if(fabs((M_Born_ -M_B_WW )/M_B_WW )>1.e-6) {
alarm=true;
cout << "WZ->WW transformation error!\n";
cout << "M_Born_ - M_B_WW (rel) = "
<< M_Born_ - M_B_WW << " ("
<< (M_Born_ - M_B_WW)/M_B_WW << ")\n";
cout << "M_Born_ = " << M_Born_ << endl;
cout << "M_B_WW = " << M_B_WW << endl;
}
if(fabs((M_V_regular_-M_V_reg_WW)/M_V_reg_WW)>1.e-6) {
alarm=true;
cout << "WZ->WW transformation error!\n";
cout << "M_V_regular_ - M_V_reg_WW (rel) = "
<< M_V_regular_ - M_V_reg_WW << " ("
<< (M_V_regular_ - M_V_reg_WW)/M_V_reg_WW << ")\n";
cout << "M_V_regular_ = " << M_V_regular_ << endl;
cout << "M_V_reg_WW = " << M_V_reg_WW << endl;
}
if(fabs((t_u_M_R_qqb_-t_u_qqb_WW)/t_u_qqb_WW)>1.e-6) {
alarm=true;
cout << "WZ->WW transformation error!\n";
cout << "t_u_M_R_qqb_ - t_u_qqb_WW (rel) = "
<< (t_u_M_R_qqb_ - t_u_qqb_WW)/GeV2 << " ("
<< (t_u_M_R_qqb_ - t_u_qqb_WW)/t_u_qqb_WW << ")\n";
cout << "t_u_M_R_qqb_ = " << t_u_M_R_qqb_/GeV2 << endl;
cout << "t_u_qqb_WW = " << t_u_qqb_WW /GeV2 << endl;
}
}
// Check that the transformation from NPB 383 (1992) 3-44 WZ
// matrix elements to ZZ matrix elements actually works, by
// comparing them to the explicit ZZ matrix elements in
// NPB 357 (1991) 409-438.
if(abs(mePartonData()[2]->id())==23&&abs(mePartonData()[3]->id())==23) {
if(fabs((M_Born_ -M_B_ZZ )/M_B_ZZ )>1.e-6) {
alarm=true;
cout << "WZ->ZZ transformation error!\n";
cout << "M_Born_ - M_B_ZZ (rel) = "
<< M_Born_ - M_B_ZZ << " ("
<< (M_Born_ - M_B_ZZ)/M_B_ZZ << ")\n";
cout << "M_Born_ = " << M_Born_ << endl;
cout << "M_B_ZZ = " << M_B_ZZ << endl;
}
if(fabs((M_V_regular_-M_V_reg_ZZ)/M_V_reg_ZZ)>1.e-6) {
alarm=true;
cout << "WZ->ZZ transformation error!\n";
cout << "M_V_regular_ - M_V_reg_ZZ (rel) = "
<< M_V_regular_ - M_V_reg_ZZ << " ("
<< (M_V_regular_ - M_V_reg_ZZ)/M_V_reg_ZZ << ")\n";
cout << "M_V_regular_ = " << M_V_regular_ << endl;
cout << "M_V_reg_ZZ = " << M_V_reg_ZZ << endl;
}
if(fabs((t_u_M_R_qqb_-t_u_qqb_ZZ)/t_u_qqb_ZZ)>1.e-6) {
alarm=true;
cout << "WZ->ZZ transformation error!\n";
cout << "t_u_M_R_qqb_ - t_u_qqb_ZZ (rel) = "
<< (t_u_M_R_qqb_ - t_u_qqb_ZZ)/GeV2 << " ("
<< (t_u_M_R_qqb_ - t_u_qqb_ZZ)/t_u_qqb_ZZ << ")\n";
cout << "t_u_M_R_qqb_ = " << t_u_M_R_qqb_/GeV2 << endl;
cout << "t_u_qqb_ZZ = " << t_u_qqb_ZZ /GeV2 << endl;
}
}
// Check the soft limit of the q + qbar matrix element.
Energy2 absDiff_qqbs
= t_u_M_R_qqb(S_) - prefacs*2.*CF_*M_Born_;
double relDiff_qqbs = absDiff_qqbs / t_u_M_R_qqb(S_);
if(fabs(relDiff_qqbs)>1.e-6) {
alarm=true;
cout << "\n";
cout << "t_u_M_R_qqb(S_) " << t_u_M_R_qqb(S_) /GeV2 << endl;
cout << "t_u_M_R_qqb(S_)-8*pi*alphaS*sHat/x*2*Cab*M_Born_ (rel):\n"
<< absDiff_qqbs / GeV2 << " (" << relDiff_qqbs << ")\n";
}
// Check the positive soft-collinearlimit of the q + qbar matrix element.
Energy2 absDiff_qqbsp
= t_u_M_R_qqb(SCp_) - prefacsp*2.*CF_*M_Born_;
double relDiff_qqbsp = absDiff_qqbsp / t_u_M_R_qqb(SCp_);
if(fabs(relDiff_qqbsp)>1.e-6) {
alarm=true;
cout << "\n";
cout << "t_u_M_R_qqb(SCp_) " << t_u_M_R_qqb(SCp_)/GeV2 << endl;
cout << "t_u_M_R_qqb(SCp_)-8*pi*alphaS*sHat/x*2*Cab*M_Born_ (rel):\n"
<< absDiff_qqbsp / GeV2 << " (" << relDiff_qqbsp << ")\n";
}
// Check the negative soft-collinearlimit of the q + qbar matrix element.
Energy2 absDiff_qqbsm
= t_u_M_R_qqb(SCm_) - prefacsm*2.*CF_*M_Born_;
double relDiff_qqbsm = absDiff_qqbsm / t_u_M_R_qqb(SCm_);
if(fabs(relDiff_qqbsm)>1.e-6) {
alarm=true;
cout << "\n";
cout << "t_u_M_R_qqb(SCm_) " << t_u_M_R_qqb(SCm_)/GeV2 << endl;
cout << "t_u_M_R_qqb(SCm_)-8*pi*alphaS*sHat/x*2*Cab*M_Born_ (rel):\n"
<< absDiff_qqbsm / GeV2 << " (" << relDiff_qqbsm << ")\n";
}
// Check the positive collinearlimit of the q + qbar matrix element.
Energy2 absDiff_qqbp
= t_u_M_R_qqb(Cp_) - prefacp*CF_*(1.+xp*xp)*M_Born_;
double relDiff_qqbp = absDiff_qqbp / t_u_M_R_qqb(Cp_);
if(fabs(relDiff_qqbp)>1.e-6) {
alarm=true;
cout << "\n";
cout << "t_u_M_R_qqb(Cp_) " << t_u_M_R_qqb(Cp_) /GeV2 << endl;
cout << "t_u_M_R_qqb(Cp_)-8*pi*alphaS*sHat/x*(1-x)*Pqq*M_Born_ (rel):\n"
<< absDiff_qqbp / GeV2 << " (" << relDiff_qqbp << ")\n";
}
// Check the negative collinearlimit of the q + qbar matrix element.
Energy2 absDiff_qqbm
= t_u_M_R_qqb(Cm_) - prefacm*CF_*(1.+xm*xm)*M_Born_;
double relDiff_qqbm = absDiff_qqbm / t_u_M_R_qqb(Cm_);
if(fabs(relDiff_qqbm)>1.e-6) {
alarm=true;
cout << "\n";
cout << "t_u_M_R_qqb(Cm_) " << t_u_M_R_qqb(Cm_) /GeV2 << endl;
cout << "t_u_M_R_qqb(Cm_)-8*pi*alphaS*sHat/x*(1-x)*Pqq*M_Born_ (rel):\n"
<< absDiff_qqbm / GeV2 << " (" << relDiff_qqbm << ")\n";
}
// Check the positive collinear limit of the g + qbar matrix element.
Energy2 absDiff_gqbp
= t_u_M_R_gqb(Cp_) - prefacp*(1.-xp)*TR_*(xp*xp+sqr(1.-xp))*M_Born_;
double relDiff_gqbp = absDiff_gqbp/ t_u_M_R_gqb(Cp_);
if(fabs(relDiff_gqbp)>1.e-6) {
alarm=true;
cout << "\n";
cout << "t_u_M_R_gqb(Cp_) " << t_u_M_R_gqb(Cp_) /GeV2 << endl;
cout << "t_u_M_R_gqb(Cp_)-8*pi*alphaS*sHat/x*(1-x)*Pgq*M_Born_ (rel):\n"
<< absDiff_gqbp / GeV2 << " (" << relDiff_gqbp << ")\n";
}
// Check the negative collinear limit of the q + g matrix element.
Energy2 absDiff_qgm
= t_u_M_R_qg(Cm_) - prefacm*(1.-xm)*TR_*(xm*xm+sqr(1.-xm))*M_Born_;
double relDiff_qgm = absDiff_qgm / t_u_M_R_qg(Cm_);
if(fabs(relDiff_qgm)>1.e-6) {
alarm=true;
cout << "\n";
cout << "t_u_M_R_qg(Cm_) " << t_u_M_R_qg(Cm_) /GeV2 << endl;
cout << "t_u_M_R_qg(Cm_)-8*pi*alphaS*sHat/x*(1-x)*Pgq*M_Born_ (rel):\n"
<< absDiff_qgm / GeV2 << " (" << relDiff_qgm << ")\n";
}
return alarm;
}
/***************************************************************************/
// M_Born_ZZ is the Born matrix element exactly as defined in Eqs. 2.18-2.19
// of of NPB 357(1991)409-438.
double MEPP2VVPowheg::M_Born_ZZ(bornVVKinematics B) const {
Energy2 s(B.sb());
Energy2 t(B.tb());
Energy2 u(B.ub());
Energy2 mZ2(B.k22b()); // the 2->2 from the 2->3 kinematics.
double cosThetaW(sqrt(1.-sin2ThetaW_));
double gV2,gA2,gX,gY,gZ;
gV2 = sqr(guL_/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_);
gA2 = sqr(guL_/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_);
gX = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.;
gV2 = sqr(gdL_/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_);
gA2 = sqr(gdL_/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_);
gY = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.;
gZ = gX;
if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) gZ = gY;
return 1./NC_*sqr(gZ*2.)*(t/u+u/t+4.*mZ2*s/t/u-mZ2*mZ2*(1./t/t+1./u/u));
}
/***************************************************************************/
// M_V_regular_ZZ is the one-loop ZZ matrix element exactly as defined in
// Eqs. B.1 & B.2 of NPB 357(1991)409-438.
double MEPP2VVPowheg::M_V_regular_ZZ(realVVKinematics S) const {
Energy2 s(S.bornVariables().sb());
Energy2 t(S.bornVariables().tb());
Energy2 u(S.bornVariables().ub());
Energy2 mZ2(S.k22r()); // the 2->2 from the 2->3 kinematics.
double beta(S.betaxr()); // N.B. for x=1 \beta_x=\beta in NPB 383(1992)3-44.
double cosThetaW(sqrt(1.-sin2ThetaW_));
double gV2,gA2,gX,gY,gZ;
gV2 = sqr(guL_/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_);
gA2 = sqr(guL_/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_);
gX = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.;
gV2 = sqr(gdL_/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_);
gA2 = sqr(gdL_/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_);
gY = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.;
gZ = gX;
if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) gZ = gY;
double M_V_reg(0.);
M_V_reg = 2.*s*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/sqr(4.*pi)/2.
*( 2.*sqr(t+mZ2)/sqr(beta)/s/t/u + 4.*s/(t-mZ2)/u
- ( 16.*t*t*t+(28.*s-68.*mZ2)*t*t+(18.*s*s-36.*mZ2*s+88.*mZ2*mZ2)*t
+ 18.*mZ2*mZ2*s-36.*mZ2*mZ2*mZ2
)/t/t/s/u
+ ( 12.*s/(t-mZ2)/u-4.*mZ2*s/sqr(t-mZ2)/u+2.*(t+4.*s)/s/u
- 6.*(s*s+mZ2*mZ2)/s/t/u+6.*mZ2*mZ2*(2.*mZ2-s)/t/t/s/u
)*log(-t/mZ2)
+ ( - ( 5.*t*t*t+(8.*s-18.*mZ2)*t*t+(6.*s*s+25.*mZ2*mZ2)*t
+ 6.*mZ2*mZ2*s-12.*mZ2*mZ2*mZ2
)/t/t/s/u
- 12.*mZ2*sqr(t+mZ2)/sqr(sqr(beta))/s/s/t/u
+ ( 3.*t*t-26.*mZ2*t-25.*mZ2*mZ2)/sqr(beta)/s/t/u
)*log(s/mZ2)
+ ( (-2.*t*t+8.*mZ2*t-2.*s*s-12.*mZ2*mZ2)/u + 4.*mZ2*mZ2*(2.*mZ2-s)/t/u)
/ (s*t)
* ( 2.*sqr(log(-t/mZ2))-4.*log(-t/mZ2)*log((mZ2-t)/mZ2)-4.*ReLi2(t/mZ2))
+ ( 4.*(t*t-5.*mZ2*t+s*s+10.*mZ2*mZ2)/s/u
+ 4.*mZ2*(-s*s+2.*mZ2*s-10.*mZ2*mZ2)/s/t/u
+ 8.*mZ2*mZ2*mZ2*(2.*mZ2-s)/t/t/s/u
)
/ (t-mZ2)
* (pi*pi/2.+log(-t/mZ2)*log(-t/s)-1./2.*sqr(log(-t/mZ2)))
+ ( ( (2.*s-3.*mZ2)*t*t+(6.*mZ2*mZ2-8.*mZ2*s)*t+2.*s*s*s-4.*mZ2*s*s
+ 12.*mZ2*mZ2*s-3.*mZ2*mZ2*mZ2
) /s/t/u
+ 12.*mZ2*mZ2*sqr(t+mZ2)/sqr(sqr(beta))/s/s/t/u
- (mZ2*t*t-30.*mZ2*mZ2*t-27.*mZ2*mZ2*mZ2)/beta/beta/s/t/u
)
/ (beta*s)
* (pi*pi/3.+sqr(log((1.-beta)/(1.+beta)))+4.*ReLi2(-(1.-beta)/(1.+beta)))
+ (4.*(t+4.*s-4.*mZ2)/3./s/u+4.*sqr(s-2.*mZ2)/3./s/t/u)*pi*pi
);
swap(t,u);
M_V_reg += 2.*s*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/sqr(4.*pi)/2.
*( 2.*sqr(t+mZ2)/sqr(beta)/s/t/u + 4.*s/(t-mZ2)/u
- ( 16.*t*t*t+(28.*s-68.*mZ2)*t*t+(18.*s*s-36.*mZ2*s+88.*mZ2*mZ2)*t
+ 18.*mZ2*mZ2*s-36.*mZ2*mZ2*mZ2
)/t/t/s/u
+ ( 12.*s/(t-mZ2)/u-4.*mZ2*s/sqr(t-mZ2)/u+2.*(t+4.*s)/s/u
- 6.*(s*s+mZ2*mZ2)/s/t/u+6.*mZ2*mZ2*(2.*mZ2-s)/t/t/s/u
)*log(-t/mZ2)
+ ( - ( 5.*t*t*t+(8.*s-18.*mZ2)*t*t+(6.*s*s+25.*mZ2*mZ2)*t
+ 6.*mZ2*mZ2*s-12.*mZ2*mZ2*mZ2
)/t/t/s/u
- 12.*mZ2*sqr(t+mZ2)/sqr(sqr(beta))/s/s/t/u
+ ( 3.*t*t-26.*mZ2*t-25.*mZ2*mZ2)/sqr(beta)/s/t/u
)*log(s/mZ2)
+ ( (-2.*t*t+8.*mZ2*t-2.*s*s-12.*mZ2*mZ2)/u + 4.*mZ2*mZ2*(2.*mZ2-s)/t/u)
/ (s*t)
* ( 2.*sqr(log(-t/mZ2))-4.*log(-t/mZ2)*log((mZ2-t)/mZ2)-4.*ReLi2(t/mZ2))
+ ( 4.*(t*t-5.*mZ2*t+s*s+10.*mZ2*mZ2)/s/u
+ 4.*mZ2*(-s*s+2.*mZ2*s-10.*mZ2*mZ2)/s/t/u
+ 8.*mZ2*mZ2*mZ2*(2.*mZ2-s)/t/t/s/u
)
/ (t-mZ2)
* (pi*pi/2.+log(-t/mZ2)*log(-t/s)-1./2.*sqr(log(-t/mZ2)))
+ ( ( (2.*s-3.*mZ2)*t*t+(6.*mZ2*mZ2-8.*mZ2*s)*t+2.*s*s*s-4.*mZ2*s*s
+ 12.*mZ2*mZ2*s-3.*mZ2*mZ2*mZ2
) /s/t/u
+ 12.*mZ2*mZ2*sqr(t+mZ2)/sqr(sqr(beta))/s/s/t/u
- (mZ2*t*t-30.*mZ2*mZ2*t-27.*mZ2*mZ2*mZ2)/beta/beta/s/t/u
)
/ (beta*s)
* (pi*pi/3.+sqr(log((1.-beta)/(1.+beta)))+4.*ReLi2(-(1.-beta)/(1.+beta)))
+ (4.*(t+4.*s-4.*mZ2)/3./s/u+4.*sqr(s-2.*mZ2)/3./s/t/u)*pi*pi
);
return M_V_reg;
}
/***************************************************************************/
// t_u_M_R_qqb_ZZ is the real emission q + qb -> n + g matrix element
// exactly as defined in Eqs. C.1 of NPB 357(1991)409-438, multiplied by
// tk * uk!
Energy2 MEPP2VVPowheg::t_u_M_R_qqb_ZZ(realVVKinematics R) const {
// First the Born variables:
Energy2 mZ2(R.k22r());
// Then the rest:
Energy2 s(R.sr());
Energy2 tk(R.tkr());
Energy2 uk(R.ukr());
Energy2 q1(R.q1r());
Energy2 q2(R.q2r());
Energy2 q1h(R.q1hatr());
Energy2 q2h(R.q2hatr());
double cosThetaW(sqrt(1.-sin2ThetaW_));
double gV2,gA2,gX,gY,gZ;
gV2 = sqr(guL_/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_);
gA2 = sqr(guL_/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_);
gX = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.;
gV2 = sqr(gdL_/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_);
gA2 = sqr(gdL_/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_);
gY = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.;
gZ = gX;
if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) gZ = gY;
Energy2 t_u_qqb(0.*GeV2);
t_u_qqb = (2.*s)*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/2.
* ( - ( tk*uk*uk+2.*s*uk*uk-tk*tk*uk
- 2.*s*tk*uk+mZ2*(tk*tk-uk*uk+2.*s*uk-2.*s*tk-2.*s*s)
)/q1h/q1/q2h/s*tk
+ 2.*(tk*uk*uk-mZ2*uk*(s+3.*tk)+mZ2*mZ2*(2.*uk-s))/q1/q2/s
+ ( tk*uk*(uk+s)-mZ2*(uk*uk+3.*tk*uk+3.*s*uk+s*tk)
+ 2.*mZ2*mZ2*(uk+tk+2.*s)
)/q1h/q1/q2/s*tk
+ ( tk*(uk*uk+tk*uk-s*s)+mZ2*(4.*s*uk-3.*tk*uk-tk*tk+4.*s*s)
)/q1h/q2/s
- ( tk*uk+s*uk-s*tk-s*s+2.*mZ2*(s-tk) ) /q1h/q1/s*tk
+ q2*(tk*uk-s*uk-2.*s*tk-2.*s*s)/q1/q2h/s
+ 2.*(tk*uk-tk*tk-s*tk-s*s+mZ2*(2.*s-uk))/q1/s
- 2.*mZ2*(uk*uk-2.*mZ2*uk+2.*mZ2*mZ2)/q1/q1/q2/s*tk
+ (2.*s*uk+tk*tk+3.*s*tk+2*s*s)/q1h/s
+ q1*(uk+s)*(uk+tk)/q1h/q2h/s
+ (tk*uk+s*uk+3.*s*tk+2.*s*s-mZ2*(uk+tk+2.*s))/q1h/q2h/s*uk
+ (uk-tk)/2./q1h/q2h/s*(q1*(uk+s)/q2/tk-q2*(tk+s)/q1/uk)*tk*uk
+ (tk-2.*mZ2)*(uk-2.*mZ2)/q1h/q1/q2h/q2*tk*uk
- (q1*q1+q2*q2)/q1/q2
- 2.*mZ2*(q2-2.*mZ2)/q1/q1/s*tk
);
swap(tk ,uk );
swap(q1 ,q2 );
swap(q1h,q2h);
t_u_qqb += (2.*s)*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/2.
* ( - ( tk*uk*uk+2.*s*uk*uk-tk*tk*uk
- 2.*s*tk*uk+mZ2*(tk*tk-uk*uk+2.*s*uk-2.*s*tk-2.*s*s)
)/q1h/q1/q2h/s*tk
+ 2.*(tk*uk*uk-mZ2*uk*(s+3.*tk)+mZ2*mZ2*(2.*uk-s))/q1/q2/s
+ ( tk*uk*(uk+s)-mZ2*(uk*uk+3.*tk*uk+3.*s*uk+s*tk)
+ 2.*mZ2*mZ2*(uk+tk+2.*s)
)/q1h/q1/q2/s*tk
+ ( tk*(uk*uk+tk*uk-s*s)+mZ2*(4.*s*uk-3.*tk*uk-tk*tk+4.*s*s)
)/q1h/q2/s
- ( tk*uk+s*uk-s*tk-s*s+2.*mZ2*(s-tk) ) /q1h/q1/s*tk
+ q2*(tk*uk-s*uk-2.*s*tk-2.*s*s)/q1/q2h/s
+ 2.*(tk*uk-tk*tk-s*tk-s*s+mZ2*(2.*s-uk))/q1/s
- 2.*mZ2*(uk*uk-2.*mZ2*uk+2.*mZ2*mZ2)/q1/q1/q2/s*tk
+ (2.*s*uk+tk*tk+3.*s*tk+2*s*s)/q1h/s
+ q1*(uk+s)*(uk+tk)/q1h/q2h/s
+ (tk*uk+s*uk+3.*s*tk+2.*s*s-mZ2*(uk+tk+2.*s))/q1h/q2h/s*uk
+ (uk-tk)/2./q1h/q2h/s*(q1*(uk+s)/q2/tk-q2*(tk+s)/q1/uk)*tk*uk
+ (tk-2.*mZ2)*(uk-2.*mZ2)/q1h/q1/q2h/q2*tk*uk
- (q1*q1+q2*q2)/q1/q2
- 2.*mZ2*(q2-2.*mZ2)/q1/q1/s*tk
);
swap(tk ,uk );
swap(q1 ,q2 );
swap(q1h,q2h);
swap(q1 ,q1h);
swap(q2 ,q2h);
t_u_qqb += (2.*s)*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/2.
* ( - ( tk*uk*uk+2.*s*uk*uk-tk*tk*uk
- 2.*s*tk*uk+mZ2*(tk*tk-uk*uk+2.*s*uk-2.*s*tk-2.*s*s)
)/q1h/q1/q2h/s*tk
+ 2.*(tk*uk*uk-mZ2*uk*(s+3.*tk)+mZ2*mZ2*(2.*uk-s))/q1/q2/s
+ ( tk*uk*(uk+s)-mZ2*(uk*uk+3.*tk*uk+3.*s*uk+s*tk)
+ 2.*mZ2*mZ2*(uk+tk+2.*s)
)/q1h/q1/q2/s*tk
+ ( tk*(uk*uk+tk*uk-s*s)+mZ2*(4.*s*uk-3.*tk*uk-tk*tk+4.*s*s)
)/q1h/q2/s
- ( tk*uk+s*uk-s*tk-s*s+2.*mZ2*(s-tk) ) /q1h/q1/s*tk
+ q2*(tk*uk-s*uk-2.*s*tk-2.*s*s)/q1/q2h/s
+ 2.*(tk*uk-tk*tk-s*tk-s*s+mZ2*(2.*s-uk))/q1/s
- 2.*mZ2*(uk*uk-2.*mZ2*uk+2.*mZ2*mZ2)/q1/q1/q2/s*tk
+ (2.*s*uk+tk*tk+3.*s*tk+2*s*s)/q1h/s
+ q1*(uk+s)*(uk+tk)/q1h/q2h/s
+ (tk*uk+s*uk+3.*s*tk+2.*s*s-mZ2*(uk+tk+2.*s))/q1h/q2h/s*uk
+ (uk-tk)/2./q1h/q2h/s*(q1*(uk+s)/q2/tk-q2*(tk+s)/q1/uk)*tk*uk
+ (tk-2.*mZ2)*(uk-2.*mZ2)/q1h/q1/q2h/q2*tk*uk
- (q1*q1+q2*q2)/q1/q2
- 2.*mZ2*(q2-2.*mZ2)/q1/q1/s*tk
);
swap(q1 ,q1h);
swap(q2 ,q2h);
swap(tk ,uk );
swap(q1 ,q2h);
swap(q2 ,q1h);
t_u_qqb += (2.*s)*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/2.
* ( - ( tk*uk*uk+2.*s*uk*uk-tk*tk*uk
- 2.*s*tk*uk+mZ2*(tk*tk-uk*uk+2.*s*uk-2.*s*tk-2.*s*s)
)/q1h/q1/q2h/s*tk
+ 2.*(tk*uk*uk-mZ2*uk*(s+3.*tk)+mZ2*mZ2*(2.*uk-s))/q1/q2/s
+ ( tk*uk*(uk+s)-mZ2*(uk*uk+3.*tk*uk+3.*s*uk+s*tk)
+ 2.*mZ2*mZ2*(uk+tk+2.*s)
)/q1h/q1/q2/s*tk
+ ( tk*(uk*uk+tk*uk-s*s)+mZ2*(4.*s*uk-3.*tk*uk-tk*tk+4.*s*s)
)/q1h/q2/s
- ( tk*uk+s*uk-s*tk-s*s+2.*mZ2*(s-tk) ) /q1h/q1/s*tk
+ q2*(tk*uk-s*uk-2.*s*tk-2.*s*s)/q1/q2h/s
+ 2.*(tk*uk-tk*tk-s*tk-s*s+mZ2*(2.*s-uk))/q1/s
- 2.*mZ2*(uk*uk-2.*mZ2*uk+2.*mZ2*mZ2)/q1/q1/q2/s*tk
+ (2.*s*uk+tk*tk+3.*s*tk+2*s*s)/q1h/s
+ q1*(uk+s)*(uk+tk)/q1h/q2h/s
+ (tk*uk+s*uk+3.*s*tk+2.*s*s-mZ2*(uk+tk+2.*s))/q1h/q2h/s*uk
+ (uk-tk)/2./q1h/q2h/s*(q1*(uk+s)/q2/tk-q2*(tk+s)/q1/uk)*tk*uk
+ (tk-2.*mZ2)*(uk-2.*mZ2)/q1h/q1/q2h/q2*tk*uk
- (q1*q1+q2*q2)/q1/q2
- 2.*mZ2*(q2-2.*mZ2)/q1/q1/s*tk
);
swap(tk ,uk );
swap(q1 ,q2h);
swap(q2 ,q1h);
return t_u_qqb;
}
/***************************************************************************/
// M_B_WW is the Born matrix element exactly as defined in Eqs. 3.2-3.8
// of of NPB 410(1993)280-384.
double MEPP2VVPowheg::M_Born_WW(bornVVKinematics B) const {
Energy2 s(B.sb());
Energy2 t(B.tb());
Energy2 u(B.ub());
Energy2 mW2(B.k12b()); // N.B. the diboson masses are preserved in getting
bool up_type = abs(quark_->id())%2==0 ? true : false;
double Qi = up_type ? 2./3. : -1./3. ;
double giL = up_type ? guL_/2. : gdL_/2.;
double giR = up_type ? guR_/2. : gdR_/2.;
double e2 = sqr(gW_)*sin2ThetaW_;
double cos2ThetaW(1.-sin2ThetaW_);
double ctt_i(gW_*gW_*gW_*gW_/16.);
InvEnergy2 cts_i(gW_*gW_*e2/4./s *(Qi+2.*eZ_*giL/e2*s/(s-mW2/cos2ThetaW)));
InvEnergy4 css_i(e2*e2/s/s*(sqr(Qi+eZ_*(giL+giR)/e2*s/(s-mW2/cos2ThetaW))
+sqr( eZ_*(giL-giR)/e2*s/(s-mW2/cos2ThetaW)))
);
ctt_i *= 8.*Fij2_/gW_/gW_;
cts_i *= sqrt(8.*Fij2_/gW_/gW_);
if(quark_->id()!=-antiquark_->id()) {
cts_i = 0./GeV2;
css_i = 0./GeV2/GeV2;
}
if(!up_type) swap(t,u);
double signf = up_type ? 1. : -1.;
return 1./4./NC_
* (
ctt_i*( 16.*(u*t/mW2/mW2-1.)*(1./4.+mW2*mW2/t/t)+16.*s/mW2)
- cts_i*( 16.*(u*t/mW2/mW2-1.)*(s/4.-mW2/2.-mW2*mW2/t)
+ 16.*s*(s/mW2-2.+2.*mW2/t)
)
*signf
+
css_i*( 8.*(u*t/mW2/mW2-1.)*(s*s/4.-s*mW2+3.*mW2*mW2)
+ 8.*s*s*(s/mW2-4.)
)
);
}
/***************************************************************************/
// M_V_regular_WW is the regular part of the one-loop WW matrix element
// exactly as defined in Eqs. C.1 - C.7 of of NPB 410(1993)280-324 ***
// modulo a factor 1/(2s) ***, which is a flux factor that those authors
// absorb in the matrix element.
double MEPP2VVPowheg::M_V_regular_WW(realVVKinematics S) const {
Energy2 s(S.bornVariables().sb());
Energy2 t(S.bornVariables().tb());
Energy2 u(S.bornVariables().ub());
Energy2 mW2(S.k12r()); // N.B. the diboson masses are preserved in getting
double beta(S.betaxr()); // N.B. for x=1 \beta_x=\beta in NPB 383(1992)3-44.
bool up_type = abs(quark_->id())%2==0 ? true : false;
double Qi = up_type ? 2./3. : -1./3.;
double giL = up_type ? guL_/2. : gdL_/2.;
double giR = up_type ? guR_/2. : gdR_/2.;
double e2 = sqr(gW_)*sin2ThetaW_;
double cos2ThetaW(1.-sin2ThetaW_);
double ctt_i(gW_*gW_*gW_*gW_/16.);
InvEnergy2 cts_i(gW_*gW_*e2/4./s *(Qi+2.*eZ_*giL/e2*s/(s-mW2/cos2ThetaW)));
InvEnergy4 css_i(e2*e2/s/s*(sqr(Qi+eZ_*(giL+giR)/e2*s/(s-mW2/cos2ThetaW))
+sqr( eZ_*(giL-giR)/e2*s/(s-mW2/cos2ThetaW)))
);
ctt_i *= 8.*Fij2_/gW_/gW_;
cts_i *= sqrt(8.*Fij2_/gW_/gW_);
if(quark_->id()!=-antiquark_->id()) {
cts_i = 0./GeV2;
css_i = 0./GeV2/GeV2;
}
if(!up_type) swap(t,u);
double signf = up_type ? 1. : -1.;
InvEnergy4 TildeI4 = ( 2.*sqr(log(-t/mW2))-4.*log((mW2-t)/mW2)*log(-t/mW2)
- 4.*ReLi2(t/mW2) )/s/t;
InvEnergy2 TildeI3t = 1./(mW2-t)
*(sqr(log(mW2/s))/2.-sqr(log(-t/s))/2.-pi*pi/2.);
InvEnergy2 TildeI3l = 1./s/beta*( 4.*ReLi2((beta-1.)/(beta+1.))
+ sqr(log((1.-beta)/(1.+beta)))
+ pi*pi/3.);
double Fup1_st(0.);
Fup1_st = 4.*(80.*t*t+73.*s*t-140.*mW2*t+72.*mW2*mW2)/t/t
- 4.*sqr(4.*t+s)/s/beta/beta/t
- 128.*(t+2.*s)/mW2
+ 64.*t*(t+s)/mW2/mW2
- (32.*(t*t-3.*s*t-3.*mW2*mW2)/t/t+128.*s/(t-mW2))*log(-t/mW2)
+ ( 8.*(6.*t*t+8.*s*t-19.*mW2*t+12.*mW2*mW2)/t/t
- (32.*t*t-128.*s*t-26.*s*s)/s/beta/beta/t
+ 6.*sqr(4.*t+s)/s/sqr(sqr(beta))/t
)*log(s/mW2)
+ 32.*s*(2.*mW2*mW2/t-u)*TildeI4
- 64.*(t-mW2)*(2.*mW2*mW2/t/t-u/t)*TildeI3t
+ ( (16.*t*(4.*mW2-u)-49.*s*s+72.*mW2*s-48.*mW2*mW2)/2./t
+ 2.*(8.*t*t-14.*s*t-3.*s*s)/beta/beta/t
- 3.*sqr(4.*t+s)/2./sqr(sqr(beta))/t
)*TildeI3l
+ 32./3.*( 2.*(t+2.*s)/mW2
- (3.*t+2.*s-4.*mW2)/t
- t*(t+s)/mW2/mW2
)*pi*pi;
Energy2 Jup1_st(0.*GeV2);
Jup1_st = -128.*(t*t+2.*s*t+2.*s*s)/mW2
- 16.*(t*t-21.*s*t-26.*mW2*t+34.*mW2*s+17.*mW2*mW2)/t
+ 64.*s*t*(t+s)/mW2/mW2 +32.*s*s/(t-mW2)
+ ( 16.*(t-5.*s+2.*mW2)-48.*mW2*(2.*s+mW2)/t
+ 64.*s*(2.*t+s)/(t-mW2) - 32.*s*s*t/sqr(t-mW2)
)*log(-t/mW2)
+ ( 16.*(4.*t+s)/beta/beta
- 16.*(3.*t-2.*s)
+ 48.*mW2*(2.*t-2.*s-mW2)/t
)*log(s/mW2)
+ 16.*s*(t*(2.*s+u)-2.*mW2*(2.*s+mW2))*TildeI4
+ 32.*(t-mW2)*(2.*mW2*(2.*s+mW2)/t-2.*s-u)*TildeI3t
+ ( 32.*s*t-12.*s*s+32.*mW2*mW2
- 16.*mW2*(2.*t+7.*s)-4.*s*(4.*t+s)/beta/beta
)*TildeI3l
+ 32./3.*( 2.*(t*t+2.*s*t+2.*s*s)/mW2
- s*t*(t+s)/mW2/mW2-2.*mW2*(2.*t-2.*s-mW2)/t-t-4.*s
)*pi*pi;
Energy4 Kup1_st(0.*GeV2*GeV2);
Kup1_st = 16.*( 12.*t*t+20.*s*t-24.*mW2*t+17.*s*s-4.*mW2*s+12.*mW2*mW2
+ s*s*t*(t+s)/mW2/mW2-2.*s*(2.*t*t+3.*s*t+2.*s*s)/mW2)
*(2.-pi*pi/3.);
return pi*alphaS_*CF_/NC_/(sqr(4.*pi))
* ( ctt_i*Fup1_st - cts_i*Jup1_st*signf + css_i*Kup1_st );
}
/***************************************************************************/
// t_u_M_R_qqb is the real emission q + qb -> n + g matrix element
// exactly as defined in Eqs. C.1 of NPB 383(1992)3-44, multiplied by
// tk * uk!
Energy2 MEPP2VVPowheg::t_u_M_R_qqb_WW(realVVKinematics R) const {
// First the Born variables:
Energy2 s2(R.s2r());
Energy2 mW2(R.k12r());
// Then the rest:
Energy2 s(R.sr());
Energy2 tk(R.tkr());
Energy2 uk(R.ukr());
Energy2 q1(R.q1r());
Energy2 q2(R.q2r());
Energy2 q1h(R.q1hatr());
Energy2 q2h(R.q2hatr());
bool up_type = abs(quark_->id())%2==0 ? true : false;
double Qi = up_type ? 2./3. : -1./3.;
double giL = up_type ? guL_/2. : gdL_/2.;
double giR = up_type ? guR_/2. : gdR_/2.;
double e2 = sqr(gW_)*sin2ThetaW_;
double cos2ThetaW(1.-sin2ThetaW_);
double ctt_i(gW_*gW_*gW_*gW_/16.);
InvEnergy2 cts_i(gW_*gW_*e2/4./s2*(Qi+2.*eZ_*giL/e2*s2/(s2-mW2/cos2ThetaW)));
InvEnergy4 css_i(e2*e2/s2/s2*(sqr(Qi+eZ_*(giL+giR)/e2*s2/(s2-mW2/cos2ThetaW))
+sqr( eZ_*(giL-giR)/e2*s2/(s2-mW2/cos2ThetaW)))
);
ctt_i *= 8.*Fij2_/gW_/gW_;
cts_i *= sqrt(8.*Fij2_/gW_/gW_);
if(quark_->id()!=-antiquark_->id()) {
cts_i = 0./GeV2;
css_i = 0./GeV2/GeV2;
}
if(!up_type) {
swap(q1,q1h);
swap(q2,q2h);
}
double signf = up_type ? 1. : -1.;
Energy2 t_u_Xup(0.*GeV2);
Energy4 t_u_Yup(0.*GeV2*GeV2);
Energy6 t_u_Zup(0.*GeV2*GeV2*GeV2);
t_u_Xup = 32.*mW2*(tk*uk+3.*q2*uk+q2*s+q1*q2)/q1/q2/q2*tk
+ 32.*mW2*q1/q2/q2*uk
- 64.*mW2*s/q2
- 32.*tk*(uk-q2)/q1/q2*tk
+ 64.*mW2*mW2*mW2/q1/q1/q2*tk
- 16.*(2.*tk-2.*s-q2)/q2*uk
+ 16.*s*(2.*s+2.*q1+q2/2.)/q2
- 8.*(4.*tk+uk+9.*s+2.*q2+2.*q1)/mW2*tk
- 16.*s*(2.*s+q1)/mW2
- 64.*mW2*mW2*(tk*uk+q2*tk+q1*uk-q2*s/2.)/q1/q2/q2
+ 8.*s2*q1*(tk+s+q1)/mW2/mW2;
swap(tk,uk);
swap(q1,q2);
t_u_Xup += 32.*mW2*(tk*uk+3.*q2*uk+q2*s+q1*q2)/q1/q2/q2*tk
+ 32.*mW2*q1/q2/q2*uk
- 64.*mW2*s/q2
- 32.*tk*(uk-q2)/q1/q2*tk
+ 64.*mW2*mW2*mW2/q1/q1/q2*tk
- 16.*(2.*tk-2.*s-q2)/q2*uk
+ 16.*s*(2.*s+2.*q1+q2/2.)/q2
- 8.*(4.*tk+uk+9.*s+2.*q2+2.*q1)/mW2*tk
- 16.*s*(2.*s+q1)/mW2
- 64.*mW2*mW2*(tk*uk+q2*tk+q1*uk-q2*s/2.)/q1/q2/q2
+ 8.*s2*q1*(tk+s+q1)/mW2/mW2;
swap(tk,uk);
swap(q1,q2);
t_u_Yup = - 16.*tk*(uk*(uk+s+q1)+q2*(s-2.*q1))/q1/q2*tk
- 32.*mW2*mW2*s/q2
- 32.*mW2*mW2*mW2/q1/q2*tk
+ 16.*(2.*q2*uk+s*s+q1*s+5.*q2*s+q1*q2+2.*q2*q2)/q2*tk
- 16.*(q2*q2+s*s-q2*s)/q1*tk
+ 16.*s*(q1*s+3./2.*q2*s+q1*q2-q1*q1)/q2
+ 16.*mW2*tk*(4.*uk+s+q1-2.*q2)/q1/q2*tk
+ 16.*mW2*(3.*s*uk+q1*uk-q1*s-3.*q2*s-q1*q1+q2*q2)/q1/q2*tk
+ 16.*mW2*s*(q2-4.*s+2.*q1)/q2
- 8.*s2*(4.*tk+uk+9.*s+4.*q1+2.*q2)/mW2*tk
- 16.*s2*(2.*s*s+2.*q1*s+q1*q1)/mW2
- 32.*mW2*mW2*(tk+uk/2.+2.*s-q1)/q1/q2*tk
+ 8.*s2*s2*q1*(tk+s+q1)/mW2/mW2;
swap(tk,uk);
swap(q1,q2);
t_u_Yup += - 16.*tk*(uk*(uk+s+q1)+q2*(s-2.*q1))/q1/q2*tk
- 32.*mW2*mW2*s/q2
- 32.*mW2*mW2*mW2/q1/q2*tk
+ 16.*(2.*q2*uk+s*s+q1*s+5.*q2*s+q1*q2+2.*q2*q2)/q2*tk
- 16.*(q2*q2+s*s-q2*s)/q1*tk
+ 16.*s*(q1*s+3./2.*q2*s+q1*q2-q1*q1)/q2
+ 16.*mW2*tk*(4.*uk+s+q1-2.*q2)/q1/q2*tk
+ 16.*mW2*(3.*s*uk+q1*uk-q1*s-3.*q2*s-q1*q1+q2*q2)/q1/q2*tk
+ 16.*mW2*s*(q2-4.*s+2.*q1)/q2
- 8.*s2*(4.*tk+uk+9.*s+4.*q1+2.*q2)/mW2*tk
- 16.*s2*(2.*s*s+2.*q1*s+q1*q1)/mW2
- 32.*mW2*mW2*(tk+uk/2.+2.*s-q1)/q1/q2*tk
+ 8.*s2*s2*q1*(tk+s+q1)/mW2/mW2;
swap(tk,uk);
swap(q1,q2);
t_u_Zup = 8.*s2*(9.*tk+3.*uk+20.*s+10.*q1+4.*q2)*tk
+ 8.*s2*(17./2.*s*s+10.*q1*s+6.*q1*q1)
- 4.*s2*s2*(4.*tk+uk+9.*s+6.*q1+2.*q2)/mW2*tk
- 8.*s2*s2*(2.*s*s+3.*q1*s+2.*q1*q1)/mW2
- 16.*mW2*(2.*tk+5.*uk+7.*s+6.*q1+6.*q2)*tk
- 16.*mW2*s*(s+6.*q1)
+ 4.*s2*s2*s2*q1*(tk+s+q1)/mW2/mW2
+ 48.*mW2*mW2*s2;
swap(tk,uk);
swap(q1,q2);
t_u_Zup += 8.*s2*(9.*tk+3.*uk+20.*s+10.*q1+4.*q2)*tk
+ 8.*s2*(17./2.*s*s+10.*q1*s+6.*q1*q1)
- 4.*s2*s2*(4.*tk+uk+9.*s+6.*q1+2.*q2)/mW2*tk
- 8.*s2*s2*(2.*s*s+3.*q1*s+2.*q1*q1)/mW2
- 16.*mW2*(2.*tk+5.*uk+7.*s+6.*q1+6.*q2)*tk
- 16.*mW2*s*(s+6.*q1)
+ 4.*s2*s2*s2*q1*(tk+s+q1)/mW2/mW2
+ 48.*mW2*mW2*s2;
swap(tk,uk);
swap(q1,q2);
return -pi*alphaS_*CF_/NC_
* ( ctt_i*t_u_Xup - cts_i*t_u_Yup*signf + css_i*t_u_Zup );
}
/***************************************************************************/
// The game here is to get this helicity amplitude squared to return all the
// same values as t_u_M_R_qqb above, TIMES a further factor tk*uk!
Energy2 MEPP2VVPowheg::t_u_M_R_qqb_hel_amp(realVVKinematics R) const {
using namespace ThePEG::Helicity;
// qqb_hel_amps_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
// PDT::Spin1,PDT::Spin1,
// PDT::Spin1));
double sum_hel_amps_sqr(0.);
tcPDPtr p1data(quark_);
tcPDPtr p2data(antiquark_);
tcPDPtr k1data(mePartonData()[2]);
tcPDPtr k2data(mePartonData()[3]);
tcPDPtr kdata(getParticleData(ParticleID::g));
if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data);
SpinorWaveFunction qSpinor(R.p1r(),p1data,incoming);
SpinorBarWaveFunction qbSpinor(R.p2r(),p2data,incoming);
vector<SpinorWaveFunction> q;
vector<SpinorBarWaveFunction> 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<VectorWaveFunction> v1;
vector<VectorWaveFunction> 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<VectorWaveFunction> 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<tcPDPtr> 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<Complex> diagrams;
// Get all t-channel diagram contributions
tcPDPtr intermediate_t;
for(unsigned int ix=0;ix<tc.size();ix++) {
intermediate_t = (!(k1data->id()==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;ix<diagrams.size();ix++) hel_amp += diagrams[ix];
// If we need to fill the production ME we do it here:
// if(getMatrix) {
// if(khel==0)
// qqb_hel_amps_(p1hel,p2hel,k1hel,k2hel,0) = hel_amp;
// else
// qqb_hel_amps_(p1hel,p2hel,k1hel,k2hel,2) = hel_amp;
// }
sum_hel_amps_sqr += norm(hel_amp);
}
}
}
}
}
// Fill up the remaining bits of the production ME, corresponding
// to longitudinal gluon polarization, with (0.,0.).
// if(getMatrix) {
// 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) {
// qqb_hel_amps_(p1hel,p2hel,k1hel,k2hel,1) = Complex(0.,0.);
// }
// }
// }
// }
// }
// Spin and colour averaging factors = 1/4 * CF * 1/3 = 1/9
sum_hel_amps_sqr /= 9.;
// Symmetry factor for identical Z bosons in the final state
if(k1data->id()==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<SpinorWaveFunction> qin;
vector<SpinorBarWaveFunction> 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<VectorWaveFunction> v1;
vector<VectorWaveFunction> 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<VectorWaveFunction> 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<tcPDPtr> 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<Complex> diagrams;
// Get all t-channel diagram contributions
tcPDPtr intermediate_q;
for(unsigned int ix=0;ix<tc.size();ix++) {
intermediate_q = (!(k1data->id()==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;ix<diagrams.size();ix++) hel_amp += diagrams[ix];
// If we need to fill the production ME we do it here:
// if(getMatrix) {
// if(p2hel==0)
// qg_hel_amps_(p1hel,0,k1hel,k2hel,khel) = hel_amp;
// else
// qg_hel_amps_(p1hel,2,k1hel,k2hel,khel) = hel_amp;
// }
sum_hel_amps_sqr += norm(hel_amp);
}
}
}
}
}
// Fill up the remaining bits of the production ME, corresponding
// to longitudinal gluon polarization, with (0.,0.).
// if(getMatrix) {
// for(unsigned int p1hel=0;p1hel<2;++p1hel) {
// for(unsigned int k1hel=0;k1hel<3;++k1hel) {
// for(unsigned int k2hel=0;k2hel<3;++k2hel) {
// for(unsigned int khel=0;khel<2;++khel) {
// qg_hel_amps_(p1hel,1,k1hel,k2hel,khel) = Complex(0.,0.);
// }
// }
// }
// }
// }
// Spin and colour averaging factors = 1/4 * TR * 1/3 = 1/24
sum_hel_amps_sqr /= 24.;
// Symmetry factor for identical Z bosons in the final state
if(k1data->id()==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<SpinorBarWaveFunction> qbin;
vector<SpinorWaveFunction> 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<VectorWaveFunction> v1;
vector<VectorWaveFunction> 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<VectorWaveFunction> 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<tcPDPtr> 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<Complex> diagrams;
// Get all t-channel diagram contributions
tcPDPtr intermediate_q;
for(unsigned int ix=0;ix<tc.size();ix++) {
intermediate_q = (!(k1data->id()==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;ix<diagrams.size();ix++) hel_amp += diagrams[ix];
// If we need to fill the production ME we do it here:
// if(getMatrix) {
// if(p1hel==0)
// gqb_hel_amps_(0,p2hel,k1hel,k2hel,khel) = hel_amp;
// else
// gqb_hel_amps_(2,p2hel,k1hel,k2hel,khel) = hel_amp;
// }
sum_hel_amps_sqr += norm(hel_amp);
}
}
}
}
}
// Fill up the remaining bits of the production ME, corresponding
// to longitudinal gluon polarization, with (0.,0.).
// if(getMatrix) {
// for(unsigned int p2hel=0;p2hel<2;++p2hel) {
// for(unsigned int k1hel=0;k1hel<3;++k1hel) {
// for(unsigned int k2hel=0;k2hel<3;++k2hel) {
// for(unsigned int khel=0;khel<2;++khel) {
// gqb_hel_amps_(1,p2hel,k1hel,k2hel,khel) = Complex(0.,0.);
// }
// }
// }
// }
// }
// Spin and colour averaging factors = 1/4 * TR * 1/3 = 1/24
sum_hel_amps_sqr /= 24.;
// Symmetry factor for identical Z bosons in the final state
if(k1data->id()==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<SpinorWaveFunction> q;
vector<SpinorBarWaveFunction> 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<VectorWaveFunction> v1;
vector<VectorWaveFunction> 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<tcPDPtr> 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<Complex> diagrams;
// Get all t-channel diagram contributions
tcPDPtr intermediate_t;
for(unsigned int ix=0;ix<tc.size();ix++) {
intermediate_t = (!(k1data->id()==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;ix<diagrams.size();ix++) hel_amp += diagrams[ix];
// If we need to fill the production ME we do it here:
// if(getMatrix) lo_hel_amps_(p1hel,p2hel,k1hel,k2hel) = hel_amp;
sum_hel_amps_sqr += norm(hel_amp);
}
}
}
}
// Spin and colour averaging factors = 1/4 * 1/3 = 1/12
sum_hel_amps_sqr /= 12.;
// Symmetry factor for identical Z bosons in the final state
if(k1data->id()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.;
return sum_hel_amps_sqr;
}
HardTreePtr MEPP2VVPowheg::generateHardest(ShowerTreePtr tree,
- vector<ShowerInteraction::Type> inter) {
- // check QCD emission switched on
- bool QCD=false;
- for(unsigned int ix=0;ix<inter.size();++ix)
- QCD |= inter[ix]==ShowerInteraction::QCD;
- if(!QCD) return HardTreePtr();
+ ShowerInteraction::Type inter) {
+ // check if generating QCD radiation
+ if(inter!=ShowerInteraction::QCD && inter!=ShowerInteraction::QEDQCD &&
+ inter!=ShowerInteraction::ALL)
+ return HardTreePtr();
// Now we want to set these data vectors according to the particles we've
// received from the current 2->2 hard collision:
vector<ShowerProgenitorPtr> particlesToShower;
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit )
particlesToShower.push_back(cit->first);
qProgenitor_ = particlesToShower[0];
qbProgenitor_ = particlesToShower[1];
showerQuark_ = particlesToShower[0]->progenitor();
showerAntiquark_ = particlesToShower[1]->progenitor();
qHadron_ = particlesToShower[0]->beam();
qbHadron_ = particlesToShower[1]->beam();
if(showerQuark_->id()<0) {
swap(qProgenitor_,qbProgenitor_);
swap(showerQuark_,showerAntiquark_);
swap(qHadron_,qbHadron_);
}
// In _our_ calculation we basically define the +z axis as being given
// by the direction of the incoming quark for q+qb & q+g processes and
// the incoming gluon for g+qbar processes. So now we might need to flip
// the beams, bjorken x values, colliding partons accordingly:
flipped_ = showerQuark_->momentum().z()<ZERO ? true : false;
assert(tree->outgoingLines().size()==2);
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit )
particlesToShower.push_back(cit->first);
V1_ = particlesToShower[2]->progenitor();
V2_ = particlesToShower[3]->progenitor();
gluon_ = getParticleData(ParticleID::g)->produceParticle();
// Abort the run if V1_ and V2_ are not just pointers to different gauge bosons
if(!V1_||!V2_)
throw Exception()
<< "MEPP2VVPowheg::generateHardest()\n"
<< "one or both of the gauge boson pointers is null." << Exception::abortnow;
if(!(abs(V1_->id())==24||V1_->id()==23)||!(abs(V2_->id())==24||V2_->id()==23))
throw Exception()
<< "MEPP2VVPowheg::generateHardest()\nmisidentified gauge bosons"
<< "V1_ = " << V1_->PDGName() << "\n"
<< "V2_ = " << V2_->PDGName() << "\n"
<< Exception::abortnow;
// Order the gauge bosons in the same way as in the NLO calculation
// (the same way as in the NLO matrix element):
// W+(->e+,nu_e) W-(->e-,nu_ebar) (MCFM: 61 [nproc])
if(V1_->id()==-24&&V2_->id()== 24) swap(V1_,V2_);
// W+/-(mu+,nu_mu / mu-,nu_mubar) Z(nu_e,nu_ebar) (MCFM: 72+77 [nproc])
if(V1_->id()== 23&&abs(V2_->id())== 24) swap(V1_,V2_);
// *** N.B. ***
// We should not have to do a swap in the ZZ case, even if the different
// (off-shell) masses of the Z's are taken into account by generating
// the Born variables using the WZ LO/NLO matrix element(s), because
// those transformed matrix elements are, according to mathematica,
// symmetric in the momenta (and therefore also the masses) of the 2 Z's.
// If the vector bosons have decayed already then we may want to
// to get the children_ (and any associated photons) to correct
// spin correlations:
StepPtr theSubProcess = generator()->eventHandler()->currentStep();
tPVector outgoing = theSubProcess->getFinalState();
children_.clear();
photons_.clear();
if(outgoing.size()>=4) {
for(unsigned int ix=0;ix<outgoing.size();ix++)
if(outgoing[ix]->parents()[0]&&
(abs(outgoing[ix]->parents()[0]->id())==24||
abs(outgoing[ix]->parents()[0]->id())==23)) {
if(outgoing[ix]->id()!=ParticleID::gamma)
children_.push_back(outgoing[ix]);
else
photons_.push_back(outgoing[ix]);
}
assert(children_.size()==4);
if(children_[0]->parents()[0]!=children_[1]->parents()[0])
swap(children_[0],children_[2]);
if(children_[0]->parents()[0]!=children_[1]->parents()[0])
swap(children_[0],children_[3]);
if(children_[0]->parents()[0]->id()!=V1_->id()) {
swap(children_[0],children_[2]);
swap(children_[1],children_[3]);
}
if(children_[0]->id()<0) swap(children_[0],children_[1]);
if(children_[2]->id()<0) swap(children_[2],children_[3]);
assert(children_[0]->parents()[0]==children_[1]->parents()[0]);
assert(children_[2]->parents()[0]==children_[3]->parents()[0]);
}
// Now we want to construct a bornVVKinematics object. The
// constructor for that needs all 4 momenta, q, qbar, V1_, V2_
// in that order, as well as the Bjorken xq and xqbar.
// Get the momenta first:
vector<Lorentz5Momentum> 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<Lorentz5Momentum> theRealMomenta;
channel_ = 999;
if(!getEvent(theRealMomenta,channel_)) return HardTreePtr();
// Set the maximum pT for subsequent emissions:
pT_ < min_pT_ ? qProgenitor_ ->maximumpT(min_pT_,ShowerInteraction::QCD) :
qProgenitor_ ->maximumpT(pT_ ,ShowerInteraction::QCD);
pT_ < min_pT_ ? qbProgenitor_->maximumpT(min_pT_,ShowerInteraction::QCD) :
qbProgenitor_->maximumpT(pT_ ,ShowerInteraction::QCD);
// Determine whether the quark or antiquark emitted:
fermionNumberOfMother_=0;
if((channel_==0&&theRealMomenta[0].z()/theRealMomenta[4].z()>=ZERO)||
channel_==2) fermionNumberOfMother_ = 1;
else if((channel_==0&&theRealMomenta[0].z()/theRealMomenta[4].z()<ZERO)||
channel_==1) fermionNumberOfMother_ = -1;
assert(fermionNumberOfMother_!=0);
// If the quark in the original tree was travelling in the -z direction
// then we need to unflip the event (flips are automatically carried out
// when the original quark travels in the in -z direction when the
// bornVVKinematics object is created):
if(flipped_)
for(unsigned int ix=0;ix<theRealMomenta.size();ix++)
theRealMomenta[ix].rotateY(-Constants::pi);
// Randomly rotate the event about the beam axis:
double randomPhi(UseRandom::rnd()*2.*Constants::pi);
for(unsigned int ix=0;ix<theRealMomenta.size();ix++)
theRealMomenta[ix].rotateZ(randomPhi);
// Warn if momentum conservation is not obeyed:
Lorentz5Momentum inMinusOut(theRealMomenta[0]+theRealMomenta[1]
-theRealMomenta[2]-theRealMomenta[3]
-theRealMomenta[4]);
if(inMinusOut.t()>0.1*GeV||inMinusOut.x()>0.1*GeV||
inMinusOut.y()>0.1*GeV||inMinusOut.z()>0.1*GeV)
cout << "MEPP2VVPowheg::generateHardest\n"
<< "Momentum imbalance in V1 V2 rest frame\n"
<< "P_in minus P_out = " << inMinusOut/GeV << endl;
// From the radiative kinematics we now have to form ShowerParticle objects:
ShowerParticlePtr p1;
ShowerParticlePtr p2;
ShowerParticlePtr k1(new_ptr(ShowerParticle(V1_->dataPtr(),true )));
ShowerParticlePtr k2(new_ptr(ShowerParticle(V2_->dataPtr(),true )));
ShowerParticlePtr k ;
// q+qbar -> V1+V2+g
if(channel_==0) {
p1 = new_ptr(ShowerParticle(showerQuark_->dataPtr() ,false));
p2 = new_ptr(ShowerParticle(showerAntiquark_->dataPtr() ,false));
k = new_ptr(ShowerParticle(gluon_->dataPtr() ,true ));
}
// q+g -> V1+V2+q
else if(channel_==1) {
p1 = new_ptr(ShowerParticle(showerQuark_->dataPtr() ,false));
p2 = new_ptr(ShowerParticle(gluon_->dataPtr() ,false));
k = new_ptr(ShowerParticle(showerAntiquark_->dataPtr()->CC() ,true ));
}
// g+qbar -> V1+V2+qbar
else {
p1 = new_ptr(ShowerParticle(gluon_->dataPtr() ,false));
p2 = new_ptr(ShowerParticle(showerAntiquark_->dataPtr() ,false));
k = new_ptr(ShowerParticle(showerQuark_->dataPtr()->CC() ,true ));
}
// Set the momenta of the ShowerParticlePtr's:
p1->set5Momentum(theRealMomenta[0]);
p2->set5Momentum(theRealMomenta[1]);
k1->set5Momentum(theRealMomenta[2]);
k2->set5Momentum(theRealMomenta[3]);
k ->set5Momentum(theRealMomenta[4]);
// Then construct another set of ShowerPointers that will be
// useful in creating the hardTree, using this information:
ShowerParticlePtr mother;
ShowerParticlePtr spacelikeSon;
ShowerParticlePtr timelikeSon;
ShowerParticlePtr spectator;
if(fermionNumberOfMother_==1) {
mother = new_ptr(ShowerParticle(showerQuark_->dataPtr() ,false));
spacelikeSon = p1;
timelikeSon = k;
spectator = p2;
} else if(fermionNumberOfMother_==-1) {
mother = new_ptr(ShowerParticle(showerAntiquark_->dataPtr(),false));
spacelikeSon = p2;
timelikeSon = k;
spectator = p1;
} else {
throw Exception() << "MEPP2VVPowheg::generateHardest()"
<< "Failed to determine whether the q or qbar branched"
<< Exception::runerror;
}
Lorentz5Momentum motherMomentum(spacelikeSon->momentum()-timelikeSon->momentum());
motherMomentum.rescaleMass();
mother->set5Momentum(motherMomentum);
// Create HardBranchingPtrs for the particles
HardBranchingPtr spacelikeSonBranching =
new_ptr(HardBranching(spacelikeSon,SudakovPtr(),HardBranchingPtr() ,HardBranching::Incoming ));
HardBranchingPtr timelikeSonBranching =
new_ptr(HardBranching(timelikeSon ,SudakovPtr(),spacelikeSonBranching,HardBranching::Outgoing));
HardBranchingPtr spectatorBranching =
new_ptr(HardBranching(spectator ,SudakovPtr(),HardBranchingPtr() ,HardBranching::Incoming ));
HardBranchingPtr motherBranching =
new_ptr(HardBranching(mother ,SudakovPtr(),spacelikeSonBranching,HardBranching::Incoming ));
HardBranchingPtr V1_Branching =
new_ptr(HardBranching(k1 ,SudakovPtr(),HardBranchingPtr() ,HardBranching::Outgoing));
HardBranchingPtr V2_Branching =
new_ptr(HardBranching(k2 ,SudakovPtr(),HardBranchingPtr() ,HardBranching::Outgoing));
// N.B. The DrellYanHardGenerator first adds the timelikeSonBranching as a child
// child of the spacelikeSonBranching before adding the motherBranching. We do
// it the other way round in accordance with PowhegEvolver::checkShowerMomentum.
spacelikeSonBranching->addChild(motherBranching);
spacelikeSonBranching->addChild(timelikeSonBranching);
spacelikeSonBranching->type(motherBranching->branchingParticle()->id()>0 ?
ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine);
motherBranching->colourPartner(spectatorBranching);
spectatorBranching->colourPartner(motherBranching);
vector<HardBranchingPtr> spacelikeBranchings,hardBranchings;
spacelikeBranchings.push_back(fermionNumberOfMother_ == 1 ?
spacelikeSonBranching : spectatorBranching);
spacelikeBranchings.push_back(fermionNumberOfMother_ == -1 ?
spacelikeSonBranching : spectatorBranching);
hardBranchings.push_back(motherBranching);
hardBranchings.push_back(spectatorBranching);
hardBranchings.push_back(V1_Branching);
hardBranchings.push_back(V2_Branching);
// Recalculate the hard vertex for this event:
// For spin correlations, if an emission occurs go calculate the relevant
// combination of amplitudes for the ProductionMatrixElement.
if(realMESpinCorrelations_) {
// Here we reset the realVVKinematics n+1 momenta to be those
// of the lab frame in order to calculate the spin correlations.
// Note that these momenta are not used for anything else after
// this.
R_.p1r(theRealMomenta[0]);
R_.p2r(theRealMomenta[1]);
R_.k1r(theRealMomenta[2]);
R_.k2r(theRealMomenta[3]);
R_.kr (theRealMomenta[4]);
if(channel_==0) t_u_M_R_qqb_hel_amp(R_,true);
else if(channel_==1) t_u_M_R_qg_hel_amp (R_,true);
else if(channel_==2) t_u_M_R_gqb_hel_amp(R_,true);
recalculateVertex();
}
// Construct the HardTree object needed to perform the showers
HardTreePtr hardTree=new_ptr(HardTree(hardBranchings,spacelikeBranchings,
ShowerInteraction::QCD));
if(hardTree->branchings().size()!=4) throw Exception()
<< "MEPP2VVPowheg::generateHardest()\n"
<< "The hardTree has " << hardTree->branchings().size() << "branchings\n"
<< hardTree << "\n" << Exception::runerror;
if((motherBranching->parent()!=spacelikeSonBranching)&&
spacelikeSonBranching->parent()!=HardBranchingPtr()&&
spectatorBranching->parent()!=HardBranchingPtr()) throw Exception()
<< "MEPP2VVPowheg::generateHardest()\n"
<< "The parent-child relationships are not valid.\n"
<< "motherBranching->parent() = " << motherBranching->parent() << "\n"
<< "spacelikeSonBranching = " << spacelikeSonBranching << "\n"
<< "spectatorBranching->parent() = " << spectatorBranching->parent() << "\n"
<< "spacelikeSonBranching->parent() = " << spacelikeSonBranching->parent() << "\n"
<< Exception::runerror;
if(fermionNumberOfMother_== 1) {
hardTree->connect(showerQuark_ ,motherBranching );
hardTree->connect(showerAntiquark_,spectatorBranching);
spacelikeSonBranching->beam(qProgenitor_ ->original()->parents()[0]);
motherBranching ->beam(qProgenitor_ ->original()->parents()[0]);
spectatorBranching ->beam(qbProgenitor_->original()->parents()[0]);
} else if(fermionNumberOfMother_==-1) {
hardTree->connect(showerAntiquark_,motherBranching );
hardTree->connect(showerQuark_ ,spectatorBranching);
spacelikeSonBranching->beam(qbProgenitor_->original()->parents()[0]);
motherBranching ->beam(qbProgenitor_->original()->parents()[0]);
spectatorBranching ->beam(qProgenitor_ ->original()->parents()[0]);
}
// hardTree->connect(V1_ ,V1_Branching );
// hardTree->connect(V2_ ,V2_Branching );
// This if {...} else if {...} puts the mother and spectator on the same colour
// line. If we don't do this, then when reconstructFinalStateShower calls
// setInitialEvolutionScales it says it failed to set the colour partners, so
// it can't set the scale and it just forgets the emission / event. This seems
// like an unintrusive work-around until reconstructFinalStateShower is sorted.
ColinePtr bornColourLine=new_ptr(ColourLine());
if(fermionNumberOfMother_== 1) {
bornColourLine->addColoured(mother);
bornColourLine->addAntiColoured(spectator);
if(timelikeSon->id()==ParticleID::g) {
bornColourLine->addAntiColoured(timelikeSon);
ColinePtr newLine=new_ptr(ColourLine());
newLine->addColoured(timelikeSon);
newLine->addColoured(spacelikeSon);
}
else {
bornColourLine->addColoured(spacelikeSon);
ColinePtr newLine=new_ptr(ColourLine());
newLine->addAntiColoured(timelikeSon);
newLine->addAntiColoured(spacelikeSon);
}
} else if(fermionNumberOfMother_==-1) {
bornColourLine->addAntiColoured(mother);
bornColourLine->addColoured(spectator);
if(timelikeSon->id()==ParticleID::g) {
bornColourLine->addColoured(timelikeSon);
ColinePtr newLine=new_ptr(ColourLine());
newLine->addAntiColoured(timelikeSon);
newLine->addAntiColoured(spacelikeSon);
}
else {
bornColourLine->addAntiColoured(spacelikeSon);
ColinePtr newLine=new_ptr(ColourLine());
newLine->addColoured(timelikeSon);
newLine->addColoured(spacelikeSon);
}
}
// this is a pain but we need the boost, which we don't have yet here!!
vector<Lorentz5Momentum> pin(2);
vector<Lorentz5Momentum> pq (2);
vector<HardBranchingPtr>::iterator cit;
pin[0] = motherBranching ->branchingParticle()->momentum();
pin[1] = spectatorBranching->branchingParticle()->momentum();
Energy etemp = motherBranching ->beam()->momentum().z();
pq[0] = Lorentz5Momentum(ZERO, ZERO,etemp, abs(etemp));
etemp = spectatorBranching->beam()->momentum().z();
pq[1] = Lorentz5Momentum(ZERO, ZERO,etemp, abs(etemp));
// decompose the momenta
double alpha[2],beta[2];
Energy2 p12=pq[0]*pq[1];
Lorentz5Momentum pt[2];
for(unsigned int ix=0;ix<2;++ix) {
alpha[ix] = pin[ix]*pq[1]/p12;
beta [ix] = pin[ix]*pq[0]/p12;
pt[ix] = pin[ix]-alpha[ix]*pq[0]-beta[ix]*pq[1];
}
// parton level centre-of-mass
Lorentz5Momentum pcm=pin[0]+pin[1];
pcm.rescaleMass();
double rap=pcm.rapidity();
// hadron level cmf
Energy2 s = (pq[0] +pq[1] ).m2();
// calculate the x values
double x[2]={sqrt(pcm.mass2()/s*exp(2.*rap)),pcm.mass2()/s/x[0]};
if(pq[0].z()<ZERO) swap(x[0],x[1]);
Lorentz5Momentum pnew = x[0]*pq[0]+x[1]*pq[1];
LorentzRotation toRest = LorentzRotation(-pcm .boostVector());
LorentzRotation fromRest = LorentzRotation( pnew.boostVector());
Lorentz5Momentum pv[2]=
{fromRest*toRest*V1_Branching->branchingParticle()->momentum(),
fromRest*toRest*V2_Branching->branchingParticle()->momentum()};
LorentzRotation R(-(mother->momentum()+spectator ->momentum()).boostVector());
R.boost((showerQuark_->momentum()+showerAntiquark_->momentum()).boostVector());
for(map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator
tit = tree->treelinks().begin();
tit != tree->treelinks().end();++tit) {
ShowerTreePtr decayTree = tit->first;
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit = decayTree->incomingLines().begin();
// reset the momentum of the decay particle
Lorentz5Momentum oldMomentum = cit->first->progenitor()->momentum();
Lorentz5Momentum newMomentum = tit->second.second == V1_ ? pv[0] : pv[1];
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cjt;
// reset the momenta of the decay products,
LorentzRotation boostToORF(newMomentum.findBoostToCM(),
newMomentum.e()/newMomentum.mass());
tPPtr children[2];
if(children_[0]->parents()[0]==cit->first->original()) {
children[0] = children_[0];
children[1] = children_[1];
}
else {
children[0] = children_[2];
children[1] = children_[3];
}
if(UseRandom::rndbool()) swap(children[0],children[1]);
double originalTheta0 = (boostToORF*R*children[0]->momentum()).theta();
double originalPhi0 = (boostToORF*R*children[0]->momentum()).phi();
boostToORF.rotateZ(-originalPhi0);
boostToORF.rotateY(-originalTheta0);
double originalPhi1 = (boostToORF*children[1]->momentum()).phi();
LorentzRotation boost(oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass());
tPPtr newChildren[2];
for(cjt=decayTree->outgoingLines().begin();
cjt!=decayTree->outgoingLines().end();++cjt) {
if(cjt->first->progenitor()->id()==children[0]->id())
newChildren[0] = cjt->first->progenitor();
else if(cjt->first->progenitor()->id()==children[1]->id())
newChildren[1] = cjt->first->progenitor();
}
boost.rotateZ(-(boost*newChildren[0]->momentum()).phi());
boost.rotateY(-(boost*newChildren[0]->momentum()).theta());
boost.rotateZ(-(boost*newChildren[1]->momentum()).phi());
boost.rotateZ( originalPhi1);
boost.rotateY( originalTheta0);
boost.rotateZ( originalPhi0);
boost.boost(-oldMomentum.findBoostToCM(),
oldMomentum.e()/oldMomentum.mass());
for(cjt=decayTree->outgoingLines().begin();
cjt!=decayTree->outgoingLines().end();++cjt) {
cjt->first->original() ->set5Momentum(cjt->first->progenitor()->momentum());
cjt->first->progenitor()->deepTransform(boost);
cjt->first->original() ->deepTransform(boost);
cjt->first->copy() ->deepTransform(boost);
}
}
return hardTree;
}
double MEPP2VVPowheg::getResult(int channel, realVVKinematics R, Energy pT) {
// This routine should return the integrand of the exact Sudakov form factor,
// defined precisely as
// KH 19th August - next 2 lines changed for phi in 0->pi not 0->2pi
// \Delta(pT) = exp[ - \int_{pT}^{pTmax} dpT dYk d\phi/pi * getResult(...) ]
// (Where phi is in 0->pi NOT 0->2*pi !)
// Get pi for the prefactor:
using Constants::pi;
// Get the VV invariant mass^2:
Energy2 p2 = B_.sb();
// Get the momentum fractions for the n+1 body event:
double x1 = R.x1r();
double x2 = R.x2r();
// Reject the event if the x1 and x2 values are outside the phase space:
if(x1<0.||x1>1.||x2<0.||x2>1.||x1*x2<p2/sqr(generator()->maximumCMEnergy())) 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<Lorentz5Momentum> & 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(pT<min_pT_) {
pT=ZERO;
rejectEmission = false;
}
if(rejectionWeight>1.) {
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_<min_pT_) {
pT_ = ZERO;
channel = 3;
}
if(channel==3) return false;
if(channel>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<SpinorWaveFunction> q;
vector<SpinorBarWaveFunction> 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<VectorWaveFunction> v1;
vector<VectorWaveFunction> 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<VectorWaveFunction> 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<tcPDPtr> 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<Complex> diagrams;
// Get all t-channel diagram contributions
tcPDPtr intermediate_t;
for(unsigned int ix=0;ix<tc.size();ix++) {
intermediate_t = (!(k1data->id()==24&&k2data->id()==-24)) ? p2data : tc[ix];
// Note: choosing 5 as the second argument ffvX_->evaluate() sets
// option 5 in thepeg/Helicity/Vertex/VertexBase.cc, which makes
// the (fermion) propagator denominator massless: 1/p^2.
// If W+Z / W-Z calculate the two V+jet-like s-channel diagrams
SpinorWaveFunction p1_v1 = ffv1->evaluate(EWScale_,5,intermediate_t,q[p1hel],v1[k1hel]);
SpinorBarWaveFunction p2_v2 = ffv2->evaluate(EWScale_,5,intermediate_t,qb[p2hel],v2[k2hel]);
// First calculate all the off-shell fermion currents
// Now calculate the 6 t-channel diagrams
// q+qb->g+v1+v2, q+qb->v1+g+v2, q+qb->v1+v2+g
if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) {
diagrams.push_back(ffv1->evaluate(EWScale_,p1_k,p2_v2,v1[k1hel]));
diagrams.push_back(ffg->evaluate(QCDScale_,p1_v1,p2_v2,g[khel]));
diagrams.push_back(ffv2->evaluate(EWScale_,p1_v1,p2_k,v2[k2hel]));
}
intermediate_t = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix];
SpinorWaveFunction p1_v2 = ffv2->evaluate(EWScale_,5,intermediate_t,q[p1hel],v2[k2hel]);
SpinorBarWaveFunction p2_v1 = ffv1->evaluate(EWScale_,5,intermediate_t,qb[p2hel],v1[k1hel]);
// q+qb->g+v2+v1, q+qb->v2+g+v1, q+qb->v2+v1+g
if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) {
diagrams.push_back(ffv2->evaluate(EWScale_,p1_k,p2_v1,v2[k2hel]));
diagrams.push_back(ffg->evaluate(QCDScale_,p1_v2,p2_v1,g[khel]));
diagrams.push_back(ffv1->evaluate(EWScale_,p1_v2,p2_k,v1[k1hel]));
}
}
// Note: choosing 3 as the second argument in WWWvertex_->evaluate()
// sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which
// means the propagator does not contain a width factor (which is
// good re. gauge invariance).
// If W+Z / W-Z calculate the two V+jet-like s-channel diagrams
if(abs(k1data->id())==24&&k2data->id()==23) {
// The off-shell s-channel boson current
VectorWaveFunction k1_k2 =
WWWvertex_->evaluate(EWScale_,3,k1data->CC(),v2[k2hel],v1[k1hel]);
// q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g
diagrams.push_back(ffv1->evaluate(EWScale_,p1_k,qb[p2hel],k1_k2));
diagrams.push_back(ffv1->evaluate(EWScale_,q[p1hel],p2_k,k1_k2));
}
// If W+W- calculate the four V+jet-like s-channel diagrams
if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==-p2data->id())) {
// The off-shell s-channel boson current
VectorWaveFunction k1_k2;
// q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g,
tcPDPtr Z0 = getParticleData(ParticleID::Z0);
k1_k2 = WWWvertex_->evaluate(EWScale_,3,Z0,v2[k2hel],v1[k1hel]);
diagrams.push_back(FFZvertex_->evaluate(EWScale_,p1_k,qb[p2hel],k1_k2));
diagrams.push_back(FFZvertex_->evaluate(EWScale_,q[p1hel],p2_k,k1_k2));
// q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g,
tcPDPtr gamma = getParticleData(ParticleID::gamma);
k1_k2 = WWWvertex_->evaluate(EWScale_,3,gamma,v2[k2hel],v1[k1hel]);
diagrams.push_back(FFPvertex_->evaluate(EWScale_,p1_k,qb[p2hel],k1_k2));
diagrams.push_back(FFPvertex_->evaluate(EWScale_,q[p1hel],p2_k,k1_k2));
}
// Add up all diagrams to get the total amplitude:
Complex hel_amp(0.);
for(unsigned int ix=0;ix<diagrams.size();ix++) hel_amp += diagrams[ix];
// If we need to fill the production ME we do it here:
if(getMatrix) {
if(khel==0)
qqb_hel_amps(p1hel,p2hel,k1hel,k2hel,0) = hel_amp;
else
qqb_hel_amps(p1hel,p2hel,k1hel,k2hel,2) = hel_amp;
}
sum_hel_amps_sqr += norm(hel_amp);
}
}
}
}
}
// Fill up the remaining bits of the production ME, corresponding
// to longitudinal gluon polarization, with (0.,0.).
if(getMatrix) {
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) {
qqb_hel_amps(p1hel,p2hel,k1hel,k2hel,1) = Complex(0.,0.);
}
}
}
}
}
// Calculate the production density matrix:
if(getMatrix) {
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) {
Complex theElement(0.,0.);
// For each k1hel, k1helpr, k2hel, k2helpr sum over fermion and gluon spins...
for(unsigned int p1hel=0;p1hel<2;++p1hel) {
for(unsigned int p2hel=0;p2hel<2;++p2hel) {
for(unsigned int khel=0;khel<3;khel+=2) {
theElement += qqb_hel_amps(p1hel,p2hel,k1hel ,k2hel ,khel)
*conj(qqb_hel_amps(p1hel,p2hel,k1helpr,k2helpr,khel));
}
}
}
// ...and then set the production matrix element to the sum:
productionMatrix_[k1hel][k1helpr][k2hel][k2helpr] = theElement;
}
}
}
}
}
// Spin and colour averaging factors = 1/4 * CF * 1/3 = 1/9
sum_hel_amps_sqr /= 9.;
// Symmetry factor for identical Z bosons in the final state
if(k1data->id()==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<SpinorWaveFunction> qin;
vector<SpinorBarWaveFunction> 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<VectorWaveFunction> v1;
vector<VectorWaveFunction> 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<VectorWaveFunction> 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<tcPDPtr> 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<Complex> diagrams;
// Get all t-channel diagram contributions
tcPDPtr intermediate_q;
for(unsigned int ix=0;ix<tc.size();ix++) {
intermediate_q = (!(k1data->id()==24&&k2data->id()==-24)) ? showerAntiquark_->dataPtr() : tc[ix];
SpinorWaveFunction p1_v1 = ffv1->evaluate(EWScale_,5,intermediate_q,qin[p1hel],v1[k1hel]);
SpinorBarWaveFunction k_v2 = ffv2->evaluate(EWScale_,5,intermediate_q,qout[khel],v2[k2hel]);
// First calculate all the off-shell fermion currents
// Now calculate the 6 abelian diagrams
// q+g->v1+v2+q with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones.
if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) {
diagrams.push_back(ffv2->evaluate(EWScale_,p1_v1,p2_k,v2[k2hel]));
diagrams.push_back(ffg->evaluate(QCDScale_,p1_v1,k_v2,g[p2hel]));
diagrams.push_back(ffv1->evaluate(EWScale_,p1_p2,k_v2,v1[k1hel]));
}
intermediate_q = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix];
SpinorWaveFunction p1_v2 = ffv2->evaluate(EWScale_,5,intermediate_q,qin[p1hel],v2[k2hel]);
SpinorBarWaveFunction k_v1 = ffv1->evaluate(EWScale_,5,intermediate_q,qout[khel],v1[k1hel]);
// q+g->v2+v1+q, with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones.
if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) {
diagrams.push_back(ffv1->evaluate(EWScale_,p1_v2,p2_k,v1[k1hel]));
diagrams.push_back(ffg->evaluate(QCDScale_,p1_v2,k_v1,g[p2hel]));
diagrams.push_back(ffv2->evaluate(EWScale_,p1_p2,k_v1,v2[k2hel]));
}
}
// Note: choosing 3 as the second argument in WWWvertex_->evaluate()
// sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which
// means the propagator does not contain a width factor (which is
// good re. gauge invariance).
// If W+Z / W-Z calculate the two V+jet-like s-channel diagrams
if(abs(k1data->id())==24&&k2data->id()==23) {
// The off-shell s-channel boson current
VectorWaveFunction k1_k2 =
WWWvertex_->evaluate(EWScale_,3,k1data->CC(),v2[k2hel],v1[k1hel]);
// q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g
diagrams.push_back(ffv1->evaluate(EWScale_,p1_p2,qout[khel],k1_k2));
diagrams.push_back(ffv1->evaluate(EWScale_,qin[p1hel],p2_k,k1_k2));
}
// If W+W- calculate the four V+jet-like s-channel diagrams
if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==kdata->id())) {
// The off-shell s-channel boson current
VectorWaveFunction k1_k2;
// q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g,
tcPDPtr Z0 = getParticleData(ParticleID::Z0);
k1_k2 = WWWvertex_->evaluate(EWScale_,3,Z0,v2[k2hel],v1[k1hel]);
diagrams.push_back(FFZvertex_->evaluate(EWScale_,p1_p2,qout[khel],k1_k2));
diagrams.push_back(FFZvertex_->evaluate(EWScale_,qin[p1hel],p2_k,k1_k2));
// q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g,
tcPDPtr gamma = getParticleData(ParticleID::gamma);
k1_k2 = WWWvertex_->evaluate(EWScale_,3,gamma,v2[k2hel],v1[k1hel]);
diagrams.push_back(FFPvertex_->evaluate(EWScale_,p1_p2,qout[khel],k1_k2));
diagrams.push_back(FFPvertex_->evaluate(EWScale_,qin[p1hel],p2_k,k1_k2));
}
// Add up all diagrams to get the total amplitude:
Complex hel_amp(0.);
for(unsigned int ix=0;ix<diagrams.size();ix++) hel_amp += diagrams[ix];
// If we need to fill the production ME we do it here:
if(getMatrix) {
if(p2hel==0)
qg_hel_amps(p1hel,0,k1hel,k2hel,khel) = hel_amp;
else
qg_hel_amps(p1hel,2,k1hel,k2hel,khel) = hel_amp;
}
sum_hel_amps_sqr += norm(hel_amp);
}
}
}
}
}
// Fill up the remaining bits of the production ME, corresponding
// to longitudinal gluon polarization, with (0.,0.).
if(getMatrix) {
for(unsigned int p1hel=0;p1hel<2;++p1hel) {
for(unsigned int k1hel=0;k1hel<3;++k1hel) {
for(unsigned int k2hel=0;k2hel<3;++k2hel) {
for(unsigned int khel=0;khel<2;++khel) {
qg_hel_amps(p1hel,1,k1hel,k2hel,khel) = Complex(0.,0.);
}
}
}
}
}
// Calculate the production density matrix:
if(getMatrix) {
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) {
Complex theElement(0.,0.);
// For each k1hel, k1helpr, k2hel, k2helpr sum over fermion and gluon spins...
for(unsigned int p1hel=0;p1hel<2;++p1hel) {
for(unsigned int p2hel=0;p2hel<3;p2hel+=2) {
for(unsigned int khel=0;khel<2;++khel) {
theElement += qg_hel_amps(p1hel,p2hel,k1hel ,k2hel ,khel)
*conj(qg_hel_amps(p1hel,p2hel,k1helpr,k2helpr,khel));
}
}
}
// ...and then set the production matrix element to the sum:
productionMatrix_[k1hel][k1helpr][k2hel][k2helpr] = theElement;
}
}
}
}
}
// Spin and colour averaging factors = 1/4 * TR * 1/3 = 1/24
sum_hel_amps_sqr /= 24.;
// Symmetry factor for identical Z bosons in the final state
if(k1data->id()==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<SpinorBarWaveFunction> qbin;
vector<SpinorWaveFunction> 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<VectorWaveFunction> v1;
vector<VectorWaveFunction> 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<VectorWaveFunction> 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<tcPDPtr> 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<Complex> diagrams;
// Get all t-channel diagram contributions
tcPDPtr intermediate_q;
for(unsigned int ix=0;ix<tc.size();ix++) {
intermediate_q = (!(k1data->id()==24&&k2data->id()==-24)) ? showerQuark_->dataPtr() : tc[ix];
SpinorBarWaveFunction p2_v1 = ffv1->evaluate(EWScale_,5,intermediate_q,qbin[p2hel],v1[k1hel]);
SpinorWaveFunction k_v2 = ffv2->evaluate(EWScale_,5,intermediate_q,qbout[khel],v2[k2hel]);
// First calculate all the off-shell fermion currents
// Now calculate the 6 abelian diagrams q+g->v1+v2+q
// with 2 t-channel propagators, 1 s- and 1 t-channel
// and 2 t-channel ones.
if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p2data->id())%2==0))) {
diagrams.push_back(ffv2->evaluate(EWScale_,p1_k,p2_v1,v2[k2hel]));
diagrams.push_back(ffg->evaluate(QCDScale_,k_v2,p2_v1,g[p1hel]));
diagrams.push_back(ffv1->evaluate(EWScale_,k_v2,p1_p2,v1[k1hel]));
}
intermediate_q = (!(k1data->id()==24&&k2data->id()==-24)) ? p2data : tc[ix];
SpinorBarWaveFunction p2_v2 = ffv2->evaluate(EWScale_,5,intermediate_q,qbin[p2hel],v2[k2hel]);
SpinorWaveFunction k_v1 = ffv1->evaluate(EWScale_,5,intermediate_q,qbout[khel],v1[k1hel]);
// q+g->v2+v1+q, with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones.
if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p2data->id())%2==1))) {
diagrams.push_back(ffv1->evaluate(EWScale_,p1_k,p2_v2,v1[k1hel]));
diagrams.push_back(ffg->evaluate(QCDScale_,k_v1,p2_v2,g[p1hel]));
diagrams.push_back(ffv2->evaluate(EWScale_,k_v1,p1_p2,v2[k2hel]));
}
}
// Note: choosing 3 as the second argument in WWWvertex_->evaluate()
// sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which
// means the propagator does not contain a width factor (which is
// good re. gauge invariance).
// If W+Z / W-Z calculate the two V+jet-like s-channel diagrams
if(abs(k1data->id())==24&&k2data->id()==23) {
// The off-shell s-channel boson current
VectorWaveFunction k1_k2 =
WWWvertex_->evaluate(EWScale_,3,k1data->CC(),v2[k2hel],v1[k1hel]);
// q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g
diagrams.push_back(ffv1->evaluate(EWScale_,qbout[khel],p1_p2,k1_k2));
diagrams.push_back(ffv1->evaluate(EWScale_,p1_k,qbin[p2hel],k1_k2));
}
// If W+W- calculate the four V+jet-like s-channel diagrams
if((k1data->id()==24&&k2data->id()==-24)&&(p2data->id()==kdata->id())) {
// The off-shell s-channel boson current
VectorWaveFunction k1_k2;
// q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g,
tcPDPtr Z0 = getParticleData(ParticleID::Z0);
k1_k2 = WWWvertex_->evaluate(EWScale_,3,Z0,v2[k2hel],v1[k1hel]);
diagrams.push_back(FFZvertex_->evaluate(EWScale_,qbout[khel],p1_p2,k1_k2));
diagrams.push_back(FFZvertex_->evaluate(EWScale_,p1_k,qbin[p2hel],k1_k2));
// q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g,
tcPDPtr gamma = getParticleData(ParticleID::gamma);
k1_k2 = WWWvertex_->evaluate(EWScale_,3,gamma,v2[k2hel],v1[k1hel]);
diagrams.push_back(FFPvertex_->evaluate(EWScale_,qbout[khel],p1_p2,k1_k2));
diagrams.push_back(FFPvertex_->evaluate(EWScale_,p1_k,qbin[p2hel],k1_k2));
}
// Add up all diagrams to get the total amplitude:
Complex hel_amp(0.);
for(unsigned int ix=0;ix<diagrams.size();ix++) hel_amp += diagrams[ix];
// If we need to fill the production ME we do it here:
if(getMatrix) {
if(p1hel==0)
gqb_hel_amps(0,p2hel,k1hel,k2hel,khel) = hel_amp;
else
gqb_hel_amps(2,p2hel,k1hel,k2hel,khel) = hel_amp;
}
sum_hel_amps_sqr += norm(hel_amp);
}
}
}
}
}
// Fill up the remaining bits of the production ME, corresponding
// to longitudinal gluon polarization, with (0.,0.).
if(getMatrix) {
for(unsigned int p2hel=0;p2hel<2;++p2hel) {
for(unsigned int k1hel=0;k1hel<3;++k1hel) {
for(unsigned int k2hel=0;k2hel<3;++k2hel) {
for(unsigned int khel=0;khel<2;++khel) {
gqb_hel_amps(1,p2hel,k1hel,k2hel,khel) = Complex(0.,0.);
}
}
}
}
}
// Calculate the production density matrix:
if(getMatrix) {
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) {
Complex theElement(0.,0.);
// For each k1hel, k1helpr, k2hel, k2helpr sum over fermion and gluon spins...
for(unsigned int p1hel=0;p1hel<3;p1hel+=2) {
for(unsigned int p2hel=0;p2hel<2;++p2hel) {
for(unsigned int khel=0;khel<2;++khel) {
theElement += gqb_hel_amps(p1hel,p2hel,k1hel ,k2hel ,khel)
*conj(gqb_hel_amps(p1hel,p2hel,k1helpr,k2helpr,khel));
}
}
}
// ...and then set the production matrix element to the sum:
productionMatrix_[k1hel][k1helpr][k2hel][k2helpr] = theElement;
}
}
}
}
}
// Spin and colour averaging factors = 1/4 * TR * 1/3 = 1/24
sum_hel_amps_sqr /= 24.;
// Symmetry factor for identical Z bosons in the final state
if(k1data->id()==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<SpinorWaveFunction> q;
vector<SpinorBarWaveFunction> 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<VectorWaveFunction> v1;
vector<VectorWaveFunction> 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<tcPDPtr> 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<Complex> diagrams;
// Get all t-channel diagram contributions
tcPDPtr intermediate_t;
for(unsigned int ix=0;ix<tc.size();ix++) {
intermediate_t = (!(k1data->id()==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;ix<diagrams.size();ix++) hel_amp += diagrams[ix];
// If we need to fill the production ME we do it here:
if(getMatrix) lo_hel_amps(p1hel,p2hel,k1hel,k2hel) = hel_amp;
sum_hel_amps_sqr += norm(hel_amp);
}
}
}
}
// Calculate the production density matrix:
if(getMatrix) {
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) {
Complex theElement(0.,0.);
// For each k1hel, k1helpr, k2hel, k2helpr sum over the fermion spins...
for(unsigned int p1hel=0;p1hel<2;++p1hel) {
for(unsigned int p2hel=0;p2hel<2;++p2hel) {
if((p1hel==p2hel)&&helicityConservation_) continue;
theElement += lo_hel_amps(p1hel,p2hel,k1hel ,k2hel )
*conj(lo_hel_amps(p1hel,p2hel,k1helpr,k2helpr));
}
}
// ...and then set the production matrix element to the sum:
productionMatrix_[k1hel][k1helpr][k2hel][k2helpr] = theElement;
}
}
}
}
}
// Spin and colour averaging factors = 1/4 * 1/3 = 1/12
sum_hel_amps_sqr /= 12.;
// Symmetry factor for identical Z bosons in the final state
if(k1data->id()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.;
return sum_hel_amps_sqr;
}
/***************************************************************************/
// This member selects a [2-body] decay mode and assigns children to the
// vector bosons with momenta which are isotropic in their rest frames.
bool MEPP2VVPowheg::isotropicDecayer() {
using namespace ThePEG::Helicity;
// Generate the children's momenta isotropically in
// the rest frames of V1 and V2:
double cth,phi;
// First V1's children:
cth = UseRandom::rnd()*2.-1.;
phi = UseRandom::rnd()*2.*Constants::pi;
Energy m1(V1_->momentum().m());
Energy m3(children_[0]->data().constituentMass());
Energy m4(children_[1]->data().constituentMass());
Energy p34(triangleFn(sqr(m1),sqr(m3),sqr(m4))
/2./m1);
if(isnan(p34/GeV)||cth>1.||cth<-1.) return false;
Energy pT34(p34*sqrt(1.-cth)*sqrt(1.+cth));
Lorentz5Momentum k3(pT34*sin(phi),pT34*cos(phi),p34 *cth,
sqrt(p34*p34+sqr(m3)),m3);
Lorentz5Momentum k4(-k3);
k4.setE(sqrt(p34*p34+sqr(m4)));
k4.setTau(m4);
Boost boostToV1RF(R_.k1r().boostVector());
k3.boost(boostToV1RF);
k3.rescaleRho();
k4.boost(boostToV1RF);
k4.rescaleRho();
// Second V2's children:
cth = UseRandom::rnd()*2.-1.;
phi = UseRandom::rnd()*2.*Constants::pi;
Energy m2(V2_->momentum().m());
Energy m5(children_[2]->data().constituentMass());
Energy m6(children_[3]->data().constituentMass());
Energy p56(triangleFn(sqr(m2),sqr(m5),sqr(m6))
/2./m2);
if(isnan(p56/GeV)||cth>1.||cth<-1.) return false;
Energy pT56(p56*sqrt(1.-cth)*sqrt(1.+cth));
Lorentz5Momentum k5(pT56*sin(phi),pT56*cos(phi),p56*cth,
sqrt(p56*p56+sqr(m5)),m5);
Lorentz5Momentum k6(-k5);
k6.setE(sqrt(p56*p56+sqr(m6)));
k6.setTau(m6);
Boost boostToV2RF(R_.k2r().boostVector());
k5.boost(boostToV2RF);
k5.rescaleRho();
k6.boost(boostToV2RF);
k6.rescaleRho();
// Assign the momenta to the children:
children_[0]->set5Momentum(k3);
children_[1]->set5Momentum(k4);
children_[2]->set5Momentum(k5);
children_[3]->set5Momentum(k6);
return true;
}
// Override 2->2 production matrix here:
void MEPP2VVPowheg::recalculateVertex() {
// Zero the squared amplitude; this equals sum_hel_amps_sqr if all
// is working as it should:
Complex productionMatrix2(0.,0.);
for(unsigned int k1hel=0;k1hel<3;++k1hel)
for(unsigned int k2hel=0;k2hel<3;++k2hel)
productionMatrix2 += productionMatrix_[k1hel][k1hel][k2hel][k2hel];
// Get the vector wavefunctions:
VectorWaveFunction v1Polarization;
VectorWaveFunction v2Polarization;
v1Polarization=VectorWaveFunction(R_.k1r(),V1_->dataPtr(),outgoing);
v2Polarization=VectorWaveFunction(R_.k2r(),V2_->dataPtr(),outgoing);
vector<VectorWaveFunction> v1;
vector<VectorWaveFunction> 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<SpinorWaveFunction> k3,k5;
vector<SpinorBarWaveFunction> 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()<decayWeight) vetoed = false;
else vetoed = true;
}
return;
}
Energy2 MEPP2VVPowheg::triangleFn(Energy2 m12,Energy2 m22, Energy2 m32) {
Energy4 lambda2(m12*m12+m22*m22+m32*m32-2.*m12*m22-2.*m12*m32-2.*m22*m32);
if(lambda2>=ZERO) {
return sqrt(lambda2);
} else {
generator()->log()
<< "MEPP2VVPowheg::triangleFn "
<< "kinematic instability, imaginary triangle function\n";
return -999999.*GeV2;
}
}
diff --git a/MatrixElement/Powheg/MEPP2VVPowheg.h b/MatrixElement/Powheg/MEPP2VVPowheg.h
--- a/MatrixElement/Powheg/MEPP2VVPowheg.h
+++ b/MatrixElement/Powheg/MEPP2VVPowheg.h
@@ -1,874 +1,874 @@
// -*- C++ -*-
#ifndef HERWIG_MEPP2VVPowheg_H
#define HERWIG_MEPP2VVPowheg_H
//
// This is the declaration of the MEPP2VVPowheg class.
//
#include "Herwig/MatrixElement/Hadron/MEPP2VV.h"
#include "Herwig/MatrixElement/Powheg/VVKinematics.h"
#include "Herwig/Utilities/Maths.h"
#include "Herwig/Models/StandardModel/StandardCKM.h"
#include "Herwig/Shower/Couplings/ShowerAlpha.h"
namespace Herwig {
using namespace ThePEG;
using Math::ReLi2;
using Constants::pi;
/**
* Here is the documentation of the MEPP2VVPowheg class.
*
* @see \ref MEPP2VVPowhegInterfaces "The interfaces"
* defined for MEPP2VVPowheg.
*/
class MEPP2VVPowheg: public MEPP2VV {
public:
/**
* The default constructor.
*/
MEPP2VVPowheg();
/** @name Member functions for the generation of hard QCD radiation */
//@{
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return ISR;}
/**
* Apply the POWHEG style correction
*/
virtual HardTreePtr generateHardest(ShowerTreePtr,
- vector<ShowerInteraction::Type> inter);
+ ShowerInteraction::Type inter);
//@}
public:
/**
* Generate internal degrees of freedom given nDim() uniform
* random numbers in the interval \f$ ]0,1[ \f$. To help the phase space
* generator, the dSigHatDR should be a smooth function of these
* numbers, although this is not strictly necessary.
* @param r a pointer to the first of nDim() consecutive random numbers.
* @return true if the generation succeeded, otherwise false.
*/
virtual bool generateKinematics(const double * r);
/**
* The number of internal degrees of freedom used in the matrix
* element.
*/
virtual int nDim() const;
/**
* The matrix element for the kinematical configuration
* previously provided by the last call to setKinematics(), suitably
* scaled by sHat() to give a dimension-less number.
* @return the matrix element scaled with sHat() to give a
* dimensionless number.
*/
virtual double me2() const;
/**
* Return the scale associated with the last set phase space point.
*/
virtual Energy2 scale() const;
/**
* This member check the collinear limits of the
* real emission matrix elements are equal to the
* appropriate combinations of Born ME's multiplied
* by the splitting functions.
*/
bool sanityCheck() const;
/**
* Return the CKM matrix elements.
*/
Complex CKM(int ix,int iy) const { return ckm_[ix][iy]; }
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
//@}
public:
/**
* Function to set the born variables.
*/
void getKinematics(double xt, double y, double theta2);
/**
* Calculate the correction weight with which leading-order
* configurations are re-weighted.
*/
double NLOweight() const;
/**
* Calculate the ratio of the NLO luminosity to the LO
* luminosity function for the \f$q\bar{q}\f$ initiated channel.
*/
double Lhat_ab(tcPDPtr a, tcPDPtr b, realVVKinematics Kinematics) const;
/**
* Calculate the universal soft-virtual contribution to the NLO weight.
*/
double Vtilde_universal(realVVKinematics S) const;
/**
* Function for calculation of the \f$q\bar{q}\f$ initiated real
* contribution.
*/
double Ctilde_Ltilde_qq_on_x(tcPDPtr a,tcPDPtr b,realVVKinematics C) const;
/**
* Function for calculation of the \f$gq\f$ initiated real
* contribution.
*/
double Ctilde_Ltilde_gq_on_x(tcPDPtr a,tcPDPtr b,realVVKinematics C) const;
/**
* Function for calculation of the \f$q\bar{q}\f$ initiated real
* contribution.
*/
double Rtilde_Ltilde_qqb_on_x(tcPDPtr a,tcPDPtr b) const;
/**
* Function for calculation of the \f$qg\f$ initiated real
* contribution.
*/
double Rtilde_Ltilde_qg_on_x(tcPDPtr a,tcPDPtr b) const;
/**
* Function for calculation of the \f$gqb\f$ initiated real
* contribution.
*/
double Rtilde_Ltilde_gqb_on_x(tcPDPtr a,tcPDPtr b) const;
/**
* The regular part of the virtual correction matrix element(s).
* For WZ production this is given by Equation B.2 in NPB 383 (1992)
* 3-44 *** modulo a factor 1/(2s) ***, which is a flux factor that
* those authors absorb in the matrix element.
*/
double M_V_regular(realVVKinematics S) const;
/**
* Member variable to store the
* regular part of the virtual correction matrix element(s).
* For WZ production this is given by Equation B.2 in NPB 383 (1992)
* 3-44 *** modulo a factor 1/(2s) ***, which is a flux factor that
* those authors absorb in the matrix element.
*/
mutable double M_V_regular_;
/**
* The matrix element q + qb -> n + g times tk*uk
*/
Energy2 t_u_M_R_qqb(realVVKinematics R) const;
/**
* Member variable to store the matrix element q + qb -> n + g times tk*uk
*/
mutable Energy2 t_u_M_R_qqb_;
/**
* The matrix element q + g -> n + q times tk*uk
*/
Energy2 t_u_M_R_qg(realVVKinematics R) const;
/**
* Member variable to store the matrix element q + g -> n + q times tk*uk
*/
mutable Energy2 t_u_M_R_qg_;
/**
* The matrix element g + qb -> n + q times tk*uk
*/
Energy2 t_u_M_R_gqb(realVVKinematics R) const;
/**
* Member variable to store the matrix element g + qb -> n + q times tk*uk
*/
mutable Energy2 t_u_M_R_gqb_;
/**
* The matrix element q + qb -> n + g times (tk*uk)^2 - using helicity amplitudes
*/
Energy2 t_u_M_R_qqb_hel_amp(realVVKinematics R) const;
/**
* Member variable to store the
* matrix element q + qb -> n + g times (tk*uk)^2 - using helicity amplitudes
*/
mutable Energy2 t_u_M_R_qqb_hel_amp_;
/**
* The matrix element q + g -> n + q times (tk*uk)^2 - using helicity amplitudes
*/
Energy2 t_u_M_R_qg_hel_amp(realVVKinematics R) const;
/**
* Member variable to store the
* matrix element q + g -> n + q times (tk*uk)^2 - using helicity amplitudes
*/
mutable Energy2 t_u_M_R_qg_hel_amp_;
/**
* The matrix element g + qb -> n + qb times (tk*uk)^2 - using helicity amplitudes
*/
Energy2 t_u_M_R_gqb_hel_amp(realVVKinematics R) const;
/**
* Member variable to store the
* matrix element g + qb -> n + qb times (tk*uk)^2 - using helicity amplitudes
*/
mutable Energy2 t_u_M_R_gqb_hel_amp_;
/**
* The leading order matrix element - using helicity amplitudes
*/
double lo_me() const;
/**
* The Born matrix element as given in Equation 3.1 - 3.3 in NPB 383
* (1992) *** modulo a factor 1/(2s) ***, which is a flux factor that
* those authors absorb in the matrix element.
*/
double M_Born_WZ(bornVVKinematics B) const;
/**
* Member variable to store the
* Born matrix element as given in Equation 3.1 - 3.3 in NPB 383
* (1992) *** modulo a factor 1/(2s) ***, which is a flux factor that
* those authors absorb in the matrix element.
*/
mutable double M_Born_;
/**
* The Born matrix element as given in Equation 2.18 - 2.19 in NPB 357
* (1991) *** modulo a factor 1/(2s) ***, which is a flux factor that
* those authors absorb in the matrix element.
*/
double M_Born_ZZ(bornVVKinematics B) const;
/**
* M_V_regular_ZZ is the regular part of the one-loop ZZ matrix element
* exactly as defined in Eqs. B.1 & B.2 of NPB 357(1991)409-438 ***
* modulo a factor 1/(2s) ***, which is a flux factor that
* those authors absorb in the matrix element.
*/
double M_V_regular_ZZ(realVVKinematics S) const;
/**
* t_u_M_R_qqb_ZZ is the q + qb -> n + g times tk*uk real emission
* matrix element as defined in Eq. C.1 of NPB 357(1991)409-438 ***
* modulo a factor 1/(2s) ***, which is a flux factor that
* those authors absorb in the matrix element.
*/
Energy2 t_u_M_R_qqb_ZZ(realVVKinematics R) const;
/**
* The Born matrix element as given in Equation 3.2 - 3.8 in NPB 410
* (1993) *** modulo a factor 1/(2s) ***, which is a flux factor that
* those authors absorb in the matrix element.
*/
double M_Born_WW(bornVVKinematics B) const;
/**
* M_V_regular_WW is the regular part of the one-loop WW matrix element
* exactly as defined in Eqs. C.1 - C.7 of of NPB 410(1993)280-324 ***
* modulo a factor 1/(2s) ***, which is a flux factor that
* those authors absorb in the matrix element.
*/
double M_V_regular_WW(realVVKinematics S) const;
/**
* t_u_M_R_qqb_WW is the q + qb -> n + g times tk*uk real emission
* matrix element as defined in Eq. D.1-D.5 of NPB 410(1993)280-324 ***
* modulo a factor 1/(2s) ***, which is a flux factor that
* those authors absorb in the matrix element.
*/
Energy2 t_u_M_R_qqb_WW(realVVKinematics R) const;
/**
* Return the factorion scale squared.
*/
Energy2 mu_F2() const;
/**
* Return the renormalisation scale squared.
*/
Energy2 mu_UV2() const;
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
inline virtual IBPtr clone() const { return new_ptr(*this); }
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
inline virtual IBPtr fullclone() const { return new_ptr(*this); }
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<MEPP2VVPowheg> initMEPP2VVPowheg;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEPP2VVPowheg & operator=(const MEPP2VVPowheg &);
private:
/**
* Parameters for the NLO weight
*/
//@{
/**
* Parameter to determine when to use limiting value of real emission
* matrix elements, to avoid rounding error issues.
*/
double tiny;
/**
* The BeamParticleData object for the plus and minus direction hadrons
*/
tcBeamPtr hadron_A_;
tcBeamPtr hadron_B_;
/**
* Born / virtual 2->2 kinematics.
*/
bornVVKinematics B_;
/**
* Soft limit of the 2->3 real emission kinematics.
*/
realVVKinematics S_;
/**
* Soft-collinear limit of the 2->3 kinematics (emission in +z direction).
*/
realVVKinematics SCp_;
/**
* The collinear limit of the 2->3 kinematics (emission in -z direction).
*/
realVVKinematics SCm_;
/**
* The collinear limit of the 2->3 kinematics (emission in +z direction).
*/
realVVKinematics Cp_;
/**
* The collinear limit of the 2->3 kinematics (emission in -z direction).
*/
realVVKinematics Cm_;
/**
* The resolved 2->3 real emission kinematics:
*/
realVVKinematics H_;
/**
* The ParticleData object for the plus and minus lo partons
*/
tcPDPtr ab_, bb_;
/**
* The ParticleData object for the quark and antiquark
* (which can be in a different order to ab_ and bb_).
*/
tcPDPtr quark_, antiquark_;
/**
* Values of the PDF's before radiation
*/
double lo_lumi_;
/**
* The value of the leading order qqbar->VV matrix element
*/
mutable double lo_me2_;
/**
* The CF_ colour factor
*/
double CF_;
/**
* The TR_ colour factor
*/
double TR_;
/**
* The number of colours
*/
double NC_;
/**
* The weak coupling and the sin (squared) of the Weinberg angle
*/
mutable double gW_, sin2ThetaW_;
/**
* The up and down, left handed, quark-boson couplings
*/
mutable double guL_, gdL_;
/**
* The up and down, right handed, quark-boson couplings (for WW & ZZ)
*/
mutable double guR_, gdR_;
/**
* The TGC coupling
*/
mutable double eZ_;
/**
* The TGC coupling squared. This is useful for debugging purposes
* when one wants to turn of t-channel * TGC interference contributions
* but leave the pure TGC contributions intact. It is also needed in
* order to transform WZ matrix elements into WW ones.
*/
mutable double eZ2_;
/**
* The CKM factor (Fij^2)
*/
mutable double Fij2_;
/**
* Whether to generate the positive, negative or leading order contribution
*/
unsigned int contrib_;
/**
* Whether to generate all channels contributions or just qqb or just
* qg+gqb contributions
*/
unsigned int channels_;
/**
* Whether to use a fixed or a running QCD coupling for the NLO weight
*/
unsigned int nlo_alphaS_opt_;
/**
* The value of alphaS to use for the nlo weight if nlo_alphaS_opt_=1
*/
double fixed_alphaS_;
/**
* Flag to remove or multiply in MCFM branching fractions for testing
*/
unsigned int removebr_;
/**
* Selects a dynamic (sHat) or fixed factorization scale
*/
unsigned int scaleopt_;
/**
* The factorization scale
*/
Energy mu_F_;
/**
* The renormalization scale
*/
Energy mu_UV_;
/**
* The pT of V1 in a radiative event in the lab frame (for scale setting only)
*/
Energy2 k1r_perp2_lab_;
/**
* The pT of V2 in a radiative event in the lab frame (for scale setting only)
*/
Energy2 k2r_perp2_lab_;
/**
* The ckm matrix elements (unsquared, to allow interference)
*/
vector< vector<Complex> > ckm_;
/**
* Option to impose helicity conservation on the real NLO ME's (greatly improves evaluation time).
*/
bool helicityConservation_;
/**
* The q + qb -> v1 + v2 + g helicity amplitudes
*/
mutable ProductionMatrixElement qqb_hel_amps_;
/**
* The q + g -> v1 + v2 + q helicity amplitudes
*/
mutable ProductionMatrixElement qg_hel_amps_;
/**
* The g + qb -> v1 + v2 + qb helicity amplitudes
*/
mutable ProductionMatrixElement gqb_hel_amps_;
//@}
/**
* The vertices
*/
//@{
/**
* The photon fermion-antifermion vertex
*/
AbstractFFVVertexPtr FFPvertex_;
/**
* The W fermion-antifermion vertex
*/
AbstractFFVVertexPtr FFWvertex_;
/**
* The Z fermion-antifermionvertex
*/
AbstractFFVVertexPtr FFZvertex_;
/**
* The triple electroweak gauge boson vertex
*/
AbstractVVVVertexPtr WWWvertex_;
/**
* The quark-antiquark gluon vertex
*/
AbstractFFVVertexPtr FFGvertex_;
//@}
/**
* The value of \f$\alpha_S\f$ used for the calculation
*/
mutable double alphaS_;
protected:
/**
* Returns the matrix element for a given type of process,
* rapidity of the jet \f$y_j\f$ and transverse momentum \f$p_T\f$
* @param emis_type the type of emission,
* (0 is \f$q\bar{q}\to Vg\f$, 1 is \f$qg\to Vq\f$ and 2 is \f$g\bar{q}\to V\bar{q}\f$)
* @param pT The transverse momentum of the jet
* @param R The object containing the kinematics
*/
double getResult(int emis_type, realVVKinematics R, Energy pT);
/**
* generates the hardest emission (yj,p)
* @param pnew The momenta of the new particles
* @param emissiontype The type of emission, as for getResult
* @return Whether not an emission was generated
*/
bool getEvent(vector<Lorentz5Momentum> & pnew,unsigned int & emissiontype);
/**
* sets the QCD, EW and PDF scales
* @param pT The pT of the current step in the veto algorithm
*/
void setTheScales(Energy pT);
/**
* The matrix element q + qb -> n + g times tk*uk
*/
Energy2 t_u_M_R_qqb_hel_amp(realVVKinematics R, bool getMatrix) const;
/**
* The matrix element q + g -> n + q times tk*uk
*/
Energy2 t_u_M_R_qg_hel_amp(realVVKinematics R, bool getMatrix) const;
/**
* The matrix element g + qb -> n + q times tk*uk
*/
Energy2 t_u_M_R_gqb_hel_amp(realVVKinematics R, bool getMatrix) const;
/**
* The matrix element for the kinematical configuration
* previously provided by the last call to setKinematics(), suitably
* scaled by sHat() to give a dimension-less number.
* @return the matrix element scaled with sHat() to give a
* dimensionless number.
*/
double lo_me(bool getMatrix) const;
/**
* Recalculate hard vertex to include spin correlations for radiative events.
*/
void recalculateVertex();
/**
* Member which selects a two body decay mode for each vector
* boson and distributes decay products isotropically
*/
bool isotropicDecayer();
/**
* The triangle function lambda(x,y,z)=sqrt(x^2+y^2+z^2-2*x*y-2*y*z-2*x*z)
*/
Energy2 triangleFn(Energy2,Energy2,Energy2);
private:
/**
* If this boolean is true the n+1 body helicity amplitudes will be
* used to calculate a hard vertex based on those kinematics for spin
* correlations in the decays.
*/
bool realMESpinCorrelations_;
/**
* The colour & spin averaged n-body (leading order) matrix element squared.
*/
double lo_me_;
/**
* The resolved 2->3 real emission kinematics.
*/
realVVKinematics R_;
/**
* This specifies the emitting configuration:
* 1: q + qbar -> V1 + V2 + g
* 2: q + g -> V1 + V2 + q
* 3: g + qbar -> V1 + V2 + qbar.
*/
unsigned int channel_;
/**
* Identifies the space-like mother of the branching
* as quark (+1) or antiquark (-1):
*/
int fermionNumberOfMother_;
/**
* Pointer to the object calculating the strong coupling
*/
ShowerAlphaPtr showerAlphaS_;
/**
* Constants for the sampling. The distribution is assumed to have the
* form \f$\frac{c}{{\rm GeV}}\times\left(\frac{{\rm GeV}}{p_T}\right)^n\f$
*/
//@{
/**
* The power, \f$n\f$, for the sampling
*/
double power_;
/**
* The prefactor, \f$c\f$ for the \f$q\bar{q}\f$ channel
*/
double preqqbar_;
/**
* The prefactor, \f$c\f$ for the \f$qg\f$ channel
*/
double preqg_;
/**
* The prefactor, \f$c\f$ for the \f$g\bar{q}\f$ channel
*/
double pregqbar_;
/**
* The QCD beta function divided by 4pi, (11-2/3*nf)/4/pi, with nf = 5.
*/
double b0_;
/**
* The fundamental QCD scale in the one-loop alpha_{S} used for the crude
* (not the very crude) overestimate of the Sudakov exponent. The default
* value is set so such that alphaS(MZ), neglecting all flavour threshold
* effects i.e. MZ*exp(-1/2/b0_/alphaS(MZ)).
*/
Energy LambdaQCD_;
/**
* The prefactors as a vector for easy use
*/
vector<double> prefactor_;
//@}
/**
* Properties of the incoming particles
*/
//@{
/**
* Pointers to the ShowerProgenitor objects for the partons
*/
ShowerProgenitorPtr qProgenitor_;
ShowerProgenitorPtr qbProgenitor_;
/**
* Pointers to the Shower particle objects for the partons
*/
ShowerParticlePtr showerQuark_;
ShowerParticlePtr showerAntiquark_;
/**
* Pointers to the BeamParticleData objects
*/
tcBeamPtr qHadron_;
tcBeamPtr qbHadron_;
//@}
/**
* Properties of the boson and jets
*/
//@{
/**
* Pointers to the Shower particle objects for the partons
*/
PPtr gluon_;
ShowerParticlePtr V1_;
ShowerParticlePtr V2_;
vector<PPtr> children_;
vector<PPtr> photons_;
/**
* Flag indicating if the q & qbar are flipped or not i.e. this
* is true if q enters from the -z direction in the lab frame.
*/
bool flipped_;
/**
* the rapidity of the jet
*/
double Yk_;
/**
* The transverse momentum of the jet
*/
Energy pT_;
//@}
/**
* The transverse momentum of the jet
*/
Energy min_pT_;
// Work out the scales we want to use in the matrix elements and the pdfs:
/**
* Scale for alpha_S: pT^2 of the diboson system.
*/
Energy2 QCDScale_;
/**
* Scale for real emission PDF:
*/
Energy2 PDFScale_;
/**
* Scale of electroweak vertices: mVV^2 the invariant mass of the diboson system.
*/
Energy2 EWScale_;
/**
* A matrix to hold the home-grown production matrix element
*/
mutable Complex productionMatrix_[3][3][3][3];
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of MEPP2VVPowheg. */
template <>
struct BaseClassTrait<Herwig::MEPP2VVPowheg,1> {
/** Typedef of the first base class of MEPP2VVPowheg. */
typedef Herwig::MEPP2VV NthBase;
};
/** This template specialization informs ThePEG about the name of
* the MEPP2VVPowheg class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::MEPP2VVPowheg>
: public ClassTraitsBase<Herwig::MEPP2VVPowheg> {
/** Return a platform-independent class name */
static string className() { return "Herwig::MEPP2VVPowheg"; }
/**
* The name of a file containing the dynamic library where the class
* MEPP2VVPowheg is implemented. It may also include several, space-separated,
* libraries if the class MEPP2VVPowheg depends on other classes (base classes
* excepted). In this case the listed libraries will be dynamically
* linked in the order they are specified.
*/
static string library() { return "HwMEHadron.so HwPowhegMEHadron.so"; }
};
/** @endcond */
}
#endif /* HERWIG_MEPP2VVPowheg_H */
diff --git a/Shower/Base/Evolver.cc b/Shower/Base/Evolver.cc
--- a/Shower/Base/Evolver.cc
+++ b/Shower/Base/Evolver.cc
@@ -1,3629 +1,3214 @@
// -*- C++ -*-
//
// Evolver.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the Evolver class.
//
#include "Evolver.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/RefVector.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Shower/Base/ShowerParticle.h"
#include "ThePEG/Utilities/EnumIO.h"
#include "ShowerKinematics.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Handlers/EventHandler.h"
#include "ThePEG/Utilities/Throw.h"
#include "ShowerTree.h"
#include "ShowerProgenitor.h"
#include "KinematicsReconstructor.h"
#include "PartnerFinder.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "ThePEG/PDT/DecayMode.h"
#include "Herwig/Shower/ShowerHandler.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ShowerVertex.h"
#include "ThePEG/Repository/CurrentGenerator.h"
#include "Herwig/MatrixElement/Matchbox/Base/SubtractedME.h"
#include "Herwig/MatrixElement/Matchbox/MatchboxFactory.h"
#include "ThePEG/Handlers/StandardXComb.h"
using namespace Herwig;
namespace {
/**
* A struct to order the particles in the same way as in the DecayMode's
*/
struct ParticleOrdering {
/**
* Operator for the ordering
* @param p1 The first ParticleData object
* @param p2 The second ParticleData object
*/
bool operator() (tcPDPtr p1, tcPDPtr p2) {
return abs(p1->id()) > abs(p2->id()) ||
( abs(p1->id()) == abs(p2->id()) && p1->id() > p2->id() ) ||
( p1->id() == p2->id() && p1->fullName() > p2->fullName() );
}
};
typedef multiset<tcPDPtr,ParticleOrdering> OrderedParticles;
/**
* Cached lookup of decay modes.
* Generator::findDecayMode() is not efficient.
*/
tDMPtr findDecayMode(const string & tag) {
static map<string,DMPtr> cache;
map<string,DMPtr>::const_iterator pos = cache.find(tag);
if ( pos != cache.end() )
return pos->second;
tDMPtr dm = CurrentGenerator::current().findDecayMode(tag);
cache[tag] = dm;
return dm;
}
}
DescribeClass<Evolver,Interfaced>
describeEvolver ("Herwig::Evolver","HwShower.so");
bool Evolver::_hardEmissionModeWarn = true;
bool Evolver::_missingTruncWarn = true;
IBPtr Evolver::clone() const {
return new_ptr(*this);
}
IBPtr Evolver::fullclone() const {
return new_ptr(*this);
}
void Evolver::persistentOutput(PersistentOStream & os) const {
os << _model << _splittingGenerator << _maxtry
<< _meCorrMode << _hardVetoMode << _hardVetoRead << _hardVetoReadOption
<< _limitEmissions << _spinOpt << _softOpt << _hardPOWHEG
<< ounit(_iptrms,GeV) << _beta << ounit(_gamma,GeV) << ounit(_iptmax,GeV)
<< _vetoes << _trunc_Mode << _hardEmissionMode << _reconOpt
<< isMCatNLOSEvent << isMCatNLOHEvent
<< isPowhegSEvent << isPowhegHEvent
<< theFactorizationScaleFactor << theRenormalizationScaleFactor << ounit(muPt,GeV)
- << interaction_ << _maxTryFSR << _maxFailFSR << _fracFSR << interactions_.size();
- for(unsigned int ix=0;ix<interactions_.size();++ix)
- os << oenum(interactions_[ix]);
+ << oenum(interaction_) << _maxTryFSR << _maxFailFSR << _fracFSR;
}
void Evolver::persistentInput(PersistentIStream & is, int) {
- unsigned int isize;
is >> _model >> _splittingGenerator >> _maxtry
>> _meCorrMode >> _hardVetoMode >> _hardVetoRead >> _hardVetoReadOption
>> _limitEmissions >> _spinOpt >> _softOpt >> _hardPOWHEG
>> iunit(_iptrms,GeV) >> _beta >> iunit(_gamma,GeV) >> iunit(_iptmax,GeV)
>> _vetoes >> _trunc_Mode >> _hardEmissionMode >> _reconOpt
>> isMCatNLOSEvent >> isMCatNLOHEvent
>> isPowhegSEvent >> isPowhegHEvent
>> theFactorizationScaleFactor >> theRenormalizationScaleFactor >> iunit(muPt,GeV)
- >> interaction_ >> _maxTryFSR >> _maxFailFSR >> _fracFSR >> isize;
- interactions_.resize(isize);
- for(unsigned int ix=0;ix<interactions_.size();++ix)
- is >> ienum(interactions_[ix]);
+ >> ienum(interaction_) >> _maxTryFSR >> _maxFailFSR >> _fracFSR;
}
void Evolver::doinit() {
Interfaced::doinit();
- // interactions may have been changed through a setup file so we
- // clear it up here
- interactions_.clear();
- if(interaction_==0) {
- interactions_.push_back(ShowerInteraction::QCD);
- interactions_.push_back(ShowerInteraction::QED);
- }
- else if(interaction_==1) {
- interactions_.push_back(ShowerInteraction::QCD);
- }
- else if(interaction_==2) {
- interactions_.push_back(ShowerInteraction::QED);
- interactions_.push_back(ShowerInteraction::QCD);
- }
- else if(interaction_==3) {
- interactions_.push_back(ShowerInteraction::QED);
- }
- else if(interaction_==4) {
- interactions_.push_back(ShowerInteraction::QEDQCD);
- }
// calculate max no of FSR vetos
_maxFailFSR = max(int(_maxFailFSR), int(_fracFSR*double(generator()->N())));
}
void Evolver::Init() {
static ClassDocumentation<Evolver> documentation
("This class is responsible for carrying out the showering,",
"including the kinematics reconstruction, in a given scale range,"
"including the option of the POWHEG approach to simulated next-to-leading order"
" radiation\\cite{Nason:2004rx}.",
"%\\cite{Nason:2004rx}\n"
"\\bibitem{Nason:2004rx}\n"
" P.~Nason,\n"
" ``A new method for combining NLO QCD with shower Monte Carlo algorithms,''\n"
" JHEP {\\bf 0411} (2004) 040\n"
" [arXiv:hep-ph/0409146].\n"
" %%CITATION = JHEPA,0411,040;%%\n");
static Reference<Evolver,SplittingGenerator>
interfaceSplitGen("SplittingGenerator",
"A reference to the SplittingGenerator object",
&Herwig::Evolver::_splittingGenerator,
false, false, true, false);
static Reference<Evolver,ShowerModel> interfaceShowerModel
("ShowerModel",
"The pointer to the object which defines the shower evolution model.",
&Evolver::_model, false, false, true, false, false);
static Parameter<Evolver,unsigned int> interfaceMaxTry
("MaxTry",
"The maximum number of attempts to generate the shower from a"
" particular ShowerTree",
&Evolver::_maxtry, 100, 1, 1000,
false, false, Interface::limited);
static Switch<Evolver, unsigned int> ifaceMECorrMode
("MECorrMode",
"Choice of the ME Correction Mode",
&Evolver::_meCorrMode, 1, false, false);
static SwitchOption off
(ifaceMECorrMode,"No","MECorrections off", 0);
static SwitchOption on
(ifaceMECorrMode,"Yes","hard+soft on", 1);
static SwitchOption hard
(ifaceMECorrMode,"Hard","only hard on", 2);
static SwitchOption soft
(ifaceMECorrMode,"Soft","only soft on", 3);
static Switch<Evolver, unsigned int> ifaceHardVetoMode
("HardVetoMode",
"Choice of the Hard Veto Mode",
&Evolver::_hardVetoMode, 1, false, false);
static SwitchOption HVoff
(ifaceHardVetoMode,"No","hard vetos off", 0);
static SwitchOption HVon
(ifaceHardVetoMode,"Yes","hard vetos on", 1);
static SwitchOption HVIS
(ifaceHardVetoMode,"Initial", "only IS emissions vetoed", 2);
static SwitchOption HVFS
(ifaceHardVetoMode,"Final","only FS emissions vetoed", 3);
static Switch<Evolver, unsigned int> ifaceHardVetoRead
("HardVetoScaleSource",
"If hard veto scale is to be read",
&Evolver::_hardVetoRead, 0, false, false);
static SwitchOption HVRcalc
(ifaceHardVetoRead,"Calculate","Calculate from hard process", 0);
static SwitchOption HVRread
(ifaceHardVetoRead,"Read","Read from XComb->lastScale", 1);
static Switch<Evolver, bool> ifaceHardVetoReadOption
("HardVetoReadOption",
"Apply read-in scale veto to all collisions or just the primary one?",
&Evolver::_hardVetoReadOption, false, false, false);
static SwitchOption AllCollisions
(ifaceHardVetoReadOption,
"AllCollisions",
"Read-in pT veto applied to primary and secondary collisions.",
false);
static SwitchOption PrimaryCollision
(ifaceHardVetoReadOption,
"PrimaryCollision",
"Read-in pT veto applied to primary but not secondary collisions.",
true);
static Parameter<Evolver, Energy> ifaceiptrms
("IntrinsicPtGaussian",
"RMS of intrinsic pT of Gaussian distribution:\n"
"2*(1-Beta)*exp(-sqr(intrinsicpT/RMS))/sqr(RMS)",
&Evolver::_iptrms, GeV, ZERO, ZERO, 1000000.0*GeV,
false, false, Interface::limited);
static Parameter<Evolver, double> ifacebeta
("IntrinsicPtBeta",
"Proportion of inverse quadratic distribution in generating intrinsic pT.\n"
"(1-Beta) is the proportion of Gaussian distribution",
&Evolver::_beta, 0, 0, 1,
false, false, Interface::limited);
static Parameter<Evolver, Energy> ifacegamma
("IntrinsicPtGamma",
"Parameter for inverse quadratic:\n"
"2*Beta*Gamma/(sqr(Gamma)+sqr(intrinsicpT))",
&Evolver::_gamma,GeV, ZERO, ZERO, 100000.0*GeV,
false, false, Interface::limited);
static Parameter<Evolver, Energy> ifaceiptmax
("IntrinsicPtIptmax",
"Upper bound on intrinsic pT for inverse quadratic",
&Evolver::_iptmax,GeV, ZERO, ZERO, 100000.0*GeV,
false, false, Interface::limited);
static RefVector<Evolver,ShowerVeto> ifaceVetoes
("Vetoes",
"The vetoes to be checked during showering",
&Evolver::_vetoes, -1,
false,false,true,true,false);
static Switch<Evolver,unsigned int> interfaceLimitEmissions
("LimitEmissions",
"Limit the number and type of emissions for testing",
&Evolver::_limitEmissions, 0, false, false);
static SwitchOption interfaceLimitEmissionsNoLimit
(interfaceLimitEmissions,
"NoLimit",
"Allow an arbitrary number of emissions",
0);
static SwitchOption interfaceLimitEmissionsOneInitialStateEmission
(interfaceLimitEmissions,
"OneInitialStateEmission",
"Allow one emission in the initial state and none in the final state",
1);
static SwitchOption interfaceLimitEmissionsOneFinalStateEmission
(interfaceLimitEmissions,
"OneFinalStateEmission",
"Allow one emission in the final state and none in the initial state",
2);
static SwitchOption interfaceLimitEmissionsHardOnly
(interfaceLimitEmissions,
"HardOnly",
"Only allow radiation from the hard ME correction",
3);
static SwitchOption interfaceLimitEmissionsOneEmission
(interfaceLimitEmissions,
"OneEmission",
"Allow one emission in either the final state or initial state, but not both",
4);
static Switch<Evolver,bool> interfaceTruncMode
("TruncatedShower", "Include the truncated shower?",
&Evolver::_trunc_Mode, 1, false, false);
static SwitchOption interfaceTruncMode0
(interfaceTruncMode,"No","Truncated Shower is OFF", 0);
static SwitchOption interfaceTruncMode1
(interfaceTruncMode,"Yes","Truncated Shower is ON", 1);
static Switch<Evolver,int> interfaceHardEmissionMode
("HardEmissionMode",
"Whether to use ME corrections or POWHEG for the hardest emission",
&Evolver::_hardEmissionMode, 0, false, false);
static SwitchOption interfaceHardEmissionModeDecayMECorrection
(interfaceHardEmissionMode,
"DecayMECorrection",
"Old fashioned ME correction for decays only",
-1);
static SwitchOption interfaceHardEmissionModeMECorrection
(interfaceHardEmissionMode,
"MECorrection",
"Old fashioned ME correction",
0);
static SwitchOption interfaceHardEmissionModePOWHEG
(interfaceHardEmissionMode,
"POWHEG",
"Powheg style hard emission using internal matrix elements",
1);
static SwitchOption interfaceHardEmissionModeMatchboxPOWHEG
(interfaceHardEmissionMode,
"MatchboxPOWHEG",
"Powheg style emission for the hard process using Matchbox",
2);
static SwitchOption interfaceHardEmissionModeFullPOWHEG
(interfaceHardEmissionMode,
"FullPOWHEG",
"Powheg style emission for the hard process using Matchbox "
"and decays using internal matrix elements",
3);
- static Switch<Evolver,unsigned int > interfaceInteractions
- ("Interactions",
+ static Switch<Evolver,ShowerInteraction::Type > interfaceInteraction
+ ("Interaction",
"The interactions to be used in the shower",
- &Evolver::interaction_, 1, false, false);
- static SwitchOption interfaceInteractionsQCDFirst
- (interfaceInteractions,
- "QCDFirst",
- "QCD first then QED",
- 0);
- static SwitchOption interfaceInteractionsQCDOnly
- (interfaceInteractions,
+ &Evolver::interaction_, ShowerInteraction::QEDQCD, false, false);
+ static SwitchOption interfaceInteractionQCD
+ (interfaceInteraction,
"QCDOnly",
"Only QCD",
- 1);
- static SwitchOption interfaceInteractionsQEDFirst
- (interfaceInteractions,
- "QEDFirst",
- "QED first then QCD",
- 2);
- static SwitchOption interfaceInteractionsQEDOnly
- (interfaceInteractions,
+ ShowerInteraction::QCD);
+ static SwitchOption interfaceInteractionQEDOnly
+ (interfaceInteraction,
"QEDOnly",
"Only QED",
- 3);
- static SwitchOption interfaceInteractionsBothAtOnce
- (interfaceInteractions,
- "BothAtOnce",
- "Generate both at the same time",
- 4);
+ ShowerInteraction::QED);
+ static SwitchOption interfaceInteractionBothAtOnce
+ (interfaceInteraction,
+ "QEDQCD",
+ "QED and QCD",
+ ShowerInteraction::QEDQCD);
static Switch<Evolver,unsigned int> interfaceReconstructionOption
("ReconstructionOption",
"Treatment of the reconstruction of the transverse momentum of "
"a branching from the evolution scale.",
&Evolver::_reconOpt, 0, false, false);
static SwitchOption interfaceReconstructionOptionCutOff
(interfaceReconstructionOption,
"CutOff",
"Use the cut-off masses in the calculation",
0);
static SwitchOption interfaceReconstructionOptionOffShell
(interfaceReconstructionOption,
"OffShell",
"Use the off-shell masses in the calculation veto the emission of the parent,"
" no veto in generation of emissions from children",
1);
static SwitchOption interfaceReconstructionOptionOffShell2
(interfaceReconstructionOption,
"OffShell2",
"Use the off-shell masses in the calculation veto the emissions from the children."
" no veto in generation of emissions from children",
2);
static SwitchOption interfaceReconstructionOptionOffShell3
(interfaceReconstructionOption,
"OffShell3",
"Use the off-shell masses in the calculation veto the emissions from the children."
" veto in generation of emissions from children using cut-off for second parton",
3);
static Switch<Evolver,unsigned int> interfaceSpinCorrelations
("SpinCorrelations",
"Treatment of spin correlations in the parton shower",
&Evolver::_spinOpt, 1, false, false);
static SwitchOption interfaceSpinCorrelationsOff
(interfaceSpinCorrelations,
"No",
"No spin correlations",
0);
static SwitchOption interfaceSpinCorrelationsSpin
(interfaceSpinCorrelations,
"Yes",
"Include the azimuthal spin correlations only",
1);
static Switch<Evolver,unsigned int> interfaceSoftCorrelations
("SoftCorrelations",
"Option for the treatment of soft correlations in the parton shower",
&Evolver::_softOpt, 2, false, false);
static SwitchOption interfaceSoftCorrelationsNone
(interfaceSoftCorrelations,
"No",
"No soft correlations",
0);
static SwitchOption interfaceSoftCorrelationsFull
(interfaceSoftCorrelations,
"Full",
"Use the full eikonal",
1);
static SwitchOption interfaceSoftCorrelationsSingular
(interfaceSoftCorrelations,
"Singular",
"Use original Webber-Marchisini form",
2);
static Switch<Evolver,bool> interfaceHardPOWHEG
("HardPOWHEG",
"Treatment of powheg emissions which are too hard to have a shower interpretation",
&Evolver::_hardPOWHEG, false, false, false);
static SwitchOption interfaceHardPOWHEGAsShower
(interfaceHardPOWHEG,
"AsShower",
"Still interpret as shower emissions",
false);
static SwitchOption interfaceHardPOWHEGRealEmission
(interfaceHardPOWHEG,
"RealEmission",
"Generate shower from the real emmission configuration",
true);
static Parameter<Evolver,unsigned int> interfaceMaxTryFSR
("MaxTryFSR",
"The maximum number of attempted FSR emissions in"
" the generation of the FSR",
&Evolver::_maxTryFSR, 100000, 10, 100000000,
false, false, Interface::limited);
static Parameter<Evolver,unsigned int> interfaceMaxFailFSR
("MaxFailFSR",
"Maximum number of failures generating the FSR",
&Evolver::_maxFailFSR, 100, 1, 100000000,
false, false, Interface::limited);
static Parameter<Evolver,double> interfaceFSRFailureFraction
("FSRFailureFraction",
"Maximum fraction of events allowed to fail due to too many FSR emissions",
&Evolver::_fracFSR, 0.001, 1e-10, 1,
false, false, Interface::limited);
}
void Evolver::generateIntrinsicpT(vector<ShowerProgenitorPtr> particlesToShower) {
_intrinsic.clear();
if ( !ipTon() || !isISRadiationON() ) return;
// don't do anything for the moment for secondary scatters
if( !ShowerHandler::currentHandler()->firstInteraction() ) return;
// generate intrinsic pT
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
// only consider initial-state particles
if(particlesToShower[ix]->progenitor()->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<Energy,double> pt = make_pair(ipt,UseRandom::rnd(Constants::twopi));
_intrinsic[particlesToShower[ix]] = pt;
}
}
void Evolver::setupMaximumScales(const vector<ShowerProgenitorPtr> & p,
XCPtr xcomb) {
// let POWHEG events radiate freely
if(_hardEmissionMode>0&&hardTree()) {
vector<ShowerProgenitorPtr>::const_iterator ckt = p.begin();
for (; ckt != p.end(); ckt++) (*ckt)->maxHardPt(Constants::MaxEnergy);
return;
}
// return if no vetos
if (!hardVetoOn()) return;
// find out if hard partonic subprocess.
bool isPartonic(false);
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit = _currenttree->incomingLines().begin();
Lorentz5Momentum pcm;
for(; cit!=currentTree()->incomingLines().end(); ++cit) {
pcm += cit->first->progenitor()->momentum();
isPartonic |= cit->first->progenitor()->coloured();
}
// find minimum pt from hard process, the maximum pt from all outgoing
// coloured lines (this is simpler and more general than
// 2stu/(s^2+t^2+u^2)). Maximum scale for scattering processes will
// be transverse mass.
Energy ptmax = generator()->maximumCMEnergy();
// general case calculate the scale
if (!hardVetoXComb()||
(hardVetoReadOption()&&
!ShowerHandler::currentHandler()->firstInteraction())) {
// scattering process
if(currentTree()->isHard()) {
assert(xcomb);
// coloured incoming particles
if (isPartonic) {
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt = currentTree()->outgoingLines().begin();
for(; cjt!=currentTree()->outgoingLines().end(); ++cjt) {
if (cjt->first->progenitor()->coloured())
ptmax = min(ptmax,cjt->first->progenitor()->momentum().mt());
}
}
if (ptmax == generator()->maximumCMEnergy() ) ptmax = pcm.m();
if(hardVetoXComb()&&hardVetoReadOption()&&
!ShowerHandler::currentHandler()->firstInteraction()) {
ptmax=min(ptmax,sqrt(xcomb->lastShowerScale()));
}
}
// decay, incoming() is the decaying particle.
else {
ptmax = currentTree()->incomingLines().begin()->first
->progenitor()->momentum().mass();
}
}
// hepeup.SCALUP is written into the lastXComb by the
// LesHouchesReader itself - use this by user's choice.
// Can be more general than this.
else {
if(currentTree()->isHard()) {
assert(xcomb);
ptmax = sqrt( xcomb->lastShowerScale() );
}
else {
ptmax = currentTree()->incomingLines().begin()->first
->progenitor()->momentum().mass();
}
}
ptmax *= ShowerHandler::currentHandler()->hardScaleFactor();
// set maxHardPt for all progenitors. For partonic processes this
// is now the max pt in the FS, for non-partonic processes or
// processes with no coloured FS the invariant mass of the IS
vector<ShowerProgenitorPtr>::const_iterator ckt = p.begin();
for (; ckt != p.end(); ckt++) (*ckt)->maxHardPt(ptmax);
}
void Evolver::setupHardScales(const vector<ShowerProgenitorPtr> & p,
XCPtr xcomb) {
if ( hardVetoXComb() &&
(!hardVetoReadOption() ||
ShowerHandler::currentHandler()->firstInteraction()) ) {
Energy hardScale = ZERO;
if(currentTree()->isHard()) {
assert(xcomb);
hardScale = sqrt( xcomb->lastShowerScale() );
}
else {
hardScale = currentTree()->incomingLines().begin()->first
->progenitor()->momentum().mass();
}
hardScale *= ShowerHandler::currentHandler()->hardScaleFactor();
vector<ShowerProgenitorPtr>::const_iterator ckt = p.begin();
for (; ckt != p.end(); ckt++) (*ckt)->hardScale(hardScale);
muPt = hardScale;
}
}
void Evolver::showerHardProcess(ShowerTreePtr hard, XCPtr xcomb) {
isMCatNLOSEvent = false;
isMCatNLOHEvent = false;
isPowhegSEvent = false;
isPowhegHEvent = false;
Ptr<SubtractedME>::tptr subme;
Ptr<MatchboxMEBase>::tptr me;
Ptr<SubtractionDipole>::tptr dipme;
Ptr<StandardXComb>::ptr sxc = dynamic_ptr_cast<Ptr<StandardXComb>::ptr>(xcomb);
if ( sxc ) {
subme = dynamic_ptr_cast<Ptr<SubtractedME>::tptr>(sxc->matrixElement());
me = dynamic_ptr_cast<Ptr<MatchboxMEBase>::tptr>(sxc->matrixElement());
dipme = dynamic_ptr_cast<Ptr<SubtractionDipole>::tptr>(sxc->matrixElement());
}
if ( subme ) {
if ( subme->showerApproximation() ) {
theShowerApproximation = subme->showerApproximation();
// separate MCatNLO and POWHEG-type corrections
if ( !subme->showerApproximation()->needsSplittingGenerator() ) {
if ( subme->realShowerSubtraction() )
isMCatNLOHEvent = true;
else if ( subme->virtualShowerSubtraction() )
isMCatNLOSEvent = true;
}
else {
if ( subme->realShowerSubtraction() )
isPowhegHEvent = true;
else if ( subme->virtualShowerSubtraction() || subme->loopSimSubtraction() )
isPowhegSEvent = true;
}
}
} else if ( me ) {
if ( me->factory()->showerApproximation() ) {
theShowerApproximation = me->factory()->showerApproximation();
if ( !me->factory()->showerApproximation()->needsSplittingGenerator() )
isMCatNLOSEvent = true;
else
isPowhegSEvent = true;
}
}
string error = "Inconsistent hard emission set-up in Evolver::showerHardProcess(). ";
if ( ( isMCatNLOSEvent || isMCatNLOHEvent ) ){
if (_hardEmissionMode > 1)
throw Exception() << error
<< "Cannot generate POWHEG matching with MC@NLO shower "
<< "approximation. Add 'set Evolver:HardEmissionMode 0' to input file."
<< Exception::runerror;
if ( ShowerHandler::currentHandler()->canHandleMatchboxTrunc())
throw Exception() << error
<< "Cannot use truncated qtilde shower with MC@NLO shower "
<< "approximation. Set LHCGenerator:EventHandler"
<< ":CascadeHandler to '/Herwig/Shower/ShowerHandler' or "
<< "'/Herwig/DipoleShower/DipoleShowerHandler'."
<< Exception::runerror;
}
else if ( ((isPowhegSEvent || isPowhegHEvent) || dipme) &&
_hardEmissionMode < 2){
if ( ShowerHandler::currentHandler()->canHandleMatchboxTrunc())
throw Exception() << error
<< "Unmatched events requested for POWHEG shower "
<< "approximation. Set Evolver:HardEmissionMode to "
<< "'MatchboxPOWHEG' or 'FullPOWHEG'."
<< Exception::runerror;
else if (_hardEmissionModeWarn){
_hardEmissionModeWarn = false;
_hardEmissionMode+=2;
throw Exception() << error
<< "Unmatched events requested for POWHEG shower "
<< "approximation. Changing Evolver:HardEmissionMode from "
<< _hardEmissionMode-2 << " to " << _hardEmissionMode
<< Exception::warning;
}
}
if ( isPowhegSEvent || isPowhegHEvent) {
if (theShowerApproximation->needsTruncatedShower() &&
!ShowerHandler::currentHandler()->canHandleMatchboxTrunc() )
throw Exception() << error
<< "Current shower handler cannot generate truncated shower. "
<< "Set Generator:EventHandler:CascadeHandler to "
<< "'/Herwig/Shower/PowhegShowerHandler'."
<< Exception::runerror;
}
else if ( dipme && _missingTruncWarn){
_missingTruncWarn=false;
throw Exception() << "Warning: POWHEG shower approximation used without "
<< "truncated shower. Set Generator:EventHandler:"
<< "CascadeHandler to '/Herwig/Shower/PowhegShowerHandler' and "
<< "'MEMatching:TruncatedShower Yes'."
<< Exception::warning;
}
else if ( !dipme && _hardEmissionMode > 1 &&
ShowerHandler::currentHandler()->firstInteraction())
throw Exception() << error
<< "POWHEG matching requested for LO events. Include "
<< "'set Factory:ShowerApproximation MEMatching' in input file."
<< Exception::runerror;
_hardme = HwMEBasePtr();
// extract the matrix element
tStdXCombPtr lastXC = dynamic_ptr_cast<tStdXCombPtr>(xcomb);
if(lastXC) {
_hardme = dynamic_ptr_cast<HwMEBasePtr>(lastXC->matrixElement());
}
_decayme = HwDecayerBasePtr();
// set the current tree
currentTree(hard);
hardTree(HardTreePtr());
// number of attempts if more than one interaction switched on
unsigned int interactionTry=0;
do {
try {
// generate the showering
doShowering(true,xcomb);
// if no vetos return
return;
}
catch (InteractionVeto) {
currentTree()->clear();
++interactionTry;
}
}
while(interactionTry<=5);
throw Exception() << "Too many tries for shower in "
<< "Evolver::showerHardProcess()"
<< Exception::eventerror;
}
void Evolver::hardMatrixElementCorrection(bool hard) {
// set the initial enhancement factors for the soft correction
_initialenhance = 1.;
_finalenhance = 1.;
// if hard matrix element switched off return
if(!MECOn(hard)) return;
// see if we can get the correction from the matrix element
// or decayer
if(hard) {
if(_hardme&&_hardme->hasMECorrection()) {
_hardme->initializeMECorrection(_currenttree,
_initialenhance,_finalenhance);
if(hardMEC(hard))
_hardme->applyHardMatrixElementCorrection(_currenttree);
}
}
else {
if(_decayme&&_decayme->hasMECorrection()) {
_decayme->initializeMECorrection(_currenttree,
_initialenhance,_finalenhance);
if(hardMEC(hard))
_decayme->applyHardMatrixElementCorrection(_currenttree);
}
}
}
ShowerParticleVector Evolver::createTimeLikeChildren(tShowerParticlePtr particle, IdList ids) {
// Create the ShowerParticle objects for the two children of
// the emitting particle; set the parent/child relationship
// if same as definition create particles, otherwise create cc
tcPDPtr pdata[2];
for(unsigned int ix=0;ix<2;++ix) pdata[ix]=getParticleData(ids[ix+1]);
if(particle->id()!=ids[0]) {
for(unsigned int ix=0;ix<2;++ix) {
tPDPtr cc(pdata[ix]->CC());
if(cc) pdata[ix]=cc;
}
}
ShowerParticleVector children;
for(unsigned int ix=0;ix<2;++ix) {
children.push_back(new_ptr(ShowerParticle(pdata[ix],true)));
if(children[ix]->id()==_progenitor->id()&&!pdata[ix]->stable())
children[ix]->set5Momentum(Lorentz5Momentum(_progenitor->progenitor()->mass()));
else
children[ix]->set5Momentum(Lorentz5Momentum(pdata[ix]->mass()));
}
return children;
}
bool Evolver::timeLikeShower(tShowerParticlePtr particle,
ShowerInteraction::Type type,
Branching fb, bool first) {
// don't do anything if not needed
if(_limitEmissions == 1 || hardOnly() ||
( _limitEmissions == 2 && _nfs != 0) ||
( _limitEmissions == 4 && _nfs + _nis != 0) ) {
if(particle->spinInfo()) particle->spinInfo()->develop();
return false;
}
// too many tries
if(_nFSR>=_maxTryFSR) {
++_nFailedFSR;
// too many failed events
if(_nFailedFSR>=_maxFailFSR)
throw Exception() << "Too many events have failed due to too many shower emissions, in\n"
<< "Evolver::timeLikeShower(). Terminating run\n"
<< Exception::runerror;
throw Exception() << "Too many attempted emissions in Evolver::timeLikeShower()\n"
<< Exception::eventerror;
}
// generate the emission
ShowerParticleVector children;
int ntry=0;
// generate the emission
if(!fb.kinematics)
fb = selectTimeLikeBranching(particle,type,HardBranchingPtr());
// no emission, return
if(!fb.kinematics) {
if(particle->spinInfo()) particle->spinInfo()->develop();
return false;
}
Branching fc[2];
bool setupChildren = true;
while (ntry<50) {
fc[0] = Branching();
fc[1] = Branching();
++ntry;
assert(fb.kinematics);
// has emitted
// Assign the shower kinematics to the emitting particle.
if(setupChildren) {
++_nFSR;
particle->showerKinematics(fb.kinematics);
// generate phi
fb.kinematics->phi(fb.sudakov->generatePhiForward(*particle,fb.ids,fb.kinematics));
// check highest pT
if(fb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(fb.kinematics->pT());
// create the children
children = createTimeLikeChildren(particle,fb.ids);
// update the children
particle->showerKinematics()->
updateChildren(particle, children,fb.type,_reconOpt>=3);
// update number of emissions
++_nfs;
if(_limitEmissions!=0) {
if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
if(particle->spinInfo()) particle->spinInfo()->develop();
return true;
}
setupChildren = false;
}
// select branchings for children
fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr());
fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr());
// old default
if(_reconOpt==0) {
// shower the first particle
if(fc[0].kinematics) timeLikeShower(children[0],type,fc[0],false);
if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
// shower the second particle
if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],false);
if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
break;
}
// Herwig default
else if(_reconOpt==1) {
// shower the first particle
if(fc[0].kinematics) timeLikeShower(children[0],type,fc[0],false);
if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
// shower the second particle
if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],false);
if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
// branching has happened
particle->showerKinematics()->updateParent(particle, children,fb.type);
// clean up the vetoed emission
if(particle->virtualMass()==ZERO) {
particle->showerKinematics(ShoKinPtr());
for(unsigned int ix=0;ix<children.size();++ix)
particle->abandonChild(children[ix]);
children.clear();
if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr());
particle->vetoEmission(fb.type,fb.kinematics->scale());
// generate the new emission
fb = selectTimeLikeBranching(particle,type,HardBranchingPtr());
// no emission, return
if(!fb.kinematics) {
if(particle->spinInfo()) particle->spinInfo()->develop();
return false;
}
setupChildren = true;
continue;
}
else
break;
}
// veto children
else if(_reconOpt>=2) {
// cut-off masses for the branching
const vector<Energy> & virtualMasses = fb.sudakov->virtualMasses(fb.ids);
// compute the masses of the children
Energy masses[3];
for(unsigned int ix=0;ix<2;++ix) {
if(fc[ix].kinematics) {
const vector<Energy> & vm = fc[ix].sudakov->virtualMasses(fc[ix].ids);
Energy2 q2 =
fc[ix].kinematics->z()*(1.-fc[ix].kinematics->z())*sqr(fc[ix].kinematics->scale());
if(fc[ix].ids[0]!=ParticleID::g) q2 += sqr(vm[0]);
masses[ix+1] = sqrt(q2);
}
else {
masses[ix+1] = virtualMasses[ix+1];
}
}
masses[0] = fb.ids[0]!=ParticleID::g ? virtualMasses[0] : ZERO;
double z = fb.kinematics->z();
Energy2 pt2 = z*(1.-z)*(z*(1.-z)*sqr(fb.kinematics->scale()) + sqr(masses[0]))
- sqr(masses[1])*(1.-z) - sqr(masses[2])*z;
if(pt2>=ZERO) {
break;
}
else {
// reset the scales for the children
for(unsigned int ix=0;ix<2;++ix) {
if(fc[ix].kinematics)
children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale());
else
children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO);
children[ix]->virtualMass(ZERO);
}
}
}
};
if(_reconOpt>=2) {
// shower the first particle
if(fc[0].kinematics) timeLikeShower(children[0],type,fc[0],false);
if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
// shower the second particle
if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],false);
if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
// branching has happened
particle->showerKinematics()->updateParent(particle, children,fb.type);
}
if(first&&!children.empty())
particle->showerKinematics()->resetChildren(particle,children);
if(particle->spinInfo()) particle->spinInfo()->develop();
return true;
}
bool
Evolver::spaceLikeShower(tShowerParticlePtr particle, PPtr beam,
ShowerInteraction::Type type) {
//using the pdf's associated with the ShowerHandler assures, that
//modified pdf's are used for the secondary interactions via
//CascadeHandler::resetPDFs(...)
tcPDFPtr pdf;
if(ShowerHandler::currentHandler()->firstPDF().particle() == _beam)
pdf = ShowerHandler::currentHandler()->firstPDF().pdf();
if(ShowerHandler::currentHandler()->secondPDF().particle() == _beam)
pdf = ShowerHandler::currentHandler()->secondPDF().pdf();
Energy freeze = ShowerHandler::currentHandler()->pdfFreezingScale();
// don't do anything if not needed
if(_limitEmissions == 2 || hardOnly() ||
( _limitEmissions == 1 && _nis != 0 ) ||
( _limitEmissions == 4 && _nis + _nfs != 0 ) ) {
if(particle->spinInfo()) particle->spinInfo()->develop();
return false;
}
Branching bb;
// generate branching
while (true) {
bb=_splittingGenerator->chooseBackwardBranching(*particle,beam,
_initialenhance,
_beam,type,
pdf,freeze);
// return if no emission
if(!bb.kinematics) {
if(particle->spinInfo()) particle->spinInfo()->develop();
return false;
}
// if not vetoed break
if(!spaceLikeVetoed(bb,particle)) break;
// otherwise reset scale and continue
particle->vetoEmission(bb.type,bb.kinematics->scale());
if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr());
}
// assign the splitting function and shower kinematics
particle->showerKinematics(bb.kinematics);
if(bb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(bb.kinematics->pT());
// For the time being we are considering only 1->2 branching
// particles as in Sudakov form factor
tcPDPtr part[2]={getParticleData(bb.ids[0]),
getParticleData(bb.ids[2])};
if(particle->id()!=bb.ids[1]) {
if(part[0]->CC()) part[0]=part[0]->CC();
if(part[1]->CC()) part[1]=part[1]->CC();
}
// Now create the actual particles, make the otherChild a final state
// particle, while the newParent is not
ShowerParticlePtr newParent=new_ptr(ShowerParticle(part[0],false));
ShowerParticlePtr otherChild = new_ptr(ShowerParticle(part[1],true,true));
ShowerParticleVector theChildren;
theChildren.push_back(particle);
theChildren.push_back(otherChild);
//this updates the evolution scale
particle->showerKinematics()->
updateParent(newParent, theChildren,bb.type);
// update the history if needed
_currenttree->updateInitialStateShowerProduct(_progenitor,newParent);
_currenttree->addInitialStateBranching(particle,newParent,otherChild);
// for the reconstruction of kinematics, parent/child
// relationships are according to the branching process:
// now continue the shower
++_nis;
bool emitted = _limitEmissions==0 ?
spaceLikeShower(newParent,beam,type) : false;
if(newParent->spinInfo()) newParent->spinInfo()->develop();
// now reconstruct the momentum
if(!emitted) {
if(_intrinsic.find(_progenitor)==_intrinsic.end()) {
bb.kinematics->updateLast(newParent,ZERO,ZERO);
}
else {
pair<Energy,double> kt=_intrinsic[_progenitor];
bb.kinematics->updateLast(newParent,
kt.first*cos(kt.second),
kt.first*sin(kt.second));
}
}
particle->showerKinematics()->
updateChildren(newParent, theChildren,bb.type,false);
if(_limitEmissions!=0) {
if(particle->spinInfo()) particle->spinInfo()->develop();
return true;
}
// perform the shower of the final-state particle
timeLikeShower(otherChild,type,Branching(),true);
updateHistory(otherChild);
if(theChildren[1]->spinInfo()) theChildren[1]->spinInfo()->develop();
// return the emitted
if(particle->spinInfo()) particle->spinInfo()->develop();
return true;
}
void Evolver::showerDecay(ShowerTreePtr decay) {
_decayme = HwDecayerBasePtr();
_hardme = HwMEBasePtr();
// find the decayer
// try the normal way if possible
tDMPtr dm = decay->incomingLines().begin()->first->original() ->decayMode();
if(!dm) dm = decay->incomingLines().begin()->first->copy() ->decayMode();
if(!dm) dm = decay->incomingLines().begin()->first->progenitor()->decayMode();
// otherwise make a string and look it up
if(!dm) {
string tag = decay->incomingLines().begin()->first->original()->dataPtr()->name()
+ "->";
OrderedParticles outgoing;
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::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<ShowerProgenitorPtr,tShowerParticlePtr>::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<HwDecayerBasePtr>(dm->decayer());
// set the ShowerTree to be showered
currentTree(decay);
decay->applyTransforms();
hardTree(HardTreePtr());
unsigned int interactionTry=0;
do {
try {
// generate the showering
doShowering(false,XCPtr());
// if no vetos
// force calculation of spin correlations
SpinPtr spInfo = decay->incomingLines().begin()->first->progenitor()->spinInfo();
if(spInfo) {
if(!spInfo->developed()) spInfo->needsUpdate();
spInfo->develop();
}
// and then return
return;
}
catch (InteractionVeto) {
currentTree()->clear();
++interactionTry;
}
}
while(interactionTry<=5);
throw Exception() << "Too many tries for QED shower in Evolver::showerDecay()"
<< Exception::eventerror;
}
bool Evolver::spaceLikeDecayShower(tShowerParticlePtr particle,
const ShowerParticle::EvolutionScales & maxScales,
Energy minmass,ShowerInteraction::Type type,
Branching fb) {
// too many tries
if(_nFSR>=_maxTryFSR) {
++_nFailedFSR;
// too many failed events
if(_nFailedFSR>=_maxFailFSR)
throw Exception() << "Too many events have failed due to too many shower emissions, in\n"
<< "Evolver::timeLikeShower(). Terminating run\n"
<< Exception::runerror;
throw Exception() << "Too many attempted emissions in Evolver::timeLikeShower()\n"
<< Exception::eventerror;
}
// generate the emission
ShowerParticleVector children;
int ntry=0;
// generate the emission
if(!fb.kinematics)
fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type,
HardBranchingPtr());
// no emission, return
if(!fb.kinematics) return false;
Branching fc[2];
bool setupChildren = true;
while (ntry<50) {
if(particle->virtualMass()==ZERO)
particle->virtualMass(_progenitor->progenitor()->mass());
fc[0] = Branching();
fc[1] = Branching();
++ntry;
assert(fb.kinematics);
// has emitted
// Assign the shower kinematics to the emitting particle.
if(setupChildren) {
++_nFSR;
// Assign the shower kinematics to the emitting particle.
particle->showerKinematics(fb.kinematics);
if(fb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(fb.kinematics->pT());
// create the ShowerParticle objects for the two children
children = createTimeLikeChildren(particle,fb.ids);
// updateChildren the children
particle->showerKinematics()->
updateChildren(particle, children, fb.type,_reconOpt>=3);
setupChildren = false;
}
// select branchings for children
fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,
type,HardBranchingPtr());
fc[1] = selectTimeLikeBranching (children[1],type,HardBranchingPtr());
// old default
if(_reconOpt==0) {
// shower the first particle
_currenttree->updateInitialStateShowerProduct(_progenitor,children[0]);
_currenttree->addInitialStateBranching(particle,children[0],children[1]);
if(fc[0].kinematics) spaceLikeDecayShower(children[0],maxScales,minmass,type,Branching());
// shower the second particle
if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],true);
updateHistory(children[1]);
// branching has happened
break;
}
// Herwig default
else if(_reconOpt==1) {
// shower the first particle
_currenttree->updateInitialStateShowerProduct(_progenitor,children[0]);
_currenttree->addInitialStateBranching(particle,children[0],children[1]);
if(fc[0].kinematics) spaceLikeDecayShower(children[0],maxScales,minmass,type,Branching());
// shower the second particle
if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],true);
updateHistory(children[1]);
// branching has happened
particle->showerKinematics()->updateParent(particle, children,fb.type);
// clean up the vetoed emission
if(particle->virtualMass()==ZERO) {
particle->showerKinematics(ShoKinPtr());
for(unsigned int ix=0;ix<children.size();++ix)
particle->abandonChild(children[ix]);
children.clear();
particle->vetoEmission(fb.type,fb.kinematics->scale());
// generate the new emission
fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type,
HardBranchingPtr());
// no emission, return
if(!fb.kinematics) {
return false;
}
setupChildren = true;
continue;
}
else
break;
}
else if(_reconOpt>=2) {
// cut-off masses for the branching
const vector<Energy> & virtualMasses = fb.sudakov->virtualMasses(fb.ids);
// compute the masses of the children
Energy masses[3];
// space-like children
masses[1] = children[0]->virtualMass();
// time-like child
if(fc[1].kinematics) {
const vector<Energy> & vm = fc[1].sudakov->virtualMasses(fc[1].ids);
Energy2 q2 =
fc[1].kinematics->z()*(1.-fc[1].kinematics->z())*sqr(fc[1].kinematics->scale());
if(fc[1].ids[0]!=ParticleID::g) q2 += sqr(vm[0]);
masses[2] = sqrt(q2);
}
else {
masses[2] = virtualMasses[2];
}
masses[0]=particle->virtualMass();
double z = fb.kinematics->z();
Energy2 pt2 = (1.-z)*(z*sqr(masses[0])-sqr(masses[1])-z/(1.-z)*sqr(masses[2]));
if(pt2>=ZERO) {
break;
}
else {
// reset the scales for the children
for(unsigned int ix=0;ix<2;++ix) {
if(fc[ix].kinematics)
children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale());
else {
if(ix==0)
children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,Constants::MaxEnergy);
else
children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO);
}
}
children[0]->virtualMass(_progenitor->progenitor()->mass());
children[1]->virtualMass(ZERO);
}
}
};
if(_reconOpt>=2) {
// In the case of splittings which involves coloured particles,
// set properly the colour flow of the branching.
// update the history if needed
_currenttree->updateInitialStateShowerProduct(_progenitor,children[0]);
_currenttree->addInitialStateBranching(particle,children[0],children[1]);
// shower the first particle
if(fc[0].kinematics) spaceLikeDecayShower(children[0],maxScales,minmass,type,Branching());
// shower the second particle
if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],true);
updateHistory(children[1]);
// branching has happened
particle->showerKinematics()->updateParent(particle, children,fb.type);
}
// branching has happened
return true;
}
vector<ShowerProgenitorPtr> Evolver::setupShower(bool hard) {
// generate POWHEG hard emission if needed
if(_hardEmissionMode>0) hardestEmission(hard);
- ShowerInteraction::Type inter = interactions_[0];
+ ShowerInteraction::Type inter = interaction_;
if(_hardtree&&inter!=ShowerInteraction::QEDQCD && inter!=ShowerInteraction::ALL) {
inter = _hardtree->interaction();
}
// set the initial colour partners
setEvolutionPartners(hard,inter,false);
// generate hard me if needed
if(_hardEmissionMode==0 ||
(!hard && _hardEmissionMode==-1)) hardMatrixElementCorrection(hard);
// get the particles to be showered
vector<ShowerProgenitorPtr> particlesToShower =
currentTree()->extractProgenitors();
// remake the colour partners if needed
if(_currenttree->hardMatrixElementCorrection()) {
- setEvolutionPartners(hard,interactions_[0],true);
+ setEvolutionPartners(hard,interaction_,true);
_currenttree->resetShowerProducts();
}
// return the answer
return particlesToShower;
}
void Evolver::setEvolutionPartners(bool hard,ShowerInteraction::Type type,
bool clear) {
// match the particles in the ShowerTree and hardTree
if(hardTree() && !hardTree()->connect(currentTree()))
throw Exception() << "Can't match trees in "
<< "Evolver::setEvolutionPartners()"
<< Exception::eventerror;
// extract the progenitors
vector<ShowerParticlePtr> particles =
currentTree()->extractProgenitorParticles();
// clear the partners if needed
if(clear) {
for(unsigned int ix=0;ix<particles.size();++ix) {
particles[ix]->partner(ShowerParticlePtr());
particles[ix]->clearPartners();
}
}
// sort out the colour partners
if(hardTree()) {
// find the partner
for(unsigned int ix=0;ix<particles.size();++ix) {
tHardBranchingPtr partner =
hardTree()->particles()[particles[ix]]->colourPartner();
if(!partner) continue;
for(map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
it=hardTree()->particles().begin();
it!=hardTree()->particles().end();++it) {
if(it->second==partner) particles[ix]->partner(it->first);
}
if(!particles[ix]->partner())
throw Exception() << "Can't match partners in "
<< "Evolver::setEvolutionPartners()"
<< Exception::eventerror;
}
}
// Set the initial evolution scales
showerModel()->partnerFinder()->
setInitialEvolutionScales(particles,!hard,type,!_hardtree);
if(hardTree() && _hardPOWHEG) {
bool tooHard=false;
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
eit=hardTree()->particles().end();
for(unsigned int ix=0;ix<particles.size();++ix) {
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
mit = hardTree()->particles().find(particles[ix]);
Energy hardScale(ZERO);
ShowerPartnerType::Type type(ShowerPartnerType::Undefined);
// final-state
if(particles[ix]->isFinalState()) {
if(mit!= eit && !mit->second->children().empty()) {
hardScale = mit->second->scale();
type = mit->second->type();
}
}
// initial-state
else {
if(mit!= eit && mit->second->parent()) {
hardScale = mit->second->parent()->scale();
type = mit->second->parent()->type();
}
}
if(type!=ShowerPartnerType::Undefined) {
if(type==ShowerPartnerType::QED) {
tooHard |= particles[ix]->scales().QED_noAO<hardScale;
}
else if(type==ShowerPartnerType::QCDColourLine) {
tooHard |= particles[ix]->scales().QCD_c_noAO<hardScale;
}
else if(type==ShowerPartnerType::QCDAntiColourLine) {
tooHard |= particles[ix]->scales().QCD_ac_noAO<hardScale;
}
else if(type==ShowerPartnerType::EW) {
tooHard |= particles[ix]->scales().EW<hardScale;
}
}
}
if(tooHard) convertHardTree(hard,type);
}
}
void Evolver::updateHistory(tShowerParticlePtr particle) {
if(!particle->children().empty()) {
ShowerParticleVector theChildren;
for(unsigned int ix=0;ix<particle->children().size();++ix) {
ShowerParticlePtr part = dynamic_ptr_cast<ShowerParticlePtr>
(particle->children()[ix]);
theChildren.push_back(part);
}
// update the history if needed
if(particle==_currenttree->getFinalStateShowerProduct(_progenitor))
_currenttree->updateFinalStateShowerProduct(_progenitor,
particle,theChildren);
_currenttree->addFinalStateBranching(particle,theChildren);
for(unsigned int ix=0;ix<theChildren.size();++ix)
updateHistory(theChildren[ix]);
}
}
bool Evolver::startTimeLikeShower(ShowerInteraction::Type type) {
_nFSR = 0;
if(hardTree()) {
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
eit=hardTree()->particles().end(),
mit = hardTree()->particles().find(progenitor()->progenitor());
if( mit != eit && !mit->second->children().empty() ) {
bool output=truncatedTimeLikeShower(progenitor()->progenitor(),
mit->second ,type,Branching(),true);
if(output) updateHistory(progenitor()->progenitor());
return output;
}
}
bool output = hardOnly() ? false :
timeLikeShower(progenitor()->progenitor() ,type,Branching(),true) ;
if(output) updateHistory(progenitor()->progenitor());
return output;
}
bool Evolver::startSpaceLikeShower(PPtr parent, ShowerInteraction::Type type) {
if(hardTree()) {
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
eit =hardTree()->particles().end(),
mit = hardTree()->particles().find(progenitor()->progenitor());
if( mit != eit && mit->second->parent() ) {
return truncatedSpaceLikeShower( progenitor()->progenitor(),
parent, mit->second->parent(), type );
}
}
return hardOnly() ? false :
spaceLikeShower(progenitor()->progenitor(),parent,type);
}
bool Evolver::
startSpaceLikeDecayShower(const ShowerParticle::EvolutionScales & maxScales,
Energy minimumMass,ShowerInteraction::Type type) {
_nFSR = 0;
if(hardTree()) {
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
eit =hardTree()->particles().end(),
mit = hardTree()->particles().find(progenitor()->progenitor());
if( mit != eit && mit->second->parent() ) {
HardBranchingPtr branch=mit->second;
while(branch->parent()) branch=branch->parent();
return truncatedSpaceLikeDecayShower(progenitor()->progenitor(),maxScales,
minimumMass, branch ,type, Branching());
}
}
return hardOnly() ? false :
spaceLikeDecayShower(progenitor()->progenitor(),maxScales,minimumMass,type,Branching());
}
bool Evolver::timeLikeVetoed(const Branching & fb,
ShowerParticlePtr particle) {
// work out type of interaction
ShowerInteraction::Type type = convertInteraction(fb.type);
// check whether emission was harder than largest pt of hard subprocess
if ( hardVetoFS() && fb.kinematics->pT() > _progenitor->maxHardPt() )
return true;
// soft matrix element correction veto
if( softMEC()) {
if(_hardme && _hardme->hasMECorrection()) {
if(_hardme->softMatrixElementVeto(_progenitor,particle,fb))
return true;
}
else if(_decayme && _decayme->hasMECorrection()) {
if(_decayme->softMatrixElementVeto(_progenitor,particle,fb))
return true;
}
}
// veto on maximum pt
if(fb.kinematics->pT()>_progenitor->maximumpT(type)) return true;
// general vetos
if (fb.kinematics && !_vetoes.empty()) {
bool vetoed=false;
for (vector<ShowerVetoPtr>::iterator v = _vetoes.begin();
v != _vetoes.end(); ++v) {
bool test = (**v).vetoTimeLike(_progenitor,particle,fb);
switch((**v).vetoType()) {
case ShowerVeto::Emission:
vetoed |= test;
break;
case ShowerVeto::Shower:
if(test) throw VetoShower();
break;
case ShowerVeto::Event:
if(test) throw Veto();
break;
}
}
if(vetoed) return true;
}
if ( ShowerHandler::currentHandler()->firstInteraction() &&
ShowerHandler::currentHandler()->profileScales() ) {
double weight =
ShowerHandler::currentHandler()->profileScales()->
hardScaleProfile(_progenitor->hardScale(),fb.kinematics->pT());
if ( UseRandom::rnd() > weight )
return true;
}
return false;
}
bool Evolver::spaceLikeVetoed(const Branching & bb,
ShowerParticlePtr particle) {
// work out type of interaction
ShowerInteraction::Type type = convertInteraction(bb.type);
// check whether emission was harder than largest pt of hard subprocess
if (hardVetoIS() && bb.kinematics->pT() > _progenitor->maxHardPt())
return true;
// apply the soft correction
if( softMEC() && _hardme && _hardme->hasMECorrection() ) {
if(_hardme->softMatrixElementVeto(_progenitor,particle,bb))
return true;
}
// the more general vetos
// check vs max pt for the shower
if(bb.kinematics->pT()>_progenitor->maximumpT(type)) return true;
if (!_vetoes.empty()) {
bool vetoed=false;
for (vector<ShowerVetoPtr>::iterator v = _vetoes.begin();
v != _vetoes.end(); ++v) {
bool test = (**v).vetoSpaceLike(_progenitor,particle,bb);
switch ((**v).vetoType()) {
case ShowerVeto::Emission:
vetoed |= test;
break;
case ShowerVeto::Shower:
if(test) throw VetoShower();
break;
case ShowerVeto::Event:
if(test) throw Veto();
break;
}
}
if (vetoed) return true;
}
if ( ShowerHandler::currentHandler()->firstInteraction() &&
ShowerHandler::currentHandler()->profileScales() ) {
double weight =
ShowerHandler::currentHandler()->profileScales()->
hardScaleProfile(_progenitor->hardScale(),bb.kinematics->pT());
if ( UseRandom::rnd() > weight )
return true;
}
return false;
}
bool Evolver::spaceLikeDecayVetoed( const Branching & fb,
ShowerParticlePtr particle) {
// work out type of interaction
ShowerInteraction::Type type = convertInteraction(fb.type);
// apply the soft correction
if( softMEC() && _decayme && _decayme->hasMECorrection() ) {
if(_decayme->softMatrixElementVeto(_progenitor,particle,fb))
return true;
}
// veto on hardest pt in the shower
if(fb.kinematics->pT()> _progenitor->maximumpT(type)) return true;
// general vetos
if (!_vetoes.empty()) {
bool vetoed=false;
for (vector<ShowerVetoPtr>::iterator v = _vetoes.begin();
v != _vetoes.end(); ++v) {
bool test = (**v).vetoSpaceLike(_progenitor,particle,fb);
switch((**v).vetoType()) {
case ShowerVeto::Emission:
vetoed |= test;
break;
case ShowerVeto::Shower:
if(test) throw VetoShower();
break;
case ShowerVeto::Event:
if(test) throw Veto();
break;
}
if (vetoed) return true;
}
}
return false;
}
void Evolver::hardestEmission(bool hard) {
HardTreePtr ISRTree;
if( ( _hardme && _hardme->hasPOWHEGCorrection()!=0 && _hardEmissionMode< 2) ||
( _decayme && _decayme->hasPOWHEGCorrection()!=0 && _hardEmissionMode!=2) ) {
if(_hardme) {
assert(hard);
- if(interaction_==4) {
- vector<ShowerInteraction::Type> inter(2);
- inter[0] = ShowerInteraction::QCD;
- inter[1] = ShowerInteraction::QED;
- _hardtree = _hardme->generateHardest( currentTree(),inter );
- }
- else {
- _hardtree = _hardme->generateHardest( currentTree(),interactions_ );
- }
+ _hardtree = _hardme->generateHardest( currentTree(),interaction_);
}
else {
assert(!hard);
_hardtree = _decayme->generateHardest( currentTree() );
}
// store initial state POWHEG radiation
if(_hardtree && _hardme && _hardme->hasPOWHEGCorrection()==1)
ISRTree=_hardtree;
}
else if (_hardEmissionMode>1 && hard) {
// Get minimum pT cutoff used in shower approximation
Energy maxpt = 1.*GeV;
int colouredIn = 0;
int colouredOut = 0;
for( map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it
= currentTree()->outgoingLines().begin();
it != currentTree()->outgoingLines().end(); ++it ) {
if( it->second->coloured() ) colouredOut+=1;
}
for( map< ShowerProgenitorPtr, ShowerParticlePtr >::iterator it
= currentTree()->incomingLines().begin();
it != currentTree()->incomingLines().end(); ++it ) {
if( ! it->second->coloured() ) colouredIn+=1;
}
if ( theShowerApproximation ){
if ( theShowerApproximation->ffPtCut() == theShowerApproximation->fiPtCut() &&
theShowerApproximation->ffPtCut() == theShowerApproximation->iiPtCut() )
maxpt = theShowerApproximation->ffPtCut();
else if ( colouredIn == 2 && colouredOut == 0 )
maxpt = theShowerApproximation->iiPtCut();
else if ( colouredIn == 0 && colouredOut > 1 )
maxpt = theShowerApproximation->ffPtCut();
else if ( colouredIn == 2 && colouredOut == 1 )
maxpt = min(theShowerApproximation->iiPtCut(), theShowerApproximation->fiPtCut());
else if ( colouredIn == 1 && colouredOut > 1 )
maxpt = min(theShowerApproximation->ffPtCut(), theShowerApproximation->fiPtCut());
else
maxpt = min(min(theShowerApproximation->iiPtCut(), theShowerApproximation->fiPtCut()),
theShowerApproximation->ffPtCut());
}
// Generate hardtree from born and real emission subprocesses
_hardtree = ShowerHandler::currentHandler()->generateCKKW(currentTree());
// Find transverse momentum of hardest emission
if (_hardtree){
for(set<HardBranchingPtr>::iterator it=_hardtree->branchings().begin();
it!=_hardtree->branchings().end();++it) {
if ((*it)->parent() && (*it)->status()==HardBranching::Incoming)
maxpt=(*it)->branchingParticle()->momentum().perp();
if ((*it)->children().size()==2 && (*it)->status()==HardBranching::Outgoing){
if ((*it)->branchingParticle()->id()!=21 &&
abs((*it)->branchingParticle()->id())>5 ){
if ((*it)->children()[0]->branchingParticle()->id()==21 ||
abs((*it)->children()[0]->branchingParticle()->id())<6)
maxpt=(*it)->children()[0]->branchingParticle()->momentum().perp();
else if ((*it)->children()[1]->branchingParticle()->id()==21 ||
abs((*it)->children()[1]->branchingParticle()->id())<6)
maxpt=(*it)->children()[1]->branchingParticle()->momentum().perp();
}
else {
if ( abs((*it)->branchingParticle()->id())<6){
if (abs((*it)->children()[0]->branchingParticle()->id())<6)
maxpt = (*it)->children()[1]->branchingParticle()->momentum().perp();
else
maxpt = (*it)->children()[0]->branchingParticle()->momentum().perp();
}
else maxpt = (*it)->children()[1]->branchingParticle()->momentum().perp();
}
}
}
}
// Hardest (pt) emission should be the first powheg emission.
maxpt=min(sqrt(ShowerHandler::currentHandler()->lastXCombPtr()->lastShowerScale()),maxpt);
// Set maxpt to pT of emission when showering POWHEG real-emission subprocesses
if (!isPowhegSEvent && !isPowhegHEvent){
vector<int> outGluon;
vector<int> outQuark;
map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it;
for( it = currentTree()->outgoingLines().begin();
it != currentTree()->outgoingLines().end(); ++it ) {
if ( abs(it->second->id())< 6) outQuark.push_back(it->second->id());
if ( it->second->id()==21 ) outGluon.push_back(it->second->id());
}
if (outGluon.size() + outQuark.size() == 1){
for( it = currentTree()->outgoingLines().begin();
it != currentTree()->outgoingLines().end(); ++it ) {
if ( abs(it->second->id())< 6 || it->second->id()==21 )
maxpt = it->second->momentum().perp();
}
}
else if (outGluon.size() + outQuark.size() > 1){
// assume qqbar pair from a Z/gamma
if (outGluon.size()==1 && outQuark.size() == 2 && outQuark[0]==-outQuark[1]){
for( it = currentTree()->outgoingLines().begin();
it != currentTree()->outgoingLines().end(); ++it ) {
if ( it->second->id()==21 )
maxpt = it->second->momentum().perp();
}
}
// otherwise take the lowest pT avoiding born DY events
else {
maxpt = generator()->maximumCMEnergy();
for( it = currentTree()->outgoingLines().begin();
it != currentTree()->outgoingLines().end(); ++it ) {
if ( abs(it->second->id())< 6 || it->second->id()==21 )
maxpt = min(maxpt,it->second->momentum().perp());
}
}
}
}
// set maximum pT for subsequent emissions from S events
if ( isPowhegSEvent || (!isPowhegSEvent && !isPowhegHEvent)){
for( map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it
= currentTree()->outgoingLines().begin();
it != currentTree()->outgoingLines().end(); ++it ) {
if( ! it->second->coloured() ) continue;
it->first->maximumpT(maxpt, ShowerInteraction::QCD );
}
for( map< ShowerProgenitorPtr, ShowerParticlePtr >::iterator it
= currentTree()->incomingLines().begin();
it != currentTree()->incomingLines().end(); ++it ) {
if( ! it->second->coloured() ) continue;
it->first->maximumpT(maxpt, ShowerInteraction::QCD );
}
}
}
else
_hardtree = ShowerHandler::currentHandler()->generateCKKW(currentTree());
// if hard me doesn't have a FSR powheg
// correction use decay powheg correction
if (_hardme && _hardme->hasPOWHEGCorrection()<2) {
// check for intermediate colour singlet resonance
const ParticleVector inter = _hardme->subProcess()->intermediates();
if (inter.size()!=1 ||
inter[0]->momentum().m2()/GeV2 < 0 ||
inter[0]->dataPtr()->iColour()!=PDT::Colour0){
if(_hardtree) connectTrees(currentTree(),_hardtree,hard);
return;
}
map<ShowerProgenitorPtr, tShowerParticlePtr > out = currentTree()->outgoingLines();
// ignore cases where outgoing particles are not coloured
if (out.size()!=2 ||
out. begin()->second->dataPtr()->iColour()==PDT::Colour0 ||
out.rbegin()->second->dataPtr()->iColour()==PDT::Colour0) {
if(_hardtree) connectTrees(currentTree(),_hardtree,hard);
return;
}
// look up decay mode
tDMPtr dm;
string tag;
string inParticle = inter[0]->dataPtr()->name() + "->";
vector<string> 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<HwDecayerBasePtr>(dm->decayer());
// check if decayer has a FSR POWHEG correction
if (!decayer || decayer->hasPOWHEGCorrection()<2){
if(_hardtree) connectTrees(currentTree(),_hardtree,hard);
return;
}
// generate the hardest emission
ShowerDecayMap decay;
PPtr in = new_ptr(*inter[0]);
ShowerTreePtr decayTree = new_ptr(ShowerTree(in, decay));
HardTreePtr FSRTree = decayer->generateHardest(decayTree);
if (!FSRTree) {
if(_hardtree) connectTrees(currentTree(),_hardtree,hard);
return;
}
// if there is no ISRTree make _hardtree from FSRTree
if (!ISRTree){
vector<HardBranchingPtr> inBranch,hardBranch;
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::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<HardBranchingPtr>::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<tShowerParticlePtr> FSROut, ISROut;
set<HardBranchingPtr>::iterator itFSR, itISR;
// get outgoing particles
for(itFSR =FSRTree->branchings().begin();
itFSR!=FSRTree->branchings().end();++itFSR){
if ((**itFSR).status()==HardBranching::Outgoing)
FSROut.push_back((*itFSR)->branchingParticle());
}
for(itISR =ISRTree->branchings().begin();
itISR!=ISRTree->branchings().end();++itISR){
if ((**itISR).status()==HardBranching::Outgoing)
ISROut.push_back((*itISR)->branchingParticle());
}
// find COM frame formed by outgoing particles
LorentzRotation eventFrameFSR, eventFrameISR;
eventFrameFSR = ((FSROut[0]->momentum()+FSROut[1]->momentum()).findBoostToCM());
eventFrameISR = ((ISROut[0]->momentum()+ISROut[1]->momentum()).findBoostToCM());
// find rotation between ISR and FSR frames
int j=0;
if (ISROut[0]->id()!=FSROut[0]->id()) j=1;
eventFrameISR.rotateZ( (eventFrameFSR*FSROut[0]->momentum()).phi()-
(eventFrameISR*ISROut[j]->momentum()).phi() );
eventFrameISR.rotateY( (eventFrameFSR*FSROut[0]->momentum()).theta()-
(eventFrameISR*ISROut[j]->momentum()).theta() );
eventFrameISR.invert();
for (itFSR=FSRTree->branchings().begin();
itFSR!=FSRTree->branchings().end();++itFSR){
if ((**itFSR).branchingParticle()->id()==in->id()) continue;
for (itISR =ISRTree->branchings().begin();
itISR!=ISRTree->branchings().end();++itISR){
if ((**itISR).status()==HardBranching::Incoming) continue;
if ((**itFSR).branchingParticle()->id()==
(**itISR).branchingParticle()->id()){
// rotate FSRTree particle to ISRTree event frame
(**itISR).branchingParticle()->setMomentum(eventFrameISR*
eventFrameFSR*
(**itFSR).branchingParticle()->momentum());
(**itISR).branchingParticle()->rescaleMass();
// add the children of the FSRTree particles to the ISRTree
if(!(**itFSR).children().empty()){
(**itISR).addChild((**itFSR).children()[0]);
(**itISR).addChild((**itFSR).children()[1]);
// rotate momenta to ISRTree event frame
(**itISR).children()[0]->branchingParticle()->setMomentum(eventFrameISR*
eventFrameFSR*
(**itFSR).children()[0]->branchingParticle()->momentum());
(**itISR).children()[1]->branchingParticle()->setMomentum(eventFrameISR*
eventFrameFSR*
(**itFSR).children()[1]->branchingParticle()->momentum());
}
}
}
}
_hardtree = ISRTree;
}
}
if(_hardtree){
connectTrees(currentTree(),_hardtree,hard);
}
}
bool Evolver::truncatedTimeLikeShower(tShowerParticlePtr particle,
HardBranchingPtr branch,
ShowerInteraction::Type type,
Branching fb, bool first) {
// select a branching if we don't have one
if(!fb.kinematics)
fb = selectTimeLikeBranching(particle,type,branch);
// must be an emission, the forced one it not a truncated one
assert(fb.kinematics);
ShowerParticleVector children;
int ntry=0;
Branching fc[2];
bool setupChildren = true;
while (ntry<50) {
if(!fc[0].hard) fc[0] = Branching();
if(!fc[1].hard) fc[1] = Branching();
++ntry;
// Assign the shower kinematics to the emitting particle.
if(setupChildren) {
++_nFSR;
// Assign the shower kinematics to the emitting particle.
particle->showerKinematics(fb.kinematics);
if(fb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(fb.kinematics->pT());
// if not hard generate phi
if(!fb.hard)
fb.kinematics->phi(fb.sudakov->generatePhiForward(*particle,fb.ids,fb.kinematics));
// create the children
children = createTimeLikeChildren(particle,fb.ids);
// update the children
particle->showerKinematics()->
updateChildren(particle, children,fb.type,_reconOpt>=3);
setupChildren = false;
}
// select branchings for children
if(!fc[0].kinematics) {
// select branching for first particle
if(!fb.hard && fb.iout ==1 )
fc[0] = selectTimeLikeBranching(children[0],type,branch);
else if(fb.hard && !branch->children()[0]->children().empty() )
fc[0] = selectTimeLikeBranching(children[0],type,branch->children()[0]);
else
fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr());
}
// select branching for the second particle
if(!fc[1].kinematics) {
// select branching for first particle
if(!fb.hard && fb.iout ==2 )
fc[1] = selectTimeLikeBranching(children[1],type,branch);
else if(fb.hard && !branch->children()[1]->children().empty() )
fc[1] = selectTimeLikeBranching(children[1],type,branch->children()[1]);
else
fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr());
}
// old default
if(_reconOpt==0 || (_reconOpt==1 && fb.hard) ) {
// shower the first particle
if(fc[0].kinematics) {
// the parent has truncated emission and following line
if(!fb.hard && fb.iout == 1)
truncatedTimeLikeShower(children[0],branch,type,fc[0],false);
// hard emission and subsquent hard emissions
else if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false);
// normal shower
else
timeLikeShower(children[0],type,fc[0],false);
}
if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
// shower the second particle
if(fc[1].kinematics) {
// the parent has truncated emission and following line
if(!fb.hard && fb.iout == 2)
truncatedTimeLikeShower(children[1],branch,type,fc[1],false);
// hard emission and subsquent hard emissions
else if(fb.hard && !branch->children()[1]->children().empty() )
truncatedTimeLikeShower(children[1],branch->children()[1],type,fc[1],false);
else
timeLikeShower(children[1],type,fc[1],false);
}
if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
// branching has happened
particle->showerKinematics()->updateParent(particle, children,fb.type);
break;
}
// H7 default
else if(_reconOpt==1) {
// shower the first particle
if(fc[0].kinematics) {
// the parent has truncated emission and following line
if(!fb.hard && fb.iout == 1)
truncatedTimeLikeShower(children[0],branch,type,fc[0],false);
else
timeLikeShower(children[0],type,fc[0],false);
}
if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
// shower the second particle
if(fc[1].kinematics) {
// the parent has truncated emission and following line
if(!fb.hard && fb.iout == 2)
truncatedTimeLikeShower(children[1],branch,type,fc[1],false);
else
timeLikeShower(children[1],type,fc[1],false);
}
if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
// branching has happened
particle->showerKinematics()->updateParent(particle, children,fb.type);
// clean up the vetoed emission
if(particle->virtualMass()==ZERO) {
particle->showerKinematics(ShoKinPtr());
for(unsigned int ix=0;ix<children.size();++ix)
particle->abandonChild(children[ix]);
children.clear();
if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr());
particle->vetoEmission(fb.type,fb.kinematics->scale());
// generate the new emission
fb = selectTimeLikeBranching(particle,type,branch);
// must be at least hard emission
assert(fb.kinematics);
setupChildren = true;
continue;
}
else
break;
}
else if(_reconOpt>=2) {
// cut-off masses for the branching
const vector<Energy> & virtualMasses = fb.sudakov->virtualMasses(fb.ids);
// compute the masses of the children
Energy masses[3];
for(unsigned int ix=0;ix<2;++ix) {
if(fc[ix].kinematics) {
const vector<Energy> & vm = fc[ix].sudakov->virtualMasses(fc[ix].ids);
Energy2 q2 =
fc[ix].kinematics->z()*(1.-fc[ix].kinematics->z())*sqr(fc[ix].kinematics->scale());
if(fc[ix].ids[0]!=ParticleID::g) q2 += sqr(vm[0]);
masses[ix+1] = sqrt(q2);
}
else {
masses[ix+1] = virtualMasses[ix+1];
}
}
masses[0] = fb.ids[0]!=ParticleID::g ? virtualMasses[0] : ZERO;
double z = fb.kinematics->z();
Energy2 pt2 = z*(1.-z)*(z*(1.-z)*sqr(fb.kinematics->scale()) + sqr(masses[0]))
- sqr(masses[1])*(1.-z) - sqr(masses[2])*z;
if(pt2>=ZERO) {
break;
}
// if only the hard emission have to accept it
else if ((fc[0].hard && !fc[1].kinematics) ||
(fc[1].hard && !fc[0].kinematics) ) {
break;
}
else {
// reset the scales for the children
for(unsigned int ix=0;ix<2;++ix) {
if(fc[ix].hard) continue;
if(fc[ix].kinematics && ! fc[ix].hard )
children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale());
else
children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO);
children[ix]->virtualMass(ZERO);
}
}
}
};
if(_reconOpt>=2) {
// shower the first particle
if(fc[0].kinematics) {
// the parent has truncated emission and following line
if(!fb.hard && fb.iout == 1)
truncatedTimeLikeShower(children[0],branch,type,fc[0],false);
// hard emission and subsquent hard emissions
else if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false);
// normal shower
else
timeLikeShower(children[0],type,fc[0],false);
}
if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
// shower the second particle
if(fc[1].kinematics) {
// the parent has truncated emission and following line
if(!fb.hard && fb.iout == 2)
truncatedTimeLikeShower(children[1],branch,type,fc[1],false);
// hard emission and subsquent hard emissions
else if(fb.hard && !branch->children()[1]->children().empty() )
truncatedTimeLikeShower(children[1],branch->children()[1],type,fc[1],false);
else
timeLikeShower(children[1],type,fc[1],false);
}
if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
// branching has happened
particle->showerKinematics()->updateParent(particle, children,fb.type);
}
if(first&&!children.empty())
particle->showerKinematics()->resetChildren(particle,children);
if(particle->spinInfo()) particle->spinInfo()->develop();
return true;
}
bool Evolver::truncatedSpaceLikeShower(tShowerParticlePtr particle, PPtr beam,
HardBranchingPtr branch,
ShowerInteraction::Type type) {
tcPDFPtr pdf;
if(ShowerHandler::currentHandler()->firstPDF().particle() == beamParticle())
pdf = ShowerHandler::currentHandler()->firstPDF().pdf();
if(ShowerHandler::currentHandler()->secondPDF().particle() == beamParticle())
pdf = ShowerHandler::currentHandler()->secondPDF().pdf();
Energy freeze = ShowerHandler::currentHandler()->pdfFreezingScale();
Branching bb;
// parameters of the force branching
double z(0.);
HardBranchingPtr timelike;
for( unsigned int ix = 0; ix < branch->children().size(); ++ix ) {
if( branch->children()[ix]->status() ==HardBranching::Outgoing) {
timelike = branch->children()[ix];
}
if( branch->children()[ix]->status() ==HardBranching::Incoming )
z = branch->children()[ix]->z();
}
// generate truncated branching
tcPDPtr part[2];
if(z>=0.&&z<=1.) {
while (true) {
if( !isTruncatedShowerON() || hardOnly() ) break;
bb = splittingGenerator()->chooseBackwardBranching( *particle,
beam, 1., beamParticle(),
type , pdf,freeze);
if( !bb.kinematics || bb.kinematics->scale() < branch->scale() ) {
bb = Branching();
break;
}
// particles as in Sudakov form factor
part[0] = getParticleData( bb.ids[0] );
part[1] = getParticleData( bb.ids[2] );
//is emitter anti-particle
if( particle->id() != bb.ids[1]) {
if( part[0]->CC() ) part[0] = part[0]->CC();
if( part[1]->CC() ) part[1] = part[1]->CC();
}
double zsplit = bb.kinematics->z();
// apply the vetos for the truncated shower
// if doesn't carry most of momentum
ShowerInteraction::Type type2 = convertInteraction(bb.type);
if(type2==branch->sudakov()->interactionType() &&
zsplit < 0.5) {
particle->vetoEmission(bb.type,bb.kinematics->scale());
continue;
}
// others
if( part[0]->id() != particle->id() || // if particle changes type
bb.kinematics->pT() > progenitor()->maximumpT(type2) || // pt veto
bb.kinematics->scale() < branch->scale()) { // angular ordering veto
particle->vetoEmission(bb.type,bb.kinematics->scale());
continue;
}
// and those from the base class
if(spaceLikeVetoed(bb,particle)) {
particle->vetoEmission(bb.type,bb.kinematics->scale());
continue;
}
break;
}
}
if( !bb.kinematics ) {
//do the hard emission
ShoKinPtr kinematics =
branch->sudakov()->createInitialStateBranching( branch->scale(), z, branch->phi(),
branch->children()[0]->pT() );
kinematics->initialize( *particle, beam );
// assign the splitting function and shower kinematics
particle->showerKinematics( kinematics );
if(kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(kinematics->pT());
// For the time being we are considering only 1->2 branching
// Now create the actual particles, make the otherChild a final state
// particle, while the newParent is not
ShowerParticlePtr newParent =
new_ptr( ShowerParticle( branch->branchingParticle()->dataPtr(), false ) );
ShowerParticlePtr otherChild =
new_ptr( ShowerParticle( timelike->branchingParticle()->dataPtr(),
true, true ) );
ShowerParticleVector theChildren;
theChildren.push_back( particle );
theChildren.push_back( otherChild );
particle->showerKinematics()->
updateParent( newParent, theChildren, branch->type());
// update the history if needed
currentTree()->updateInitialStateShowerProduct( progenitor(), newParent );
currentTree()->addInitialStateBranching( particle, newParent, otherChild );
// for the reconstruction of kinematics, parent/child
// relationships are according to the branching process:
// now continue the shower
bool emitted=false;
if(!hardOnly()) {
if( branch->parent() ) {
emitted = truncatedSpaceLikeShower( newParent, beam, branch->parent() , type);
}
else {
emitted = spaceLikeShower( newParent, beam , type);
}
}
if( !emitted ) {
if( intrinsicpT().find( progenitor() ) == intrinsicpT().end() ) {
kinematics->updateLast( newParent, ZERO, ZERO );
}
else {
pair<Energy,double> kt = intrinsicpT()[progenitor()];
kinematics->updateLast( newParent,
kt.first*cos( kt.second ),
kt.first*sin( kt.second ) );
}
}
particle->showerKinematics()->
updateChildren( newParent, theChildren,bb.type,false);
if(hardOnly()) return true;
// perform the shower of the final-state particle
if( timelike->children().empty() ) {
timeLikeShower( otherChild , type,Branching(),true);
}
else {
truncatedTimeLikeShower( otherChild, timelike , type,Branching(), true);
}
updateHistory(otherChild);
// return the emitted
return true;
}
// assign the splitting function and shower kinematics
particle->showerKinematics( bb.kinematics );
if(bb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(bb.kinematics->pT());
// For the time being we are considering only 1->2 branching
// Now create the actual particles, make the otherChild a final state
// particle, while the newParent is not
ShowerParticlePtr newParent = new_ptr( ShowerParticle( part[0], false ) );
ShowerParticlePtr otherChild = new_ptr( ShowerParticle( part[1], true, true ) );
ShowerParticleVector theChildren;
theChildren.push_back( particle );
theChildren.push_back( otherChild );
particle->showerKinematics()->
updateParent( newParent, theChildren, bb.type);
// update the history if needed
currentTree()->updateInitialStateShowerProduct( progenitor(), newParent );
currentTree()->addInitialStateBranching( particle, newParent, otherChild );
// for the reconstruction of kinematics, parent/child
// relationships are according to the branching process:
// now continue the shower
bool emitted = truncatedSpaceLikeShower( newParent, beam, branch,type);
// now reconstruct the momentum
if( !emitted ) {
if( intrinsicpT().find( progenitor() ) == intrinsicpT().end() ) {
bb.kinematics->updateLast( newParent, ZERO, ZERO );
}
else {
pair<Energy,double> kt = intrinsicpT()[ progenitor() ];
bb.kinematics->updateLast( newParent,
kt.first*cos( kt.second ),
kt.first*sin( kt.second ) );
}
}
particle->showerKinematics()->
updateChildren( newParent, theChildren, bb.type,false);
// perform the shower of the final-state particle
timeLikeShower( otherChild , type,Branching(),true);
updateHistory(otherChild);
// return the emitted
return true;
}
bool Evolver::
truncatedSpaceLikeDecayShower(tShowerParticlePtr particle,
const ShowerParticle::EvolutionScales & maxScales,
Energy minmass, HardBranchingPtr branch,
ShowerInteraction::Type type, Branching fb) {
// select a branching if we don't have one
if(!fb.kinematics)
fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type,branch);
// must be an emission, the forced one it not a truncated one
assert(fb.kinematics);
ShowerParticleVector children;
int ntry=0;
Branching fc[2];
bool setupChildren = true;
while (ntry<50) {
if(!fc[0].hard) fc[0] = Branching();
if(!fc[1].hard) fc[1] = Branching();
++ntry;
if(setupChildren) {
++_nFSR;
// Assign the shower kinematics to the emitting particle.
particle->showerKinematics(fb.kinematics);
if(fb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(fb.kinematics->pT());
// create the ShowerParticle objects for the two children
children = createTimeLikeChildren(particle,fb.ids);
// updateChildren the children
particle->showerKinematics()->
updateChildren(particle, children, fb.type,_reconOpt>=3);
setupChildren = false;
}
// select branchings for children
if(!fc[0].kinematics) {
if(children[0]->id()==particle->id()) {
// select branching for first particle
if(!fb.hard)
fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type,branch);
else if(fb.hard && ! branch->children()[0]->children().empty() )
fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type,
branch->children()[0]);
else
fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type,
HardBranchingPtr());
}
else {
// select branching for first particle
if(fb.hard && !branch->children()[0]->children().empty() )
fc[0] = selectTimeLikeBranching(children[0],type,branch->children()[0]);
else
fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr());
}
}
// select branching for the second particle
if(!fc[1].kinematics) {
if(children[1]->id()==particle->id()) {
// select branching for first particle
if(!fb.hard)
fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type,branch);
else if(fb.hard && ! branch->children()[1]->children().empty() )
fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type,
branch->children()[1]);
else
fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type,
HardBranchingPtr());
}
else {
if(fb.hard && !branch->children()[1]->children().empty() )
fc[1] = selectTimeLikeBranching(children[1],type,branch->children()[1]);
else
fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr());
}
}
// old default
if(_reconOpt==0 || (_reconOpt==1 && fb.hard) ) {
// update the history if needed
currentTree()->updateInitialStateShowerProduct(progenitor(),children[0]);
currentTree()->addInitialStateBranching(particle,children[0],children[1]);
// shower the first particle
if(fc[0].kinematics) {
if(children[0]->id()==particle->id()) {
if(!fb.hard)
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch,type,fc[0]);
else if(fb.hard && ! branch->children()[0]->children().empty() )
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch->children()[0],type,fc[0]);
else
spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[0]);
}
else {
if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false);
// normal shower
else
timeLikeShower(children[0],type,fc[0],false);
}
}
// shower the second particle
if(fc[1].kinematics) {
if(children[0]->id()==particle->id()) {
if(!fb.hard)
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch,type,fc[1]);
else if(fb.hard && ! branch->children()[0]->children().empty() )
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch->children()[0],type,fc[1]);
else
spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[1]);
}
else {
if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[1],false);
// normal shower
else
timeLikeShower(children[0],type,fc[1],false);
}
}
updateHistory(children[1]);
// branching has happened
break;
}
// H7 default
else if(_reconOpt==1) {
// update the history if needed
currentTree()->updateInitialStateShowerProduct(progenitor(),children[0]);
currentTree()->addInitialStateBranching(particle,children[0],children[1]);
// shower the first particle
if(fc[0].kinematics) {
if(children[0]->id()==particle->id()) {
if(!fb.hard)
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch,type,fc[0]);
else if(fb.hard && ! branch->children()[0]->children().empty() )
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch->children()[0],type,fc[0]);
else
spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[0]);
}
else {
if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false);
// normal shower
else
timeLikeShower(children[0],type,fc[0],false);
}
}
// shower the second particle
if(fc[1].kinematics) {
if(children[0]->id()==particle->id()) {
if(!fb.hard)
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch,type,fc[1]);
else if(fb.hard && ! branch->children()[0]->children().empty() )
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch->children()[0],type,fc[1]);
else
spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[1]);
}
else {
if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[1],false);
// normal shower
else
timeLikeShower(children[0],type,fc[1],false);
}
}
// clean up the vetoed emission
if(particle->virtualMass()==ZERO) {
particle->showerKinematics(ShoKinPtr());
for(unsigned int ix=0;ix<children.size();++ix)
particle->abandonChild(children[ix]);
children.clear();
particle->vetoEmission(fb.type,fb.kinematics->scale());
// generate the new emission
fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type,branch);
// must be at least hard emission
assert(fb.kinematics);
setupChildren = true;
continue;
}
else {
updateHistory(children[1]);
break;
}
}
else if(_reconOpt>=2) {
// cut-off masses for the branching
const vector<Energy> & virtualMasses = fb.sudakov->virtualMasses(fb.ids);
// compute the masses of the children
Energy masses[3];
// space-like children
masses[1] = children[0]->virtualMass();
// time-like child
if(fc[1].kinematics) {
const vector<Energy> & vm = fc[1].sudakov->virtualMasses(fc[1].ids);
Energy2 q2 =
fc[1].kinematics->z()*(1.-fc[1].kinematics->z())*sqr(fc[1].kinematics->scale());
if(fc[1].ids[0]!=ParticleID::g) q2 += sqr(vm[0]);
masses[2] = sqrt(q2);
}
else {
masses[2] = virtualMasses[2];
}
masses[0]=particle->virtualMass();
double z = fb.kinematics->z();
Energy2 pt2 = (1.-z)*(z*sqr(masses[0])-sqr(masses[1])-z/(1.-z)*sqr(masses[2]));
if(pt2>=ZERO) {
break;
}
else {
// reset the scales for the children
for(unsigned int ix=0;ix<2;++ix) {
if(fc[ix].kinematics)
children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale());
else {
if(ix==0)
children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,Constants::MaxEnergy);
else
children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO);
}
}
children[0]->virtualMass(_progenitor->progenitor()->mass());
children[1]->virtualMass(ZERO);
}
}
};
if(_reconOpt>=2) {
// update the history if needed
currentTree()->updateInitialStateShowerProduct(progenitor(),children[0]);
currentTree()->addInitialStateBranching(particle,children[0],children[1]);
// shower the first particle
if(fc[0].kinematics) {
if(children[0]->id()==particle->id()) {
if(!fb.hard)
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch,type,fc[0]);
else if(fb.hard && ! branch->children()[0]->children().empty() )
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch->children()[0],type,fc[0]);
else
spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[0]);
}
else {
if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false);
// normal shower
else
timeLikeShower(children[0],type,fc[0],false);
}
}
// shower the second particle
if(fc[1].kinematics) {
if(children[0]->id()==particle->id()) {
if(!fb.hard)
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch,type,fc[1]);
else if(fb.hard && ! branch->children()[0]->children().empty() )
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch->children()[0],type,fc[1]);
else
spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[1]);
}
else {
if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[1],false);
// normal shower
else
timeLikeShower(children[0],type,fc[1],false);
}
}
updateHistory(children[1]);
}
return true;
}
-bool Evolver::constructDecayTree(vector<ShowerProgenitorPtr> & particlesToShower,
- ShowerInteraction::Type inter) {
- Energy ptmax(-GeV);
- // get the maximum pt is all ready a hard tree
- if(hardTree()) {
- for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
- if(particlesToShower[ix]->maximumpT(inter)>ptmax&&
- particlesToShower[ix]->progenitor()->isFinalState())
- ptmax = particlesToShower[ix]->maximumpT(inter);
- }
- }
- vector<HardBranchingPtr> spaceBranchings,allBranchings;
- for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
- if(particlesToShower[ix]->progenitor()->isFinalState()) {
- HardBranchingPtr newBranch;
- if(particlesToShower[ix]->hasEmitted()) {
- newBranch =
- new_ptr(HardBranching(particlesToShower[ix]->progenitor(),
- particlesToShower[ix]->progenitor()->
- showerKinematics()->SudakovFormFactor(),
- HardBranchingPtr(),HardBranching::Outgoing));
- constructTimeLikeLine(newBranch,particlesToShower[ix]->progenitor());
- }
- else {
- newBranch =
- new_ptr(HardBranching(particlesToShower[ix]->progenitor(),
- SudakovPtr(),HardBranchingPtr(),
- HardBranching::Outgoing));
- }
- allBranchings.push_back(newBranch);
- }
- else {
- HardBranchingPtr newBranch;
- if(particlesToShower[ix]->hasEmitted()) {
- newBranch =
- new_ptr(HardBranching(particlesToShower[ix]->progenitor(),
- particlesToShower[ix]->progenitor()->
- showerKinematics()->SudakovFormFactor(),
- HardBranchingPtr(),HardBranching::Decay));
- constructTimeLikeLine(newBranch,particlesToShower[ix]->progenitor());
- HardBranchingPtr last=newBranch;
- do {
- for(unsigned int ix=0;ix<last->children().size();++ix) {
- if(last->children()[ix]->branchingParticle()->id()==
- particlesToShower[ix]->id()) {
- last = last->children()[ix];
- continue;
- }
- }
- }
- while(!last->children().empty());
- last->status(HardBranching::Incoming);
- spaceBranchings.push_back(newBranch);
- allBranchings .push_back(last);
- }
- else {
- newBranch =
- new_ptr(HardBranching(particlesToShower[ix]->progenitor(),
- SudakovPtr(),HardBranchingPtr(),
- HardBranching::Incoming));
- spaceBranchings.push_back(newBranch);
- allBranchings .push_back(newBranch);
- }
- }
- }
- HardTreePtr QCDTree = new_ptr(HardTree(allBranchings,spaceBranchings,inter));
- // set the charge partners
- ShowerParticleVector particles;
- particles.push_back(spaceBranchings.back()->branchingParticle());
- for(set<HardBranchingPtr>::iterator cit=QCDTree->branchings().begin();
- cit!=QCDTree->branchings().end();++cit) {
- if((*cit)->status()==HardBranching::Outgoing)
- particles.push_back((*cit)->branchingParticle());
- }
- // get the partners
- showerModel()->partnerFinder()->setInitialEvolutionScales(particles,true,inter,true);
- // do the inverse recon
- if(!showerModel()->kinematicsReconstructor()->
- deconstructDecayJets(QCDTree,this,inter)) {
- return false;
- }
- // clear the old shower
- currentTree()->clear();
- // set the hard tree
- hardTree(QCDTree);
- // set the charge partners
- setEvolutionPartners(false,inter,false);
- // get the particles to be showered
- map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cit;
- map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cjt;
- particlesToShower.clear();
- // incoming particles
- for(cit=currentTree()->incomingLines().begin();
- cit!=currentTree()->incomingLines().end();++cit)
- particlesToShower.push_back(((*cit).first));
- assert(particlesToShower.size()==1);
- // outgoing particles
- for(cjt=currentTree()->outgoingLines().begin();
- cjt!=currentTree()->outgoingLines().end();++cjt) {
- particlesToShower.push_back(((*cjt).first));
- if(ptmax>ZERO) particlesToShower.back()->maximumpT(ptmax,inter);
- }
- for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
- map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
- eit=hardTree()->particles().end(),
- mit = hardTree()->particles().find(particlesToShower[ix]->progenitor());
- if( mit != eit) {
- if(mit->second->status()==HardBranching::Outgoing)
- particlesToShower[ix]->progenitor()->set5Momentum(mit->second->pVector());
- }
- }
- return true;
-}
-
-bool Evolver::constructHardTree(vector<ShowerProgenitorPtr> & particlesToShower,
- ShowerInteraction::Type inter) {
- bool noEmission = true;
- vector<HardBranchingPtr> spaceBranchings,allBranchings;
- for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
- if(particlesToShower[ix]->progenitor()->isFinalState()) {
- HardBranchingPtr newBranch;
- if(particlesToShower[ix]->hasEmitted()) {
- noEmission = false;
- newBranch =
- new_ptr(HardBranching(particlesToShower[ix]->progenitor(),
- particlesToShower[ix]->progenitor()->
- showerKinematics()->SudakovFormFactor(),
- HardBranchingPtr(),HardBranching::Outgoing));
- constructTimeLikeLine(newBranch,particlesToShower[ix]->progenitor());
- }
- else {
- newBranch =
- new_ptr(HardBranching(particlesToShower[ix]->progenitor(),
- SudakovPtr(),HardBranchingPtr(),
- HardBranching::Outgoing));
- }
- allBranchings.push_back(newBranch);
- }
- else {
- HardBranchingPtr first,last;
- if(!particlesToShower[ix]->progenitor()->parents().empty()) {
- noEmission = false;
- constructSpaceLikeLine(particlesToShower[ix]->progenitor(),
- first,last,SudakovPtr(),
- particlesToShower[ix]->original()->parents()[0]);
- }
- else {
- first = new_ptr(HardBranching(particlesToShower[ix]->progenitor(),
- SudakovPtr(),HardBranchingPtr(),
- HardBranching::Incoming));
- if(particlesToShower[ix]->original()->parents().empty())
- first->beam(particlesToShower[ix]->original());
- else
- first->beam(particlesToShower[ix]->original()->parents()[0]);
- last = first;
- }
- spaceBranchings.push_back(first);
- allBranchings.push_back(last);
- }
- }
- if(!noEmission) {
- HardTreePtr QCDTree = new_ptr(HardTree(allBranchings,spaceBranchings,
- inter));
- // set the charge partners
- ShowerParticleVector particles;
- for(set<HardBranchingPtr>::iterator cit=QCDTree->branchings().begin();
- cit!=QCDTree->branchings().end();++cit) {
- particles.push_back((*cit)->branchingParticle());
- }
- // get the partners
- showerModel()->partnerFinder()->setInitialEvolutionScales(particles,false,
- inter,true);
- // do the inverse recon
- if(!showerModel()->kinematicsReconstructor()->
- deconstructHardJets(QCDTree,this,inter))
- throw Exception() << "Can't to shower deconstruction for QED shower in"
- << "QEDEvolver::showerHard" << Exception::eventerror;
- // set the hard tree
- hardTree(QCDTree);
- }
- // clear the old shower
- currentTree()->clear();
- // set the charge partners
- setEvolutionPartners(true,inter,false);
- // get the particles to be showered
- particlesToShower = currentTree()->extractProgenitors();
- // reset momenta
- if(hardTree()) {
- for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
- map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
- eit=hardTree()->particles().end(),
- mit = hardTree()->particles().find(particlesToShower[ix]->progenitor());
- if( mit != eit) {
- particlesToShower[ix]->progenitor()->set5Momentum(mit->second->showerMomentum());
- }
- }
- }
- return true;
-}
-
-void Evolver::constructTimeLikeLine(tHardBranchingPtr branch,
- tShowerParticlePtr particle) {
- for(unsigned int ix=0;ix<particle->children().size();++ix) {
- HardBranching::Status status = branch->status();
- tShowerParticlePtr child =
- dynamic_ptr_cast<ShowerParticlePtr>(particle->children()[ix]);
- if(child->children().empty()) {
- HardBranchingPtr newBranch =
- new_ptr(HardBranching(child,SudakovPtr(),branch,status));
- branch->addChild(newBranch);
- }
- else {
- HardBranchingPtr newBranch =
- new_ptr(HardBranching(child,child->showerKinematics()->SudakovFormFactor(),
- branch,status));
- constructTimeLikeLine(newBranch,child);
- branch->addChild(newBranch);
- }
- }
- // \todo add EW
- // sort out the type of interaction
- if(!branch->children().empty()) {
- if(branch->branchingParticle()->id()==ParticleID::gamma ||
- branch->children()[0]->branchingParticle()->id()==ParticleID::gamma ||
- branch->children()[1]->branchingParticle()->id()==ParticleID::gamma)
- branch->type(ShowerPartnerType::QED);
- else {
- if(branch->branchingParticle()->id()==
- branch->children()[0]->branchingParticle()->id()) {
- if(branch->branchingParticle()->dataPtr()->iColour()==PDT::Colour8) {
- tShowerParticlePtr emittor =
- branch->branchingParticle()->showerKinematics()->z()>0.5 ?
- branch->children()[0]->branchingParticle() :
- branch->children()[1]->branchingParticle();
- if(branch->branchingParticle()->colourLine()==emittor->colourLine())
- branch->type(ShowerPartnerType::QCDAntiColourLine);
- else if(branch->branchingParticle()->antiColourLine()==emittor->antiColourLine())
- branch->type(ShowerPartnerType::QCDColourLine);
- else
- assert(false);
- }
- else if(branch->branchingParticle()->colourLine()) {
- branch->type(ShowerPartnerType::QCDColourLine);
- }
- else if(branch->branchingParticle()->antiColourLine()) {
- branch->type(ShowerPartnerType::QCDAntiColourLine);
- }
- else
- assert(false);
- }
- else if(branch->branchingParticle()->id()==ParticleID::g &&
- branch->children()[0]->branchingParticle()->id()==
- -branch->children()[1]->branchingParticle()->id()) {
- if(branch->branchingParticle()->showerKinematics()->z()>0.5)
- branch->type(ShowerPartnerType::QCDAntiColourLine);
- else
- branch->type(ShowerPartnerType::QCDColourLine);
-
- }
- else
- assert(false);
- }
- }
-}
-
-void Evolver::constructSpaceLikeLine(tShowerParticlePtr particle,
- HardBranchingPtr & first,
- HardBranchingPtr & last,
- SudakovPtr sud,PPtr beam) {
- if(!particle) return;
- if(!particle->parents().empty()) {
- tShowerParticlePtr parent =
- dynamic_ptr_cast<ShowerParticlePtr>(particle->parents()[0]);
- SudakovPtr newSud=particle->showerKinematics()->SudakovFormFactor();
- constructSpaceLikeLine(parent,first,last,newSud,beam);
- }
- HardBranchingPtr newBranch =
- new_ptr(HardBranching(particle,sud,last,HardBranching::Incoming));
- newBranch->beam(beam);
- if(!first) {
- first=newBranch;
- last =newBranch;
- return;
- }
- last->addChild(newBranch);
- tShowerParticlePtr timeChild =
- dynamic_ptr_cast<ShowerParticlePtr>(particle->parents()[0]->children()[1]);
- HardBranchingPtr timeBranch;
- if(!timeChild->children().empty()) {
- timeBranch =
- new_ptr(HardBranching(timeChild,
- timeChild->showerKinematics()->SudakovFormFactor(),
- last,HardBranching::Outgoing));
- constructTimeLikeLine(timeBranch,timeChild);
- }
- else {
- timeBranch =
- new_ptr(HardBranching(timeChild,SudakovPtr(),last,HardBranching::Outgoing));
- }
- last->addChild(timeBranch);
- // \todo add EW
- // sort out the type
- if(last->branchingParticle() ->id() == ParticleID::gamma ||
- newBranch->branchingParticle() ->id() == ParticleID::gamma ||
- timeBranch->branchingParticle()->id() == ParticleID::gamma) {
- last->type(ShowerPartnerType::QED);
- }
- else if(last->branchingParticle()->id()==newBranch->branchingParticle()->id()) {
- if(last->branchingParticle()->id()==ParticleID::g) {
- if(last->branchingParticle()->colourLine()==
- newBranch->branchingParticle()->colourLine()) {
- last->type(ShowerPartnerType::QCDAntiColourLine);
- }
- else {
- last->type(ShowerPartnerType::QCDColourLine);
- }
- }
- else if(last->branchingParticle()->hasColour()) {
- last->type(ShowerPartnerType::QCDColourLine);
- }
- else if(last->branchingParticle()->hasAntiColour()) {
- last->type(ShowerPartnerType::QCDAntiColourLine);
- }
- else
- assert(false);
- }
- else if(newBranch->branchingParticle()->id()==ParticleID::g) {
- if(last->branchingParticle()->hasColour()) {
- last->type(ShowerPartnerType::QCDAntiColourLine);
- }
- else if(last->branchingParticle()->hasAntiColour()) {
- last->type(ShowerPartnerType::QCDColourLine);
- }
- else
- assert(false);
- }
- else if(newBranch->branchingParticle()->hasColour()) {
- last->type(ShowerPartnerType::QCDColourLine);
- }
- else if(newBranch->branchingParticle()->hasAntiColour()) {
- last->type(ShowerPartnerType::QCDAntiColourLine);
- }
- else {
- assert(false);
- }
- last=newBranch;
-}
-
void Evolver::connectTrees(ShowerTreePtr showerTree,
HardTreePtr hardTree, bool hard ) {
ShowerParticleVector particles;
// find the Sudakovs
for(set<HardBranchingPtr>::iterator cit=hardTree->branchings().begin();
cit!=hardTree->branchings().end();++cit) {
// Sudakovs for ISR
if((**cit).parent()&&(**cit).status()==HardBranching::Incoming) {
++_nis;
IdList br(3);
br[0] = (**cit).parent()->branchingParticle()->id();
br[1] = (**cit). branchingParticle()->id();
br[2] = (**cit).parent()->children()[0]==*cit ?
(**cit).parent()->children()[1]->branchingParticle()->id() :
(**cit).parent()->children()[0]->branchingParticle()->id();
BranchingList branchings = splittingGenerator()->initialStateBranchings();
if(br[1]<0&&br[0]==br[1]) {
br[0] = abs(br[0]);
br[1] = abs(br[1]);
}
else if(br[1]<0) {
br[1] = -br[1];
br[2] = -br[2];
}
long index = abs(br[1]);
SudakovPtr sudakov;
for(BranchingList::const_iterator cjt = branchings.lower_bound(index);
cjt != branchings.upper_bound(index); ++cjt ) {
IdList ids = cjt->second.second;
if(ids[0]==br[0]&&ids[1]==br[1]&&ids[2]==br[2]) {
sudakov=cjt->second.first;
break;
}
}
if(!sudakov) throw Exception() << "Can't find Sudakov for the hard emission in "
<< "Evolver::connectTrees() for ISR"
<< Exception::runerror;
(**cit).parent()->sudakov(sudakov);
}
// Sudakovs for FSR
else if(!(**cit).children().empty()) {
++_nfs;
IdList br(3);
br[0] = (**cit) .branchingParticle()->id();
br[1] = (**cit).children()[0]->branchingParticle()->id();
br[2] = (**cit).children()[1]->branchingParticle()->id();
BranchingList branchings = splittingGenerator()->finalStateBranchings();
if(br[0]<0) {
br[0] = abs(br[0]);
br[1] = abs(br[1]);
br[2] = abs(br[2]);
}
long index = br[0];
SudakovPtr sudakov;
for(BranchingList::const_iterator cjt = branchings.lower_bound(index);
cjt != branchings.upper_bound(index); ++cjt ) {
IdList ids = cjt->second.second;
if(ids[0]==br[0]&&ids[1]==br[1]&&ids[2]==br[2]) {
sudakov=cjt->second.first;
break;
}
}
if(!sudakov) throw Exception() << "Can't find Sudakov for the hard emission in "
<< "Evolver::connectTrees()"
<< Exception::runerror;
(**cit).sudakov(sudakov);
}
}
// calculate the evolution scale
for(set<HardBranchingPtr>::iterator cit=hardTree->branchings().begin();
cit!=hardTree->branchings().end();++cit) {
particles.push_back((*cit)->branchingParticle());
}
showerModel()->partnerFinder()->
setInitialEvolutionScales(particles,!hard,hardTree->interaction(),
!hardTree->partnersSet());
hardTree->partnersSet(true);
// inverse reconstruction
if(hard) {
showerModel()->kinematicsReconstructor()->
deconstructHardJets(hardTree,ShowerHandler::currentHandler()->evolver(),
hardTree->interaction());
}
else
showerModel()->kinematicsReconstructor()->
deconstructDecayJets(hardTree,ShowerHandler::currentHandler()->evolver(),
hardTree->interaction());
// now reset the momenta of the showering particles
vector<ShowerProgenitorPtr> particlesToShower;
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit=showerTree->incomingLines().begin();
cit!=showerTree->incomingLines().end();++cit )
particlesToShower.push_back(cit->first);
// extract the showering particles
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cit=showerTree->outgoingLines().begin();
cit!=showerTree->outgoingLines().end();++cit )
particlesToShower.push_back(cit->first);
// match them
map<ShowerProgenitorPtr,HardBranchingPtr> partners;
for(set<HardBranchingPtr>::const_iterator bit=hardTree->branchings().begin();
bit!=hardTree->branchings().end();++bit) {
Energy2 dmin( 1e30*GeV2 );
ShowerProgenitorPtr partner;
for(vector<ShowerProgenitorPtr>::const_iterator pit=particlesToShower.begin();
pit!=particlesToShower.end();++pit) {
if(partners.find(*pit)!=partners.end()) continue;
if( (**bit).branchingParticle()->id() != (**pit).progenitor()->id() ) continue;
if( (**bit).branchingParticle()->isFinalState() !=
(**pit).progenitor()->isFinalState() ) continue;
if( (**pit).progenitor()->isFinalState() ) {
Energy2 dtest =
sqr( (**pit).progenitor()->momentum().x() - (**bit).showerMomentum().x() ) +
sqr( (**pit).progenitor()->momentum().y() - (**bit).showerMomentum().y() ) +
sqr( (**pit).progenitor()->momentum().z() - (**bit).showerMomentum().z() ) +
sqr( (**pit).progenitor()->momentum().t() - (**bit).showerMomentum().t() );
// add mass difference for identical particles (e.g. Z0 Z0 production)
dtest += 1e10*sqr((**pit).progenitor()->momentum().m()-(**bit).showerMomentum().m());
if( dtest < dmin ) {
partner = *pit;
dmin = dtest;
}
}
else {
// ensure directions are right
if((**pit).progenitor()->momentum().z()/(**bit).showerMomentum().z()>ZERO) {
partner = *pit;
break;
}
}
}
if(!partner) throw Exception() << "Failed to match shower and hard trees in Evolver::hardestEmission"
<< Exception::eventerror;
partners[partner] = *bit;
}
for(vector<ShowerProgenitorPtr>::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<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator
tit = showerTree->treelinks().begin();
tit != showerTree->treelinks().end();++tit) {
ShowerTreePtr decayTree = tit->first;
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit = decayTree->incomingLines().begin();
// reset the momentum of the decay particle
Lorentz5Momentum oldMomentum = cit->first->progenitor()->momentum();
Lorentz5Momentum newMomentum = tit->second.second->momentum();
LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass());
decayTree->transform(boost,true);
boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass());
decayTree->transform(boost,true);
}
}
void Evolver::doShowering(bool hard,XCPtr xcomb) {
- // order of the interactions
- bool showerOrder(true);
// zero number of emissions
_nis = _nfs = 0;
// if MC@NLO H event and limited emissions
// indicate both final and initial state emission
if ( isMCatNLOHEvent && _limitEmissions != 0 ) {
_nis = _nfs = 1;
}
// extract particles to shower
vector<ShowerProgenitorPtr> particlesToShower(setupShower(hard));
// setup the maximum scales for the shower
if (hardVetoOn()) setupMaximumScales(particlesToShower,xcomb);
// set the hard scales for the profiles
setupHardScales(particlesToShower,xcomb);
// specific stuff for hard processes and decays
Energy minmass(ZERO), mIn(ZERO);
// hard process generate the intrinsic p_T once and for all
if(hard) {
generateIntrinsicpT(particlesToShower);
}
// decay compute the minimum mass of the final-state
else {
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
if(particlesToShower[ix]->progenitor()->isFinalState()) {
if(particlesToShower[ix]->progenitor()->dataPtr()->stable())
minmass += particlesToShower[ix]->progenitor()->dataPtr()->constituentMass();
else
minmass += particlesToShower[ix]->progenitor()->mass();
}
else {
mIn = particlesToShower[ix]->progenitor()->mass();
}
}
// throw exception if decay can't happen
if ( minmass > mIn ) {
throw Exception() << "Evolver.cc: Mass of decaying particle is "
<< "below constituent masses of decay products."
<< Exception::eventerror;
}
}
- // check if interactions in right order
- if(hardTree() && interaction_!=4 &&
- hardTree()->interaction()!=interactions_[0]) {
- assert(interactions_.size()==2);
- showerOrder = false;
- swap(interactions_[0],interactions_[1]);
+ // create random particle vector
+ vector<ShowerProgenitorPtr> tmp;
+ unsigned int nColouredIncoming = 0;
+ while(particlesToShower.size()>0){
+ unsigned int xx=UseRandom::irnd(particlesToShower.size());
+ tmp.push_back(particlesToShower[xx]);
+ particlesToShower.erase(particlesToShower.begin()+xx);
}
- // loop over possible interactions
- for(unsigned int inter=0;inter<interactions_.size();++inter) {
- // set up for second pass if required
- if(inter!=0) {
- // zero intrinsic pt so only added first time round
- intrinsicpT().clear();
- // construct the tree and throw veto if not possible
- if(!(hard ?
- constructHardTree (particlesToShower,interactions_[inter]) :
- constructDecayTree(particlesToShower,interactions_[inter])))
- throw InteractionVeto();
- }
- // create random particle vector (only need to do once)
- vector<ShowerProgenitorPtr> 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;ix<particlesToShower.size();++ix) {
- if(!particlesToShower[ix]->progenitor()->isFinalState() &&
- particlesToShower[ix]->progenitor()->coloured()) ++nColouredIncoming;
- }
- bool switchRecon = hard && nColouredIncoming !=1;
- // main shower loop
- unsigned int ntry(0);
- bool reconstructed = false;
- do {
- // clear results of last attempt if needed
- if(ntry!=0) {
- currentTree()->clear();
- setEvolutionPartners(hard,interactions_[inter],true);
- _nis = _nfs = 0;
- // if MC@NLO H event and limited emissions
- // indicate both final and initial state emission
- if ( isMCatNLOHEvent && _limitEmissions != 0 ) {
- _nis = _nfs = 1;
- }
- for(unsigned int ix=0; ix<particlesToShower.size();++ix) {
- SpinPtr spin = particlesToShower[ix]->progenitor()->spinInfo();
- if(spin && spin->decayVertex() &&
- dynamic_ptr_cast<tcSVertexPtr>(spin->decayVertex())) {
- spin->decayVertex(VertexPtr());
- }
+ particlesToShower=tmp;
+ for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
+ if(!particlesToShower[ix]->progenitor()->isFinalState() &&
+ particlesToShower[ix]->progenitor()->coloured()) ++nColouredIncoming;
+ }
+ bool switchRecon = hard && nColouredIncoming !=1;
+ // main shower loop
+ unsigned int ntry(0);
+ bool reconstructed = false;
+ do {
+ // clear results of last attempt if needed
+ if(ntry!=0) {
+ currentTree()->clear();
+ setEvolutionPartners(hard,interaction_,true);
+ _nis = _nfs = 0;
+ // if MC@NLO H event and limited emissions
+ // indicate both final and initial state emission
+ if ( isMCatNLOHEvent && _limitEmissions != 0 ) {
+ _nis = _nfs = 1;
+ }
+ for(unsigned int ix=0; ix<particlesToShower.size();++ix) {
+ SpinPtr spin = particlesToShower[ix]->progenitor()->spinInfo();
+ if(spin && spin->decayVertex() &&
+ dynamic_ptr_cast<tcSVertexPtr>(spin->decayVertex())) {
+ spin->decayVertex(VertexPtr());
}
}
- // loop over particles
- for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
- // extract the progenitor
- progenitor(particlesToShower[ix]);
- // final-state radiation
- if(progenitor()->progenitor()->isFinalState()) {
- if(!isFSRadiationON()) continue;
+ }
+ // loop over particles
+ for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
+ // extract the progenitor
+ progenitor(particlesToShower[ix]);
+ // final-state radiation
+ if(progenitor()->progenitor()->isFinalState()) {
+ if(!isFSRadiationON()) continue;
+ // perform shower
+ progenitor()->hasEmitted(startTimeLikeShower(interaction_));
+ }
+ // initial-state radiation
+ else {
+ if(!isISRadiationON()) continue;
+ // hard process
+ if(hard) {
+ // get the PDF
+ setBeamParticle(_progenitor->beam());
+ assert(beamParticle());
+ // perform the shower
+ // set the beam particle
+ tPPtr beamparticle=progenitor()->original();
+ if(!beamparticle->parents().empty())
+ beamparticle=beamparticle->parents()[0];
+ // generate the shower
+ progenitor()->hasEmitted(startSpaceLikeShower(beamparticle,
+ interaction_));
+ }
+ // decay
+ else {
+ // skip colour and electrically neutral particles
+ if(!progenitor()->progenitor()->dataPtr()->coloured() &&
+ !progenitor()->progenitor()->dataPtr()->charged()) {
+ progenitor()->hasEmitted(false);
+ continue;
+ }
// perform shower
- progenitor()->hasEmitted(startTimeLikeShower(interactions_[inter]));
- }
- // initial-state radiation
- else {
- if(!isISRadiationON()) continue;
- // hard process
- if(hard) {
- // get the PDF
- setBeamParticle(_progenitor->beam());
- assert(beamParticle());
- // perform the shower
- // set the beam particle
- tPPtr beamparticle=progenitor()->original();
- if(!beamparticle->parents().empty())
- beamparticle=beamparticle->parents()[0];
- // generate the shower
- progenitor()->hasEmitted(startSpaceLikeShower(beamparticle,
- interactions_[inter]));
+ // set the scales correctly. The current scale is the maximum scale for
+ // emission not the starting scale
+ ShowerParticle::EvolutionScales maxScales(progenitor()->progenitor()->scales());
+ progenitor()->progenitor()->scales() = ShowerParticle::EvolutionScales();
+ if(progenitor()->progenitor()->dataPtr()->charged()) {
+ progenitor()->progenitor()->scales().QED = progenitor()->progenitor()->mass();
+ progenitor()->progenitor()->scales().QED_noAO = progenitor()->progenitor()->mass();
}
- // decay
- else {
- // skip colour and electrically neutral particles
- if(!progenitor()->progenitor()->dataPtr()->coloured() &&
- !progenitor()->progenitor()->dataPtr()->charged()) {
- progenitor()->hasEmitted(false);
- continue;
- }
- // perform shower
- // set the scales correctly. The current scale is the maximum scale for
- // emission not the starting scale
- ShowerParticle::EvolutionScales maxScales(progenitor()->progenitor()->scales());
- progenitor()->progenitor()->scales() = ShowerParticle::EvolutionScales();
- if(progenitor()->progenitor()->dataPtr()->charged()) {
- progenitor()->progenitor()->scales().QED = progenitor()->progenitor()->mass();
- progenitor()->progenitor()->scales().QED_noAO = progenitor()->progenitor()->mass();
- }
- if(progenitor()->progenitor()->hasColour()) {
- progenitor()->progenitor()->scales().QCD_c = progenitor()->progenitor()->mass();
- progenitor()->progenitor()->scales().QCD_c_noAO = progenitor()->progenitor()->mass();
- }
- if(progenitor()->progenitor()->hasAntiColour()) {
- progenitor()->progenitor()->scales().QCD_ac = progenitor()->progenitor()->mass();
- progenitor()->progenitor()->scales().QCD_ac_noAO = progenitor()->progenitor()->mass();
- }
- // perform the shower
- progenitor()->hasEmitted(startSpaceLikeDecayShower(maxScales,minmass,
- interactions_[inter]));
+ if(progenitor()->progenitor()->hasColour()) {
+ progenitor()->progenitor()->scales().QCD_c = progenitor()->progenitor()->mass();
+ progenitor()->progenitor()->scales().QCD_c_noAO = progenitor()->progenitor()->mass();
}
+ if(progenitor()->progenitor()->hasAntiColour()) {
+ progenitor()->progenitor()->scales().QCD_ac = progenitor()->progenitor()->mass();
+ progenitor()->progenitor()->scales().QCD_ac_noAO = progenitor()->progenitor()->mass();
+ }
+ // perform the shower
+ progenitor()->hasEmitted(startSpaceLikeDecayShower(maxScales,minmass,
+ interaction_));
}
}
- // do the kinematic reconstruction, checking if it worked
- reconstructed = hard ?
- showerModel()->kinematicsReconstructor()->
- reconstructHardJets (currentTree(),intrinsicpT(),interactions_[inter],
- switchRecon && ntry>maximumTries()/2) :
- showerModel()->kinematicsReconstructor()->
- reconstructDecayJets(currentTree(),interactions_[inter]);
}
- while(!reconstructed&&maximumTries()>++ntry);
- // check if failed to generate the shower
- if(ntry==maximumTries()) {
- if(hard)
- throw ShowerHandler::ShowerTriesVeto(ntry);
- else
- throw Exception() << "Failed to generate the shower after "
- << ntry << " attempts in Evolver::showerDecay()"
- << Exception::eventerror;
- }
+ // do the kinematic reconstruction, checking if it worked
+ reconstructed = hard ?
+ showerModel()->kinematicsReconstructor()->
+ reconstructHardJets (currentTree(),intrinsicpT(),interaction_,
+ switchRecon && ntry>maximumTries()/2) :
+ showerModel()->kinematicsReconstructor()->
+ reconstructDecayJets(currentTree(),interaction_);
+ }
+ while(!reconstructed&&maximumTries()>++ntry);
+ // check if failed to generate the shower
+ if(ntry==maximumTries()) {
+ if(hard)
+ throw ShowerHandler::ShowerTriesVeto(ntry);
+ else
+ throw Exception() << "Failed to generate the shower after "
+ << ntry << " attempts in Evolver::showerDecay()"
+ << Exception::eventerror;
}
// tree has now showered
_currenttree->hasShowered(true);
- if(!showerOrder) swap(interactions_[0],interactions_[1]);
hardTree(HardTreePtr());
}
void Evolver:: convertHardTree(bool hard,ShowerInteraction::Type type) {
map<ColinePtr,ColinePtr> cmap;
// incoming particles
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit=currentTree()->incomingLines().begin();cit!=currentTree()->incomingLines().end();++cit) {
map<ShowerParticlePtr,tHardBranchingPtr>::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<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cit=currentTree()->outgoingLines().begin();cit!=currentTree()->outgoingLines().end();++cit) {
map<tShowerTreePtr,pair<tShowerProgenitorPtr,
tShowerParticlePtr> >::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<ShowerParticlePtr,tHardBranchingPtr>::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<ShowerParticlePtr> particles =
currentTree()->extractProgenitorParticles();
// clear the partners
for(unsigned int ix=0;ix<particles.size();++ix) {
particles[ix]->partner(ShowerParticlePtr());
particles[ix]->clearPartners();
}
// clear the tree
hardTree(HardTreePtr());
// Set the initial evolution scales
showerModel()->partnerFinder()->
setInitialEvolutionScales(particles,!hard,type,!_hardtree);
}
Branching Evolver::selectTimeLikeBranching(tShowerParticlePtr particle,
ShowerInteraction::Type type,
HardBranchingPtr branch) {
Branching fb;
unsigned int iout=0;
tcPDPtr pdata[2];
while (true) {
// break if doing truncated shower and no truncated shower needed
if(branch && (!isTruncatedShowerON()||hardOnly())) break;
fb=_splittingGenerator->chooseForwardBranching(*particle,_finalenhance,type);
// no emission break
if(!fb.kinematics) break;
// special for truncated shower
if(branch) {
// check haven't evolved too far
if(fb.kinematics->scale() < branch->scale()) {
fb=Branching();
break;
}
// get the particle data objects
for(unsigned int ix=0;ix<2;++ix) pdata[ix]=getParticleData(fb.ids[ix+1]);
if(particle->id()!=fb.ids[0]) {
for(unsigned int ix=0;ix<2;++ix) {
tPDPtr cc(pdata[ix]->CC());
if(cc) pdata[ix]=cc;
}
}
// find the truncated line
iout=0;
if(pdata[0]->id()!=pdata[1]->id()) {
if(pdata[0]->id()==particle->id()) iout=1;
else if (pdata[1]->id()==particle->id()) iout=2;
}
else if(pdata[0]->id()==particle->id()) {
if(fb.kinematics->z()>0.5) iout=1;
else iout=2;
}
// apply the vetos for the truncated shower
// no flavour changing branchings
if(iout==0) {
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
double zsplit = iout==1 ? fb.kinematics->z() : 1-fb.kinematics->z();
// only if same interaction for forced branching
ShowerInteraction::Type type2 = convertInteraction(fb.type);
// and evolution
if(type2==branch->sudakov()->interactionType()) {
if(zsplit < 0.5 || // hardest line veto
fb.kinematics->scale()*zsplit < branch->scale() ) { // angular ordering veto
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
}
// pt veto
if(fb.kinematics->pT() > progenitor()->maximumpT(type2)) {
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
}
// standard vetos for all emissions
if(timeLikeVetoed(fb,particle)) {
particle->vetoEmission(fb.type,fb.kinematics->scale());
if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr());
continue;
}
break;
}
// normal case
if(!branch) {
if(fb.kinematics) fb.hard = false;
return fb;
}
// truncated emission
if(fb.kinematics) {
fb.hard = false;
fb.iout = iout;
return fb;
}
// otherwise need to return the hard emission
// construct the kinematics for the hard emission
ShoKinPtr showerKin=
branch->sudakov()->createFinalStateBranching(branch->scale(),
branch->children()[0]->z(),
branch->phi(),
branch->children()[0]->pT());
showerKin->initialize( *particle,PPtr() );
IdList idlist(3);
idlist[0] = particle->id();
idlist[1] = branch->children()[0]->branchingParticle()->id();
idlist[2] = branch->children()[1]->branchingParticle()->id();
fb = Branching( showerKin, idlist, branch->sudakov(),branch->type() );
fb.hard = true;
fb.iout=0;
// return it
return fb;
}
Branching Evolver::selectSpaceLikeDecayBranching(tShowerParticlePtr particle,
const ShowerParticle::EvolutionScales & maxScales,
Energy minmass,ShowerInteraction::Type type,
HardBranchingPtr branch) {
Branching fb;
unsigned int iout=0;
tcPDPtr pdata[2];
while (true) {
// break if doing truncated shower and no truncated shower needed
if(branch && (!isTruncatedShowerON()||hardOnly())) break;
// select branching
fb=_splittingGenerator->chooseDecayBranching(*particle,maxScales,minmass,
_initialenhance,type);
// return if no radiation
if(!fb.kinematics) break;
// special for truncated shower
if(branch) {
// check haven't evolved too far
if(fb.kinematics->scale() < branch->scale()) {
fb=Branching();
break;
}
// get the particle data objects
for(unsigned int ix=0;ix<2;++ix) pdata[ix]=getParticleData(fb.ids[ix+1]);
if(particle->id()!=fb.ids[0]) {
for(unsigned int ix=0;ix<2;++ix) {
tPDPtr cc(pdata[ix]->CC());
if(cc) pdata[ix]=cc;
}
}
// find the truncated line
iout=0;
if(pdata[0]->id()!=pdata[1]->id()) {
if(pdata[0]->id()==particle->id()) iout=1;
else if (pdata[1]->id()==particle->id()) iout=2;
}
else if(pdata[0]->id()==particle->id()) {
if(fb.kinematics->z()>0.5) iout=1;
else iout=2;
}
// apply the vetos for the truncated shower
// no flavour changing branchings
if(iout==0) {
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
ShowerInteraction::Type type2 = convertInteraction(fb.type);
double zsplit = iout==1 ? fb.kinematics->z() : 1-fb.kinematics->z();
if(type2==branch->sudakov()->interactionType()) {
if(zsplit < 0.5 || // hardest line veto
fb.kinematics->scale()*zsplit < branch->scale() ) { // angular ordering veto
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
}
// pt veto
if(fb.kinematics->pT() > progenitor()->maximumpT(type2)) {
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
}
// if not vetoed break
if(spaceLikeDecayVetoed(fb,particle)) {
// otherwise reset scale and continue
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
break;
}
// normal case
if(!branch) {
if(fb.kinematics) fb.hard = false;
return fb;
}
// truncated emission
if(fb.kinematics) {
fb.hard = false;
fb.iout = iout;
return fb;
}
// otherwise need to return the hard emission
// construct the kinematics for the hard emission
ShoKinPtr showerKin=
branch->sudakov()->createDecayBranching(branch->scale(),
branch->children()[0]->z(),
branch->phi(),
branch->children()[0]->pT());
showerKin->initialize( *particle,PPtr() );
IdList idlist(3);
idlist[0] = particle->id();
idlist[1] = branch->children()[0]->branchingParticle()->id();
idlist[2] = branch->children()[1]->branchingParticle()->id();
// create the branching
fb = Branching( showerKin, idlist, branch->sudakov(),ShowerPartnerType::QCDColourLine );
fb.hard=true;
fb.iout=0;
// return it
return fb;
}
diff --git a/Shower/Base/Evolver.h b/Shower/Base/Evolver.h
--- a/Shower/Base/Evolver.h
+++ b/Shower/Base/Evolver.h
@@ -1,951 +1,917 @@
// -*- C++ -*-
//
// Evolver.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_Evolver_H
#define HERWIG_Evolver_H
//
// This is the declaration of the Evolver class.
//
#include "ThePEG/Interface/Interfaced.h"
#include "Herwig/Shower/SplittingFunctions/SplittingGenerator.h"
#include "ShowerModel.h"
#include "ThePEG/PDF/BeamParticleData.h"
#include "ShowerTree.h"
#include "ShowerProgenitor.fh"
#include "Herwig/Shower/ShowerHandler.fh"
#include "Branching.h"
#include "ShowerVeto.h"
#include "HardTree.h"
#include "ThePEG/Handlers/XComb.h"
#include "Evolver.fh"
#include "Herwig/MatrixElement/HwMEBase.h"
#include "Herwig/Decay/HwDecayerBase.h"
#include "Herwig/MatrixElement/Matchbox/Matching/ShowerApproximation.h"
namespace Herwig {
using namespace ThePEG;
/**\ingroup Shower
* Exception class
* used to communicate failure of QED shower
*/
struct InteractionVeto {};
/** \ingroup Shower
* The Evolver class class performs the sohwer evolution of hard scattering
* and decay processes in Herwig.
*
* @see \ref EvolverInterfaces "The interfaces"
* defined for Evolver.
*/
class Evolver: public Interfaced {
/**
* The ShowerHandler is a friend to set some parameters at initialisation
*/
friend class ShowerHandler;
public:
/**
* Pointer to an XComb object
*/
typedef Ptr<XComb>::pointer XCPtr;
public:
/**
* Default Constructor
*/
Evolver() : _maxtry(100), _meCorrMode(1), _hardVetoMode(1),
_hardVetoRead(0), _reconOpt(0),
_hardVetoReadOption(false),
_iptrms(ZERO), _beta(0.), _gamma(ZERO), _iptmax(),
_limitEmissions(0), _initialenhance(1.), _finalenhance(1.),
- interaction_(1), _trunc_Mode(true), _hardEmissionMode(0),
+ interaction_(ShowerInteraction::QEDQCD), _trunc_Mode(true), _hardEmissionMode(0),
_spinOpt(1), _softOpt(2), _hardPOWHEG(false),
theFactorizationScaleFactor(1.0),
theRenormalizationScaleFactor(1.0), muPt(ZERO),
_maxTryFSR(100000),_maxFailFSR(100),_fracFSR(0.001),
_nFSR(0), _nFailedFSR(0)
{}
/**
* Members to perform the shower
*/
//@{
/**
* Perform the shower of the hard process
*/
virtual void showerHardProcess(ShowerTreePtr,XCPtr);
/**
* Perform the shower of a decay
*/
virtual void showerDecay(ShowerTreePtr);
//@}
/**
* Access to the flags and shower variables
*/
//@{
/**
* Is there any showering switched on
*/
bool showeringON() const { return isISRadiationON() || isFSRadiationON(); }
/**
* It returns true/false if the initial-state radiation is on/off.
*/
bool isISRadiationON() const { return _splittingGenerator->isISRadiationON(); }
/**
* It returns true/false if the final-state radiation is on/off.
*/
bool isFSRadiationON() const { return _splittingGenerator->isFSRadiationON(); }
/**
* Get the ShowerModel
*/
ShowerModelPtr showerModel() const {return _model;}
/**
* Get the SplittingGenerator
*/
tSplittingGeneratorPtr splittingGenerator() const { return _splittingGenerator; }
/**
* Mode for hard emissions
*/
int hardEmissionMode() const {return _hardEmissionMode;}
/**
* Switch on or off hard vetoes
*/
void restrictPhasespace(bool yes) {
if ( yes )
_hardVetoMode = 1;
else
_hardVetoMode = 0;
}
/**
* Switch on or off hard veto scale from muF
*/
void hardScaleIsMuF(bool yes) {
if ( yes )
_hardVetoRead = 1;
else
_hardVetoRead = 0;
}
//@}
/**
* Connect the Hard and Shower trees
*/
virtual void connectTrees(ShowerTreePtr showerTree, HardTreePtr hardTree, bool hard );
/**
* Access to switches for spin correlations
*/
//@{
/**
* Spin Correlations
*/
unsigned int spinCorrelations() const {
return _spinOpt;
}
/**
* Soft correlations
*/
unsigned int softCorrelations() const {
return _softOpt;
}
/**
* Any correlations
*/
bool correlations() const {
return _spinOpt!=0||_softOpt!=0;
}
//@}
/**
* Set the factorization scale factor
*/
void factorizationScaleFactor(double f) {
if ( f == theFactorizationScaleFactor )
return;
theFactorizationScaleFactor = f;
splittingGenerator()->factorizationScaleFactor(f);
}
/**
* Set the renormalization scale factor
*/
void renormalizationScaleFactor(double f) {
if ( f == theRenormalizationScaleFactor )
return;
theRenormalizationScaleFactor = f;
splittingGenerator()->renormalizationScaleFactor(f);
}
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/**
* Perform the shower
*/
void doShowering(bool hard,XCPtr);
/**
* Generate the hard matrix element correction
*/
virtual void hardMatrixElementCorrection(bool);
/**
* Generate the hardest emission
*/
virtual void hardestEmission(bool hard);
/**
* Extract the particles to be showered, set the evolution scales
* and apply the hard matrix element correction
* @param hard Whether this is a hard process or decay
* @return The particles to be showered
*/
virtual vector<ShowerProgenitorPtr> setupShower(bool hard);
/**
* set the colour partners
*/
virtual void setEvolutionPartners(bool hard,ShowerInteraction::Type,
bool clear);
/**
* Methods to perform the evolution of an individual particle, including
* recursive calling on the products
*/
//@{
/**
* It does the forward evolution of the time-like input particle
* (and recursively for all its radiation products).
* accepting only emissions which conforms to the showerVariables
* and soft matrix element correction.
* If at least one emission has occurred then the method returns true.
* @param particle The particle to be showered
*/
virtual bool timeLikeShower(tShowerParticlePtr particle, ShowerInteraction::Type,
Branching fb, bool first);
/**
* It does the backward evolution of the space-like input particle
* (and recursively for all its time-like radiation products).
* accepting only emissions which conforms to the showerVariables.
* If at least one emission has occurred then the method returns true
* @param particle The particle to be showered
* @param beam The beam particle
*/
virtual bool spaceLikeShower(tShowerParticlePtr particle,PPtr beam,
ShowerInteraction::Type);
/**
* If does the forward evolution of the input on-shell particle
* involved in a decay
* (and recursively for all its time-like radiation products).
* accepting only emissions which conforms to the showerVariables.
* @param particle The particle to be showered
* @param maxscale The maximum scale for the shower.
* @param minimumMass The minimum mass of the final-state system
*/
virtual bool
spaceLikeDecayShower(tShowerParticlePtr particle,
const ShowerParticle::EvolutionScales & maxScales,
Energy minimumMass,ShowerInteraction::Type,
Branching fb);
/**
* Truncated shower from a time-like particle
*/
virtual bool truncatedTimeLikeShower(tShowerParticlePtr particle,
HardBranchingPtr branch,
ShowerInteraction::Type type,
Branching fb, bool first);
/**
* Truncated shower from a space-like particle
*/
virtual bool truncatedSpaceLikeShower(tShowerParticlePtr particle,PPtr beam,
HardBranchingPtr branch,
ShowerInteraction::Type type);
/**
* Truncated shower from a time-like particle
*/
virtual bool truncatedSpaceLikeDecayShower(tShowerParticlePtr particle,
const ShowerParticle::EvolutionScales & maxScales,
Energy minimumMass, HardBranchingPtr branch,
ShowerInteraction::Type type, Branching fb);
//@}
/**
* Switches for matrix element corrections
*/
//@{
/**
* Any ME correction?
*/
bool MECOn(bool hard) const {
return ( _hardEmissionMode == 0 ||
(!hard && _hardEmissionMode ==-1) ) &&
_meCorrMode > 0;
}
/**
* Any hard ME correction?
*/
bool hardMEC(bool hard) const {
return ( _hardEmissionMode == 0 ||
(!hard && _hardEmissionMode ==-1) ) &&
(_meCorrMode == 1 || _meCorrMode == 2);
}
/**
* Any soft ME correction?
*/
bool softMEC() const {
return ( _hardEmissionMode == 0 ||
(_currenttree->isDecay() && _hardEmissionMode ==-1) ) &&
(_meCorrMode == 1 || _meCorrMode > 2);
}
//@}
/**
* Is the truncated shower on?
*/
bool isTruncatedShowerON() const {return _trunc_Mode;}
/**
* Switch for intrinsic pT
*/
//@{
/**
* Any intrinsic pT?
*/
bool ipTon() const {
return _iptrms != ZERO || ( _beta == 1.0 && _gamma != ZERO && _iptmax !=ZERO );
}
//@}
/**@name Additional shower vetoes */
//@{
/**
* Insert a veto.
*/
void addVeto (ShowerVetoPtr v) { _vetoes.push_back(v); }
/**
* Remove a veto.
*/
void removeVeto (ShowerVetoPtr v) {
vector<ShowerVetoPtr>::iterator vit = find(_vetoes.begin(),_vetoes.end(),v);
if (vit != _vetoes.end())
_vetoes.erase(vit);
}
//@}
/**
* Switches for vetoing hard emissions
*/
//@{
/**
* Vetos on?
*/
bool hardVetoOn() const { return _hardVetoMode > 0; }
/**
* veto hard emissions in IS shower?
*/
bool hardVetoIS() const { return _hardVetoMode == 1 || _hardVetoMode == 2; }
/**
* veto hard emissions in FS shower?
*/
bool hardVetoFS() const { return _hardVetoMode == 1 || _hardVetoMode > 2; }
/**
* veto hard emissions according to lastScale from XComb?
*/
bool hardVetoXComb() const {return (_hardVetoRead == 1);}
/**
* Returns true if the hard veto read-in is to be applied to only
* the primary collision and false otherwise.
*/
bool hardVetoReadOption() const {return _hardVetoReadOption;}
//@}
/**
* Enhancement factors for radiation needed to generate the soft matrix
* element correction.
*/
//@{
/**
* Access the enhancement factor for initial-state radiation
*/
double initialStateRadiationEnhancementFactor() const { return _initialenhance; }
/**
* Access the enhancement factor for final-state radiation
*/
double finalStateRadiationEnhancementFactor() const { return _finalenhance; }
/**
* Set the enhancement factor for initial-state radiation
*/
void initialStateRadiationEnhancementFactor(double in) { _initialenhance=in; }
/**
* Set the enhancement factor for final-state radiation
*/
void finalStateRadiationEnhancementFactor(double in) { _finalenhance=in; }
//@}
/**
* Access to set/get the HardTree currently beinging showered
*/
//@{
/**
* The HardTree currently being showered
*/
tHardTreePtr hardTree() {return _hardtree;}
/**
* The HardTree currently being showered
*/
void hardTree(tHardTreePtr in) {_hardtree = in;}
//@}
/**
* Access/set the beam particle for the current initial-state shower
*/
//@{
/**
* Get the beam particle data
*/
Ptr<BeamParticleData>::const_pointer beamParticle() const { return _beam; }
/**
* Set the beam particle data
*/
void setBeamParticle(Ptr<BeamParticleData>::const_pointer in) { _beam=in; }
//@}
/**
* Set/Get the current tree being evolverd for inheriting classes
*/
//@{
/**
* Get the tree
*/
tShowerTreePtr currentTree() { return _currenttree; }
/**
* Set the tree
*/
void currentTree(tShowerTreePtr tree) { _currenttree=tree; }
//@}
/**
* Access the maximum number of attempts to generate the shower
*/
unsigned int maximumTries() const { return _maxtry; }
/**
* Set/Get the ShowerProgenitor for the current shower
*/
//@{
/**
* Access the progenitor
*/
ShowerProgenitorPtr progenitor() { return _progenitor; }
/**
* Set the progenitor
*/
void progenitor(ShowerProgenitorPtr in) { _progenitor=in; }
//@}
/**
* Calculate the intrinsic \f$p_T\f$.
*/
virtual void generateIntrinsicpT(vector<ShowerProgenitorPtr>);
/**
* Access to the intrinsic \f$p_T\f$ for inheriting classes
*/
map<tShowerProgenitorPtr,pair<Energy,double> > & intrinsicpT() { return _intrinsic; }
/**
* find the maximally allowed pt acc to the hard process.
*/
void setupMaximumScales(const vector<ShowerProgenitorPtr> &,XCPtr);
/**
* find the relevant hard scales for profile scales.
*/
void setupHardScales(const vector<ShowerProgenitorPtr> &,XCPtr);
/**
* Return the relevant hard scale to be used in the profile scales
*/
Energy hardScale() const {
return muPt;
}
/**
* Convert the HardTree into an extra shower emission
*/
void convertHardTree(bool hard,ShowerInteraction::Type type);
protected:
/**
* Start the shower of a timelike particle
*/
virtual bool startTimeLikeShower(ShowerInteraction::Type);
/**
* Update of the time-like stuff
*/
void updateHistory(tShowerParticlePtr particle);
/**
* Start the shower of a spacelike particle
*/
virtual bool startSpaceLikeShower(PPtr,ShowerInteraction::Type);
/**
* Start the shower of a spacelike particle
*/
virtual bool
startSpaceLikeDecayShower(const ShowerParticle::EvolutionScales & maxScales,
Energy minimumMass,ShowerInteraction::Type);
/**
* Select the branching for the next time-like emission
*/
Branching selectTimeLikeBranching(tShowerParticlePtr particle,
ShowerInteraction::Type type,
HardBranchingPtr branch);
/**
* Select the branching for the next space-like emission in a decay
*/
Branching selectSpaceLikeDecayBranching(tShowerParticlePtr particle,
const ShowerParticle::EvolutionScales & maxScales,
Energy minmass,ShowerInteraction::Type type,
HardBranchingPtr branch);
/**
* Create the timelike child of a branching
*/
ShowerParticleVector createTimeLikeChildren(tShowerParticlePtr particle,
IdList ids);
/**
* Vetos for the timelike shower
*/
virtual bool timeLikeVetoed(const Branching &,ShowerParticlePtr);
/**
* Vetos for the spacelike shower
*/
virtual bool spaceLikeVetoed(const Branching &,ShowerParticlePtr);
/**
* Vetos for the spacelike shower
*/
virtual bool spaceLikeDecayVetoed(const Branching &,ShowerParticlePtr);
/**
* Only generate the hard emission, for testing only.
*/
bool hardOnly() const {return _limitEmissions==3;}
- /**
- * Members to construct the HardTree from the shower if needed
- */
- //@{
- /**
- * Construct the tree for a scattering process
- */
- bool constructHardTree(vector<ShowerProgenitorPtr> & particlesToShower,
- ShowerInteraction::Type inter);
-
- /**
- * Construct the tree for a decay process
- */
- bool constructDecayTree(vector<ShowerProgenitorPtr> & particlesToShower,
- ShowerInteraction::Type inter);
-
- /**
- * Construct a time-like line
- */
- void constructTimeLikeLine(tHardBranchingPtr branch,tShowerParticlePtr particle);
-
- /**
- * Construct a space-like line
- */
- void constructSpaceLikeLine(tShowerParticlePtr particle,
- HardBranchingPtr & first, HardBranchingPtr & last,
- SudakovPtr sud,PPtr beam);
- //@}
-
public:
/** @name MC@NLO diagnostics */
//@{
/**
* True, if Matchbox MC@NLO S-event
*/
bool wasMCatNLOSEvent() const { return isMCatNLOSEvent; }
/**
* True, if matchbox MC@NLO H-event
*/
bool wasMCatNLOHEvent() const { return isMCatNLOHEvent; }
//@}
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
Evolver & operator=(const Evolver &);
private:
/**
* Pointer to the model for the shower evolution model
*/
ShowerModelPtr _model;
/**
* Pointer to the splitting generator
*/
SplittingGeneratorPtr _splittingGenerator;
/**
* Maximum number of tries to generate the shower of a particular tree
*/
unsigned int _maxtry;
/**
* Matrix element correction switch
*/
unsigned int _meCorrMode;
/**
* Hard emission veto switch
*/
unsigned int _hardVetoMode;
/**
* Hard veto to be read switch
*/
unsigned int _hardVetoRead;
/**
* Control of the reconstruction option
*/
unsigned int _reconOpt;
/**
* If hard veto pT scale is being read-in this determines
* whether the read-in value is applied to primary and
* secondary (MPI) scatters or just the primary one, with
* the usual computation of the veto being performed for
* the secondary (MPI) scatters.
*/
bool _hardVetoReadOption;
/**
* rms intrinsic pT of Gaussian distribution
*/
Energy _iptrms;
/**
* Proportion of inverse quadratic intrinsic pT distribution
*/
double _beta;
/**
* Parameter for inverse quadratic: 2*Beta*Gamma/(sqr(Gamma)+sqr(intrinsicpT))
*/
Energy _gamma;
/**
* Upper bound on intrinsic pT for inverse quadratic
*/
Energy _iptmax;
/**
* Limit the number of emissions for testing
*/
unsigned int _limitEmissions;
/**
* The progenitor of the current shower
*/
ShowerProgenitorPtr _progenitor;
/**
* Matrix element
*/
HwMEBasePtr _hardme;
/**
* Decayer
*/
HwDecayerBasePtr _decayme;
/**
* The ShowerTree currently being showered
*/
ShowerTreePtr _currenttree;
/**
* The HardTree currently being showered
*/
HardTreePtr _hardtree;
/**
* Radiation enhancement factors for use with the veto algorithm
* if needed by the soft matrix element correction
*/
//@{
/**
* Enhancement factor for initial-state radiation
*/
double _initialenhance;
/**
* Enhancement factor for final-state radiation
*/
double _finalenhance;
//@}
/**
* The beam particle data for the current initial-state shower
*/
Ptr<BeamParticleData>::const_pointer _beam;
/**
* Storage of the intrinsic \f$p_t\f$ of the particles
*/
map<tShowerProgenitorPtr,pair<Energy,double> > _intrinsic;
/**
* Vetoes
*/
vector<ShowerVetoPtr> _vetoes;
/**
* number of IS emissions
*/
unsigned int _nis;
/**
* Number of FS emissions
*/
unsigned int _nfs;
/**
* The option for wqhich interactions to use
*/
- unsigned int interaction_;
-
- /**
- * Interactions allowed in the shower
- */
- vector<ShowerInteraction::Type> interactions_;
+ ShowerInteraction::Type interaction_;
/**
* Truncated shower switch
*/
bool _trunc_Mode;
/**
* Count of the number of truncated emissions
*/
unsigned int _truncEmissions;
/**
* Mode for the hard emissions
*/
int _hardEmissionMode;
/**
* Option to include spin correlations
*/
unsigned int _spinOpt;
/**
* Option for the kernal for soft correlations
*/
unsigned int _softOpt;
/**
* Option for hard radiation in POWHEG events
*/
bool _hardPOWHEG;
/**
* True, if Matchbox MC@NLO S-event
*/
bool isMCatNLOSEvent;
/**
* True, if matchbox MC@NLO H-event
*/
bool isMCatNLOHEvent;
/**
* True, if Matchbox Powheg S-event
*/
bool isPowhegSEvent;
/**
* True, if matchbox Powheg H-event
*/
bool isPowhegHEvent;
/**
* The shower approximation to provide the hard scale profile
*/
Ptr<ShowerApproximation>::tptr theShowerApproximation;
/**
* The factorization scale factor.
*/
double theFactorizationScaleFactor;
/**
* The renormalization scale factor.
*/
double theRenormalizationScaleFactor;
/**
* True if no warnings about incorrect hard emission
* mode setting have been issued yet
*/
static bool _hardEmissionModeWarn;
/**
* True if no warnings about missing truncated shower
* have been issued yet
*/
static bool _missingTruncWarn;
/**
* The relevant hard scale to be used in the profile scales
*/
Energy muPt;
/**
* Maximum number of emission attempts for FSR
*/
unsigned int _maxTryFSR;
/**
* Maximum number of failures for FSR generation
*/
unsigned int _maxFailFSR;
/**
* Failure fraction for FSR generation
*/
double _fracFSR;
/**
* Counter for number of FSR emissions
*/
unsigned int _nFSR;
/**
* Counter for the number of failed events due to FSR emissions
*/
unsigned int _nFailedFSR;
};
}
#endif /* HERWIG_Evolver_H */
diff --git a/src/defaults/Shower.in b/src/defaults/Shower.in
--- a/src/defaults/Shower.in
+++ b/src/defaults/Shower.in
@@ -1,292 +1,292 @@
# -*- ThePEG-repository -*-
############################################################
# Setup of default parton shower
#
# Useful switches for users are marked near the top of
# this file.
#
# Don't edit this file directly, but reset the switches
# in your own input files!
############################################################
library HwMPI.so
library HwShower.so
library HwMatching.so
mkdir /Herwig/Shower
cd /Herwig/Shower
create Herwig::ShowerHandler ShowerHandler
newdef ShowerHandler:MPIHandler /Herwig/UnderlyingEvent/MPIHandler
newdef ShowerHandler:RemDecayer /Herwig/Partons/RemnantDecayer
# use LO PDFs for Shower, can be changed later
newdef ShowerHandler:PDFA /Herwig/Partons/ShowerLOPDF
newdef ShowerHandler:PDFB /Herwig/Partons/ShowerLOPDF
newdef ShowerHandler:PDFARemnant /Herwig/Partons/RemnantPDF
newdef ShowerHandler:PDFBRemnant /Herwig/Partons/RemnantPDF
#####################################
# initial setup, don't change these!
#####################################
create Herwig::SplittingGenerator SplittingGenerator
create Herwig::ShowerAlphaQCD AlphaQCD
create Herwig::ShowerAlphaQED AlphaQED
create Herwig::Evolver Evolver
create Herwig::QTildeModel ShowerModel
create Herwig::QTildeFinder PartnerFinder
newdef PartnerFinder:PartnerMethod 1
newdef PartnerFinder:ScaleChoice 1
create Herwig::QTildeReconstructor KinematicsReconstructor
newdef KinematicsReconstructor:ReconstructionOption Colour3
newdef KinematicsReconstructor:InitialStateReconOption SofterFraction
newdef KinematicsReconstructor:InitialInitialBoostOption LongTransBoost
newdef /Herwig/Partons/RemnantDecayer:AlphaS AlphaQCD
newdef /Herwig/Partons/RemnantDecayer:AlphaEM AlphaQED
newdef ShowerHandler:Evolver Evolver
newdef ShowerModel:PartnerFinder PartnerFinder
newdef ShowerModel:KinematicsReconstructor KinematicsReconstructor
newdef Evolver:ShowerModel ShowerModel
newdef Evolver:SplittingGenerator SplittingGenerator
-newdef Evolver:Interactions BothAtOnce
+newdef Evolver:Interaction QEDQCD
newdef Evolver:SpinCorrelations Yes
newdef Evolver:SoftCorrelations Singular
##################################################################
# Intrinsic pT
#
# Recommended:
# 1.9 GeV for Tevatron W/Z production.
# 2.1 GeV for LHC W/Z production at 10 TeV
# 2.2 GeV for LHC W/Z production at 14 TeV
#
# Set all parameters to 0 to disable
##################################################################
newdef Evolver:IntrinsicPtGaussian 1.3*GeV
newdef Evolver:IntrinsicPtBeta 0
newdef Evolver:IntrinsicPtGamma 0*GeV
newdef Evolver:IntrinsicPtIptmax 0*GeV
#############################################################
# Main control switches for the parton shower.
#############################################################
newdef SplittingGenerator:ISR Yes
newdef SplittingGenerator:FSR Yes
#############################################################
# Set up truncated shower handler.
#############################################################
create Herwig::PowhegShowerHandler PowhegShowerHandler
set PowhegShowerHandler:MPIHandler /Herwig/UnderlyingEvent/MPIHandler
set PowhegShowerHandler:RemDecayer /Herwig/Partons/RemnantDecayer
set PowhegShowerHandler:Evolver /Herwig/Shower/Evolver
newdef PowhegShowerHandler:PDFA /Herwig/Partons/ShowerLOPDF
newdef PowhegShowerHandler:PDFB /Herwig/Partons/ShowerLOPDF
newdef PowhegShowerHandler:PDFARemnant /Herwig/Partons/RemnantPDF
newdef PowhegShowerHandler:PDFBRemnant /Herwig/Partons/RemnantPDF
#############################################################
#############################################################
# End of interesting user servicable section.
#
# Anything that follows below should only be touched if you
# know what you're doing.
#
# Really.
#############################################################
#
# a few default values
newdef Evolver:MECorrMode 1
newdef Evolver:ReconstructionOption OffShell3
newdef AlphaQCD:ScaleFactor 1.0
newdef AlphaQCD:NPAlphaS 2
newdef AlphaQCD:Qmin 0.935
newdef AlphaQCD:NumberOfLoops 2
newdef AlphaQCD:InputOption 1
newdef AlphaQCD:AlphaMZ 0.134
#
#
# Lets set up all the splittings
create Herwig::HalfHalfOneSplitFn QtoQGammaSplitFn
set QtoQGammaSplitFn:InteractionType QED
set QtoQGammaSplitFn:ColourStructure ChargedChargedNeutral
set QtoQGammaSplitFn:AngularOrdered Yes
create Herwig::HalfHalfOneSplitFn QtoQGSplitFn
newdef QtoQGSplitFn:InteractionType QCD
newdef QtoQGSplitFn:ColourStructure TripletTripletOctet
set QtoQGSplitFn:AngularOrdered Yes
create Herwig::OneOneOneSplitFn GtoGGSplitFn
newdef GtoGGSplitFn:InteractionType QCD
newdef GtoGGSplitFn:ColourStructure OctetOctetOctet
set GtoGGSplitFn:AngularOrdered Yes
create Herwig::OneHalfHalfSplitFn GtoQQbarSplitFn
newdef GtoQQbarSplitFn:InteractionType QCD
newdef GtoQQbarSplitFn:ColourStructure OctetTripletTriplet
set GtoQQbarSplitFn:AngularOrdered No
create Herwig::OneHalfHalfSplitFn GammatoQQbarSplitFn
newdef GammatoQQbarSplitFn:InteractionType QED
newdef GammatoQQbarSplitFn:ColourStructure NeutralChargedCharged
set GammatoQQbarSplitFn:AngularOrdered No
create Herwig::HalfOneHalfSplitFn QtoGQSplitFn
newdef QtoGQSplitFn:InteractionType QCD
newdef QtoGQSplitFn:ColourStructure TripletOctetTriplet
set QtoGQSplitFn:AngularOrdered Yes
create Herwig::HalfOneHalfSplitFn QtoGammaQSplitFn
newdef QtoGammaQSplitFn:InteractionType QED
newdef QtoGammaQSplitFn:ColourStructure ChargedNeutralCharged
set QtoGammaQSplitFn:AngularOrdered Yes
#
# Now the Sudakovs
create Herwig::QTildeSudakov SudakovCommon
newdef SudakovCommon:Alpha AlphaQCD
newdef SudakovCommon:cutoffKinScale 0.0*GeV
newdef SudakovCommon:PDFmax 1.0
newdef SudakovCommon:CutOffOption pT
newdef SudakovCommon:pTmin 1.67*GeV
cp SudakovCommon QtoQGSudakov
newdef QtoQGSudakov:SplittingFunction QtoQGSplitFn
newdef QtoQGSudakov:PDFmax 1.9
cp SudakovCommon QtoQGammaSudakov
set QtoQGammaSudakov:SplittingFunction QtoQGammaSplitFn
set QtoQGammaSudakov:Alpha AlphaQED
set QtoQGammaSudakov:PDFmax 1.9
cp QtoQGammaSudakov LtoLGammaSudakov
cp SudakovCommon GtoGGSudakov
newdef GtoGGSudakov:SplittingFunction GtoGGSplitFn
newdef GtoGGSudakov:PDFmax 2.0
cp SudakovCommon GtoQQbarSudakov
newdef GtoQQbarSudakov:SplittingFunction GtoQQbarSplitFn
newdef GtoQQbarSudakov:PDFmax 120.0
cp SudakovCommon GammatoQQbarSudakov
newdef GammatoQQbarSudakov:SplittingFunction GammatoQQbarSplitFn
newdef GammatoQQbarSudakov:PDFmax 120.0
cp SudakovCommon GtobbbarSudakov
newdef GtobbbarSudakov:SplittingFunction GtoQQbarSplitFn
newdef GtobbbarSudakov:PDFmax 40000.0
cp SudakovCommon GtoccbarSudakov
newdef GtoccbarSudakov:SplittingFunction GtoQQbarSplitFn
newdef GtoccbarSudakov:PDFmax 2000.0
cp SudakovCommon QtoGQSudakov
newdef QtoGQSudakov:SplittingFunction QtoGQSplitFn
cp SudakovCommon QtoGammaQSudakov
newdef QtoGammaQSudakov:SplittingFunction QtoGammaQSplitFn
cp SudakovCommon utoGuSudakov
newdef utoGuSudakov:SplittingFunction QtoGQSplitFn
newdef utoGuSudakov:PDFFactor OverOneMinusZ
newdef utoGuSudakov:PDFmax 5.0
cp SudakovCommon dtoGdSudakov
newdef dtoGdSudakov:SplittingFunction QtoGQSplitFn
newdef dtoGdSudakov:PDFFactor OverOneMinusZ
#
# Now add the final splittings
#
do SplittingGenerator:AddFinalSplitting u->u,g; QtoQGSudakov
do SplittingGenerator:AddFinalSplitting d->d,g; QtoQGSudakov
do SplittingGenerator:AddFinalSplitting s->s,g; QtoQGSudakov
do SplittingGenerator:AddFinalSplitting c->c,g; QtoQGSudakov
do SplittingGenerator:AddFinalSplitting b->b,g; QtoQGSudakov
do SplittingGenerator:AddFinalSplitting t->t,g; QtoQGSudakov
#
do SplittingGenerator:AddFinalSplitting g->g,g; GtoGGSudakov
#
do SplittingGenerator:AddFinalSplitting g->u,ubar; GtoQQbarSudakov
do SplittingGenerator:AddFinalSplitting g->d,dbar; GtoQQbarSudakov
do SplittingGenerator:AddFinalSplitting g->s,sbar; GtoQQbarSudakov
do SplittingGenerator:AddFinalSplitting g->c,cbar; GtoccbarSudakov
do SplittingGenerator:AddFinalSplitting g->b,bbar; GtobbbarSudakov
do SplittingGenerator:AddFinalSplitting g->t,tbar; GtoQQbarSudakov
#
do SplittingGenerator:AddFinalSplitting gamma->u,ubar; GammatoQQbarSudakov
do SplittingGenerator:AddFinalSplitting gamma->d,dbar; GammatoQQbarSudakov
do SplittingGenerator:AddFinalSplitting gamma->s,sbar; GammatoQQbarSudakov
do SplittingGenerator:AddFinalSplitting gamma->c,cbar; GammatoQQbarSudakov
do SplittingGenerator:AddFinalSplitting gamma->b,bbar; GammatoQQbarSudakov
do SplittingGenerator:AddFinalSplitting gamma->t,tbar; GammatoQQbarSudakov
do SplittingGenerator:AddFinalSplitting gamma->e-,e+; GammatoQQbarSudakov
do SplittingGenerator:AddFinalSplitting gamma->mu-,mu+; GammatoQQbarSudakov
do SplittingGenerator:AddFinalSplitting gamma->tau-,tau+; GammatoQQbarSudakov
#
do SplittingGenerator:AddFinalSplitting u->u,gamma; QtoQGammaSudakov
do SplittingGenerator:AddFinalSplitting d->d,gamma; QtoQGammaSudakov
do SplittingGenerator:AddFinalSplitting s->s,gamma; QtoQGammaSudakov
do SplittingGenerator:AddFinalSplitting c->c,gamma; QtoQGammaSudakov
do SplittingGenerator:AddFinalSplitting b->b,gamma; QtoQGammaSudakov
do SplittingGenerator:AddFinalSplitting t->t,gamma; QtoQGammaSudakov
do SplittingGenerator:AddFinalSplitting e-->e-,gamma; LtoLGammaSudakov
do SplittingGenerator:AddFinalSplitting mu-->mu-,gamma; LtoLGammaSudakov
do SplittingGenerator:AddFinalSplitting tau-->tau-,gamma; LtoLGammaSudakov
#
# Now lets add the initial splittings. Remember the form a->b,c; means
# that particle a is the particle given and we backward branch to
# particle b which is initial state and particle c which is final state
#
do SplittingGenerator:AddInitialSplitting u->u,g; QtoQGSudakov
do SplittingGenerator:AddInitialSplitting d->d,g; QtoQGSudakov
do SplittingGenerator:AddInitialSplitting s->s,g; QtoQGSudakov
do SplittingGenerator:AddInitialSplitting c->c,g; QtoQGSudakov
do SplittingGenerator:AddInitialSplitting b->b,g; QtoQGSudakov
do SplittingGenerator:AddInitialSplitting u->u,gamma; QtoQGammaSudakov
do SplittingGenerator:AddInitialSplitting d->d,gamma; QtoQGammaSudakov
do SplittingGenerator:AddInitialSplitting s->s,gamma; QtoQGammaSudakov
do SplittingGenerator:AddInitialSplitting c->c,gamma; QtoQGammaSudakov
do SplittingGenerator:AddInitialSplitting b->b,gamma; QtoQGammaSudakov
do SplittingGenerator:AddInitialSplitting t->t,gamma; QtoQGammaSudakov
do SplittingGenerator:AddInitialSplitting g->g,g; GtoGGSudakov
#
do SplittingGenerator:AddInitialSplitting g->d,dbar; GtoQQbarSudakov
do SplittingGenerator:AddInitialSplitting g->u,ubar; GtoQQbarSudakov
do SplittingGenerator:AddInitialSplitting g->s,sbar; GtoQQbarSudakov
do SplittingGenerator:AddInitialSplitting g->c,cbar; GtoccbarSudakov
do SplittingGenerator:AddInitialSplitting g->b,bbar; GtobbbarSudakov
#
do SplittingGenerator:AddInitialSplitting gamma->d,dbar; GammatoQQbarSudakov
do SplittingGenerator:AddInitialSplitting gamma->u,ubar; GammatoQQbarSudakov
do SplittingGenerator:AddInitialSplitting gamma->s,sbar; GammatoQQbarSudakov
do SplittingGenerator:AddInitialSplitting gamma->c,cbar; GammatoQQbarSudakov
do SplittingGenerator:AddInitialSplitting gamma->b,bbar; GammatoQQbarSudakov
#
do SplittingGenerator:AddInitialSplitting d->g,d; dtoGdSudakov
do SplittingGenerator:AddInitialSplitting u->g,u; utoGuSudakov
do SplittingGenerator:AddInitialSplitting s->g,s; QtoGQSudakov
do SplittingGenerator:AddInitialSplitting c->g,c; QtoGQSudakov
do SplittingGenerator:AddInitialSplitting b->g,b; QtoGQSudakov
do SplittingGenerator:AddInitialSplitting dbar->g,dbar; dtoGdSudakov
do SplittingGenerator:AddInitialSplitting ubar->g,ubar; utoGuSudakov
do SplittingGenerator:AddInitialSplitting sbar->g,sbar; QtoGQSudakov
do SplittingGenerator:AddInitialSplitting cbar->g,cbar; QtoGQSudakov
do SplittingGenerator:AddInitialSplitting bbar->g,bbar; QtoGQSudakov
#
do SplittingGenerator:AddInitialSplitting d->gamma,d; QtoGammaQSudakov
do SplittingGenerator:AddInitialSplitting u->gamma,u; QtoGammaQSudakov
do SplittingGenerator:AddInitialSplitting s->gamma,s; QtoGammaQSudakov
do SplittingGenerator:AddInitialSplitting c->gamma,c; QtoGammaQSudakov
do SplittingGenerator:AddInitialSplitting b->gamma,b; QtoGammaQSudakov
do SplittingGenerator:AddInitialSplitting dbar->gamma,dbar; QtoGammaQSudakov
do SplittingGenerator:AddInitialSplitting ubar->gamma,ubar; QtoGammaQSudakov
do SplittingGenerator:AddInitialSplitting sbar->gamma,sbar; QtoGammaQSudakov
do SplittingGenerator:AddInitialSplitting cbar->gamma,cbar; QtoGammaQSudakov
do SplittingGenerator:AddInitialSplitting bbar->gamma,bbar; QtoGammaQSudakov

File Metadata

Mime Type
text/x-diff
Expires
Tue, Nov 19, 6:07 PM (1 d, 19 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3805381
Default Alt Text
(886 KB)

Event Timeline