Page MenuHomeHEPForge

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/MatrixElement/Hadron/MEDiffraction.cc b/MatrixElement/Hadron/MEDiffraction.cc
--- a/MatrixElement/Hadron/MEDiffraction.cc
+++ b/MatrixElement/Hadron/MEDiffraction.cc
@@ -1,873 +1,876 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEDiffraction class.
//
#include "MEDiffraction.h"
+#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/SimplePhaseSpace.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "Herwig/Utilities/Kinematics.h"
MEDiffraction::MEDiffraction()
: HwMEBase(),
deltaOnly(false),
isInRunPhase(false),
theProtonMass(0.93827203*GeV)
{}
void MEDiffraction::getDiagrams() const {
//incoming particles
cPDPair incomingHardons = generator()->eventHandler()->incoming();
tcPDPtr pom = getParticleData(990);
//get incoming particles
tcPDPtr prt11 = getParticleData(incomingHardons.first->id());
tcPDPtr prt12 = getParticleData(incomingHardons.second->id());
//get sign of id
int sign1=0, sign2=0;
sign1 = (incomingHardons.first->id() > 0) ? 1 : -1;
sign2 = (incomingHardons.second->id() > 0) ? 1 : -1;
tcPDPtr prt21 = getParticleData(sign1*2214);//Delta+
tcPDPtr prt22 = getParticleData(sign2*2214);//Delta+
//for the left side
tcPDPtr q11 = getParticleData(sign1*2); //u
tcPDPtr q21 = getParticleData(sign1*1); //d
//for the right side
tcPDPtr q12 = getParticleData(sign2*2); //u
tcPDPtr q22 = getParticleData(sign2*1); //d
//for the left side
tcPDPtr dq11 = getParticleData(sign1*2101); //ud_0
tcPDPtr dq111 = getParticleData(sign1*2103); //ud_1
tcPDPtr dq21 = getParticleData(sign1*2203); //uu_1
//for the right side
tcPDPtr dq12 = getParticleData(sign2*2101); //ud_0
tcPDPtr dq112 = getParticleData(sign2*2103); //ud_1
tcPDPtr dq22 = getParticleData(sign2*2203); //uu_1
tcPDPtr gl = getParticleData(21);//gluon
//switch between dissociation decays to different
//number of clusters or dissociation into delta only
//(Maybe can be automated???)
//(Should be generalized to ppbar, for example!!!)
switch(dissociationDecay){
case 0: //one cluster or only delta in the final state
if(deltaOnly) //only delta in the final state
{
switch (diffDirection){
case 0:
add(new_ptr((Tree2toNDiagram(3), prt11, pom, prt12, 1, prt21, 2, prt12, -1)));
break;
case 1:
add(new_ptr((Tree2toNDiagram(3), prt11, pom, prt12, 1, prt11, 2, prt22, -1)));
break;
case 2:
add(new_ptr((Tree2toNDiagram(3), prt11, pom, prt12, 1, prt21, 2, prt22, -1)));
break;
}
}else
{
//switch between direction of dissociated proton for single diffraction or
//double diffraction
switch (diffDirection){
case 0: //left
//u -- ud_0
add(new_ptr((Tree2toNDiagram(4), prt11, q11, pom, prt12, 3, prt12, 1, dq11, 2, q11, -1)));
//d -- uu_1
add(new_ptr((Tree2toNDiagram(4), prt11, q21, pom, prt12, 3, prt12, 1, dq21, 2, q21, -2)));
break;
case 1: //right
//u -- ud_0
add(new_ptr((Tree2toNDiagram(4), prt11, pom, q12, prt12, 1, prt11, 3, dq12, 2, q12, -1)));
//d -- uu_1
add(new_ptr((Tree2toNDiagram(4), prt11, pom, q22, prt12, 1, prt11, 3, dq22, 2, q22, -2)));
break;
case 2: //double
//u -- ud_0 left u -- ud_0 right
add(new_ptr((Tree2toNDiagram(5), prt11, q11, pom, q12, prt12, 1, dq11, 2, q11, 3, q12, 4, dq12, -1)));
//u -- ud_0 left d -- uu_1 right
add(new_ptr((Tree2toNDiagram(5), prt11, q11, pom, q22, prt12, 1, dq11, 2, q11, 3, q22, 4, dq22, -2)));
//d -- uu_1 left u -- ud_0 right
add(new_ptr((Tree2toNDiagram(5), prt11, q21, pom, q12, prt12, 1,dq21, 2, q21, 3, q12, 4, dq12, -3)));
//d -- uu_1 left d -- uu_1 right
add(new_ptr((Tree2toNDiagram(5), prt11, q21, pom, q22, prt12, 1, dq21, 2, q21, 3, q22, 4, dq22, -4)));
break;
}
}
break;
case 1: //two clusters (cases with ud_1 not included)
switch (diffDirection){
case 0: //left
//u -- ud_0
add(new_ptr((Tree2toNDiagram(5), prt11, q11, gl, pom, prt12, 1, dq11, 2, q11, 3, gl, 4, prt12, -1)));
//d -- uu_1
add(new_ptr((Tree2toNDiagram(5), prt11, q21, gl, pom, prt12, 1, dq21, 2, q21, 3, gl, 4, prt12, -2)));
break;
case 1: //right
//u -- ud_0
add(new_ptr((Tree2toNDiagram(5), prt11, pom, gl, q12, prt12, 1, prt11, 2, gl, 3, q12, 4, dq12, -1)));
//d -- ud_1
add(new_ptr((Tree2toNDiagram(5), prt11, pom, gl, q22, prt12, 1, prt11, 2, gl, 3, q22, 4, dq22, -2)));
break;
case 2: //double
//u -- ud_0 left u -- ud_0 right
add(new_ptr((Tree2toNDiagram(7), prt11, q11, gl, pom, gl, q12, prt12, 1, dq11, 2, q11, 3, gl, 4,
gl, 5, q12, 6, dq12, -1)));
//u -- ud_0 left d -- uu_1 right
add(new_ptr((Tree2toNDiagram(7), prt11, q11, gl, pom, gl, q22, prt12, 1, dq11, 2, q11, 3, gl, 4,
gl, 5, q22, 6, dq22, -2)));
//d -- uu_1 left u -- ud_0 right
add(new_ptr((Tree2toNDiagram(7), prt11, q21, gl, pom, gl, q12, prt12, 1, dq21, 2, q21, 3, gl, 4,
gl, 5, q12, 6, dq12, -3)));
//d -- uu_1 left d -- uu_1 right
add(new_ptr((Tree2toNDiagram(7), prt11, q21, gl, pom, gl, q22, prt12, 1, dq21, 2, q21, 3, gl, 4,
gl, 5, q22, 6, dq22, -4)));
break;
}
break;
}
}
Energy2 MEDiffraction::scale() const {
return sqr(10*GeV);
}
int MEDiffraction::nDim() const {
return 0;
}
void MEDiffraction::setKinematics() {
HwMEBase::setKinematics(); // Always call the base class method first
}
bool MEDiffraction::generateKinematics(const double * ) {
// generate the masses of the particles
for (size_t i = 2; i < meMomenta().size(); ++i)
meMomenta()[i] = Lorentz5Momentum(mePartonData()[i]->generateMass());
/* sample M12, M22 and t, characterizing the diffractive final state */
const pair<pair<Energy2,Energy2>,Energy2> point = diffractiveMassAndMomentumTransfer();
const Energy2 M12 (point.first.first);
const Energy2 M22 (point.first.second);
const Energy2 t(point.second);
/* construct the hadronic momenta in the lab frame */
const double phi = UseRandom::rnd() * Constants::twopi;
const Energy cmEnergy = generator()->maximumCMEnergy();
const Energy2 s = sqr(cmEnergy);
//proton mass
const Energy2 m2 = sqr( theProtonMass );
const Energy E3 = (s - M22 + M12) / (2.*cmEnergy);
const Energy E4 = (s + M22 - M12) / (2.*cmEnergy);
//Momentum of outgoing proton and dissociated proton
const Energy pprime = sqrt(kallen(s, M12, M22)) / (2.*cmEnergy);
//costheta of scattering angle
double costheta = s*(s + 2*t - 2*m2 - M12 - M22)
/ sqrt( kallen(s, M12, M22)*kallen(s, m2, m2) );
assert(abs(costheta)<=1.);
const Energy pzprime = pprime*costheta;
const Energy pperp = pprime*sqrt(1 - sqr(costheta));
/* momenta in the lab frame */
const Lorentz5Momentum p3 = Lorentz5Momentum(pperp*cos(phi), pperp*sin(phi), pzprime, E3);
const Lorentz5Momentum p4 = Lorentz5Momentum(-pperp*cos(phi), -pperp*sin(phi), -pzprime, E4);
/* decay dissociated proton into quark-diquark */
//squares of constituent masses of quark and diquark
const Energy2 mq2(sqr(mq()));
Energy2 Mx2;
switch(diffDirection){
case 0:
Mx2=M12;
break;
case 1:
Mx2=M22;
break;
}
/* Select between left/right single diffraction and double diffraction */
//check if we want only delta for the excited state
//pair of momenta for double decay for a two cluster case
pair<Lorentz5Momentum,Lorentz5Momentum> momPair, momPair1;
//fraction of momenta
double frac = UseRandom::rnd();
switch(dissociationDecay){
case 0:
if(!deltaOnly)
{
pair<Lorentz5Momentum,Lorentz5Momentum> decayMomenta;
pair<Lorentz5Momentum,Lorentz5Momentum> decayMomentaTwo;
const double phiprime = UseRandom::rnd() * Constants::twopi;
//aligned with outgoing dissociated proton
const double costhetaprime = costheta;
const double sinthetaprime=sqrt(1-sqr(costhetaprime));
//axis along which diquark from associated proton is aligned
Axis dir = Axis(sinthetaprime*cos(phiprime), sinthetaprime*sin(phiprime), costhetaprime);
switch (diffDirection){
case 0://Left single diffraction
meMomenta()[4].setT(sqrt(mq2+sqr(meMomenta()[4].x())+sqr(meMomenta()[4].y())+sqr(meMomenta()[4].z())));
////////////////////////////////////////////////////
do{}
while(!Kinematics::twoBodyDecay(p3,mqq(),mq(),-dir,decayMomenta.first,decayMomenta.second));
///////////
meMomenta()[2].setVect(p4.vect());
meMomenta()[2].setT(p4.t());
meMomenta()[3].setVect(decayMomenta.first.vect());
meMomenta()[3].setT(decayMomenta.first.t());
meMomenta()[4].setVect(decayMomenta.second.vect());
meMomenta()[4].setT(decayMomenta.second.t());
meMomenta()[2].rescaleEnergy();
meMomenta()[3].rescaleEnergy();
meMomenta()[4].rescaleEnergy();
break;
case 1://Right single diffraction
meMomenta()[4].setT(sqrt(mq2+sqr(meMomenta()[4].x())+sqr(meMomenta()[4].y())+sqr(meMomenta()[4].z())));
////////////////////////////////////////////////////
do{}
while(!Kinematics::twoBodyDecay(p4,mqq(),mq(),dir,decayMomenta.first,decayMomenta.second));
meMomenta()[2].setVect(p3.vect());
meMomenta()[2].setT(p3.t());
meMomenta()[3].setVect(decayMomenta.first.vect());
meMomenta()[3].setT(decayMomenta.first.t());
meMomenta()[4].setVect(decayMomenta.second.vect());
meMomenta()[4].setT(decayMomenta.second.t());
meMomenta()[2].rescaleEnergy();
meMomenta()[3].rescaleEnergy();
meMomenta()[4].rescaleEnergy();
break;
case 2://double diffraction
do{}
while(!Kinematics::twoBodyDecay(p3,mqq(),mq(),-dir,decayMomenta.first,decayMomenta.second));
do{}
while(!Kinematics::twoBodyDecay(p4,mqq(),mq(),dir,decayMomentaTwo.first,decayMomentaTwo.second));
meMomenta()[2].setVect(decayMomenta.first.vect());
meMomenta()[2].setT(decayMomenta.first.t());
meMomenta()[3].setVect(decayMomenta.second.vect());
meMomenta()[3].setT(decayMomenta.second.t());
meMomenta()[4].setVect(decayMomentaTwo.second.vect());
meMomenta()[4].setT(decayMomentaTwo.second.t());
meMomenta()[5].setVect(decayMomentaTwo.first.vect());
meMomenta()[5].setT(decayMomentaTwo.first.t());
meMomenta()[2].rescaleEnergy();
meMomenta()[3].rescaleEnergy();
meMomenta()[4].rescaleEnergy();
meMomenta()[5].rescaleEnergy();
break;
}
}else
{
meMomenta()[2+diffDirection].setVect(p3.vect());
meMomenta()[2+diffDirection].setT(p3.t());
meMomenta()[3-diffDirection].setVect(p4.vect());
meMomenta()[3-diffDirection].setT(p4.t());
meMomenta()[2].rescaleEnergy();
meMomenta()[3].rescaleEnergy();
}
break;
case 1:
switch(diffDirection){
case 0:
//quark and diquark masses
meMomenta()[2].setMass(mqq());
meMomenta()[3].setMass(mq());
//gluon constituent mass
meMomenta()[4].setMass(getParticleData(21)->constituentMass());
//outgoing proton
meMomenta()[5].setVect(p4.vect());
meMomenta()[5].setT(p4.t());
//two body decay of the outgoing dissociation proton
do{}
while(!Kinematics::twoBodyDecay(p3,mqq()+mq(),getParticleData(21)->constituentMass(),
p3.vect().unit(),momPair.first,momPair.second));
//put gluon back-to-back with quark-diquark
//set momenta of quark and diquark
frac = mqq()/(mqq()+mq());
meMomenta()[2].setVect(frac*momPair.first.vect());
meMomenta()[2].setT(sqrt(sqr(frac)*momPair.first.vect().mag2()+sqr(mqq())));
meMomenta()[3].setVect((1-frac)*momPair.first.vect());
meMomenta()[3].setT(sqrt(sqr(1-frac)*momPair.first.vect().mag2()+sqr(mq())));
//set momentum of gluon
meMomenta()[4].setVect(momPair.second.vect());
meMomenta()[4].setT(momPair.second.t());
break;
case 1:
//quark and diquark masses
meMomenta()[5].setMass(mqq());
meMomenta()[4].setMass(mq());
//gluon constituent mass
meMomenta()[3].setMass(getParticleData(21)->constituentMass());
//outgoing proton
meMomenta()[2].setVect(p3.vect());
meMomenta()[2].setT(p3.t());
//two body decay of the outgoing dissociation proton
do{}
while(!Kinematics::twoBodyDecay(p4,mqq()+mq(),getParticleData(21)->constituentMass(),
p4.vect().unit(),momPair.first,momPair.second));
//put gluon back-to-back with quark-diquark
//set momenta of quark and diquark
frac = mqq()/(mqq()+mq());
meMomenta()[5].setVect(frac*momPair.first.vect());
meMomenta()[5].setT(sqrt(sqr(frac)*momPair.first.vect().mag2()+sqr(mqq())));
meMomenta()[4].setVect((1-frac)*momPair.first.vect());
meMomenta()[4].setT(sqrt(sqr(1-frac)*momPair.first.vect().mag2()+sqr(mq())));
//set momentum of gluon
meMomenta()[3].setVect(momPair.second.vect());
meMomenta()[3].setT(momPair.second.t());
break;
case 2:
//first dissociated proton constituents
meMomenta()[2].setMass(mqq());
meMomenta()[3].setMass(mq());
meMomenta()[4].setMass(getParticleData(21)->constituentMass());
//second dissociated proton constituents
meMomenta()[5].setMass(getParticleData(21)->constituentMass());
meMomenta()[6].setMass(mq());
meMomenta()[7].setMass(mqq());
//two body decay of the outgoing dissociation proton
do{}
while(!Kinematics::twoBodyDecay(p3,mqq()+mq(),getParticleData(21)->constituentMass(),
p3.vect().unit(),momPair.first,momPair.second));
do{}
while(!Kinematics::twoBodyDecay(p4,mqq()+mq(),getParticleData(21)->constituentMass(),
p4.vect().unit(),momPair1.first,momPair1.second));
//put gluon back-to-back with quark-diquark
frac = mqq()/(mqq()+mq());
//first dissociated proton
//set momenta of quark and diquark
meMomenta()[2].setVect(frac*momPair.first.vect());
meMomenta()[2].setT(sqrt(sqr(frac)*momPair.first.vect().mag2()+sqr(mqq())));
meMomenta()[3].setVect((1-frac)*momPair.first.vect());
meMomenta()[3].setT(sqrt(sqr(1-frac)*momPair.first.vect().mag2()+sqr(mq())));
//set momentum of gluon
meMomenta()[4].setVect(momPair.second.vect());
meMomenta()[4].setT(momPair.second.t());
//first dissociated proton
//set momenta of quark and diquark
meMomenta()[7].setVect(frac*momPair1.first.vect());
meMomenta()[7].setT(sqrt(sqr(frac)*momPair1.first.vect().mag2()+sqr(mqq())));
meMomenta()[6].setVect((1-frac)*momPair1.first.vect());
meMomenta()[6].setT(sqrt(sqr(1-frac)*momPair1.first.vect().mag2()+sqr(mq())));
//set momentum of gluon
meMomenta()[5].setVect(momPair1.second.vect());
meMomenta()[5].setT(momPair1.second.t());
break;
}
meMomenta()[2].rescaleEnergy();
meMomenta()[3].rescaleEnergy();
meMomenta()[4].rescaleEnergy();
meMomenta()[5].rescaleEnergy();
if(diffDirection==2){
meMomenta()[6].rescaleEnergy();
meMomenta()[7].rescaleEnergy();
}
break;
}
jacobian(sqr(cmEnergy)/GeV2);
return true;
}
//Generate masses of dissociated protons and momentum transfer from probability f(M2,t)
//(for single diffraction). Sample according to f(M2,t)=f(M2)f(t|M2).
pair<pair<Energy2,Energy2>,Energy2> MEDiffraction::diffractiveMassAndMomentumTransfer() const {
Energy2 theM12(ZERO),theM22(ZERO), thet(ZERO);
int count = 0;
//proton mass squared
const Energy2 m2 = sqr(theProtonMass);
//delta mass squared
const Energy2 md2 = sqr(getParticleData(2214)->mass());
Energy2 M2;
bool condition = true;
do {
//check if we want only delta
if(deltaOnly) {
switch(diffDirection){
case 0:
theM12 = md2;
theM22 = m2;
M2 = md2;
thet = randomt(md2);
break;
case 1:
theM22 = md2;
theM12 = m2;
M2 = md2;
thet = randomt(md2);
break;
case 2:
theM12 = md2;
theM22 = md2;
M2 = md2;
thet = doublediffrandomt(theM12,theM22);
break;
}
}
else {
switch (diffDirection){
case 0:
M2=randomM2();
thet = randomt(M2);
theM12=M2;
theM22=m2;
break;
case 1:
theM12=m2;
M2=randomM2();
thet = randomt(M2);
theM22=M2;
break;
case 2:
theM12=randomM2();
theM22=randomM2();
M2=(theM12>theM22) ? theM12: theM22;
thet = doublediffrandomt(theM12,theM22);
break;
}
}
count++;
const Energy cmEnergy = generator()->maximumCMEnergy();
const Energy2 s = sqr(cmEnergy);
if(generator()->maximumCMEnergy()<sqrt(theM12)+sqrt(theM22)) {
condition = true;
}
else {
InvEnergy2 slope;
if(diffDirection==2){
slope = 2*softPomeronSlope()*log(.1+(sqr(cmEnergy)/softPomeronSlope())/(theM12*theM22));
}else{
slope = protonPomeronSlope()
+ 2*softPomeronSlope()*log(sqr(cmEnergy)/M2);
}
const double expmax = exp(slope*tmaxfun(s,m2,M2));
const double expmin = exp(slope*tminfun(s,m2,M2));
//without (1-M2/s) constraint
condition = (UseRandom::rnd()>(protonPomeronSlope()*GeV2)*(expmax-expmin)/(slope*GeV2))
||((theM12/GeV2)*(theM22/GeV2)>=(sqr(cmEnergy)/GeV2)/(softPomeronSlope()*GeV2));
}
}
while(condition);
return make_pair (make_pair(theM12,theM22),thet);
}
//Decay of the excited proton to quark-diquark
pair<Lorentz5Momentum,Lorentz5Momentum> MEDiffraction::twoBodyDecayMomenta(Lorentz5Momentum pp) const{
//Decay of the excited proton
const Energy2 Mx2(sqr(pp.mass())),mq2(sqr(mq())),mqq2(sqr(mqq()));
const Energy2 psq = ((Mx2-sqr(mq()+mqq()))*(Mx2-sqr(mq()-mqq())))/(4*Mx2);
assert(psq/GeV2>0);
const Energy p(sqrt(psq));
const double phi = UseRandom::rnd() * Constants::twopi;
const double costheta =1-2*UseRandom::rnd();
const double sintheta = sqrt(1-sqr(costheta));
Lorentz5Momentum k1=Lorentz5Momentum(p*sintheta*cos(phi), p*sintheta*sin(phi), p*costheta, sqrt(mq2+psq));
Lorentz5Momentum k2=Lorentz5Momentum(-p*sintheta*cos(phi), -p*sintheta*sin(phi), -p*costheta,sqrt(mqq2+psq));
//find boost to pp center of mass
const Boost betap3 = (pp).findBoostToCM();
//k1 and k2 calculated at p3 center of mass, so boost back
k1.boost(-betap3);
k2.boost(-betap3);
//first is quark, second diquark
return make_pair(k1,k2);
}
Energy2 MEDiffraction::randomt(Energy2 M2) const {
assert(protonPomeronSlope()*GeV2 > 0);
//proton mass
const Energy2 m2 = sqr( theProtonMass );
const Energy cmEnergy = generator()->maximumCMEnergy();
const Energy2 ttmin = tminfun(sqr(cmEnergy),m2,M2);
const Energy2 ttmax = tmaxfun(sqr(cmEnergy),m2,M2);
const InvEnergy2 slope = protonPomeronSlope()
+ 2*softPomeronSlope()*log(sqr(cmEnergy)/M2);
return log( exp(slope*ttmin) +
UseRandom::rnd()*(exp(slope*ttmax) - exp(slope*ttmin)) ) / slope;
}
Energy2 MEDiffraction::doublediffrandomt(Energy2 M12, Energy2 M22) const {
const Energy cmEnergy = generator()->maximumCMEnergy();
const double shift = 0.1;
const InvEnergy2 slope = 2*softPomeronSlope()*log(shift+(sqr(cmEnergy)/softPomeronSlope())/(M12*M22));
const Energy2 ttmin = tminfun(sqr(cmEnergy),M12,M22);
const Energy2 ttmax = tmaxfun(sqr(cmEnergy),M12,M22);
double r = UseRandom::rnd();
Energy2 newVal;
if(slope*ttmax>slope*ttmin) {
newVal = ttmax + log( r + (1.-r)*exp(slope*(ttmin-ttmax)) ) / slope;
}
else {
newVal = ttmin + log( 1. - r + r*exp(slope*(ttmax-ttmin))) / slope;
}
return newVal;
}
Energy2 MEDiffraction::randomM2() const {
const double tmp = 1 - softPomeronIntercept();
const Energy cmEnergy = generator()->maximumCMEnergy();
return sqr(cmEnergy) * pow( pow(M2min()/sqr(cmEnergy),tmp) +
UseRandom::rnd() * (pow(M2max()/sqr(cmEnergy),tmp) - pow(M2min()/sqr(cmEnergy),tmp)),
1.0/tmp );
}
Energy2 MEDiffraction::tminfun(Energy2 s, Energy2 M12, Energy2 M22) const {
const Energy2 m2 = sqr( theProtonMass );
return 0.5/s*(-sqrt(kallen(s, m2, m2)*kallen(s, M12, M22))-sqr(s)+2*s*m2+s*M12+s*M22);
}
Energy2 MEDiffraction::tmaxfun(Energy2 s, Energy2 M12, Energy2 M22) const {
const Energy2 m2 = sqr( theProtonMass );
return 0.5/s*(sqrt(kallen(s, m2, m2)*kallen(s, M12, M22))-sqr(s)+2*s*m2+s*M12+s*M22);
}
double MEDiffraction::me2() const{
return theme2;
}
CrossSection MEDiffraction::dSigHatDR() const {
return me2()*jacobian()/sHat()*sqr(hbarc);
}
unsigned int MEDiffraction::orderInAlphaS() const {
return 0;
}
unsigned int MEDiffraction::orderInAlphaEW() const {
return 0;
}
Selector<MEBase::DiagramIndex>
MEDiffraction::diagrams(const DiagramVector & diags) const {
Selector<DiagramIndex> sel;
if(!deltaOnly){
if(diffDirection<2){
for(unsigned int i = 0; i < diags.size(); i++){
if(diags[0]->id()==-1)
sel.insert(2./3.,i);
else
sel.insert(1./3.,i);
}
}else{
for(unsigned int i = 0; i < diags.size(); i++){
if(diags[0]->id()==-1)
sel.insert(4./9.,i);
else if(diags[0]->id()==-2)
sel.insert(2./9.,i);
else if(diags[0]->id()==-3)
sel.insert(2./9.,i);
else
sel.insert(1./9.,i);
}
}
}else{
sel.insert(1.0,0);
}
return sel;
}
Selector<const ColourLines *>
MEDiffraction::colourGeometries(tcDiagPtr ) const {
Selector<const ColourLines *> sel;
int sign1=0, sign2=0;
sign1 = (generator()->eventHandler()->incoming().first->id() > 0) ? 1 : -1;
sign2 = (generator()->eventHandler()->incoming().second->id() > 0) ? 1 : -1;
switch(dissociationDecay){
case 0:
if(!deltaOnly)
{
if(diffDirection!=2){
if (diffDirection == 0){
if(sign1>0){
static ColourLines dqq0=ColourLines("-6 2 7");
sel.insert(1.0,&dqq0);
}else{
static ColourLines dqq0=ColourLines("6 -2 -7");
sel.insert(1.0,&dqq0);
}
}
else{
if(sign2>0){
static ColourLines dqq1=ColourLines("-6 3 7");
sel.insert(1.0,&dqq1);
}else{
static ColourLines dqq1=ColourLines("6 -3 -7");
sel.insert(1.0,&dqq1);
}
}
}else{
if(sign1>0 && sign2>0){
static ColourLines ddqq0=ColourLines("-6 2 7, -9 4 8");
sel.insert(1.0,&ddqq0);
}else if(sign1<0 && sign2>0){
static ColourLines ddqq0=ColourLines("6 -2 -7, -9 4 8");
sel.insert(1.0,&ddqq0);
}else if(sign1>0&& sign2<0){
static ColourLines ddqq0=ColourLines("-6 2 7, 9 -4 -8");
sel.insert(1.0,&ddqq0);
}else{
static ColourLines ddqq0=ColourLines("6 -2 -7, 9 -4 -8");
sel.insert(1.0,&ddqq0);
}
}
}else
{
static ColourLines cl("");
sel.insert(1.0, &cl);
}
break;
case 1:
switch(diffDirection){
case 0:
static ColourLines clleft("-6 2 3 8, -8 -3 7");
sel.insert(1.0, &clleft);
break;
case 1:
static ColourLines clright("-9 4 3 7, -7 -3 8");
sel.insert(1.0, &clright);
break;
case 2:
static ColourLines cldouble("-8 2 3 10, -10 -3 9, -13 6 5 11, -11 -5 12");
sel.insert(1.0, &cldouble);
break;
}
break;
}
return sel;
}
void MEDiffraction::doinit() {
HwMEBase::doinit();
theProtonMass = getParticleData(2212)->mass();
}
void MEDiffraction::doinitrun() {
HwMEBase::doinitrun();
isInRunPhase = true;
}
IBPtr MEDiffraction::clone() const {
return new_ptr(*this);
}
IBPtr MEDiffraction::fullclone() const {
return new_ptr(*this);
}
-ClassDescription<MEDiffraction> MEDiffraction::initMEDiffraction;
-// Definition of the static class description member.
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEDiffraction,HwMEBase>
+describeHerwigMEDiffraction("Herwig::MEDiffraction", "HwMEHadron.so");
void MEDiffraction::persistentOutput(PersistentOStream & os) const {
os << theme2 << deltaOnly << diffDirection << theprotonPomeronSlope
<< thesoftPomeronIntercept << thesoftPomeronSlope << dissociationDecay
<< ounit(theProtonMass,GeV);
}
void MEDiffraction::persistentInput(PersistentIStream & is, int) {
is >> theme2 >> deltaOnly >> diffDirection >> theprotonPomeronSlope
>> thesoftPomeronIntercept >> thesoftPomeronSlope >> dissociationDecay
>> iunit(theProtonMass,GeV);
}
InvEnergy2 MEDiffraction::protonPomeronSlope() const{
return theprotonPomeronSlope/GeV2;
}
double MEDiffraction::softPomeronIntercept() const {
return thesoftPomeronIntercept;
}
InvEnergy2 MEDiffraction::softPomeronSlope() const {
return thesoftPomeronSlope/GeV2;
}
void MEDiffraction::Init() {
static ClassDocumentation<MEDiffraction> documentation
("There is no documentation for the MEDiffraction class");
static Parameter<MEDiffraction,double> interfaceme2
("DiffractionAmplitude",
"The square of the diffraction amplitude used to determine the "
"cross section.",
&MEDiffraction::theme2, 1.0, 0.00001, 100.0,
false, false, Interface::limited);
static Parameter<MEDiffraction,double> interfaceprotonPomeronSlope
("ProtonPomeronSlope",
"The proton-pomeron slope parameter.",
&MEDiffraction::theprotonPomeronSlope, 10.1, 0.00001, 100.0,
false, false, Interface::limited);
static Parameter<MEDiffraction,double> interfacesoftPomeronIntercept
("SoftPomeronIntercept",
"The soft pomeron intercept.",
&MEDiffraction::thesoftPomeronIntercept, 1.08, 0.00001, 100.0,
false, false, Interface::limited);
static Parameter<MEDiffraction,double> interfacesoftPomeronSlope
("SoftPomeronSlope",
"The soft pomeron slope parameter.",
&MEDiffraction::thesoftPomeronSlope, 0.25, 0.00001, 100.0,
false, false, Interface::limited);
static Switch<MEDiffraction, bool> interfaceDeltaOnly
("DeltaOnly",
"proton-proton to proton-delta only",
&MEDiffraction::deltaOnly, 0, false, false);
static SwitchOption interfaceDeltaOnly0
(interfaceDeltaOnly,"No","Final state with Delta only is OFF", 0);
static SwitchOption interfaceDeltaOnly1
(interfaceDeltaOnly,"Yes","Final state with Delta only is ON", 1);
//Select if the left, right or both protons are excited
static Switch<MEDiffraction, unsigned int> interfaceDiffDirection
("DiffDirection",
"Direction of the excited proton",
&MEDiffraction::diffDirection, 0, false, false);
static SwitchOption left
(interfaceDiffDirection,"Left","Proton moving in the positive z direction", 0);
static SwitchOption right
(interfaceDiffDirection,"Right","Proton moving in the negative z direction", 1);
static SwitchOption both
(interfaceDiffDirection,"Both","Both protons", 2);
//Select if two or three body decay
static Switch<MEDiffraction, unsigned int> interfaceDissociationDecay
("DissociationDecay",
"Number of clusters the dissociated proton decays",
&MEDiffraction::dissociationDecay, 0, false, false);
static SwitchOption one
(interfaceDissociationDecay,"One","Dissociated proton decays into one cluster", 0);
static SwitchOption two
(interfaceDissociationDecay,"Two","Dissociated proton decays into two clusters", 1);
}
diff --git a/MatrixElement/Hadron/MEDiffraction.h b/MatrixElement/Hadron/MEDiffraction.h
--- a/MatrixElement/Hadron/MEDiffraction.h
+++ b/MatrixElement/Hadron/MEDiffraction.h
@@ -1,344 +1,309 @@
// -*- C++ -*-
#ifndef HERWIG_MEDiffraction_H
#define HERWIG_MEDiffraction_H
//
// This is the declaration of the MEDiffraction class.
//
#include "Herwig/MatrixElement/HwMEBase.h"
namespace Herwig {
using namespace ThePEG;
/**
* The MEDiffraction class provides a simple colour singlet exchange matrix element
* to be used in the soft component of the multiple scattering model of the
* underlying event
*
* @see \ref MEDiffractionInterfaces "The interfaces"
* defined for MEDiffraction.
*/
class MEDiffraction: public HwMEBase {
public:
MEDiffraction();
/** @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;
/**
* 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. If the function is
* overridden in a sub class the new function must call the base
* class one first.
*/
virtual void setKinematics();
/**
* 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;
//@}
/**
* Expect the incoming partons in the laboratory frame
*/
/* virtual bool wantCMS() const { return false; } */
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();
/**
* Initialize this object. Called in the run phase just before a run begins.
*/
virtual void doinitrun();
//@}
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
private:
/* The matrix element squared */
double theme2;
/* Use only delta as excited state */
bool deltaOnly;
/* Direction of the excited proton */
unsigned int diffDirection;
/* Number of clusters the dissociated proton decays into */
unsigned int dissociationDecay;
/* The mass of the consitutent quark */
Energy mq() const {return Energy(0.325*GeV);}
/* The mass of the constituent diquark */
Energy mqq() const {return Energy(0.650*GeV);}
/* The proton-pomeron slope */
double theprotonPomeronSlope;
/* The soft pomeron intercept */
double thesoftPomeronIntercept;
/* The soft pomeron slope */
double thesoftPomeronSlope;
/**
* Sample the diffractive mass squared M2 and the momentum transfer t
*/
pair<pair<Energy2,Energy2>,Energy2> diffractiveMassAndMomentumTransfer() const;
/**
* Random value for the diffractive mass squared M2 according to (M2/s0)^(-intercept)
*/
Energy2 randomM2() const;
/**
* Random value for t according to exp(diffSlope*t)
*/
Energy2 randomt(Energy2 M2) const;
/**
* Random value for t according to exp(diffSlope*t) for double diffraction
*/
Energy2 doublediffrandomt(Energy2 M12, Energy2 M22) const;
/**
* Returns the momenta of the two-body decay of momentum pp
*/
pair<Lorentz5Momentum,Lorentz5Momentum> twoBodyDecayMomenta(Lorentz5Momentum pp) const;
/**
* Returns the proton-pomeron slope
*/
InvEnergy2 protonPomeronSlope() const;
/**
* Returns the soft pomeron intercept
*/
double softPomeronIntercept() const;
//M12 and M22 are masses squared of
//outgoing particles
/**
* Returns the minimal possible value of momentum transfer t given the center
* of mass energy and diffractive masses
*/
Energy2 tminfun(Energy2 s, Energy2 M12, Energy2 M22) const;
/**
* Returns the maximal possible value of momentum transfer t given the center
* of mass energy and diffractive masses
*/
Energy2 tmaxfun(Energy2 s , Energy2 M12, Energy2 M22) const;
/**
* Returns the minimal possible value of diffractive mass
*/
//lowest possible mass given the constituent masses of quark and diquark
Energy2 M2min() const{return sqr(getParticleData(2212)->mass()+mq()+mqq());}
/**
* Returns the maximal possible value of diffractive mass
*/
Energy2 M2max() const{
return sqr(generator()->maximumCMEnergy()-getParticleData(2212)->mass());
}//TODO:modify to get proper parameters
InvEnergy2 softPomeronSlope() const;
/* Kallen function */
template<int L, int E, int Q, int DL, int DE, int DQ>
Qty<2*L,2*E,2*Q,DL,DE,DQ> kallen(Qty<L,E,Q,DL,DE,DQ> a,
Qty<L,E,Q,DL,DE,DQ> b,
Qty<L,E,Q,DL,DE,DQ> c) const {
return a*a + b*b + c*c - 2.0*(a*b + b*c + c*a);
}
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<MEDiffraction> initMEDiffraction;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEDiffraction & operator=(const MEDiffraction &);
bool isInRunPhase;
/* The proton mass */
Energy theProtonMass;
};
}
-#include "ThePEG/Utilities/ClassTraits.h"
-
-namespace ThePEG {
-
-/** @cond TRAITSPECIALIZATIONS */
-
-/** This template specialization informs ThePEG about the
- * base classes of MEDiffraction. */
-template <>
-struct BaseClassTrait<Herwig::MEDiffraction,1> {
- /** Typedef of the first base class of MEDiffraction. */
- typedef Herwig::HwMEBase NthBase;
-};
-
-/** This template specialization informs ThePEG about the name of
- * the MEDiffraction class and the shared object where it is defined. */
-template <>
-struct ClassTraits<Herwig::MEDiffraction>
- : public ClassTraitsBase<Herwig::MEDiffraction> {
- /** Return a platform-independent class name */
- static string className() { return "Herwig::MEDiffraction"; }
- /**
- * The name of a file containing the dynamic library where the class
- * MEDiffraction is implemented. It may also include several, space-separated,
- * libraries if the class MEDiffraction 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_MEDiffraction_H */
diff --git a/MatrixElement/Hadron/MEMinBias.cc b/MatrixElement/Hadron/MEMinBias.cc
--- a/MatrixElement/Hadron/MEMinBias.cc
+++ b/MatrixElement/Hadron/MEMinBias.cc
@@ -1,164 +1,167 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEMinBias class.
//
#include "MEMinBias.h"
+#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/SimplePhaseSpace.h"
//#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
void MEMinBias::getDiagrams() const {
int maxflav(2);
// Pomeron data
tcPDPtr pom = getParticleData(990);
for ( int i = 1; i <= maxflav; ++i ) {
for( int j=1; j <= i; ++j){
tcPDPtr q1 = getParticleData(i);
tcPDPtr q1b = q1->CC();
tcPDPtr q2 = getParticleData(j);
tcPDPtr q2b = q2->CC();
// For each flavour we add:
//qq -> qq
add(new_ptr((Tree2toNDiagram(3), q1, pom, q2, 1, q1, 2, q2, -1)));
//qqb -> qqb
add(new_ptr((Tree2toNDiagram(3), q1, pom, q2b, 1, q1, 2, q2b, -2)));
//qbqb -> qbqb
add(new_ptr((Tree2toNDiagram(3), q1b, pom, q2b, 1, q1b, 2, q2b, -3)));
}
}
}
Energy2 MEMinBias::scale() const {
return sqr(10*GeV);
}
int MEMinBias::nDim() const {
return 0;
}
void MEMinBias::setKinematics() {
HwMEBase::setKinematics(); // Always call the base class method first.
}
bool MEMinBias::generateKinematics(const double *) {
// generate the masses of the particles
for ( int i = 2, N = meMomenta().size(); i < N; ++i ) {
meMomenta()[i] = Lorentz5Momentum(mePartonData()[i]->generateMass());
}
Energy q = ZERO;
try {
q = SimplePhaseSpace::
getMagnitude(sHat(), meMomenta()[2].mass(), meMomenta()[3].mass());
} catch ( ImpossibleKinematics ) {
return false;
}
Energy pt = ZERO;
meMomenta()[2].setVect(Momentum3( pt, pt, q));
meMomenta()[3].setVect(Momentum3(-pt, -pt, -q));
meMomenta()[2].rescaleEnergy();
meMomenta()[3].rescaleEnergy();
jacobian(1.0);
return true;
}
double MEMinBias::me2() const {
//tuned so it gives the correct normalization for xmin = 0.11
return csNorm_*(sqr(generator()->maximumCMEnergy())/GeV2);
}
CrossSection MEMinBias::dSigHatDR() const {
return me2()*jacobian()/sHat()*sqr(hbarc);
}
unsigned int MEMinBias::orderInAlphaS() const {
return 2;
}
unsigned int MEMinBias::orderInAlphaEW() const {
return 0;
}
Selector<MEBase::DiagramIndex>
MEMinBias::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 *>
MEMinBias::colourGeometries(tcDiagPtr diag) const {
static ColourLines qq("1 4, 3 5");
static ColourLines qqb("1 4, -3 -5");
static ColourLines qbqb("-1 -4, -3 -5");
Selector<const ColourLines *> sel;
switch(diag->id()){
case -1:
sel.insert(1.0, &qq);
break;
case -2:
sel.insert(1.0, &qqb);
break;
case -3:
sel.insert(1.0, &qbqb);
break;
}
return sel;
}
IBPtr MEMinBias::clone() const {
return new_ptr(*this);
}
IBPtr MEMinBias::fullclone() const {
return new_ptr(*this);
}
-ClassDescription<MEMinBias> MEMinBias::initMEMinBias;
-// Definition of the static class description member.
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEMinBias,HwMEBase>
+describeHerwigMEMinBias("Herwig::MEMinBias", "HwMEHadron.so");
void MEMinBias::persistentOutput(PersistentOStream & os) const {
os << csNorm_;
}
void MEMinBias::persistentInput(PersistentIStream & is, int) {
is >> csNorm_;
}
void MEMinBias::Init() {
static ClassDocumentation<MEMinBias> documentation
("There is no documentation for the MEMinBias class");
static Parameter<MEMinBias,double> interfacecsNorm
("csNorm",
"Normalization of the min-bias cross section.",
&MEMinBias::csNorm_,
1.0, 0.0, 100.0,
false, false, Interface::limited);
}
diff --git a/MatrixElement/Hadron/MEMinBias.h b/MatrixElement/Hadron/MEMinBias.h
--- a/MatrixElement/Hadron/MEMinBias.h
+++ b/MatrixElement/Hadron/MEMinBias.h
@@ -1,231 +1,196 @@
// -*- C++ -*-
#ifndef HERWIG_MEMinBias_H
#define HERWIG_MEMinBias_H
//
// This is the declaration of the MEMinBias class.
//
#include "Herwig/MatrixElement/HwMEBase.h"
namespace Herwig {
using namespace ThePEG;
/**
* The MEMinBias class provides a simple colour singlet exchange matrix element
* to be used in the soft component of the multiple scattering model of the
* underlying event
*
* @see \ref MEMinBiasInterfaces "The interfaces"
* defined for MEMinBias.
*/
class MEMinBias: public HwMEBase {
public:
/**
* The default constructor.
*/
MEMinBias() : csNorm_(1.) {}
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;
/**
* 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. If the function is
* overridden in a sub class the new function must call the base
* class one first.
*/
virtual void setKinematics();
/**
* 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.
*/
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
// If needed, insert declarations of virtual function defined in the
// InterfacedBase class here (using ThePEG-interfaced-decl in Emacs).
private:
/**
* Normalization of the min-bias cross section
*/
double csNorm_;
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<MEMinBias> initMEMinBias;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEMinBias & operator=(const MEMinBias &);
};
}
-#include "ThePEG/Utilities/ClassTraits.h"
-
-namespace ThePEG {
-
-/** @cond TRAITSPECIALIZATIONS */
-
-/** This template specialization informs ThePEG about the
- * base classes of MEMinBias. */
-template <>
-struct BaseClassTrait<Herwig::MEMinBias,1> {
- /** Typedef of the first base class of MEMinBias. */
- typedef Herwig::HwMEBase NthBase;
-};
-
-/** This template specialization informs ThePEG about the name of
- * the MEMinBias class and the shared object where it is defined. */
-template <>
-struct ClassTraits<Herwig::MEMinBias>
- : public ClassTraitsBase<Herwig::MEMinBias> {
- /** Return a platform-independent class name */
- static string className() { return "Herwig::MEMinBias"; }
- /**
- * The name of a file containing the dynamic library where the class
- * MEMinBias is implemented. It may also include several, space-separated,
- * libraries if the class MEMinBias 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_MEMinBias_H */
diff --git a/MatrixElement/Hadron/MEPP2GammaGamma.cc b/MatrixElement/Hadron/MEPP2GammaGamma.cc
--- a/MatrixElement/Hadron/MEPP2GammaGamma.cc
+++ b/MatrixElement/Hadron/MEPP2GammaGamma.cc
@@ -1,368 +1,371 @@
// -*- C++ -*-
//
// MEPP2GammaGamma.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2GammaGamma class.
//
#include "MEPP2GammaGamma.h"
+#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "Herwig/MatrixElement/HardVertex.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
using namespace Herwig;
IBPtr MEPP2GammaGamma::clone() const {
return new_ptr(*this);
}
IBPtr MEPP2GammaGamma::fullclone() const {
return new_ptr(*this);
}
unsigned int MEPP2GammaGamma::orderInAlphaS() const {
return 0;
}
unsigned int MEPP2GammaGamma::orderInAlphaEW() const {
return 2;
}
void MEPP2GammaGamma::doinit() {
// get the vedrtex pointers from the SM object
tcHwSMPtr hwsm= dynamic_ptr_cast<tcHwSMPtr>(standardModel());
// do the initialisation
if(hwsm)
{_photonvertex = hwsm->vertexFFP();}
else throw InitException() << "Wrong type of StandardModel object in "
<< "MEPP2GammaGamma::doinit() the Herwig"
<< " version must be used"
<< Exception::runerror;
// call the base class
HwMEBase::doinit();
}
void MEPP2GammaGamma::getDiagrams() const {
// diagrams for q qbar to gamma gamma
tcPDPtr p = getParticleData(ParticleID::gamma);
if(_process==0||_process==1) {
for ( int i = 1; i <= 5; ++i ) {
tcPDPtr q = getParticleData(i);
tcPDPtr qb = q->CC();
// t channel
add(new_ptr((Tree2toNDiagram(3), q, qb, qb, 1, p, 2, p, -1)));
// u channel
add(new_ptr((Tree2toNDiagram(3), q, qb, qb, 2, p, 1, p, -2)));
}
}
// diagrams for g g to gamma gamma (this is garbage)
tcPDPtr g = getParticleData(ParticleID::g);
if(_process==0||_process==2)
add(new_ptr((Tree2toNDiagram(2), g, g, 1, p, 3, p, 3, p, -3)));
}
Energy2 MEPP2GammaGamma::scale() const {
Energy2 s(sHat()),u(uHat()),t(tHat());
return scalePreFactor_*2.*s*t*u/(s*s+t*t+u*u);
}
Selector<MEBase::DiagramIndex>
MEPP2GammaGamma::diagrams(const DiagramVector & diags) const {
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i )
if ( diags[i]->id() == -1 ) sel.insert(_diagwgt[0], i);
else if ( diags[i]->id() == -2 ) sel.insert(_diagwgt[1], i);
else if ( diags[i]->id() == -3 ) sel.insert(1.0, i);
return sel;
}
Selector<const ColourLines *>
MEPP2GammaGamma::colourGeometries(tcDiagPtr diag) const {
// q qbar colour lines
static const ColourLines cqqbar("1 -2 -3");
// g g colour lines
static const ColourLines cgluon("1 -2,-1 2");
// selector
Selector<const ColourLines *> sel;
if ( diag->id() == -1 || diag->id() == -2 ) sel.insert(1.0, &cqqbar);
else sel.insert(1.0, &cgluon);
return sel;
}
void MEPP2GammaGamma::persistentOutput(PersistentOStream & os) const {
os << _photonvertex << _maxflavour << _process << scalePreFactor_;
}
void MEPP2GammaGamma::persistentInput(PersistentIStream & is, int) {
is >> _photonvertex >> _maxflavour >> _process >> scalePreFactor_;
}
-ClassDescription<MEPP2GammaGamma> MEPP2GammaGamma::initMEPP2GammaGamma;
-// Definition of the static class description member.
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEPP2GammaGamma,HwMEBase>
+describeHerwigMEPP2GammaGamma("Herwig::MEPP2GammaGamma", "HwMEHadron.so");
void MEPP2GammaGamma::Init() {
static ClassDocumentation<MEPP2GammaGamma> documentation
("The MEPP2GammaGamma class implements the matrix element for photon pair"
" production in hadron collisions.");
static Parameter<MEPP2GammaGamma,unsigned int> interfaceMaximumFlavour
("MaximumFlavour",
"The maximum flavour of the quarks in the process",
&MEPP2GammaGamma::_maxflavour, 5, 1, 5,
false, false, Interface::limited);
static Switch<MEPP2GammaGamma,unsigned int> interfaceProcess
("Process",
"Subprocesses to include",
&MEPP2GammaGamma::_process, 0, false, false);
static SwitchOption interfaceProcessAll
(interfaceProcess,
"All",
"Include all the subprocesses",
0);
static SwitchOption interfaceProcessqqbar
(interfaceProcess,
"qqbar",
"Only include the incoming q qbar subproces",
1);
static SwitchOption interfaceProcessgg
(interfaceProcess,
"gg",
"Only include the incoming gg subprocess",
2);
static Parameter<MEPP2GammaGamma,double> interfaceScalePreFactor
("ScalePreFactor",
"Prefactor for the scale",
&MEPP2GammaGamma::scalePreFactor_, 1.0, 0.0, 10.0,
false, false, Interface::limited);
}
double MEPP2GammaGamma::me2() const {
// total matrix element
double me(0.);
// g g to gamma gamma
if(mePartonData()[0]->id()==ParticleID::g) {
VectorWaveFunction g1in(meMomenta()[0],mePartonData()[0],incoming);
VectorWaveFunction g2in(meMomenta()[1],mePartonData()[1],incoming);
VectorWaveFunction p1out(meMomenta()[2],mePartonData()[2],outgoing);
VectorWaveFunction p2out(meMomenta()[3],mePartonData()[3],outgoing);
vector<VectorWaveFunction> g1,g2,p1,p2;
for(unsigned int ix=0;ix<2;++ix) {
g1in.reset(2*ix) ;g1.push_back( g1in);
g2in.reset(2*ix) ;g2.push_back( g2in);
p1out.reset(2*ix);p1.push_back(p1out);
p2out.reset(2*ix);p2.push_back(p2out);
}
// calculate the matrix element
me = ggME(g1,g2,p1,p2,false);
}
// q qbar to gamma gamma
else {
unsigned int iq(1),iqb(0);
if(mePartonData()[0]->id()>0){iq=0;iqb=1;}
SpinorWaveFunction qin (meMomenta()[iq ],mePartonData()[iq ],incoming);
SpinorBarWaveFunction qbin(meMomenta()[iqb],mePartonData()[iqb],incoming);
VectorWaveFunction p1out(meMomenta()[ 2 ],mePartonData()[ 2 ],outgoing);
VectorWaveFunction p2out(meMomenta()[ 3 ],mePartonData()[ 3 ],outgoing);
vector<SpinorWaveFunction> fin;
vector<SpinorBarWaveFunction> ain;
vector<VectorWaveFunction> p1,p2;
for(unsigned int ix=0;ix<2;++ix) {
qin.reset(ix) ;fin.push_back( qin );
qbin.reset(ix) ;ain.push_back( qbin);
p1out.reset(2*ix); p1.push_back(p1out);
p2out.reset(2*ix); p2.push_back(p2out);
}
// calculate the matrix element
me= qqbarME(fin,ain,p1,p2,false);
}
return me;
}
double MEPP2GammaGamma::qqbarME(vector<SpinorWaveFunction> & fin,
vector<SpinorBarWaveFunction> & ain,
vector<VectorWaveFunction> & p1,
vector<VectorWaveFunction> & p2,
bool calc) const {
// the particles should be in the order
// for the incoming
// 0 incoming fermion (u spinor)
// 1 incoming antifermion (vbar spinor)
// for the outgoing
// 0 first outgoing photon
// 1 second outgoing photon
// me to be returned
ProductionMatrixElement newme(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1,PDT::Spin1);
// wavefunction for the intermediate particles
SpinorWaveFunction inter;
unsigned int inhel1,inhel2,outhel1,outhel2;
Complex diag[3];
double me(0.),diag1(0.),diag2(0.);
for(inhel1=0;inhel1<2;++inhel1) {
for(inhel2=0;inhel2<2;++inhel2) {
for(outhel1=0;outhel1<2;++outhel1) {
for(outhel2=0;outhel2<2;++outhel2) {
// first diagram
inter = _photonvertex->evaluate(ZERO,5,fin[inhel1].particle()->CC(),
fin[inhel1],p1[outhel1]);
diag[0] = _photonvertex->evaluate(ZERO,inter,ain[inhel2],p2[outhel2]);
// second diagram
inter = _photonvertex->evaluate(ZERO,5,fin[inhel1].particle()->CC(),
fin[inhel1],p2[outhel2]);
diag[1] = _photonvertex->evaluate(ZERO,inter,ain[inhel2],p1[outhel1]);
// compute the running totals
diag[2]=diag[0]+diag[1];
diag1 += norm(diag[0]);
diag2 += norm(diag[1]);
me += norm(diag[2]);
// matrix element
if(calc) newme(inhel1,inhel2,2*outhel1,2*outhel2)=diag[2];
}
}
}
}
// save the info on the diagrams
if(!calc) {
_diagwgt[0]=diag1;
_diagwgt[1]=diag2;
}
// check versus analytic result
// Energy2 s(sHat()),u(uHat()),t(tHat());
// double test = 2./3.*sqr(4.*Constants::pi*SM().alphaEM(ZERO))*(t/u+u/t)*
// pow(double(mePartonData()[0]->iCharge())/3.,4);
// cerr << "testing me " << 12./me*test << endl;
// return the answer (including colour and spin factor)
if(calc) _me.reset(newme);
// this is 1/3 colour average, 1/4 spin aver, 1/2 identical particles
return me/24.;
}
double MEPP2GammaGamma::ggME(vector<VectorWaveFunction> &,
vector<VectorWaveFunction> &,
vector<VectorWaveFunction> &,
vector<VectorWaveFunction> &,
bool calc) const {
// we probably need some basis rotation here ?????
// get the scales
Energy2 s(sHat()),u(uHat()),t(tHat());
Complex me[2][2][2][2];
double charge(11./9.);
// ++++
me[1][1][1][1] = charge*ggme(s,t,u);
// +++-
me[1][1][1][0] =-charge;
// ++-+
me[1][1][0][1] =-charge;
// ++--
me[1][1][0][0] =-charge;
// +-++
me[1][0][1][1] =-charge;
// +-+-
me[1][0][1][0] = charge*ggme(u,t,s);
// +--+
me[1][0][0][1] = charge*ggme(t,s,u);
// +---
me[1][0][0][0] = charge;
// -+++
me[0][1][1][1] =-charge;
// -++-
me[0][1][1][0] =-me[1][0][0][1];
// -+-+
me[0][1][0][1] =-me[1][0][1][0];
// -+--
me[0][1][0][0] = charge;
// --++
me[0][0][1][1] = charge;
// --+-
me[0][0][1][0] = charge;
// ---+
me[0][0][0][1] = charge;
// ----
me[0][0][0][0] =-me[1][1][1][1];
ProductionMatrixElement newme(PDT::Spin1,PDT::Spin1,
PDT::Spin1,PDT::Spin1);
unsigned int inhel1,inhel2,outhel1,outhel2;
double sum(0.);
for(inhel1=0;inhel1<2;++inhel1) {
for(inhel2=0;inhel2<2;++inhel2) {
for(outhel1=0;outhel1<2;++outhel1) {
for(outhel2=0;outhel2<2;++outhel2) {
sum+=real( me[inhel1][inhel2][outhel1][outhel2]*
conj(me[inhel1][inhel2][outhel1][outhel2]));
// matrix element
if(calc) newme(2*inhel1,2*inhel2,
2*outhel1,2*outhel2)=me[inhel1][inhel2][outhel1][outhel2];
}
}
}
}
// double pi2(sqr(pi));
// Energy2 s2(sqr(s)),t2(sqr(t)),u2(sqr(u));
// double alntu=log(t/u);
// double alnst=log(-s/t);
// double alnsu=alnst+alntu;
// double test=5.*4.
// +sqr((2.*s2+2.*(u2-t2)*alntu+(t2+u2)*(sqr(alntu)+pi2))/s2)
// +sqr((2.*u2+2.*(t2-s2)*alnst+(t2+s2)* sqr(alnst) )/u2)
// +sqr((2.*t2+2.*(u2-s2)*alnsu+(u2+s2)* sqr(alnsu) )/t2)
// +4.*pi2*(sqr((t2-s2+(t2+s2)*alnst)/u2)+sqr((u2-s2+(u2+s2)*alnsu)/t2));
// cerr << "testing ratio " << sum/test/sqr(charge)*2. << endl;
// final factors
if(calc) _me.reset(newme);
return 0.25*sum*sqr(SM().alphaS(scale())*SM().alphaEM(ZERO));
}
void MEPP2GammaGamma::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]);
// order of particles
unsigned int order[4]={0,1,2,3};
// identify the process and calculate matrix element
vector<VectorWaveFunction> g1,g2,p1,p2;
if(hard[0]->id()==ParticleID::g) {
VectorWaveFunction (g1,hard[order[0]],incoming,false,true,true);
VectorWaveFunction (g2,hard[order[1]],incoming,false,true,true);
VectorWaveFunction (p1,hard[order[2]],outgoing,true ,true,true);
VectorWaveFunction (p2,hard[order[3]],outgoing,true ,true,true);
g1[1]=g1[2];g2[1]=g2[2];p1[1]=p1[2];p2[1]=p2[2];
ggME(g1,g2,p1,p2,true);
}
else {
if(hard[order[0]]->id()<0) swap(order[0],order[1]);
vector<SpinorWaveFunction> q;
vector<SpinorBarWaveFunction> qb;
SpinorWaveFunction (q ,hard[order[0]],incoming,false,true);
SpinorBarWaveFunction(qb,hard[order[1]],incoming,false,true);
VectorWaveFunction (p1,hard[order[2]],outgoing,true ,true,true);
VectorWaveFunction (p2,hard[order[3]],outgoing,true ,true,true);
p1[1]=p1[2];p2[1]=p2[2];
qqbarME(q,qb,p1,p2,true);
}
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(_me);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<4;++ix)
hard[order[ix]]->spinInfo()->productionVertex(hardvertex);
}
diff --git a/MatrixElement/Hadron/MEPP2GammaGamma.h b/MatrixElement/Hadron/MEPP2GammaGamma.h
--- a/MatrixElement/Hadron/MEPP2GammaGamma.h
+++ b/MatrixElement/Hadron/MEPP2GammaGamma.h
@@ -1,292 +1,257 @@
// -*- C++ -*-
//
// MEPP2GammaGamma.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_MEPP2GammaGamma_H
#define HERWIG_MEPP2GammaGamma_H
//
// This is the declaration of the MEPP2GammaGamma class.
//
#include "Herwig/MatrixElement/HwMEBase.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
namespace Herwig {
using namespace ThePEG;
using namespace ThePEG::Helicity;
/**
* The MEPP2GammaGamma class implements the production of photon pairs in
* hadron hadron collisions.
*
* @see \ref MEPP2GammaGammaInterfaces "The interfaces"
* defined for MEPP2GammaGamma.
*/
class MEPP2GammaGamma: public HwMEBase {
public:
/**
* The default constructor.
*/
MEPP2GammaGamma() : _maxflavour(5),_process(0), scalePreFactor_(1.) {
massOption(vector<unsigned int>(2,0));
}
/** @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;
/** 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:
/**
* Members to return the matrix elements for the different subprocesses
*/
//@{
/**
* Matrix element for \f$q\bar{q}\to \gamma\gamma\f$.
* @param fin Spinors for incoming quark
* @param ain Spinors for incoming antiquark
* @param p1 Polarization vectors for the first outgoing photon
* @param p2 Polarization vectors for the second outgoing photon
* @param me Whether or not to calculate the matrix element for spin correlations
*/
double qqbarME(vector<SpinorWaveFunction> & fin, vector<SpinorBarWaveFunction> & ain,
vector<VectorWaveFunction> & p1 , vector<VectorWaveFunction> & p2 ,
bool me) const;
/**
* Matrix element for \f$gg \to \gamma\gamma\f$.
* @param g1 Polarization vectors for the first incoming gluon
* @param g2 Polarization vectors for the second incoming gluon
* @param p1 Polarization vectors for the first outgoing photon
* @param p2 Polarization vectors for the second outgoing photon
* @param me Whether or not to calculate the matrix element for spin correlations
*/
double ggME(vector<VectorWaveFunction> & g1 , vector<VectorWaveFunction> & g2 ,
vector<VectorWaveFunction> & p1 , vector<VectorWaveFunction> & p2 ,
bool me) const;
//@}
/**
* \f$gg\to\gamma\gamma\f$ matrix element for the \f$++++\f$ helicity configuration.
* @param s The \f$s\f$ invariant
* @param t The \f$t\f$ invariant
* @param u The \f$u\f$ invariant
*/
Complex ggme(Energy2 s,Energy2 t,Energy2 u) const {
double ltu(log(abs(t/u)));
double frac1((t-u)/s),frac2((sqr(t)+sqr(u))/sqr(s));
double thetatu = (t/u<0) ? 0 : 1;
double thetat = (t<ZERO) ? 0 : 1;
double thetau = (u<ZERO) ? 0 : 1;
using Constants::pi;
return Complex(1.+frac1*ltu+0.5*frac2*(sqr(ltu)+sqr(pi)*thetatu),
-pi*(thetat-thetau)*(frac1+frac2*ltu));
}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<MEPP2GammaGamma> initMEPP2GammaGamma;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEPP2GammaGamma & operator=(const MEPP2GammaGamma &);
private:
/**
* Pointer to the quark-antiquark-photon vertex
*/
AbstractFFVVertexPtr _photonvertex;
/**
* Maximum PDG code of the quarks allowed
*/
unsigned int _maxflavour;
/**
* Option for which processes to include
*/
unsigned int _process;
/**
* Matrix element for spin correlations
*/
ProductionMatrixElement _me;
/**
* weights for the different quark annhilation diagrams
*/
mutable double _diagwgt[2];
/**
* Scale prefactor
*/
double scalePreFactor_;
};
}
-#include "ThePEG/Utilities/ClassTraits.h"
-
-namespace ThePEG {
-
-/** @cond TRAITSPECIALIZATIONS */
-
-/** This template specialization informs ThePEG about the
- * base classes of MEPP2GammaGamma. */
-template <>
-struct BaseClassTrait<Herwig::MEPP2GammaGamma,1> {
- /** Typedef of the first base class of MEPP2GammaGamma. */
- typedef Herwig::HwMEBase NthBase;
-};
-
-/** This template specialization informs ThePEG about the name of
- * the MEPP2GammaGamma class and the shared object where it is defined. */
-template <>
-struct ClassTraits<Herwig::MEPP2GammaGamma>
- : public ClassTraitsBase<Herwig::MEPP2GammaGamma> {
- /** Return a platform-independent class name */
- static string className() { return "Herwig::MEPP2GammaGamma"; }
- /**
- * The name of a file containing the dynamic library where the class
- * MEPP2GammaGamma is implemented. It may also include several, space-separated,
- * libraries if the class MEPP2GammaGamma 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_MEPP2GammaGamma_H */
diff --git a/MatrixElement/Hadron/MEPP2GammaJet.cc b/MatrixElement/Hadron/MEPP2GammaJet.cc
--- a/MatrixElement/Hadron/MEPP2GammaJet.cc
+++ b/MatrixElement/Hadron/MEPP2GammaJet.cc
@@ -1,532 +1,535 @@
// -*- C++ -*-
//
// MEPP2GammaJet.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2GammaJet class.
//
#include "MEPP2GammaJet.h"
+#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/Utilities/SimplePhaseSpace.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "Herwig/MatrixElement/HardVertex.h"
#include "ThePEG/Cuts/Cuts.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
using namespace Herwig;
MEPP2GammaJet::MEPP2GammaJet() : _maxflavour(5), _processopt(0), scalePreFactor_(1.) {
massOption(vector<unsigned int>(2,0));
}
void MEPP2GammaJet::rebind(const TranslationMap & trans)
{
// dummy = trans.translate(dummy);
HwMEBase::rebind(trans);
_gluonvertex =trans.translate(_gluonvertex );
_photonvertex=trans.translate(_photonvertex);
}
IVector MEPP2GammaJet::getReferences() {
IVector ret = HwMEBase::getReferences();
ret.push_back(_gluonvertex);
ret.push_back(_photonvertex);
return ret;
}
void MEPP2GammaJet::doinit() {
// get the vedrtex pointers from the SM object
tcHwSMPtr hwsm= dynamic_ptr_cast<tcHwSMPtr>(standardModel());
// do the initialisation
if(hwsm) {
_gluonvertex = hwsm->vertexFFG();
_photonvertex = hwsm->vertexFFP();
}
else throw InitException() << "Wrong type of StandardModel object in "
<< "MEPP2GammaJet::doinit() the Herwig"
<< " version must be used"
<< Exception::runerror;
// call the base class
HwMEBase::doinit();
}
void MEPP2GammaJet::getDiagrams() const {
// need the gluon and the photon in all processes
tcPDPtr g = getParticleData(ParticleID::g);
tcPDPtr p = getParticleData(ParticleID::gamma);
// for each quark species there are three subprocesses
for ( int iq=1; iq<=_maxflavour; ++iq ) {
tcPDPtr q = getParticleData(iq);
tcPDPtr qb = q->CC();
// q qbar to gamma gluon (two diagrams)
if(_processopt==0||_processopt==1) {
add(new_ptr((Tree2toNDiagram(3), q, qb, qb, 1, p, 2, g, -1)));
add(new_ptr((Tree2toNDiagram(3), q, q, qb, 2, p, 1, g, -2)));
}
// q gluon to gamma q (two diagrams)
if(_processopt==0||_processopt==2) {
add(new_ptr((Tree2toNDiagram(3), q, q, g, 1, p, 2, q, -3)));
add(new_ptr((Tree2toNDiagram(2), q, g, 1, q , 3, p, 3, q, -4)));
}
// qbar gluon to gamma qbar (two diagrams)
if(_processopt==0||_processopt==3) {
add(new_ptr((Tree2toNDiagram(3), qb, qb, g, 1, p, 2, qb, -5)));
add(new_ptr((Tree2toNDiagram(2), qb, g, 1, qb , 3, p, 3, qb, -6)));
}
}
}
unsigned int MEPP2GammaJet::orderInAlphaS() const {
return 1;
}
unsigned int MEPP2GammaJet::orderInAlphaEW() const {
return 1;
}
Energy2 MEPP2GammaJet::scale() const {
Energy2 s(sHat()),u(uHat()),t(tHat());
return scalePreFactor_*2.*s*t*u/(s*s+t*t+u*u);
}
Selector<MEBase::DiagramIndex>
MEPP2GammaJet::diagrams(const DiagramVector & diags) const {
// This example corresponds to the diagrams specified in the example
// in the getDiagrams() function.
double diag1(0.5),diag2(0.5);
diag1 = meInfo()[0];
diag2 = meInfo()[1];
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i ) {
if ( abs(diags[i]->id())%2 == 1 ) sel.insert(diag1, i);
else sel.insert(diag2, i);
}
return sel;
}
void MEPP2GammaJet::persistentOutput(PersistentOStream & os) const {
os << _gluonvertex << _photonvertex << _maxflavour << _processopt << scalePreFactor_;
}
void MEPP2GammaJet::persistentInput(PersistentIStream & is, int) {
is >> _gluonvertex >> _photonvertex >> _maxflavour >> _processopt >> scalePreFactor_;
}
-ClassDescription<MEPP2GammaJet> MEPP2GammaJet::initMEPP2GammaJet;
-// Definition of the static class description member.
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEPP2GammaJet,HwMEBase>
+describeHerwigMEPP2GammaJet("Herwig::MEPP2GammaJet", "HwMEHadron.so");
void MEPP2GammaJet::Init() {
static ClassDocumentation<MEPP2GammaJet> documentation
("The MEPP2GammaJet class implements the matrix element for"
" hadron-hadron to photon+jet");
static Parameter<MEPP2GammaJet,int> interfaceMaximumFlavour
("MaximumFlavour",
"The maximum flavour of the quarks in the process",
&MEPP2GammaJet::_maxflavour, 5, 1, 5,
false, false, Interface::limited);
static Switch<MEPP2GammaJet,unsigned int> interfaceProcesses
("Process",
"Subprocesses to include",
&MEPP2GammaJet::_processopt, 0, false, false);
static SwitchOption interfaceProcessesAll
(interfaceProcesses,
"All",
"Include all the subprocesses",
0);
static SwitchOption interfaceProcessesqqbar
(interfaceProcesses,
"qqbar",
"Only include the incoming q qbar subprocess",
1);
static SwitchOption interfaceProcessesqg
(interfaceProcesses,
"qg",
"Only include the incoming q g subprocess",
2);
static SwitchOption interfaceProcessesqbarg
(interfaceProcesses,
"qbarg",
"Only include the incoming qbar g subprocess",
3);
static Parameter<MEPP2GammaJet,double> interfaceScalePreFactor
("ScalePreFactor",
"Prefactor for the scale",
&MEPP2GammaJet::scalePreFactor_, 1.0, 0.0, 10.0,
false, false, Interface::limited);
}
Selector<const ColourLines *>
MEPP2GammaJet::colourGeometries(tcDiagPtr diag) const {
// q qbar to gamma gluon colour lines
static const ColourLines qqbar1("1 5, -5 -2 -3");
static const ColourLines qqbar2("1 2 5, -5 -3");
// q gluon to gamma q colour lines
static const ColourLines qg1("1 2 -3, 3 5");
static const ColourLines qg2("1 -2, 2 3 5");
// qbar gluon to gamma qbar lines
static const ColourLines qbarg1("-1 -2 3, -3 -5");
static const ColourLines qbarg2("-1 2, -2 -3 -5");
// only one flow per diagram so insert the right one
Selector<const ColourLines *> sel;
switch (diag->id()) {
case -1 :
sel.insert(1.0, &qqbar1);
break;
case -2 :
sel.insert(1.0, &qqbar2);
break;
case -3 :
sel.insert(1.0, &qg1);
break;
case -4 :
sel.insert(1.0, &qg2);
break;
case -5 :
sel.insert(1.0, &qbarg1);
break;
case -6 :
sel.insert(1.0, &qbarg2);
break;
}
return sel;
}
double MEPP2GammaJet::me2() const {
// total matrix element and the various components
double me(0.);
// first case, q qbar to gluon photon
if(mePartonData()[0]->id()==-mePartonData()[1]->id()) {
// order of the particles
unsigned int iq(1),iqb(0),ip(3),ig(2);
if(mePartonData()[0]->id()>0) swap(iq,iqb);
if(mePartonData()[3]->id()==ParticleID::g) swap(ig, ip);
// calculate the spinors and polarization vectors
vector<SpinorWaveFunction> fin;
vector<SpinorBarWaveFunction> ain;
vector<VectorWaveFunction> pout,gout;
SpinorWaveFunction qin (meMomenta()[iq ],mePartonData()[iq ],incoming);
SpinorBarWaveFunction qbin(meMomenta()[iqb],mePartonData()[iqb],incoming);
VectorWaveFunction glout(meMomenta()[ig ],mePartonData()[ig ],outgoing);
VectorWaveFunction phout(meMomenta()[ip ],mePartonData()[ip ],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
qin.reset(ix) ; fin.push_back( qin );
qbin.reset(ix) ; ain.push_back( qbin);
glout.reset(2*ix);gout.push_back(glout);
phout.reset(2*ix);pout.push_back(phout);
}
// calculate the matrix element
me = qqbarME(fin,ain,gout,pout,false)/9.;
// Energy2 mt(scale());
// double coupling=sqr(4.*Constants::pi)*SM().alphaEM(ZERO)*SM().alphaS(mt)*
// sqr(mePartonData()[0]->iCharge()/3.);
// Energy2 t(tHat()),u(uHat());
// double me2=8./9./u/t*(t*t+u*u)*coupling;
// cerr << "testing matrix element A"
// << me << " "
// << me2 << " " << me/me2
// << endl;
}
else if(mePartonData()[0]->id()>0&&mePartonData()[1]->id()) {
// order of the particles
unsigned int iqin(0),iqout(2),ip(3),ig(1);
if(mePartonData()[0]->id()==ParticleID::g ) swap(iqin,ig);
if(mePartonData()[2]->id()==ParticleID::gamma) swap(ip,iqout);
// calculate the spinors and polarization vectors
vector<SpinorWaveFunction> fin;
vector<SpinorBarWaveFunction> fout;
vector<VectorWaveFunction> pout,gin;
SpinorWaveFunction qin (meMomenta()[iqin ],mePartonData()[iqin ],incoming);
SpinorBarWaveFunction qout(meMomenta()[iqout],mePartonData()[iqout],outgoing);
VectorWaveFunction glin(meMomenta()[ig ],mePartonData()[ig ],incoming);
VectorWaveFunction phout(meMomenta()[ip ],mePartonData()[ip ],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
qin.reset(ix) ;fin.push_back( qin );
qout.reset(ix) ;fout.push_back( qout);
glin.reset(2*ix) ;gin.push_back( glin);
phout.reset(2*ix);pout.push_back(phout);
}
// calculate the matrix element
me = qgME(fin,gin,pout,fout,false)/24.;
// Energy2 mt(scale());
// double coupling=sqr(4.*Constants::pi)*SM().alphaEM(ZERO)*SM().alphaS(mt);
// Energy2 s(sHat()),t(tHat()),u(uHat());
// double me2=-1./3./s/t*(s*s+t*t+2.*u*(s+t+u))*coupling*
// sqr(mePartonData()[0]->iCharge()/3.);
// cerr << "testing matrix element B"
// << me << " "
// << me2 << " " << me/me2
// << endl;
}
else {
// order of the particles
unsigned int iqin(0),iqout(2),ip(3),ig(1);
if(mePartonData()[0]->id()==ParticleID::g ) swap(iqin,ig);
if(mePartonData()[2]->id()==ParticleID::gamma) swap(ip,iqout);
// calculate the spinors and polarization vectors
vector<SpinorBarWaveFunction> ain;
vector<SpinorWaveFunction> aout;
vector<VectorWaveFunction> pout,gin;
SpinorBarWaveFunction qin (meMomenta()[iqin ],mePartonData()[iqin ],incoming);
SpinorWaveFunction qout(meMomenta()[iqout],mePartonData()[iqout],outgoing);
VectorWaveFunction glin(meMomenta()[ig ],mePartonData()[ig ],incoming);
VectorWaveFunction phout(meMomenta()[ip ],mePartonData()[ip ],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
qin.reset(ix) ;ain.push_back( qin );
qout.reset(ix) ;aout.push_back( qout);
glin.reset(2*ix) ;gin.push_back( glin);
phout.reset(2*ix);pout.push_back(phout);
}
// calculate the matrix element
me=qbargME(ain,gin,pout,aout,false)/24.;
// Energy2 mt(scale());
// double coupling=sqr(4.*Constants::pi)*SM().alphaEM(ZERO)*SM().alphaS(mt);
// Energy2 s(sHat()),t(tHat()),u(uHat());
// double me2=-1./3./s/t*(s*s+t*t+2.*u*(s+t+u))*coupling*
// sqr(mePartonData()[0]->iCharge()/3.);
// cerr << "testing matrix element C"
// << me << " "
// << me2 << " " << me/me2
// << endl;
}
return me;
}
double MEPP2GammaJet::qqbarME(vector<SpinorWaveFunction> & fin,
vector<SpinorBarWaveFunction> & ain,
vector<VectorWaveFunction> & gout,
vector<VectorWaveFunction> & pout,
bool calc) const {
// the particles should be in the order
// for the incoming
// 0 incoming fermion (u spinor)
// 1 incoming antifermion (vbar spinor)
// for the outgoing
// 0 outgoing gluon
// 1 outgoing photon
// me to be returned
ProductionMatrixElement newme(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1,PDT::Spin1);
// wavefunction for the intermediate particles
SpinorWaveFunction inter;
unsigned int inhel1,inhel2,outhel1,outhel2;
Energy2 mt(scale());
Complex diag[3];
double me(0.),diag1(0.),diag2(0.);
for(inhel1=0;inhel1<2;++inhel1) {
for(inhel2=0;inhel2<2;++inhel2) {
for(outhel1=0;outhel1<2;++outhel1) {
for(outhel2=0;outhel2<2;++outhel2) {
// first diagram
inter = _gluonvertex->evaluate(mt,5,fin[inhel1].particle()->CC(),
fin[inhel1],gout[outhel1]);
diag[0] = _photonvertex->evaluate(ZERO,inter,ain[inhel2],pout[outhel2]);
// second diagram
inter = _photonvertex->evaluate(ZERO,5,fin[inhel1].particle()->CC(),
fin[inhel1],pout[outhel2]);
diag[1] = _gluonvertex->evaluate(mt,inter,ain[inhel2],gout[outhel1]);
// compute the running totals
diag[2]=diag[0]+diag[1];
diag1 +=norm(diag[0]);
diag2 +=norm(diag[1]);
me +=norm(diag[2]);
// matrix element
if(calc) newme(inhel1,inhel2,2*outhel1,2*outhel2)=diag[2];
}
}
}
}
// save the info on the diagrams
if(!calc) {
DVector save;
save.push_back(diag1);
save.push_back(diag2);
meInfo(save);
}
// return the answer
if(calc) _me.reset(newme);
return me;
}
double MEPP2GammaJet::qgME(vector<SpinorWaveFunction> & fin,
vector<VectorWaveFunction> & gin,
vector<VectorWaveFunction> & pout,
vector<SpinorBarWaveFunction> & fout,
bool calc) const {
// the particles should be in the order
// for the incoming
// 0 incoming fermion (u spinor)
// 1 incoming gluon
// for the outgoing
// 0 outgoing photon
// 1 outgoing fermion (ubar spinor)
// me to be returned
ProductionMatrixElement newme(PDT::Spin1Half,PDT::Spin1,
PDT::Spin1,PDT::Spin1Half);
// wavefunction for the intermediate particles
SpinorWaveFunction inter;
unsigned int inhel1,inhel2,outhel1,outhel2;
Energy2 mt(scale());
Complex diag[3];
double me(0.),diag1(0.),diag2(0.);
for(inhel1=0;inhel1<2;++inhel1) {
for(inhel2=0;inhel2<2;++inhel2) {
for(outhel1=0;outhel1<2;++outhel1) {
for(outhel2=0;outhel2<2;++outhel2) {
// first diagram
inter = _photonvertex->evaluate(ZERO,5,fin[inhel1].particle()->CC(),
fin[inhel1],pout[outhel1]);
diag[0]=_gluonvertex->evaluate(mt,inter,fout[outhel2],gin[inhel2]);
// second diagram
inter = _gluonvertex->evaluate(mt,5,fin[inhel1].particle()->CC(),
fin[inhel1],gin[inhel2]);
diag[1]=_photonvertex->evaluate(ZERO,inter,fout[outhel2],pout[outhel1]);
// compute the running totals
diag[2]=diag[0]+diag[1];
diag1 +=norm(diag[0]);
diag2 +=norm(diag[1]);
me +=norm(diag[2]);
// matrix element
if(calc) newme(inhel1,2*inhel2,2*outhel1,outhel2)=diag[2];
}
}
}
}
// save the info on the diagrams
if(!calc) {
DVector save;
save.push_back(diag1);
save.push_back(diag2);
meInfo(save);
}
// return the answer
if(calc) _me.reset(newme);
return me;
}
double MEPP2GammaJet::qbargME(vector<SpinorBarWaveFunction> & ain,
vector<VectorWaveFunction> & gin,
vector<VectorWaveFunction> & pout,
vector<SpinorWaveFunction> & aout,
bool calc) const {
// the particles should be in the order
// for the incoming
// 0 incoming fermion (vbar spinor)
// 1 incoming gluon
// for the outgoing
// 0 outgoing photon
// 1 outgoing fermion (v spinor)
//me to be returned
ProductionMatrixElement newme(PDT::Spin1Half,PDT::Spin1,
PDT::Spin1,PDT::Spin1Half);
// wavefunction for the intermediate particles
SpinorBarWaveFunction inter;
SpinorWaveFunction interb;
unsigned int inhel1,inhel2,outhel1,outhel2;
Energy2 mt(scale());
Complex diag[3];
double me(0.),diag1(0.),diag2(0.);
for(inhel1=0;inhel1<2;++inhel1) {
for(inhel2=0;inhel2<2;++inhel2) {
for(outhel1=0;outhel1<2;++outhel1) {
for(outhel2=0;outhel2<2;++outhel2) {
// first diagram
inter = _photonvertex->evaluate(ZERO,5,ain[inhel1].particle()->CC(),
ain[inhel1],pout[outhel1]);
diag[0]=_gluonvertex->evaluate(mt,aout[outhel2],inter,gin[inhel2]);
// second diagram
inter = _gluonvertex->evaluate(mt,5,ain[inhel1].particle()->CC(),
ain[inhel1],gin[inhel2]);
diag[1]=_photonvertex->evaluate(ZERO,aout[outhel2],inter,pout[outhel1]);
// compute the running totals
diag[2]=diag[0]+diag[1];
diag1 +=norm(diag[0]);
diag2 +=norm(diag[1]);
me +=norm(diag[2]);
// matrix element
if(calc) newme(inhel1,2*inhel2,2*outhel1,outhel2)=diag[2];
}
}
}
}
// save the info on the diagrams
if(!calc) {
DVector save;
save.push_back(diag1);
save.push_back(diag2);
meInfo(save);
}
// return the answer
if(calc) _me.reset(newme);
return me;
}
void MEPP2GammaJet::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]);
// order of particles
unsigned int order[4]={0,1,2,3};
// identify the process and calculate matrix element
if(hard[0]->id()==ParticleID::g||hard[1]->id()==ParticleID::g) {
if(hard[0]->id()==ParticleID::g ) swap(order[0],order[1]);
if(hard[3]->id()==ParticleID::gamma) swap(order[2],order[3]);
if(hard[order[0]]->id()>0) {
vector<SpinorWaveFunction> q;
vector<SpinorBarWaveFunction> qb;
vector<VectorWaveFunction> p,g;
SpinorWaveFunction (q ,hard[order[0]],incoming,false,true);
VectorWaveFunction (g ,hard[order[1]],incoming,false,true,true);
VectorWaveFunction (p ,hard[order[2]],outgoing,true ,true,true);
SpinorBarWaveFunction(qb,hard[order[3]],outgoing,true,true);
qgME(q,g,p,qb,true);
}
else {
vector<SpinorWaveFunction> q;
vector<SpinorBarWaveFunction> qb;
vector<VectorWaveFunction> p,g;
SpinorBarWaveFunction(qb,hard[order[0]],incoming,false,true);
VectorWaveFunction (g ,hard[order[1]],incoming,false,true,true);
VectorWaveFunction (p ,hard[order[2]],outgoing,true ,true,true);
SpinorWaveFunction (q ,hard[order[3]],outgoing,true,true);
qbargME(qb,g,p,q,true);
}
}
else {
if(hard[0]->id()<0) swap(order[0],order[1]);
if(hard[2]->id()==ParticleID::gamma) swap(order[2],order[3]);
vector<SpinorWaveFunction> q;
vector<SpinorBarWaveFunction> qb;
vector<VectorWaveFunction> p,g;
SpinorWaveFunction (q ,hard[order[0]],incoming,false,true);
SpinorBarWaveFunction(qb,hard[order[1]],incoming,false,true);
VectorWaveFunction (g ,hard[order[2]],outgoing,true ,true,true);
VectorWaveFunction (p ,hard[order[3]],outgoing,true ,true,true);
p[1]=p[2];g[1]=g[2];
qqbarME(q,qb,g,p,true);
}
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(_me);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<4;++ix)
hard[order[ix]]->spinInfo()->productionVertex(hardvertex);
}
diff --git a/MatrixElement/Hadron/MEPP2GammaJet.h b/MatrixElement/Hadron/MEPP2GammaJet.h
--- a/MatrixElement/Hadron/MEPP2GammaJet.h
+++ b/MatrixElement/Hadron/MEPP2GammaJet.h
@@ -1,304 +1,269 @@
// -*- C++ -*-
//
// MEPP2GammaJet.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_MEPP2GammaJet_H
#define HERWIG_MEPP2GammaJet_H
//
// This is the declaration of the MEPP2GammaJet class.
//
#include "Herwig/MatrixElement/HwMEBase.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
namespace Herwig {
using namespace ThePEG;
using namespace ThePEG::Helicity;
/** \ingroup MatrixElements
* The MEPP2GammaJet class implements the matrix element for photon+jet
* production in hadron-hadron collisions.
*
* @see \ref MEPP2GammaJetInterfaces "The interfaces"
* defined for MEPP2GammaJet.
*/
class MEPP2GammaJet: public HwMEBase {
public:
/**
* The default constructor.
*/
MEPP2GammaJet();
/** @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();
//@}
private:
/**
* Members to return the matrix elements for the different subprocesses
*/
//@{
/**
* Matrix element for \f$q\bar{q}\to g\gamma\f$.
* @param fin Spinors for incoming quark
* @param ain Spinors for incoming antiquark
* @param gout Polarization vectors for the outgoing gluon
* @param pout Polarization vectors for the outgoing photon
* @param me Whether or not to calculate the matrix element for spin correlations
*/
double qqbarME(vector<SpinorWaveFunction> & fin, vector<SpinorBarWaveFunction> & ain,
vector<VectorWaveFunction> & gout, vector<VectorWaveFunction> & pout,
bool me) const;
/**
* Matrix element for \f$qg\to \gamma q\f$.
* @param fin Spinors for incoming quark
* @param gin Polarization vectors for the incoming gluon
* @param pout Polarization vectors for the outgoing photon
* @param fout Spinors for outgoing quark
* @param me Whether or not to calculate the matrix element for spin correlations
*/
double qgME(vector<SpinorWaveFunction> & fin,vector<VectorWaveFunction> & gin,
vector<VectorWaveFunction> & pout,vector<SpinorBarWaveFunction> & fout,
bool me) const;
/**
* Matrix element for \f$\bar{q}g\to \gamma \bar{q}\f$.
* @param ain Spinors for the incoming antiquark
* @param gin Polarization vectors for the incoming gluon
* @param pout Polarization vectors for the outgoing photon
* @param aout Spinors for the outgoing antiquark
* @param me Whether or not to calculate the matrix element for spin correlations
*/
double qbargME(vector<SpinorBarWaveFunction> & ain, vector<VectorWaveFunction> & gin,
vector<VectorWaveFunction> & pout, vector<SpinorWaveFunction> & aout,
bool me) const;
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<MEPP2GammaJet> initMEPP2GammaJet;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEPP2GammaJet & operator=(const MEPP2GammaJet &);
private:
/**
* Pointer to the quark-antiquark-gluon vertex
*/
AbstractFFVVertexPtr _gluonvertex;
/**
* Pointer to the quark-antiquark-photon vertex
*/
AbstractFFVVertexPtr _photonvertex;
/**
* Maximum PDG code of the quarks allowed
*/
int _maxflavour;
/**
* Option for which processes to include
*/
unsigned int _processopt;
/**
* Matrix element for spin correlations
*/
ProductionMatrixElement _me;
/**
* Scale prefactor
*/
double scalePreFactor_;
};
}
-#include "ThePEG/Utilities/ClassTraits.h"
-
-namespace ThePEG {
-
-/** @cond TRAITSPECIALIZATIONS */
-
-/** This template specialization informs ThePEG about the
- * base classes of MEPP2GammaJet. */
-template <>
-struct BaseClassTrait<Herwig::MEPP2GammaJet,1> {
- /** Typedef of the first base class of MEPP2GammaJet. */
- typedef Herwig::HwMEBase NthBase;
-};
-
-/** This template specialization informs ThePEG about the name of
- * the MEPP2GammaJet class and the shared object where it is defined. */
-template <>
-struct ClassTraits<Herwig::MEPP2GammaJet>
- : public ClassTraitsBase<Herwig::MEPP2GammaJet> {
- /** Return a platform-independent class name */
- static string className() { return "Herwig::MEPP2GammaJet"; }
- /**
- * The name of a file containing the dynamic library where the class
- * MEPP2GammaJet is implemented. It may also include several, space-separated,
- * libraries if the class MEPP2GammaJet 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_MEPP2GammaJet_H */
diff --git a/MatrixElement/Hadron/MEPP2Higgs.cc b/MatrixElement/Hadron/MEPP2Higgs.cc
--- a/MatrixElement/Hadron/MEPP2Higgs.cc
+++ b/MatrixElement/Hadron/MEPP2Higgs.cc
@@ -1,1439 +1,1442 @@
// -*- C++ -*-
//
// MEPP2Higgs.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2Higgs class.
//
#include "MEPP2Higgs.h"
+#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "ThePEG/Cuts/Cuts.h"
#include "Herwig/MatrixElement/HardVertex.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "Herwig/Utilities/Maths.h"
#include "Herwig/Shower/Core/Base/ShowerProgenitor.h"
#include "Herwig/Shower/RealEmissionProcess.h"
#include "Herwig/Shower/Core/Base/Branching.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.
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEPP2Higgs,HwMEBase>
+describeHerwigMEPP2Higgs("Herwig::MEPP2Higgs", "HwMEHadron.so");
void MEPP2Higgs::persistentOutput(PersistentOStream & os) const {
os << HGGVertex_ << HFFVertex_ << shapeOption_ << processOption_
<< minFlavour_ << maxFlavour_ << hmass_ << ounit(mh_,GeV)
<< ounit(wh_,GeV) << minLoop_ << maxLoop_ << massOption_
<< alpha_ << prefactor_ << power_ << pregg_ << preqg_
<< pregqbar_ << ounit( minpT_, GeV ) << ggPow_ << qgPow_
<< enhance_ << channelwgtA_ << channelwgtB_ << channelWeights_
<< mu_R_opt_ << mu_F_opt_ << spinCorrelations_;
}
void MEPP2Higgs::persistentInput(PersistentIStream & is, int) {
is >> HGGVertex_ >> HFFVertex_ >> shapeOption_ >> processOption_
>> minFlavour_ >> maxFlavour_ >> hmass_ >> iunit(mh_,GeV)
>> iunit(wh_,GeV) >> minLoop_ >> maxLoop_ >> massOption_
>> alpha_ >> prefactor_ >> power_ >> pregg_ >> preqg_
>> pregqbar_ >> iunit( minpT_, GeV ) >> ggPow_ >> qgPow_
>> enhance_ >> channelwgtA_ >> channelwgtB_ >> channelWeights_
>> mu_R_opt_ >> mu_F_opt_ >> spinCorrelations_;
}
void MEPP2Higgs::Init() {
static ClassDocumentation<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.;
}
RealEmissionProcessPtr MEPP2Higgs::applyHardMatrixElementCorrection(RealEmissionProcessPtr born) {
useMe();
assert(born->bornOutgoing().size()==1);
if(born->bornIncoming()[0]->id()!=ParticleID::g)
return RealEmissionProcessPtr();
// get gluons and Higgs
// get the gluons
ParticleVector incoming;
vector<tcBeamPtr> beams;
for(unsigned int ix=0;ix<born->bornIncoming().size();++ix) {
incoming.push_back(born->bornIncoming()[ix]);
beams.push_back(dynamic_ptr_cast<tcBeamPtr>(born->hadrons()[ix]->dataPtr()));
}
pair<double,double> xnew=born->x();
if(incoming[0]->momentum().z()<ZERO) {
swap(incoming[0],incoming[1]);
swap(beams[0],beams[1]);
swap(xnew.first,xnew.second);
}
// get the Higgs
PPtr higgs;
higgs=born->bornOutgoing()[0];
// calculate the momenta
unsigned int iemit,itype;
vector<Lorentz5Momentum> pnew;
// if not accepted return
tPDPtr out;
if(!applyHard(incoming,beams,higgs,iemit,itype,pnew,xnew,out)) return RealEmissionProcessPtr();
// fix the momentum of the higgs
Boost boostv=born->bornOutgoing()[0]->momentum().findBoostToCM();
LorentzRotation trans(pnew[3].boostVector());
trans *=LorentzRotation(boostv);
born->transformation(trans);
born->outgoing().push_back(born->bornOutgoing()[0]->dataPtr()->produceParticle(pnew[3]));
born->emitted(3);
// if applying ME correction create the new particles
if(itype==0) {
// ensure gluon can be put on shell
Lorentz5Momentum ptest(pnew[2]);
if(ptest.boost(-(pnew[0]+pnew[1]).boostVector()).e() <
getParticleData(ParticleID::g)->constituentMass()) return RealEmissionProcessPtr();
// create the new gluon
PPtr newg= getParticleData(ParticleID::g)->produceParticle(pnew[2]);
PPtr newg1 = incoming[0]->dataPtr()->produceParticle(pnew[0]);
PPtr newg2 = incoming[1]->dataPtr()->produceParticle(pnew[1]);
// set emitter and spectator
if(born->bornIncoming()[0]->momentum().z()>ZERO) {
born->incoming().push_back(newg1);
born->incoming().push_back(newg2);
if(iemit==0) {
born->emitter(0);
born->spectator(1);
}
else {
born->emitter(1);
born->spectator(0);
}
}
else {
born->incoming().push_back(newg2);
born->incoming().push_back(newg1);
if(iemit==0) {
born->emitter(1);
born->spectator(0);
}
else {
born->emitter(0);
born->spectator(1);
}
}
bool colour = UseRandom::rndbool();
newg ->incomingColour(newg1,!colour);
newg ->incomingColour(newg2, colour);
newg1->colourConnect(newg2,!colour);
born->outgoing().push_back(newg);
}
else if(itype==1) {
// ensure outgoing quark can be put on-shell
Lorentz5Momentum ptest(pnew[2]);
if(ptest.boost(-(pnew[0]+pnew[1]).boostVector()).e() <
out->constituentMass()) return RealEmissionProcessPtr();
// create the new particles
PPtr newqout = out->produceParticle(pnew[2]);
PPtr newqin,newg;
if(iemit==0) {
newqin = out ->produceParticle(pnew[0]);
newg = incoming[1]->dataPtr()->produceParticle(pnew[1]);
}
else {
newg = incoming[0]->dataPtr()->produceParticle(pnew[0]);
newqin = out ->produceParticle(pnew[1]);
}
newqout->incomingColour(newg);
newg->colourConnect(newqin);
if((born->bornIncoming()[0]->momentum().z()>ZERO && iemit==0) ||
(born->bornIncoming()[0]->momentum().z()<ZERO && iemit==1)) {
born->incoming().push_back(newqin);
born->incoming().push_back(newg );
born->emitter(0);
born->spectator(1);
}
else {
born->incoming().push_back(newg );
born->incoming().push_back(newqin);
born->emitter(1);
born->spectator(0);
}
born->outgoing().push_back(newqout);
}
else if(itype==2) {
// ensure outgoing antiquark can be put on-shell
Lorentz5Momentum ptest(pnew[2]);
if(ptest.boost(-(pnew[0]+pnew[1]).boostVector()).e() <
incoming[0]->dataPtr()->constituentMass()) return RealEmissionProcessPtr();
// create the new particles
PPtr newqout = out->produceParticle(pnew[2]);
PPtr newqin,newg;
if(iemit==0) {
newqin = out ->produceParticle(pnew[0]);
newg = incoming[1]->dataPtr()->produceParticle(pnew[1]);
}
else {
newg = incoming[0]->dataPtr()->produceParticle(pnew[0]);
newqin = out ->produceParticle(pnew[1]);
}
newqout->incomingAntiColour(newg);
newg->colourConnect(newqin,true);
if((born->bornIncoming()[0]->momentum().z()>ZERO && iemit==0) ||
(born->bornIncoming()[0]->momentum().z()<ZERO && iemit==1)) {
born->incoming().push_back(newqin);
born->incoming().push_back(newg );
born->emitter(0);
born->spectator(1);
}
else {
born->incoming().push_back(newg );
born->incoming().push_back(newqin);
born->emitter(1);
born->spectator(0);
}
born->outgoing().push_back(newqout);
}
if(born->bornIncoming()[0]->momentum().z()<ZERO) {
swap(xnew.first,xnew.second);
}
born->x(xnew);
born->interaction(ShowerInteraction::QCD);
return born;
}
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]->id()!=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]->id()==ParticleID::g&&br.ids[2]->id()==ParticleID::g) {
double split = 6.*(z/(1.-z)+(1.-z)/z+z*(1.-z));
me = ggME(shat,that,uhat)/split;
}
// q g
else if(br.ids[0]->id() >= 1 && br.ids[0]->id() <= 5 && br.ids[2]->id()==br.ids[0]->id()) {
double split = 4./3./z*(1.+sqr(1.-z));
me = qgME(shat,uhat,that)/split;
}
// qbar g
else if(br.ids[0]->id() <= -1 && br.ids[0]->id() >= -5 && br.ids[2]->id()==br.ids[0]->id()) {
double split = 4./3./z*(1.+sqr(1.-z));
me = qbargME(shat,uhat,that)/split;
}
else {
return false;
}
InvEnergy2 pre = 0.125/Constants::pi/loME()*sqr(mh2_)*that/shat/(shat+uhat);
double wgt = -pre*me/enhance_;
if(wgt<.0||wgt>1.) generator()->log() << "Soft ME correction weight too large or "
<< "negative in MEPP2Higgs::"
<< "softMatrixElementVeto()\n soft weight "
<< " sbar = " << shat/mh2_
<< " tbar = " << that/mh2_
<< "weight = " << wgt << " for "
<< br.ids[0]->id() << " " << br.ids[1]->id() << " "
<< br.ids[2]->id() << "\n";
// if not vetoed
if(UseRandom::rndbool(wgt)) return false;
// otherwise
parent->vetoEmission(br.type,br.kinematics->scale());
return true;
}
RealEmissionProcessPtr MEPP2Higgs::generateHardest(RealEmissionProcessPtr born,
ShowerInteraction inter) {
if(inter==ShowerInteraction::QED) return RealEmissionProcessPtr();
useMe();
// get the particles to be showered
beams_.clear();
partons_.clear();
// find the incoming particles
ParticleVector incoming;
ParticleVector particlesToShower;
for(unsigned int ix=0;ix<born->bornIncoming().size();++ix) {
incoming.push_back( born->bornIncoming()[ix] );
beams_.push_back( dynamic_ptr_cast<tcBeamPtr>(born->hadrons()[ix]->dataPtr()));
partons_.push_back( born->bornIncoming()[ix]->dataPtr() );
particlesToShower.push_back( born->bornIncoming()[ix] );
}
// find the higgs boson
assert(born->bornOutgoing().size()==1);
PPtr higgs = born->bornOutgoing()[0];
// calculate the rapidity of the higgs
yh_ = 0.5 * log((higgs->momentum().e()+higgs->momentum().z())/
(higgs->momentum().e()-higgs->momentum().z()));
mass_=higgs->mass();
mh2_ = sqr(mass_);
vector<Lorentz5Momentum> pnew;
int emission_type(-1);
// generate the hard emission and return if no emission
if(!getEvent(pnew,emission_type)) {
born->pT()[ShowerInteraction::QCD] = minpT_;
return born;
}
// construct the HardTree object needed to perform the showers
ParticleVector newparticles(4);
// create the partons
int iemit=-1;
// create the jet
newparticles[3] = out_->produceParticle(pnew[3]);
// g g -> h g
if(emission_type==0) {
newparticles[0] = partons_[0]->produceParticle(pnew[0]);
newparticles[1] = partons_[1]->produceParticle(pnew[1]);
iemit = pnew[0].z()/pnew[3].z()>0. ? 0 : 1;
bool colour = UseRandom::rndbool();
newparticles[3]->incomingColour(newparticles[0],!colour);
newparticles[3]->incomingColour(newparticles[1], colour);
newparticles[0]-> colourConnect(newparticles[1],!colour);
}
// g q -> H q
else if(emission_type==1) {
newparticles[0] = partons_[0]->produceParticle(pnew[0]);
newparticles[1] = out_ ->produceParticle(pnew[1]);
iemit = 1;
newparticles[3]->incomingColour(newparticles[0]);
newparticles[0]->colourConnect (newparticles[1]);
}
// q g -> H q
else if(emission_type==2) {
newparticles[0] = out_ ->produceParticle(pnew[0]);
newparticles[1] = partons_[1]->produceParticle(pnew[1]);
iemit = 0;
newparticles[3]->incomingColour(newparticles[1]);
newparticles[1]->colourConnect (newparticles[0]);
}
// g qbar -> H qbar
else if(emission_type==3) {
newparticles[0] = partons_[0]->produceParticle(pnew[0]);
newparticles[1] = out_ ->produceParticle(pnew[1]);
iemit = 1;
newparticles[3]->incomingAntiColour(newparticles[0]);
newparticles[0]->colourConnect(newparticles[1],true);
}
// qbar g -> H qbar
else if(emission_type==4) {
newparticles[0] = out_ ->produceParticle(pnew[0]);
newparticles[1] = partons_[1]->produceParticle(pnew[1]);
iemit = 0;
newparticles[3]->incomingAntiColour(newparticles[1]);
newparticles[1]->colourConnect(newparticles[0],true);
}
unsigned int ispect = iemit==0 ? 1 : 0;
// create the boson
newparticles[2] = higgs->dataPtr()->produceParticle(pnew[2]);
born->emitter (iemit);
born->spectator(ispect);
born->emitted(3);
born->pT()[ShowerInteraction::QCD] = pt_;
pair<double,double> xnew;
for(unsigned int ix=0;ix<2;++ix) {
born->incoming().push_back(newparticles[ix]);
if(ix==0) xnew.first = newparticles[ix]->momentum().rho()/born->hadrons()[ix]->momentum().rho();
else xnew.second = newparticles[ix]->momentum().rho()/born->hadrons()[ix]->momentum().rho();
}
born->x(xnew);
for(unsigned int ix=0;ix<2;++ix)
born->outgoing().push_back(newparticles[ix+2]);
// return the answer
born->interaction(ShowerInteraction::QCD);
return born;
}
bool MEPP2Higgs::applyHard(ParticleVector gluons,
vector<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]={xout.first,xout.second},fx[2]={-99.99e99,-99.99e99};
tcPDFPtr pdf[2];
for(unsigned int ix=0;ix<gluons.size();++ix) {
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(RealEmissionProcessPtr born, double & initial,
double & final) {
final = 1.;
initial = born->bornIncoming()[0]->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,708 @@
// -*- C++ -*-
//
// MEPP2Higgs.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_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/Core/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(RealEmissionProcessPtr, double &,
double & );
/**
* Apply the hard matrix element correction to a given hard process or decay
*/
virtual RealEmissionProcessPtr applyHardMatrixElementCorrection(RealEmissionProcessPtr);
/**
* Apply the soft matrix element correction
* @param 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 RealEmissionProcessPtr generateHardest(RealEmissionProcessPtr,
ShowerInteraction);
//@}
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(ParticleVector 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/MEPP2HiggsJet.cc b/MatrixElement/Hadron/MEPP2HiggsJet.cc
--- a/MatrixElement/Hadron/MEPP2HiggsJet.cc
+++ b/MatrixElement/Hadron/MEPP2HiggsJet.cc
@@ -1,875 +1,878 @@
// -*- C++ -*-
//
// MEPP2HiggsJet.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2HiggsJet class.
//
#include "MEPP2HiggsJet.h"
+#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/StandardModel/StandardModelBase.h"
#include "ThePEG/Utilities/SimplePhaseSpace.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "ThePEG/Cuts/Cuts.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "Herwig/MatrixElement/HardVertex.h"
using namespace Herwig;
const Complex MEPP2HiggsJet::_epsi = Complex(0.,-1.e-20);
IBPtr MEPP2HiggsJet::clone() const {
return new_ptr(*this);
}
IBPtr MEPP2HiggsJet::fullclone() const {
return new_ptr(*this);
}
unsigned int MEPP2HiggsJet::orderInAlphaS() const {
return 3;
}
unsigned int MEPP2HiggsJet::orderInAlphaEW() const {
return 1;
}
void MEPP2HiggsJet::persistentOutput(PersistentOStream & os) const {
os << _shapeopt << _maxflavour << _process << _minloop << _maxloop << _massopt
<< ounit(_mh,GeV) << ounit(_wh,GeV) << _hmass;
}
void MEPP2HiggsJet::persistentInput(PersistentIStream & is, int) {
is >> _shapeopt >> _maxflavour >> _process >> _minloop >> _maxloop >> _massopt
>> iunit(_mh,GeV) >> iunit(_wh,GeV) >> _hmass;
}
-ClassDescription<MEPP2HiggsJet> MEPP2HiggsJet::initMEPP2HiggsJet;
-// Definition of the static class description member.
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEPP2HiggsJet,ME2to2Base>
+describeHerwigMEPP2HiggsJet("Herwig::MEPP2HiggsJet", "HwMEHadron.so");
void MEPP2HiggsJet::Init() {
static ClassDocumentation<MEPP2HiggsJet> documentation
("The MEPP2HiggsJet class implements the matrix elements for"
" Higgs+Jet production in hadron-hadron collisions.",
"The theoretical calculations of \\cite{Baur:1989cm} and \\cite{Ellis:1987xu}"
" were used for the Higgs+jet matrix element in hadron-hadron collisions.",
"\\bibitem{Baur:1989cm} U.~Baur and E.~W.~N.~Glover,"
"Nucl.\\ Phys.\\ B {\\bf 339} (1990) 38.\n"
"\\bibitem{Ellis:1987xu} R.~K.~Ellis, I.~Hinchliffe, M.~Soldate and "
"J.~J.~van der Bij, Nucl.\\ Phys.\\ B {\\bf 297} (1988) 221.");
static Parameter<MEPP2HiggsJet,unsigned int> interfaceMaximumFlavour
("MaximumFlavour",
"The maximum flavour of the quarks in the process",
&MEPP2HiggsJet::_maxflavour, 5, 1, 5,
false, false, Interface::limited);
static Switch<MEPP2HiggsJet,unsigned int> interfaceShapeOption
("ShapeScheme",
"Option for the treatment of the Higgs resonance shape",
&MEPP2HiggsJet::_shapeopt, 1, false, false);
static SwitchOption interfaceStandardShapeFixed
(interfaceShapeOption,
"FixedBreitWigner",
"Breit-Wigner s-channel resonanse",
1);
static SwitchOption interfaceStandardShapeRunning
(interfaceShapeOption,
"MassGenerator",
"Use the mass generator to give the shape",
2);
static Switch<MEPP2HiggsJet,unsigned int> interfaceProcess
("Process",
"Which subprocesses to include",
&MEPP2HiggsJet::_process, 0, false, false);
static SwitchOption interfaceProcessAll
(interfaceProcess,
"All",
"Include all subprocesses",
0);
static SwitchOption interfaceProcess1
(interfaceProcess,
"qqbar",
"Only include the incoming q qbar subprocess",
1);
static SwitchOption interfaceProcessqg
(interfaceProcess,
"qg",
"Only include the incoming qg subprocess",
2);
static SwitchOption interfaceProcessqbarg
(interfaceProcess,
"qbarg",
"Only include the incoming qbar g subprocess",
3);
static SwitchOption interfaceProcessgg
(interfaceProcess,
"gg",
"Only include the incoming gg subprocess",
4);
static Parameter<MEPP2HiggsJet,int> interfaceMinimumInLoop
("MinimumInLoop",
"The minimum flavour of the quarks to include in the loops",
&MEPP2HiggsJet::_minloop, 6, 4, 6,
false, false, Interface::limited);
static Parameter<MEPP2HiggsJet,int> interfaceMaximumInLoop
("MaximumInLoop",
"The maximum flavour of the quarks to include in the loops",
&MEPP2HiggsJet::_maxloop, 6, 4, 6,
false, false, Interface::limited);
static Switch<MEPP2HiggsJet,unsigned int> interfaceMassOption
("MassOption",
"Option for the treatment of the masses in the loop diagrams",
&MEPP2HiggsJet::_massopt, 0, false, false);
static SwitchOption interfaceMassOptionFull
(interfaceMassOption,
"Full",
"Include the full mass dependence",
0);
static SwitchOption interfaceMassOptionLarge
(interfaceMassOption,
"Large",
"Use the heavy mass limit",
1);
}
bool MEPP2HiggsJet::generateKinematics(const double * r) {
Energy ptmin = max(lastCuts().minKT(mePartonData()[2]),
lastCuts().minKT(mePartonData()[3]));
Energy e = sqrt(sHat())/2.0;
// generate the mass of the higgs boson
Energy2 mhmax2 = sHat()-4.*ptmin*e;
Energy2 mhmin2 =ZERO;
if(mhmax2<=mhmin2) return false;
double rhomin = atan2((mhmin2-sqr(_mh)), _mh*_wh);
double rhomax = atan2((mhmax2-sqr(_mh)), _mh*_wh);
Energy mh = sqrt(_mh*_wh*tan(rhomin+r[1]*(rhomax-rhomin))+sqr(_mh));
// assign masses
if(mePartonData()[2]->id()!=ParticleID::h0) {
meMomenta()[2].setMass(ZERO);
meMomenta()[3].setMass(mh);
}
else {
meMomenta()[3].setMass(ZERO);
meMomenta()[2].setMass(mh);
}
Energy q = ZERO;
try {
q = SimplePhaseSpace::
getMagnitude(sHat(), meMomenta()[2].mass(), meMomenta()[3].mass());
}
catch ( ImpossibleKinematics ) {
return false;
}
Energy2 m22 = meMomenta()[2].mass2();
Energy2 m32 = meMomenta()[3].mass2();
Energy2 e0e2 = 2.0*e*sqrt(sqr(q) + m22);
Energy2 e1e2 = 2.0*e*sqrt(sqr(q) + m22);
Energy2 e0e3 = 2.0*e*sqrt(sqr(q) + m32);
Energy2 e1e3 = 2.0*e*sqrt(sqr(q) + m32);
Energy2 pq = 2.0*e*q;
double ctmin = -1.0,ctmax = 1.0;
Energy2 thmin = lastCuts().minTij(mePartonData()[0], mePartonData()[2]);
if ( thmin > ZERO ) ctmax = min(ctmax, (e0e2 - m22 - thmin)/pq);
thmin = lastCuts().minTij(mePartonData()[1], mePartonData()[2]);
if ( thmin > ZERO ) ctmin = max(ctmin, (thmin + m22 - e1e2)/pq);
thmin = lastCuts().minTij(mePartonData()[1], mePartonData()[3]);
if ( thmin > ZERO ) ctmax = min(ctmax, (e1e3 - m32 - thmin)/pq);
thmin = lastCuts().minTij(mePartonData()[0], mePartonData()[3]);
if ( thmin > ZERO ) ctmin = max(ctmin, (thmin + m32 - e0e3)/pq);
if ( ptmin > ZERO ) {
double ctm = 1.0 - sqr(ptmin/q);
if ( ctm <= 0.0 ) return false;
ctmin = max(ctmin, -sqrt(ctm));
ctmax = min(ctmax, sqrt(ctm));
}
if ( ctmin >= ctmax ) return false;
double cth = getCosTheta(ctmin, ctmax, r);
Energy pt = q*sqrt(1.0-sqr(cth));
phi(rnd(2.0*Constants::pi));
meMomenta()[2].setX(pt*sin(phi()));
meMomenta()[2].setY(pt*cos(phi()));
meMomenta()[2].setZ(q*cth);
meMomenta()[3].setX(-pt*sin(phi()));
meMomenta()[3].setY(-pt*cos(phi()));
meMomenta()[3].setZ(-q*cth);
meMomenta()[2].rescaleEnergy();
meMomenta()[3].rescaleEnergy();
vector<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());
// main piece
jacobian((pq/sHat())*Constants::pi*jacobian());
// mass piece
jacobian((rhomax-rhomin)*jacobian());
return true;
}
void MEPP2HiggsJet::getDiagrams() const {
tcPDPtr h0=getParticleData(ParticleID::h0);
tcPDPtr g =getParticleData(ParticleID::g);
tcPDPtr q[6],qb[6];
for(int ix=0;ix<int(_maxflavour);++ix) {
q [ix]=getParticleData( ix+1);
qb[ix]=getParticleData(-ix-1);
}
// q qbar -> H g
if(_process==0||_process==1)
{for(unsigned int ix=0;ix<_maxflavour;++ix)
{add(new_ptr((Tree2toNDiagram(2), q[ix], qb[ix], 1, g , 3, h0, 3, g, -1)));}}
// q g -> H g
if(_process==0||_process==2)
{for(unsigned int ix=0;ix<_maxflavour;++ix)
{add(new_ptr((Tree2toNDiagram(3), q[ix], g, g, 2, h0, 1, q[ix], -2)));}}
// qbar g -> H qbar
if(_process==0||_process==3)
{for(unsigned int ix=0;ix<_maxflavour;++ix)
{add(new_ptr((Tree2toNDiagram(3), qb[ix], g, g, 2, h0, 1, qb[ix], -3)));}}
// g g -> H g
if(_process==0||_process==4)
{
// t channel
add(new_ptr((Tree2toNDiagram(3), g, g, g, 1, h0, 2, g, -4)));
// u channel
add(new_ptr((Tree2toNDiagram(3), g, g, g, 2, h0, 1, g, -5)));
// s channel
add(new_ptr((Tree2toNDiagram(2), g, g, 1, g , 3, h0, 3, g, -6)));
}
}
Energy2 MEPP2HiggsJet::scale() const {
return meMomenta()[2].perp2()+ meMomenta()[2].m2();
}
double MEPP2HiggsJet::me2() const {
useMe();
double output(0.);
// g g to H g
if(mePartonData()[0]->id()==ParticleID::g&&mePartonData()[1]->id()==ParticleID::g) {
// order of the particles
unsigned int ih(2),ig(3);
if(mePartonData()[3]->id()==ParticleID::h0){ig=2;ih=3;}
VectorWaveFunction glin1(meMomenta()[ 0],mePartonData()[ 0],incoming);
VectorWaveFunction glin2(meMomenta()[ 1],mePartonData()[ 1],incoming);
ScalarWaveFunction hout(meMomenta()[ih],mePartonData()[ih],outgoing);
VectorWaveFunction glout(meMomenta()[ig],mePartonData()[ig],outgoing);
vector<VectorWaveFunction> g1,g2,g4;
for(unsigned int ix=0;ix<2;++ix) {
glin1.reset(2*ix);g1.push_back(glin1);
glin2.reset(2*ix);g2.push_back(glin2);
glout.reset(2*ix);g4.push_back(glout);
}
// calculate the matrix element
output = ggME(g1,g2,hout,g4,false);
}
// qg -> H q
else if(mePartonData()[0]->id()>0&&mePartonData()[1]->id()==ParticleID::g) {
// order of the particles
unsigned int iq(0),iqb(3),ih(2),ig(1);
if(mePartonData()[0]->id()==ParticleID::g){iq=1;ig=0;}
if(mePartonData()[3]->id()==ParticleID::h0){iqb=2;ih=3;}
// calculate the spinors and polarization vectors
vector<SpinorWaveFunction> fin;
vector<SpinorBarWaveFunction> fout;
vector<VectorWaveFunction> gin;
SpinorWaveFunction qin (meMomenta()[iq ],mePartonData()[iq ],incoming);
VectorWaveFunction glin(meMomenta()[ig ],mePartonData()[ig ],incoming);
ScalarWaveFunction hout(meMomenta()[ih ],mePartonData()[ih ],outgoing);
SpinorBarWaveFunction qout(meMomenta()[iqb],mePartonData()[iqb],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
qin.reset(ix) ; fin.push_back( qin);
qout.reset(ix) ;fout.push_back(qout);
glin.reset(2*ix); gin.push_back(glin);
}
// calculate the matrix element
output = qgME(fin,gin,hout,fout,false);
}
// qbar g -> H q
else if(mePartonData()[0]->id()<0&&mePartonData()[1]->id()==ParticleID::g) {
// order of the particles
unsigned int iq(0),iqb(3),ih(2),ig(1);
if(mePartonData()[0]->id()==ParticleID::g){iq=1;ig=0;}
if(mePartonData()[3]->id()==ParticleID::h0){iqb=2;ih=3;}
// calculate the spinors and polarization vectors
vector<SpinorBarWaveFunction> fin;
vector<SpinorWaveFunction> fout;
vector<VectorWaveFunction> gin;
SpinorBarWaveFunction qin (meMomenta()[iq ],mePartonData()[iq ],incoming);
VectorWaveFunction glin(meMomenta()[ig ],mePartonData()[ig ],incoming);
ScalarWaveFunction hout(meMomenta()[ih ],mePartonData()[ih ],outgoing);
SpinorWaveFunction qout(meMomenta()[iqb],mePartonData()[iqb],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
qin.reset(ix) ; fin.push_back( qin);
qout.reset(ix) ;fout.push_back(qout);
glin.reset(2*ix); gin.push_back(glin);
}
// calculate the matrix element
output = qbargME(fin,gin,hout,fout,false);
}
// q qbar to H g
else if(mePartonData()[0]->id()==-mePartonData()[1]->id()) {
// order of the particles
unsigned int iq(0),iqb(1),ih(2),ig(3);
if(mePartonData()[0]->id()<0){iq=1;iqb=0;}
if(mePartonData()[2]->id()==ParticleID::g){ig=2;ih=3;}
// calculate the spinors and polarization vectors
vector<SpinorWaveFunction> fin;
vector<SpinorBarWaveFunction> ain;
vector<VectorWaveFunction> gout;
SpinorWaveFunction qin (meMomenta()[iq ],mePartonData()[iq ],incoming);
SpinorBarWaveFunction qbin(meMomenta()[iqb],mePartonData()[iqb],incoming);
ScalarWaveFunction hout(meMomenta()[ih ],mePartonData()[ih ],outgoing);
VectorWaveFunction glout(meMomenta()[ig ],mePartonData()[ig ],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
qin.reset(ix) ; fin.push_back( qin);
qbin.reset(ix) ; ain.push_back( qbin);
glout.reset(2*ix);gout.push_back(glout);
}
// calculate the matrix element
output = qqbarME(fin,ain,hout,gout,false);
}
else
throw Exception() << "Unknown subprocess in MEPP2HiggsJet::me2()"
<< Exception::runerror;
// return the answer
return output;
}
double MEPP2HiggsJet::qqbarME(vector<SpinorWaveFunction> & fin,
vector<SpinorBarWaveFunction> & ain,
ScalarWaveFunction & hout,
vector<VectorWaveFunction> & gout,
bool calc) const {
// the particles should be in the order
// for the incoming
// 0 incoming fermion (u spinor)
// 1 incoming antifermion (vbar spinor)
// for the outgoing
// 0 outgoing higgs
// 1 outgoing gluon
// me to be returned
ProductionMatrixElement newme(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin0,PDT::Spin1);
// get the kinematic invariants
Energy2 s(sHat()),u(uHat()),t(tHat()),mh2(hout.m2()),et(scale());
// calculate the loop function
complex<Energy2> A5 = Energy2();
for ( int ix=_minloop; ix<=_maxloop; ++ix ) {
// full mass dependance
if(_massopt==0) {
Energy2 mf2=sqr(getParticleData(ix)->mass());
A5+= mf2*(4.+4.*double(s/(u+t))*(W1(s,mf2)-W1(mh2,mf2))
+(1.-4.*double(mf2/(u+t)))*(W2(s,mf2)-W2(mh2,mf2)));
}
// infinite mass limit
else {
A5+=2.*(s-mh2)/3.;
}
}
// multiply by the rest of the form factors
using Constants::pi;
double g(sqrt(4.*pi*SM().alphaEM(mh2)/SM().sin2ThetaW()));
double gs(sqrt(4.*pi*SM().alphaS(et)));
Energy mw(getParticleData(ParticleID::Wplus)->mass());
complex<InvEnergy> A5c = A5 * Complex(0.,1.)*g*sqr(gs)*gs/(32.*s*sqr(pi)*mw);
// compute the matrix element
LorentzPolarizationVectorE fcurrent;
complex<Energy2> fdotp;
complex<Energy> epsdot[2];
Complex diag;
Lorentz5Momentum ps(fin[0].momentum()+ain[0].momentum());
ps.rescaleMass();
for(unsigned int ix=0;ix<2;++ix){epsdot[ix]=gout[ix].wave().dot(ps);}
Energy2 denom(-ps*gout[0].momentum());
LorentzSpinorBar<double> atemp;
double output(0.);
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
// compute the fermion current
atemp=ain[ihel2].wave();
fcurrent=UnitRemoval::E*fin[ihel1].wave().vectorCurrent(atemp);
fdotp = -(fcurrent.dot(gout[0].momentum()));
for(unsigned int ghel=0;ghel<2;++ghel) {
// calculate the matrix element
diag=A5c*(fcurrent.dot(gout[ghel].wave())
-fdotp*epsdot[ghel]/denom);
// calculate the matrix element
output+=real(diag*conj(diag));
if(calc) newme(ihel1,ihel2,0,2*ghel)=diag;
}
}
}
// test with glover form
// final colour/spin factors
if(calc) _me.reset(newme);
return output/9.;
}
double MEPP2HiggsJet::qgME(vector<SpinorWaveFunction> & fin,
vector<VectorWaveFunction> & gin,
ScalarWaveFunction & hout,
vector<SpinorBarWaveFunction> & fout,bool calc) const {
// the particles should be in the order
// for the incoming
// 0 incoming fermion (u spinor)
// 1 incoming gluon
// for the outgoing
// 0 outgoing higgs
// 1 outgoing fermion (ubar spinor)
// me to be returned
ProductionMatrixElement newme(PDT::Spin1Half,PDT::Spin1,
PDT::Spin0,PDT::Spin1Half);
// get the kinematic invariants
Energy2 s(sHat()),u(uHat()),t(tHat()),mh2(hout.m2()),et(scale());
// calculate the loop function
complex<Energy2> A5 = Energy2();
for(int ix=_minloop;ix<=_maxloop;++ix) {
if(_massopt==0) {
Energy2 mf2=sqr(getParticleData(ix)->mass());
A5+= mf2*(4.+4.*double(u/(s+t))*(W1(u,mf2)-W1(mh2,mf2))
+(1.-4.*double(mf2/(s+t)))*(W2(u,mf2)-W2(mh2,mf2)));
}
else {
A5+=2.*(u-mh2)/3.;
}
}
// multiply by the rest of the form factors
using Constants::pi;
double g(sqrt(4.*pi*SM().alphaEM(mh2)/SM().sin2ThetaW()));
double gs(sqrt(4.*pi*SM().alphaS(et)));
Energy mw(getParticleData(ParticleID::Wplus)->mass());
complex<InvEnergy> A5c =A5*Complex(0.,1.)*g*sqr(gs)*gs/(32.*u*sqr(pi)*mw);
// compute the matrix element
LorentzPolarizationVectorE fcurrent;
complex<Energy2> fdotp;
complex<Energy> epsdot[2];
Complex diag;
Lorentz5Momentum pu(fin[0].momentum()+fout[0].momentum());
pu.rescaleMass();
for(unsigned int ix=0;ix<2;++ix){epsdot[ix]=gin[ix].wave().dot(pu);}
Energy2 denom(pu*gin[0].momentum());
LorentzSpinorBar<double> atemp;
double output(0.);
for(unsigned int ihel=0;ihel<2;++ihel) {
for(unsigned int ohel=0;ohel<2;++ohel) {
// compute the fermion current
atemp=fout[ohel].wave();
fcurrent=UnitRemoval::E*fin[ihel].wave().vectorCurrent(atemp);
fdotp=fcurrent.dot(gin[0].momentum());
for(unsigned int ghel=0;ghel<2;++ghel) {
// calculate the matrix element
diag=A5c*(fcurrent.dot(gin[ghel].wave())-fdotp*epsdot[ghel]/denom);
// calculate the matrix element
output+=real(diag*conj(diag));
if(calc) newme(ihel,2*ghel,0,ohel)=diag;
}
}
}
// final colour/spin factors
if(calc) _me.reset(newme);
return output/24.;
}
double MEPP2HiggsJet::qbargME(vector<SpinorBarWaveFunction> & fin,
vector<VectorWaveFunction> & gin,
ScalarWaveFunction & hout,
vector<SpinorWaveFunction> & fout,bool calc) const {
// the particles should be in the order
// for the incoming
// 0 incoming antifermion (vbar spinor)
// 1 incoming gluon
// for the outgoing
// 0 outgoing higgs
// 1 outgoing antifermion (v spinor)
// me to be returned
ProductionMatrixElement newme(PDT::Spin1Half,PDT::Spin1,
PDT::Spin0,PDT::Spin1Half);
// get the kinematic invariants
Energy2 s(sHat()),u(uHat()),t(tHat()),mh2(hout.m2()),et(scale());
// calculate the loop function
complex<Energy2> A5 = Energy2();
for(int ix=_minloop;ix<=_maxloop;++ix) {
if(_massopt==0) {
Energy2 mf2=sqr(getParticleData(ix)->mass());
A5+= mf2*(4.+4.*double(u/(s+t))*(W1(u,mf2)-W1(mh2,mf2))
+(1.-4.*double(mf2/(s+t)))*(W2(u,mf2)-W2(mh2,mf2)));
}
else {
A5+=2.*(u-mh2)/3.;
}
}
// multiply by the rest of the form factors
using Constants::pi;
double g(sqrt(4.*pi*SM().alphaEM(mh2)/SM().sin2ThetaW()));
double gs(sqrt(4.*pi*SM().alphaS(et)));
Energy mw(getParticleData(ParticleID::Wplus)->mass());
complex<InvEnergy> A5c = A5*Complex(0.,1.)*g*sqr(gs)*gs/(32.*u*sqr(pi)*mw);
// compute the matrix element
LorentzPolarizationVectorE fcurrent;
complex<Energy2> fdotp;
complex<Energy> epsdot[2];
Complex diag;
Lorentz5Momentum pu(fin[0].momentum()+fout[0].momentum());
pu.rescaleMass();
for(unsigned int ix=0;ix<2;++ix){epsdot[ix]=gin[ix].wave().dot(pu);}
Energy2 denom(pu*gin[0].momentum());
LorentzSpinorBar<double> atemp;
double output(0.);
for(unsigned int ihel=0;ihel<2;++ihel) {
for(unsigned int ohel=0;ohel<2;++ohel) {
// compute the fermion current
atemp=fin[ihel].wave();
fcurrent=UnitRemoval::E*fout[ohel].wave().vectorCurrent(atemp);
fdotp=fcurrent.dot(gin[0].momentum());
for(unsigned int ghel=0;ghel<2;++ghel) {
// calculate the matrix element
diag=A5c*(fcurrent.dot(gin[ghel].wave())-fdotp*epsdot[ghel]/denom);
// calculate the matrix element
output+=real(diag*conj(diag));
if(calc) newme(ihel,2*ghel,0,ohel)=diag;
}
}
}
// final colour/spin factors
if(calc) _me.reset(newme);
return output/24.;
}
Selector<MEBase::DiagramIndex>
MEPP2HiggsJet::diagrams(const DiagramVector & diags) const {
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i )
{
if(abs(diags[i]->id())<4) sel.insert(1.0, i);
else sel.insert(_diagwgt[abs(diags[i]->id())-4], i);
}
return sel;
}
Selector<const ColourLines *>
MEPP2HiggsJet::colourGeometries(tcDiagPtr diag) const {
// colour lines for q qbar -> h0 g
static const ColourLines cqqbar("1 3 5,-2 -3 -5");
// colour lines for q g -> h0 q
static const ColourLines cqg("1 2 -3, 3 -2 5");
// colour lines for qbar q -> h0 qbar
static const ColourLines cqbarg("-1 -2 3, -3 2 -5");
// colour lines for g g -> h0 g
static const ColourLines cgg[6]={ColourLines("1 2 5, -3 -5, 3 -2 -1"),
ColourLines("-1 -2 -5, 3 5, -3 2 1"),
ColourLines("1 5, -1 -2 3, -3 2 -5"),
ColourLines("-1 -5, 1 2 -3, 3 -2 5"),
ColourLines("1 3 5, -5 -3 -2, 2 -1"),
ColourLines("-1 -3 -5, 5 3 2 ,-2 1")};
// select the colour flow
Selector<const ColourLines *> sel;
if ( diag->id() == -1) sel.insert(1.0, &cqqbar);
else if ( diag->id() == -2) sel.insert(1.0, &cqg);
else if ( diag->id() == -3) sel.insert(1.0, &cqbarg);
else
{
sel.insert(0.5, &cgg[2*(abs(diag->id())-4) ]);
sel.insert(0.5, &cgg[2*(abs(diag->id())-4)+1]);
}
// return the answer
return sel;
}
double MEPP2HiggsJet::ggME(vector<VectorWaveFunction> g1, vector<VectorWaveFunction> g2,
ScalarWaveFunction & hout, vector<VectorWaveFunction> g4,
bool calc) const {
// the particles should be in the order
// for the incoming
// 0 first incoming gluon
// 1 second incoming gluon
// for the outgoing
// 0 outgoing higgs
// 1 outgoing gluon
// me to be returned
ProductionMatrixElement newme(PDT::Spin1,PDT::Spin1,
PDT::Spin0,PDT::Spin1);
// get the kinematic invariants
Energy2 s(sHat()),u(uHat()),t(tHat()),mh2(hout.m2()),et(scale());
// calculate the loop functions
Complex A4stu(0.),A2stu(0.),A2tsu(0.),A2ust(0.);
Complex A5s(0.),A5t(0.),A5u(0.);
for(int ix=_minloop;ix<=_maxloop;++ix) {
Energy2 mf2=sqr(getParticleData(ix)->mass());
// loop functions
if(_massopt==0) {
A4stu+=A4(s,t,u,mf2);
A2stu+=A2(s,t,u,mf2);
A2tsu+=A2(u,s,t,mf2);
A2ust+=A2(t,s,u,mf2);
A5s+= mf2/s*(4.+4.*double(s/(u+t))*(W1(s,mf2)-W1(mh2,mf2))
+(1.-4.*double(mf2/(u+t)))*(W2(s,mf2)-W2(mh2,mf2)));
A5t+= mf2/t*(4.+4.*double(t/(s+u))*(W1(t,mf2)-W1(mh2,mf2))
+(1.-4.*double(mf2/(s+u)))*(W2(t,mf2)-W2(mh2,mf2)));
A5u+= mf2/u*(4.+4.*double(u/(s+t))*(W1(u,mf2)-W1(mh2,mf2))
+(1.-4.*double(mf2/(s+t)))*(W2(u,mf2)-W2(mh2,mf2)));
}
else {
A4stu=-1./3.;
A2stu=-sqr(s/mh2)/3.;
A2tsu=-sqr(t/mh2)/3.;
A2ust=-sqr(u/mh2)/3.;
A5s+=2.*(s-mh2)/3./s;
A5t+=2.*(t-mh2)/3./t;
A5u+=2.*(u-mh2)/3./u;
}
}
Complex A3stu=0.5*(A2stu+A2ust+A2tsu-A4stu);
// compute the dot products for the matrix element
complex<InvEnergy> eps[3][4][2];
Energy2 pdot[4][4];
pdot[0][0]=ZERO;
pdot[0][1]= g1[0].momentum()*g2[0].momentum();
pdot[0][2]=-1.*g1[0].momentum()*g4[0].momentum();
pdot[0][3]=-1.*g1[0].momentum()*hout.momentum();
pdot[1][0]= pdot[0][1];
pdot[1][1]= ZERO;
pdot[1][2]=-1.*g2[0].momentum()*g4[0].momentum();
pdot[1][3]=-1.*g2[0].momentum()*hout.momentum();
pdot[2][0]= pdot[0][2];
pdot[2][1]= pdot[1][2];
pdot[2][2]= ZERO;
pdot[2][3]= g4[0].momentum()*hout.momentum();
pdot[3][0]=pdot[0][3];
pdot[3][1]=pdot[1][3];
pdot[3][2]=pdot[2][3];
pdot[3][3]=mh2;
for(unsigned int ix=0;ix<2;++ix)
{
eps[0][0][ix]=InvEnergy();
eps[0][1][ix]=g1[ix].wave().dot(g2[0].momentum())/pdot[0][1];
eps[0][2][ix]=-1.*g1[ix].wave().dot(g4[0].momentum())/pdot[0][2];
eps[0][3][ix]=-1.*g1[ix].wave().dot(hout.momentum())/ pdot[0][3];
eps[1][0][ix]=g2[ix].wave().dot(g1[0].momentum())/ pdot[1][0];
eps[1][1][ix]=InvEnergy();
eps[1][2][ix]=-1.*g2[ix].wave().dot(g4[0].momentum())/pdot[1][2];
eps[1][3][ix]=-1.*g2[ix].wave().dot(hout.momentum())/ pdot[1][3];
eps[2][0][ix]=g4[ix].wave().dot(g1[0].momentum())/ pdot[2][0];
eps[2][1][ix]=g4[ix].wave().dot(g2[0].momentum())/ pdot[2][1];
eps[2][2][ix]=InvEnergy();
eps[2][3][ix]=-1.*g4[ix].wave().dot(hout.momentum())/ pdot[2][3];
}
// prefactors
using Constants::pi;
double g(sqrt(4.*pi*SM().alphaEM(mh2)/SM().sin2ThetaW()));
double gs(sqrt(4.*pi*SM().alphaS(et)));
Energy mw(getParticleData(ParticleID::Wplus)->mass());
Energy3 pre=g*sqr(mh2)*gs*sqr(gs)/(32.*sqr(pi)*mw);
// compute the matrix element
double output(0.);
Complex diag[4],wdot[3][3];
_diagwgt[0]=0.;
_diagwgt[1]=0.;
_diagwgt[2]=0.;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
for(unsigned int ohel=0;ohel<2;++ohel) {
wdot[0][1]=g1[ihel1].wave().dot(g2[ihel2].wave());
wdot[0][2]=g1[ihel1].wave().dot(g4[ohel ].wave());
wdot[1][0]=wdot[0][1];
wdot[1][2]=g2[ihel2].wave().dot(g4[ohel ].wave());
wdot[2][0]=wdot[0][2];
wdot[2][1]=wdot[1][2];
// last piece
diag[3]=pre*A3stu*(eps[0][2][ihel1]*eps[1][0][ihel2]*eps[2][1][ohel]-
eps[0][1][ihel1]*eps[1][2][ihel2]*eps[2][0][ohel]+
(eps[2][0][ohel ]-eps[2][1][ohel ])*wdot[0][1]/pdot[0][1]+
(eps[1][2][ihel2]-eps[1][0][ihel2])*wdot[0][2]/pdot[0][2]+
(eps[0][1][ihel1]-eps[0][2][ihel1])*wdot[1][2]/pdot[1][2]);
// first piece
diag[3]+=pre*(
+A2stu*(eps[0][1][ihel1]*eps[1][0][ihel2]-wdot[0][1]/pdot[0][1])*
(eps[2][0][ohel ]-eps[2][1][ohel ])
+A2ust*(eps[0][2][ihel1]*eps[2][0][ohel ]-wdot[0][2]/pdot[0][2])*
(eps[1][2][ihel2]-eps[1][0][ihel2])
+A2tsu*(eps[1][2][ihel2]*eps[2][1][ohel ]-wdot[1][2]/pdot[1][2])*
(eps[0][1][ihel1]-eps[0][2][ihel1])
);
output+=real(diag[3]*conj(diag[3]));
// matrix element if needed
if(calc) newme(2*ihel1,2*ihel2,0,2*ohel)=diag[3];
// different diagrams
diag[0] = A5t*UnitRemoval::InvE*(-eps[0][3][ihel1]*
(-2.*eps[2][1][ohel ]*eps[1][0][ihel2]*pdot[2][1]*pdot[1][0]
-2.*eps[1][2][ihel2]*eps[2][0][ohel ]*pdot[1][2]*pdot[2][0]
+wdot[1][2]*(pdot[0][1]+pdot[0][2]))
-2.*eps[2][1][ohel ]*pdot[2][1]*wdot[0][1]
-2.*eps[1][2][ihel2]*pdot[1][2]*wdot[0][2]
+wdot[1][2]*(eps[0][1][ihel1]*pdot[0][1]+
eps[0][2][ihel1]*pdot[0][2]));
diag[1] = A5u*UnitRemoval::InvE*(-eps[1][3][ihel2]*
(+2.*eps[0][1][ihel1]*eps[2][0][ohel ]*pdot[0][1]*pdot[2][0]
+2.*eps[0][2][ihel1]*eps[2][1][ohel ]*pdot[0][2]*pdot[2][1]
-wdot[0][2]*(pdot[1][0]+pdot[1][2]))
+2.*eps[2][0][ohel ]*pdot[2][0]*wdot[0][1]
+2.*eps[0][2][ihel1]*pdot[0][2]*wdot[2][1]
-wdot[0][2]*(eps[1][0][ihel2]*pdot[1][0]+
eps[1][2][ihel2]*pdot[1][2]));
diag[2] = A5s*UnitRemoval::InvE*(-eps[2][3][ohel ]*
(+2.*eps[0][1][ihel1]*eps[1][2][ihel2]*pdot[0][1]*pdot[1][2]
-2.*eps[1][0][ihel2]*eps[0][2][ihel1]*pdot[1][0]*pdot[1][3]
+wdot[0][1]*(pdot[2][0]-pdot[2][1]))
+2.*eps[0][1][ihel1]*pdot[0][1]*wdot[1][2]
-2.*eps[1][0][ihel2]*pdot[1][0]*wdot[0][2]
+wdot[0][1]*(eps[2][0][ohel]*pdot[2][0]-
eps[2][1][ohel]*pdot[2][1]));
_diagwgt[0]+=real(diag[0]*conj(diag[0]));
_diagwgt[1]+=real(diag[1]*conj(diag[1]));
_diagwgt[2]+=real(diag[2]*conj(diag[2]));
}
}
}
// final colour and spin factors
if(calc){_me.reset(newme);}
return 3.*output/32.;
}
void MEPP2HiggsJet::constructVertex(tSubProPtr sub)
{
// extract the particles in the hard process
ParticleVector hard;
hard.push_back(sub->incoming().first);hard.push_back(sub->incoming().second);
hard.push_back(sub->outgoing()[0]);hard.push_back(sub->outgoing()[1]);
// ensure correct order or particles
if((hard[0]->id()==ParticleID::g&&hard[1]->id()!=ParticleID::g)||
(hard[0]->id()<0&&hard[1]->id()<6)) swap(hard[0],hard[1]);
if(hard[2]->id()!=ParticleID::h0) swap(hard[2],hard[3]);
// different processes
// g g to H g
if(hard[0]->id()==ParticleID::g) {
vector<VectorWaveFunction> g1,g2,g4;
VectorWaveFunction(g1,hard[0],incoming,false,true,true);
VectorWaveFunction(g2,hard[1],incoming,false,true,true);
VectorWaveFunction(g4,hard[3],outgoing,true ,true,true);
ScalarWaveFunction hout(hard[2],outgoing,true);
g1[1]=g1[2];g2[1]=g2[2];g4[1]=g4[2];
ggME(g1,g2,hout,g4,true);
}
// qg -> H q
else if(hard[0]->id()>0&&hard[1]->id()==ParticleID::g) {
vector<VectorWaveFunction> g2;
vector<SpinorWaveFunction> qin;
vector<SpinorBarWaveFunction> qout;
SpinorWaveFunction( qin,hard[0],incoming,false,true);
VectorWaveFunction( g2,hard[1],incoming,false,true,true);
SpinorBarWaveFunction(qout,hard[3],outgoing,true ,true);
ScalarWaveFunction hout(hard[2],outgoing,true);
g2[1]=g2[2];
qgME(qin,g2,hout,qout,true);
}
// qbar g -> H q
else if(hard[0]->id()<0&&hard[1]->id()==ParticleID::g) {
vector<VectorWaveFunction> g2;
vector<SpinorBarWaveFunction> qin;
vector<SpinorWaveFunction> qout;
SpinorBarWaveFunction( qin,hard[0],incoming,false,true);
VectorWaveFunction( g2,hard[1],incoming,false,true,true);
SpinorWaveFunction( qout,hard[3],outgoing,true ,true);
ScalarWaveFunction hout(hard[2],outgoing,true);
g2[1]=g2[2];
qbargME(qin,g2,hout,qout,true);
}
// q qbar to H g
else if(hard[0]->id()==-hard[1]->id()) {
vector<SpinorBarWaveFunction> qbar;
vector<SpinorWaveFunction> q;
vector<VectorWaveFunction> g4;
SpinorWaveFunction( q ,hard[0],incoming,false,true);
SpinorBarWaveFunction(qbar,hard[1],incoming,false,true);
VectorWaveFunction( g4,hard[3],outgoing,true ,true,true);
ScalarWaveFunction hout(hard[2],outgoing,true);
g4[1]=g4[2];
qqbarME(q,qbar,hout,g4,true);
}
else throw Exception() << "Unknown subprocess in MEPP2HiggsJet::constructVertex()"
<< Exception::runerror;
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(_me);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<4;++ix) {
(hard[ix]->spinInfo())->
productionVertex(hardvertex);
}
}
int MEPP2HiggsJet::nDim() const {
return 2;
}
void MEPP2HiggsJet::doinit() {
ME2to2Base::doinit();
tcPDPtr h0=getParticleData(ParticleID::h0);
_mh = h0->mass();
_wh = h0->generateWidth(_mh);
if(h0->massGenerator()) {
_hmass=dynamic_ptr_cast<GenericMassGeneratorPtr>(h0->massGenerator());
}
if(_shapeopt==2&&!_hmass) throw InitException()
<< "If using the mass generator for the line shape in MEPP2HiggsJet::doinit()"
<< "the mass generator must be an instance of the GenericMassGenerator class"
<< Exception::runerror;
}
CrossSection MEPP2HiggsJet::dSigHatDR() const {
using Constants::pi;
InvEnergy2 bwfact;
Energy moff = mePartonData()[2]->id()==ParticleID::h0 ?
meMomenta()[2].mass() : meMomenta()[3].mass();
if(_shapeopt==1) {
tcPDPtr h0 = mePartonData()[2]->id()==ParticleID::h0 ?
mePartonData()[2] : mePartonData()[3];
bwfact = h0->generateWidth(moff)*moff/pi/
(sqr(sqr(moff)-sqr(_mh))+sqr(_mh*_wh));
}
else {
bwfact = _hmass->BreitWignerWeight(moff);
}
return me2()*jacobian()/(16.0*sqr(Constants::pi)*sHat())*sqr(hbarc)*
(sqr(sqr(moff)-sqr(_mh))+sqr(_mh*_wh))/(_mh*_wh)*bwfact;
}
diff --git a/MatrixElement/Hadron/MEPP2HiggsJet.h b/MatrixElement/Hadron/MEPP2HiggsJet.h
--- a/MatrixElement/Hadron/MEPP2HiggsJet.h
+++ b/MatrixElement/Hadron/MEPP2HiggsJet.h
@@ -1,490 +1,455 @@
// -*- C++ -*-
//
// MEPP2HiggsJet.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_MEPP2HiggsJet_H
#define HERWIG_MEPP2HiggsJet_H
//
// This is the declaration of the MEPP2HiggsJet class.
//
#include "ThePEG/MatrixElement/ME2to2Base.h"
#include "Herwig/Utilities/Maths.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/PDT/GenericMassGenerator.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
namespace Herwig {
using namespace ThePEG;
using namespace ThePEG::Helicity;
/**
* The MEPP2HiggsJet class implements the matrix element for Higgs+jet production.
*
* @see \ref MEPP2HiggsJetInterfaces "The interfaces"
* defined for MEPP2HiggsJet.
*/
class MEPP2HiggsJet: public ME2to2Base {
public:
/**
* The default constructor.
*/
MEPP2HiggsJet() :
_shapeopt(2),_maxflavour(5), _process(0),
_minloop(6),_maxloop(6),_massopt(0) , _mh(ZERO),_wh(ZERO)
{}
/** @name Virtual functions required by the MEBase class. */
//@{
/**
* Return the matrix element for the kinematical configuation
* previously provided by the last call to setKinematics(). Uses
* me().
*/
virtual CrossSection dSigHatDR() const;
/**
* The number of internal degreed of freedom used in the matrix
* element.
*/
virtual int nDim() const;
/**
* 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;
/**
* 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);
/**
* 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;
/** 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:
/**
* Members to return the matrix elements for the different subprocesses
*/
//@{
/**
* Matrix element for \f$q\bar{q}\to Hg\f$.
* @param fin Spinors for incoming quark
* @param ain Spinors for incoming antiquark
* @param hout Wavefunction for the outgoing higgs
* @param gout Polarization vectors for the outgoing gluon
* @param me Whether or not to calculate the matrix element for spin correlations
**/
double qqbarME(vector<SpinorWaveFunction> & fin, vector<SpinorBarWaveFunction> & ain,
ScalarWaveFunction & hout, vector<VectorWaveFunction> & gout,
bool me) const;
/**
* Matrix element for \f$qg\to Hq\f$.
* @param fin Spinors for incoming quark
* @param gin Polarization vectors for the incoming gluon
* @param hout Wavefunction for the outgoing higgs
* @param fout Spinors for outgoing quark
* @param me Whether or not to calculate the matrix element for spin correlations
**/
double qgME(vector<SpinorWaveFunction> & fin,vector<VectorWaveFunction> & gin,
ScalarWaveFunction & hout, vector<SpinorBarWaveFunction> & fout,
bool me) const;
/**
* Matrix element for \f$\bar{q}g\to H\bar{q}\f$.
* @param fin Spinors for incoming antiquark
* @param gin Polarization vectors for the incoming gluon
* @param hout Wavefunction for the outgoing higgs
* @param fout Spinors for outgoing antiquark
* @param me Whether or not to calculate the matrix element for spin correlations
**/
double qbargME(vector<SpinorBarWaveFunction> & fin,vector<VectorWaveFunction> & gin,
ScalarWaveFunction & hout, vector<SpinorWaveFunction> & fout,
bool me) const;
/**
* Matrix element for \f$gg\to Hg\f$.
* @param g1 Polarization vectors for the first incoming gluon
* @param g2 Polarization vectors for the second incoming gluon
* @param hout Wavefunction for the outgoing higgs
* @param g4 Polarization vectors for the outgoing gluon
* @param me Whether or not to calculate the matrix element for spin correlations
**/
double ggME(vector<VectorWaveFunction> g1, vector<VectorWaveFunction> g2,
ScalarWaveFunction & hout, vector<VectorWaveFunction> g4,
bool me) const;
//@}
private:
/**
* Members to calculate the functions for the loop diagrams
*/
//@{
/**
* The \f$W_1(s)\f$ function of NPB297 (1988) 221-243.
* @param s The invariant
* @param mf2 The fermion mass squared
*/
Complex W1(Energy2 s,Energy2 mf2) const {
double root = sqrt(abs(1.-4.*mf2/s));
if(s<ZERO) return 2.*root*asinh(0.5*sqrt(-s/mf2));
else if(s<4.*mf2) return 2.*root*asin(0.5*sqrt( s/mf2));
else return root*(2.*acosh(0.5*sqrt(s/mf2))
-Constants::pi*Complex(0.,1.));
}
/**
* The \f$W_2(s)\f$ function of NPB297 (1988) 221-243.
* @param s The invariant
* @param mf2 The fermion mass squared
*/
Complex W2(Energy2 s,Energy2 mf2) const {
double root=0.5*sqrt(abs(s)/mf2);
if(s<ZERO) return 4.*sqr(asinh(root));
else if(s<4.*mf2) return -4.*sqr(asin(root));
else return 4.*sqr(acosh(root))-sqr(Constants::pi)
-4.*Constants::pi*acosh(root)*Complex(0.,1.);
}
/**
* The \f$W_3(s,t,u,v)\f$ function of NPB297 (1988) 221-243.
* @param s The \f$s\f$ invariant
* @param t The \f$t\f$ invariant
* @param u The \f$u\f$ invariant
* @param v The \f$u\f$ invariant
* @param mf2 The fermion mass squared.
*/
Complex W3(Energy2 s, Energy2 t, Energy2 u, Energy2 v, Energy2 mf2) const {
return I3(s,t,u,v,mf2)-I3(s,t,u,s,mf2)-I3(s,t,u,u,mf2);
}
/**
* The \f$I_3(s,t,u,v)\f$ function of NPB297 (1988) 221-243.
* @param s The \f$s\f$ invariant
* @param t The \f$t\f$ invariant
* @param u The \f$u\f$ invariant
* @param v The \f$v\f$ invariant
* @param mf2 The fermion mass squared
*/
Complex I3(Energy2 s, Energy2 t, Energy2 u, Energy2 v, Energy2 mf2) const {
double ratio=(4.*mf2*t/(u*s)),root(sqrt(1+ratio));
if(v==ZERO) return 0.;
Complex y=0.5*(1.+sqrt(1.-4.*(mf2+_epsi*MeV*MeV)/v));
Complex xp=0.5*(1.+root),xm=0.5*(1.-root);
Complex output =
Math::Li2(xm/(xm-y))-Math::Li2(xp/(xp-y))+
Math::Li2(xm/(y-xp))-Math::Li2(xp/(y-xm))+
log(-xm/xp)*log(1.-_epsi-v/mf2*xp*xm);
return output*2./root;
}
/**
* The \f$b_2(s,t,u)\f$ function of NPB297 (1988) 221-243.
* @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 b2(Energy2 s, Energy2 t, Energy2 u, Energy2 mf2) const {
Energy2 mh2(s+u+t);
complex<Energy2> output=s*(u-s)/(s+u)+2.*u*t*(u+2.*s)/sqr(s+u)*(W1(t,mf2)-W1(mh2,mf2))
+(mf2-0.25*s)*(0.5*(W2(s,mf2)+W2(mh2,mf2))-W2(t,mf2)+W3(s,t,u,mh2,mf2))
+sqr(s)*(2.*mf2/sqr(s+u)-0.5/(s+u))*(W2(t,mf2)-W2(mh2,mf2))
+0.5*u*t/s*(W2(mh2,mf2)-2.*W2(t,mf2))
+0.125*(s-12.*mf2-4.*u*t/s)*W3(t,s,u,mh2,mf2);
return output*mf2/sqr(mh2);
}
/**
* The \f$b_2(s,t,u)\f$ function of NPB297 (1988) 221-243.
* @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 b4(Energy2 s, Energy2 t, Energy2 u, Energy2 mf2) const {
Energy2 mh2(s+t+u);
return mf2/mh2*(-2./3.+(mf2/mh2-0.25)*(W2(t,mf2)-W2(mh2,mf2)+W3(s,t,u,mh2,mf2)));
}
/**
* The \f$A_2(s,t,u)\f$ function of NPB297 (1988) 221-243.
* @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 A2(Energy2 s, Energy2 t, Energy2 u, Energy2 mf2) const {
return b2(s,t,u,mf2)+b2(s,u,t,mf2);
}
/**
* The \f$A_4(s,t,u)\f$ function of NPB297 (1988) 221-243.
* @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 A4(Energy2 s, Energy2 t, Energy2 u, Energy2 mf2) const {
return b4(s,t,u,mf2)+b4(u,s,t,mf2)+b4(t,u,s,mf2);
}
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<MEPP2HiggsJet> initMEPP2HiggsJet;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEPP2HiggsJet & operator=(const MEPP2HiggsJet &);
private:
/**
* Defines the Higgs resonance shape
*/
unsigned int _shapeopt;
/**
* Maximum PDG code of the quarks allowed
*/
unsigned int _maxflavour;
/**
* Option for which processes to include
*/
unsigned int _process;
/**
* Matrix element for spin correlations
*/
ProductionMatrixElement _me;
/**
* Minimum flavour of quarks to include in the loops
*/
int _minloop;
/**
* Maximum flavour of quarks to include in the loops
*/
int _maxloop;
/**
* Option for treatment of the fermion loops
*/
unsigned int _massopt;
/**
* Small complex number to regularize some integrals
*/
static const Complex _epsi;
/**
* On-shell mass for the higgs
*/
Energy _mh;
/**
* On-shell width for the higgs
*/
Energy _wh;
/**
* The mass generator for the Higgs
*/
GenericMassGeneratorPtr _hmass;
/**
* Storage of the loop functions
*/
//@{
/**
* B functions
*/
mutable Complex _bi[5];
/**
* C functions
*/
mutable Complex _ci[8];
/**
* D functions
*/
mutable Complex _di[4];
//@}
/**
* Storage of the diagram weights for the \f$gg\to Hg\f$ subprocess
*/
mutable double _diagwgt[3];
};
}
-#include "ThePEG/Utilities/ClassTraits.h"
-
-namespace ThePEG {
-
-/** @cond TRAITSPECIALIZATIONS */
-
-/** This template specialization informs ThePEG about the
- * base classes of MEPP2HiggsJet. */
-template <>
-struct BaseClassTrait<Herwig::MEPP2HiggsJet,1> {
- /** Typedef of the first base class of MEPP2HiggsJet. */
- typedef ME2to2Base NthBase;
-};
-
-/** This template specialization informs ThePEG about the name of
- * the MEPP2HiggsJet class and the shared object where it is defined. */
-template <>
-struct ClassTraits<Herwig::MEPP2HiggsJet>
- : public ClassTraitsBase<Herwig::MEPP2HiggsJet> {
- /** Return a platform-independent class name */
- static string className() { return "Herwig::MEPP2HiggsJet"; }
- /**
- * The name of a file containing the dynamic library where the class
- * MEPP2HiggsJet is implemented. It may also include several, space-separated,
- * libraries if the class MEPP2HiggsJet 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_MEPP2HiggsJet_H */
diff --git a/MatrixElement/Hadron/MEPP2HiggsVBF.cc b/MatrixElement/Hadron/MEPP2HiggsVBF.cc
--- a/MatrixElement/Hadron/MEPP2HiggsVBF.cc
+++ b/MatrixElement/Hadron/MEPP2HiggsVBF.cc
@@ -1,1453 +1,1456 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2HiggsVBF class.
//
#include "MEPP2HiggsVBF.h"
+#include "ThePEG/Utilities/DescribeClass.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/Core/Base/ShowerProgenitor.h"
#include "Herwig/Shower/Core/Base/Branching.h"
#include "Herwig/Shower/RealEmissionProcess.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.
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEPP2HiggsVBF,MEfftoffH>
+describeHerwigMEPP2HiggsVBF("Herwig::MEPP2HiggsVBF", "HwMEHadron.so");
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);
}
RealEmissionProcessPtr MEPP2HiggsVBF::generateHardest(RealEmissionProcessPtr born,
ShowerInteraction inter) {
if(inter==ShowerInteraction::QED) return RealEmissionProcessPtr();
pair<tPPtr,tPPtr> first,second;
pair<tcBeamPtr,tcBeamPtr> beams;
pair<tPPtr,tPPtr> hadrons;
// get the incoming particles
for(unsigned int ix=0;ix<born->bornIncoming().size();++ix) {
if(!first.first) {
first.first = born->bornIncoming()[ix];
hadrons.first = born->hadrons()[ix];
beams.first = dynamic_ptr_cast<tcBeamPtr>(born->hadrons()[ix]->dataPtr());
}
else {
second.first = born->bornIncoming()[ix];
hadrons.second = born->hadrons()[ix];
beams.second = dynamic_ptr_cast<tcBeamPtr>(born->hadrons()[ix]->dataPtr());
}
}
// and the outgoing
for(unsigned int ix=0;ix<born->bornOutgoing().size();++ix) {
if(born->bornOutgoing()[ix]->id()==ParticleID::h0) {
higgs_ = born->bornOutgoing()[ix];
}
else {
if(abs(born->bornOutgoing()[ix]->id())>5) continue;
if(born->bornOutgoing()[ix]->colourLine()&&
born->bornOutgoing()[ix]->colourLine()==first.first->colourLine()) {
first.second = born->bornOutgoing()[ix];
continue;
}
if(born->bornOutgoing()[ix]->antiColourLine()&&
born->bornOutgoing()[ix]->antiColourLine()==first.first->antiColourLine()) {
first.second = born->bornOutgoing()[ix];
continue;
}
if(born->bornOutgoing()[ix]->colourLine()&&
born->bornOutgoing()[ix]->colourLine()==second.first->colourLine()) {
second.second = born->bornOutgoing()[ix];
continue;
}
if(born->bornOutgoing()[ix]->antiColourLine()&&
born->bornOutgoing()[ix]->antiColourLine()==second.first->antiColourLine()) {
second.second = born->bornOutgoing()[ix];
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);
swap(hadrons.first,hadrons.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->momentum().rho()/hadrons.first->momentum().rho();
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) {
born->pT()[ShowerInteraction::QCD] = pTmin_;
return born;
}
// 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);
swap(hadrons.first,hadrons.second);
}
// the non emitting particles
PPtr spectin =second.first ->dataPtr()->produceParticle(second.first ->momentum());
PPtr spectout=second.second->dataPtr()->produceParticle(second.second->momentum());
spectout->incomingColour(spectin,spectout->id()<0);
PPtr higgs = higgs_->dataPtr()->produceParticle(higgs_->momentum());
rot_[system].invert();
PPtr newout,newin,emitted;
bool FSR = false;
bool isQuark = first.first->colourLine();
// compton hardest
if(isCompton) {
for(unsigned int ix=0;ix<ComptonMomenta_[system].size();++ix) {
ComptonMomenta_[system][ix].transform(rot_[system]);
}
newout = partons_[system][1]->produceParticle(ComptonMomenta_[system][1]);
emitted = gluon_ ->produceParticle(ComptonMomenta_[system][2]);
newin = partons_[system][0]->produceParticle(ComptonMomenta_[system][0]);
FSR = !ComptonISFS_[system];
emitted->incomingColour(newin,!isQuark);
emitted->colourConnect(newout,!isQuark);
}
// BGF hardest
else {
for(unsigned int ix=0;ix<BGFMomenta_[system].size();++ix) {
BGFMomenta_[system][ix].transform(rot_[system]);
}
FSR = false;
newin = gluon_ ->produceParticle(BGFMomenta_[system][0]);
emitted = partons_[system][0]->CC()->produceParticle(BGFMomenta_[system][2]);
newout = partons_[system][1] ->produceParticle(BGFMomenta_[system][1]);
emitted->incomingColour(newin, isQuark);
newout ->incomingColour(newin,!isQuark);
}
pair<double,double> x;
pair<unsigned int,unsigned int> radiators;
if(born->bornIncoming()[0]!=first.first) {
born->incoming().push_back(spectin);
born->incoming().push_back(newin);
x.first = born->bornIncoming()[0]->momentum().rho()/born->hadrons()[0]->momentum().rho();
x.second = newin ->momentum().rho()/born->hadrons()[1]->momentum().rho();
radiators.first = 1;
}
else {
born->incoming().push_back(newin);
born->incoming().push_back(spectin);
x.first = newin ->momentum().rho()/born->hadrons()[0]->momentum().rho();
x.second = born->bornIncoming()[1]->momentum().rho()/born->hadrons()[1]->momentum().rho();
radiators.first = 0;
}
born->x(x);
for(unsigned int ix=0;ix<born->bornOutgoing().size();++ix) {
if(born->bornOutgoing()[ix]==second.second) {
born->outgoing().push_back(spectout);
}
else if(born->bornOutgoing()[ix]==first.second) {
radiators.second = born->outgoing().size()+2;
born->outgoing().push_back(newout);
}
else
born->outgoing().push_back(higgs);
}
if(FSR) swap(radiators.first,radiators.second);
born->emitter (radiators.first );
born->spectator(radiators.second);
born->emitted(born->outgoing().size()+2);
// radiated particle
born->outgoing().push_back(emitted);
born->pT()[ShowerInteraction::QCD] = isCompton ? pTCompton_[system] : pTBGF_[system];
born->interaction(ShowerInteraction::QCD);
return born;
}
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<-1e-8) {
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<-1e-8) {
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(RealEmissionProcessPtr born,
double & initial,
double & final) {
systems_.clear();
for(unsigned int ix=0;ix<born->bornIncoming().size();++ix) {
if(QuarkMatcher::Check(born->bornIncoming()[ix]->data())) {
systems_.push_back(tChannelPair());
systems_.back().hadron = born->hadrons()[ix];
systems_.back().beam = dynamic_ptr_cast<tcBeamPtr>(systems_.back().hadron->dataPtr());
systems_.back().incoming = born->bornIncoming()[ix];
systems_.back().pdf = systems_.back().beam->pdf();
}
}
vector<PPtr> outgoing;
for(unsigned int ix=0;ix<born->bornOutgoing().size();++ix) {
if(born->bornOutgoing()[ix]->id()==ParticleID::h0)
higgs_ = born->bornOutgoing()[ix];
else if(QuarkMatcher::Check(born->bornOutgoing()[ix]->data()))
outgoing.push_back(born->bornOutgoing()[ix]);
}
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_;
}
RealEmissionProcessPtr MEPP2HiggsVBF::applyHardMatrixElementCorrection(RealEmissionProcessPtr born) {
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->momentum().rho()/systems_[0].hadron->momentum().rho();
// 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 RealEmissionProcessPtr();
// 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 RealEmissionProcessPtr();
// 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 RealEmissionProcessPtr();
// 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 RealEmissionProcessPtr();
if(p2.e()<gluon_ ->constituentMass()) return RealEmissionProcessPtr();
}
else {
if(p1.e()<systems_[0].outgoing->dataPtr() ->constituentMass()) return RealEmissionProcessPtr();
if(p2.e()<systems_[0].incoming->dataPtr()->CC()->constituentMass()) return RealEmissionProcessPtr();
}
// 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();
bool FSR= false;
PPtr newin,newout,emitted;
if(!BGF) {
newin = systems_[0].incoming->dataPtr()->produceParticle(pin);
emitted = gluon_ ->produceParticle(p2 );
newout = systems_[0].outgoing->dataPtr()->produceParticle(p1 );
emitted->incomingColour(newin,!isQuark);
emitted->colourConnect(newout,!isQuark);
FSR = xp>zp;
}
else {
newin = gluon_ ->produceParticle(pin);
emitted = systems_[0].incoming->dataPtr()->CC()->produceParticle(p2 );
newout = systems_[0].outgoing->dataPtr() ->produceParticle(p1 );
emitted->incomingColour(newin, isQuark);
newout ->incomingColour(newin,!isQuark);
FSR = false;
}
pair<double,double> x;
pair<unsigned int,unsigned int> radiators;
if(born->bornIncoming()[0]!=systems_[0].incoming) {
born->incoming().push_back(born->bornIncoming()[0]);
born->incoming().push_back(newin);
x.first = born->bornIncoming()[0]->momentum().rho()/born->hadrons()[0]->momentum().rho();
x.second = x.first = xB_[0]/xp;
radiators.first = 1;
}
else {
born->incoming().push_back(newin);
born->incoming().push_back(born->bornIncoming()[1]);
x.first = xB_[0]/xp;
x.second = born->bornIncoming()[1]->momentum().rho()/born->hadrons()[1]->momentum().rho();
radiators.first = 0;
}
born->x(x);
for(unsigned int ix=0;ix<born->bornOutgoing().size();++ix) {
if(born->bornOutgoing()[ix]!=systems_[0].outgoing) {
born->outgoing().push_back(born->bornOutgoing()[ix]);
}
else {
radiators.second = born->outgoing().size()+2;
born->outgoing().push_back(newout);
}
}
if(FSR) swap(radiators.first,radiators.second);
born->emitter (radiators.first );
born->spectator(radiators.second);
born->emitted(born->outgoing().size()+2);
// radiated particle
born->outgoing().push_back(emitted);
born->interaction(ShowerInteraction::QCD);
return born;
}
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]->id()!=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,467 @@
// -*- 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/Core/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
*/
PPtr incoming;
/**
* The outgoing particle
*/
PPtr 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(RealEmissionProcessPtr, double &,
double & );
/**
* Apply the hard matrix element correction to a given hard process or decay
*/
virtual RealEmissionProcessPtr applyHardMatrixElementCorrection(RealEmissionProcessPtr);
/**
* Apply the soft matrix element correction
* @param 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 RealEmissionProcessPtr generateHardest(RealEmissionProcessPtr,
ShowerInteraction);
//@}
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
*/
PPtr 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/Hadron/MEPP2QQ.cc b/MatrixElement/Hadron/MEPP2QQ.cc
--- a/MatrixElement/Hadron/MEPP2QQ.cc
+++ b/MatrixElement/Hadron/MEPP2QQ.cc
@@ -1,1048 +1,1051 @@
// -*- C++ -*-
//
// MEPP2QQ.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2QQ class.
//
#include "MEPP2QQ.h"
+#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "Herwig/MatrixElement/HardVertex.h"
#include "ThePEG/Repository/EventGenerator.h"
using namespace Herwig;
MEPP2QQ::MEPP2QQ() : _quarkflavour(6), _process(0),
_bottomopt(1), _topopt(1), _maxflavour(5) {
}
void MEPP2QQ::rebind(const TranslationMap & trans) {
_gggvertex = trans.translate( _gggvertex);
_qqgvertex = trans.translate( _qqgvertex);
_gluon = trans.translate( _gluon);
for(unsigned int ix=0;ix<_quark.size();++ix)
_quark[ix]=trans.translate(_quark[ix]);
for(unsigned int ix=0;ix<_antiquark.size();++ix)
_antiquark[ix]=trans.translate(_quark[ix]);
HwMEBase::rebind(trans);
}
IVector MEPP2QQ::getReferences() {
IVector ret = HwMEBase::getReferences();
ret.push_back(_gggvertex);
ret.push_back(_qqgvertex);
ret.push_back(_gluon);
for(unsigned int ix=0;ix<_quark.size();++ix)
ret.push_back(_quark[ix]);
for(unsigned int ix=0;ix<_antiquark.size();++ix)
ret.push_back(_antiquark[ix]);
return ret;
}
void MEPP2QQ::doinit() {
HwMEBase::doinit();
// handling of masses
if(_quarkflavour==6) {
massOption(vector<unsigned int>(2,_topopt));
}
else {
massOption(vector<unsigned int>(2,_bottomopt));
}
// get the vertex pointers from the SM object
tcHwSMPtr hwsm= dynamic_ptr_cast<tcHwSMPtr>(standardModel());
// do the initialisation
if(hwsm) {
_qqgvertex = hwsm->vertexFFG();
_gggvertex = hwsm->vertexGGG();
}
else throw InitException()
<< "Wrong type of StandardModel object in "
<< "MEPP2QQ::doinit() the Herwig version must be used"
<< Exception::runerror;
// get the particle data objects
_gluon=getParticleData(ParticleID::g);
for(int ix=1;ix<=6;++ix) {
_quark.push_back( getParticleData( ix));
_antiquark.push_back(getParticleData(-ix));
}
}
Energy2 MEPP2QQ::scale() const {
Energy2 mq2 = max(meMomenta()[2].mass2(),meMomenta()[3].mass2());
Energy2 s(0.5*sHat()),u(0.5*(uHat()-mq2)),t(0.5*(tHat()-mq2));
return 4.*s*t*u/(s*s+t*t+u*u);
}
void MEPP2QQ::persistentOutput(PersistentOStream & os) const {
os << _gggvertex << _qqgvertex << _quarkflavour << _bottomopt << _topopt
<< _process << _gluon << _quark << _antiquark << _maxflavour;
}
void MEPP2QQ::persistentInput(PersistentIStream & is, int) {
is >> _gggvertex >> _qqgvertex >> _quarkflavour >> _bottomopt >> _topopt
>> _process >> _gluon >> _quark >> _antiquark >> _maxflavour;
}
unsigned int MEPP2QQ::orderInAlphaS() const {
return 2;
}
unsigned int MEPP2QQ::orderInAlphaEW() const {
return 0;
}
-ClassDescription<MEPP2QQ> MEPP2QQ::initMEPP2QQ;
-// Definition of the static class description member.
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEPP2QQ,HwMEBase>
+describeHerwigMEPP2QQ("Herwig::MEPP2QQ", "HwMEHadron.so");
void MEPP2QQ::Init() {
static ClassDocumentation<MEPP2QQ> documentation
("The MEPP2QQ class implements the matrix element for"
" heavy quark pair production");
static Switch<MEPP2QQ,unsigned int> interfaceQuarkType
("QuarkType",
"The type of quark",
&MEPP2QQ::_quarkflavour, 6, false, false);
static SwitchOption interfaceQuarkTypeCharm
(interfaceQuarkType,
"Charm",
"Produce charm-anticharm",
4);
static SwitchOption interfaceQuarkTypeBottom
(interfaceQuarkType,
"Bottom",
"Produce bottom-antibottom",
5);
static SwitchOption interfaceQuarkTypeTop
(interfaceQuarkType,
"Top",
"Produce top-antitop",
6);
static Switch<MEPP2QQ,unsigned int> interfaceProcess
("Process",
"Which subprocesses to include",
&MEPP2QQ::_process, 0, false, false);
static SwitchOption interfaceProcessAll
(interfaceProcess,
"All",
"Include all subprocesses",
0);
static SwitchOption interfaceProcessPair
(interfaceProcess,
"Pair",
"Only include quark-antiquark pair production subprocesses",
1);
static SwitchOption interfaceProcess1
(interfaceProcess,
"gg2qqbar",
"Include only gg -> q qbar processes",
2);
static SwitchOption interfaceProcessqgqg
(interfaceProcess,
"qg2qg",
"Include only q g -> q g processes",
4);
static SwitchOption interfaceProcessqbargqbarg
(interfaceProcess,
"qbarg2qbarg",
"Include only qbar g -> qbar g processes",
5);
static SwitchOption interfaceProcessqqqq
(interfaceProcess,
"qq2qq",
"Include only q q -> q q processes",
6);
static SwitchOption interfaceProcessqbarqbarqbarqbar
(interfaceProcess,
"qbarqbar2qbarqbar",
"Include only qbar qbar -> qbar qbar processes",
7);
static SwitchOption interfaceProcessqqbarqqbar
(interfaceProcess,
"qqbar2qqbar",
"Include only q qbar -> q qbar processes",
8);
static Switch<MEPP2QQ,unsigned int> interfaceTopMassOption
("TopMassOption",
"Option for the treatment of the top quark mass",
&MEPP2QQ::_topopt, 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 Switch<MEPP2QQ,unsigned int> interfaceBottomMassOption
("CharmBottomMassOption",
"Option for the treatment of bottom and lighter quark masses",
&MEPP2QQ::_bottomopt, 1, false, false);
static SwitchOption interfaceBottomMassOptionOnMassShell
(interfaceBottomMassOption,
"OnMassShell",
"The bottom is produced on its mass shell, this mass used everywhere",
1);
static SwitchOption interfaceBottomMassOptionZeroMass
(interfaceBottomMassOption,
"ZeroMass",
"The bottom is generated on mass shell, but zero mass is used in"
" the matrix element",
0);
static Parameter<MEPP2QQ,unsigned int> interfaceMaximumFlavour
("MaximumFlavour",
"The maximum flavour of the quarks in the process",
&MEPP2QQ::_maxflavour, 5, 1, 5,
false, false, Interface::limited);
}
Selector<MEBase::DiagramIndex>
MEPP2QQ::diagrams(const DiagramVector & diags) const {
// select the diagram, this is easy for us as we have already done it
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i ) {
if(diags[i]->id()==-int(_diagram)) sel.insert(1.0, i);
else sel.insert(0., i);
}
return sel;
}
double MEPP2QQ::gg2qqbarME(vector<VectorWaveFunction> &g1,
vector<VectorWaveFunction> &g2,
vector<SpinorBarWaveFunction> & q,
vector<SpinorWaveFunction> & qbar,
unsigned int iflow) const {
// scale
Energy2 mt(scale());
Energy mass = q[0].mass();
// matrix element to be stored
if(iflow!=0) _me.reset(ProductionMatrixElement(PDT::Spin1,PDT::Spin1,
PDT::Spin1Half,PDT::Spin1Half));
// calculate the matrix element
double output(0.),sumdiag[3]={0.,0.,0.},sumflow[2]={0.,0.};
Complex diag[3],flow[2];
VectorWaveFunction interv;
SpinorWaveFunction inters;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
interv=_gggvertex->evaluate(mt,5,_gluon,g1[ihel1],g2[ihel2]);
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
//first t-channel diagram
inters =_qqgvertex->evaluate(mt,3,qbar[ohel2].particle(),
qbar[ohel2],g2[ihel2],mass);
diag[0]=_qqgvertex->evaluate(mt,inters,q[ohel1],g1[ihel1]);
//second t-channel diagram
inters =_qqgvertex->evaluate(mt,3,qbar[ohel2].particle(),
qbar[ohel2],g1[ihel1],mass);
diag[1]=_qqgvertex->evaluate(mt,inters,q[ohel1],g2[ihel2]);
// s-channel diagram
diag[2]=_qqgvertex->evaluate(mt,qbar[ohel2],q[ohel1],interv);
// colour flows
flow[0]=diag[0]+diag[2];
flow[1]=diag[1]-diag[2];
// sums
for(unsigned int ix=0;ix<3;++ix) sumdiag[ix] += norm(diag[ix]);
for(unsigned int ix=0;ix<2;++ix) sumflow[ix] += norm(flow[ix]);
// total
output +=real(flow[0]*conj(flow[0])+flow[1]*conj(flow[1])
-0.25*flow[0]*conj(flow[1]));
// store the me if needed
if(iflow!=0) _me(2*ihel1,2*ihel2,ohel1,ohel2)=flow[iflow-1];
}
}
}
}
// select a colour flow
_flow=1+UseRandom::rnd2(sumflow[0],sumflow[1]);
// select a diagram ensuring it is one of those in the selected colour flow
sumdiag[_flow%2]=0.;
_diagram=4+UseRandom::rnd3(sumdiag[0],sumdiag[1],sumdiag[2]);
// final part of colour and spin factors
// Energy2 mq2=sqr(getParticleData(6)->mass());
// double tau1=(tHat()-mq2)/sHat(),tau2=(uHat()-mq2)/sHat(),rho=4*mq2/sHat();
// double test=(1./6./tau1/tau2-3./8.)*sqr(4.*pi*SM().alphaS(mt))*
// (sqr(tau1)+sqr(tau2)+rho-0.25*sqr(rho)/tau1/tau2);
// cerr << "testing matrix element "
// << output/48./test << "\n";
return output/48.;
}
double MEPP2QQ::qg2qgME(vector<SpinorWaveFunction> & qin,
vector<VectorWaveFunction> &g2,
vector<SpinorBarWaveFunction> & qout,
vector<VectorWaveFunction> &g4,
unsigned int iflow) const {
// scale
Energy2 mt(scale());
Energy mass = qout[0].mass();
// matrix element to be stored
if(iflow!=0) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1,
PDT::Spin1Half,PDT::Spin1));
// calculate the matrix element
double output(0.),sumdiag[3]={0.,0.,0.},sumflow[2]={0.,0.};
Complex diag[3],flow[2];
VectorWaveFunction interv;
SpinorWaveFunction inters,inters2;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
inters=_qqgvertex->evaluate(mt,3,qin[ihel1].particle()->CC(),
qin[ihel1],g2[ihel2],mass);
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
// s-channel diagram
diag[0]=_qqgvertex->evaluate(mt,inters,qout[ohel1],g4[ohel2]);
// first t-channel
inters2=_qqgvertex->evaluate(mt,3,qin[ihel1].particle()->CC(),
qin[ihel1],g4[ohel2],mass);
diag[1]=_qqgvertex->evaluate(mt,inters2,qout[ohel1],g2[ihel2]);
// second t-channel
interv=_qqgvertex->evaluate(mt,5,_gluon,qin[ihel1],qout[ohel1]);
diag[2]=_gggvertex->evaluate(mt,g2[ihel2],g4[ohel2],interv);
// colour flows
flow[0]=diag[0]-diag[2];
flow[1]=diag[1]+diag[2];
// sums
for(unsigned int ix=0;ix<3;++ix) sumdiag[ix] += norm(diag[ix]);
for(unsigned int ix=0;ix<2;++ix) sumflow[ix] += norm(flow[ix]);
// total
output +=real(flow[0]*conj(flow[0])+flow[1]*conj(flow[1])
-0.25*flow[0]*conj(flow[1]));
// store the me if needed
if(iflow!=0) _me(ihel1,2*ihel2,ohel1,2*ohel2)=flow[iflow-1];
}
}
}
}
// test code vs me from ESW
//Energy2 u(uHat()),t(tHat()),s(sHat());
//double alphas(4.*pi*SM().alphaS(mt));
//cerr << "testing matrix element "
// << 18./output*(-4./9./s/u+1./t/t)*(s*s+u*u)*sqr(alphas) << endl;
//select a colour flow
_flow=1+UseRandom::rnd2(sumflow[0],sumflow[1]);
// select a diagram ensuring it is one of those in the selected colour flow
sumdiag[_flow%2]=0.;
_diagram=10+UseRandom::rnd3(sumdiag[0],sumdiag[1],sumdiag[2]);
// final part of colour and spin factors
return output/18.;
}
double MEPP2QQ::qbarg2qbargME(vector<SpinorBarWaveFunction> & qin,
vector<VectorWaveFunction> &g2,
vector<SpinorWaveFunction> & qout,
vector<VectorWaveFunction> &g4,
unsigned int iflow) const {
// scale
Energy2 mt(scale());
Energy mass = qout[0].mass();
// matrix element to be stored
if(iflow!=0) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1,
PDT::Spin1Half,PDT::Spin1));
// calculate the matrix element
double output(0.),sumdiag[3]={0.,0.,0.},sumflow[2]={0.,0.};
Complex diag[3],flow[2];
VectorWaveFunction interv;
SpinorBarWaveFunction inters,inters2;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
inters=_qqgvertex->evaluate(mt,3,qin[ihel1].particle()->CC(),
qin[ihel1],g2[ihel2],mass);
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
// s-channel diagram
diag[0]=_qqgvertex->evaluate(mt,qout[ohel1],inters,g4[ohel2]);
// first t-channel
inters2=_qqgvertex->evaluate(mt,3,qin[ihel1].particle()->CC(),
qin[ihel1],g4[ohel2],mass);
diag[1]=_qqgvertex->evaluate(mt,qout[ohel1],inters2,g2[ihel2]);
// second t-channel
interv=_qqgvertex->evaluate(mt,5,_gluon,qout[ohel1],qin[ihel1]);
diag[2]=_gggvertex->evaluate(mt,g2[ihel2],g4[ohel2],interv);
// colour flows
flow[0]=diag[0]+diag[2];
flow[1]=diag[1]-diag[2];
// sums
for(unsigned int ix=0;ix<3;++ix) sumdiag[ix] += norm(diag[ix]);
for(unsigned int ix=0;ix<2;++ix) sumflow[ix] += norm(flow[ix]);
// total
output +=real(flow[0]*conj(flow[0])+flow[1]*conj(flow[1])
-0.25*flow[0]*conj(flow[1]));
// store the me if needed
if(iflow!=0) _me(ihel1,2*ihel2,ohel1,2*ohel2)=flow[iflow-1];
}
}
}
}
// test code vs me from ESW
//Energy2 u(uHat()),t(tHat()),s(sHat());
//double alphas(4.*pi*SM().alphaS(mt));
//cerr << "testing matrix element "
// << 18./output*(-4./9./s/u+1./t/t)*(s*s+u*u)*sqr(alphas) << endl;
//select a colour flow
_flow=1+UseRandom::rnd2(sumflow[0],sumflow[1]);
// select a diagram ensuring it is one of those in the selected colour flow
sumdiag[_flow%2]=0.;
_diagram=13+UseRandom::rnd3(sumdiag[0],sumdiag[1],sumdiag[2]);
// final part of colour and spin factors
return output/18.;
}
double MEPP2QQ::qq2qqME(vector<SpinorWaveFunction> & q1,
vector<SpinorWaveFunction> & q2,
vector<SpinorBarWaveFunction> & q3,
vector<SpinorBarWaveFunction> & q4,
unsigned int iflow) const {
// identify special case of identical quarks
bool identical(q1[0].id()==q2[0].id());
// scale
Energy2 mt(scale());
// matrix element to be stored
if(iflow!=0) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half));
// calculate the matrix element
double output(0.),sumdiag[2]={0.,0.};
Complex diag[2];
VectorWaveFunction interv;
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) {
// first diagram
interv = _qqgvertex->evaluate(mt,5,_gluon,q1[ihel1],q3[ohel1]);
diag[0] = _qqgvertex->evaluate(mt,q2[ihel2],q4[ohel2],interv);
// second diagram if identical
if(identical) {
interv = _qqgvertex->evaluate(mt,5,_gluon,q1[ihel1],q4[ohel2]);
diag[1]=_qqgvertex->evaluate(mt,q2[ihel2],q3[ohel1],interv);
}
else diag[1]=0.;
// sum of diagrams
for(unsigned int ix=0;ix<2;++ix) sumdiag[ix] += norm(diag[ix]);
// total
output +=real(diag[0]*conj(diag[0])+diag[1]*conj(diag[1])
+2./3.*diag[0]*conj(diag[1]));
// store the me if needed
if(iflow!=0) _me(ihel1,ihel2,ohel1,ohel2)=diag[iflow-1];
}
}
}
}
// identical particle symmetry factor if needed
if(identical) output*=0.5;
// test code vs me from ESW
//Energy2 u(uHat()),t(tHat()),s(sHat());
//double alphas(4.*pi*SM().alphaS(mt));
//if(identical)
// {cerr << "testing matrix element A "
// << 18./output*0.5*(4./9.*((s*s+u*u)/t/t+(s*s+t*t)/u/u)
// -8./27.*s*s/u/t)*sqr(alphas) << endl;}
//else
// {cerr << "testing matrix element B "
// << 18./output*(4./9.*(s*s+u*u)/t/t)*sqr(alphas) << endl;}
//select a colour flow
_flow=1+UseRandom::rnd2(sumdiag[0],sumdiag[1]);
// select a diagram ensuring it is one of those in the selected colour flow
sumdiag[_flow%2]=0.;
_diagram=16+UseRandom::rnd2(sumdiag[0],sumdiag[1]);
// final part of colour and spin factors
return output/18.;
}
double MEPP2QQ::qbarqbar2qbarqbarME(vector<SpinorBarWaveFunction> & q1,
vector<SpinorBarWaveFunction> & q2,
vector<SpinorWaveFunction> & q3,
vector<SpinorWaveFunction> & q4,
unsigned int iflow) const {
// identify special case of identical quarks
bool identical(q1[0].id()==q2[0].id());
// scale
Energy2 mt(scale());
// matrix element to be stored
if(iflow!=0)
{_me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half));}
// calculate the matrix element
double output(0.),sumdiag[2]={0.,0.};
Complex diag[2];
VectorWaveFunction interv;
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) {
// first diagram
interv = _qqgvertex->evaluate(mt,5,_gluon,q3[ohel1],q1[ihel1]);
diag[0] = _qqgvertex->evaluate(mt,q4[ohel2],q2[ihel2],interv);
// second diagram if identical
if(identical) {
interv = _qqgvertex->evaluate(mt,5,_gluon,q4[ohel2],q1[ihel1]);
diag[1]=_qqgvertex->evaluate(mt,q3[ohel1],q2[ihel2],interv);
}
else diag[1]=0.;
// sum of diagrams
for(unsigned int ix=0;ix<2;++ix) sumdiag[ix] += norm(diag[ix]);
// total
output +=real(diag[0]*conj(diag[0])+diag[1]*conj(diag[1])
+2./3.*diag[0]*conj(diag[1]));
// store the me if needed
if(iflow!=0) _me(ihel1,ihel2,ohel1,ohel2)=diag[iflow-1];
}
}
}
}
// identical particle symmetry factor if needed
if(identical){output*=0.5;}
// test code vs me from ESW
// Energy2 u(uHat()),t(tHat()),s(sHat());
// double alphas(4.*pi*SM().alphaS(mt));
// if(identical)
// {cerr << "testing matrix element A "
// << 18./output*0.5*(4./9.*((s*s+u*u)/t/t+(s*s+t*t)/u/u)
// -8./27.*s*s/u/t)*sqr(alphas) << endl;}
// else
// {cerr << "testing matrix element B "
// << 18./output*(4./9.*(s*s+u*u)/t/t)*sqr(alphas) << endl;}
//select a colour flow
_flow=1+UseRandom::rnd2(sumdiag[0],sumdiag[1]);
// select a diagram ensuring it is one of those in the selected colour flow
sumdiag[_flow%2]=0.;
_diagram=18+UseRandom::rnd2(sumdiag[0],sumdiag[1]);
// final part of colour and spin factors
return output/18.;
}
double MEPP2QQ::qqbar2qqbarME(vector<SpinorWaveFunction> & q1,
vector<SpinorBarWaveFunction> & q2,
vector<SpinorBarWaveFunction> & q3,
vector<SpinorWaveFunction> & q4,
unsigned int iflow) const {
// type of process
bool diagon[2]={q1[0].id()== -q2[0].id(),
q1[0].id()== -q3[0].id()};
// scale
Energy2 mt(scale());
// matrix element to be stored
if(iflow!=0) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half));
// calculate the matrix element
double output(0.),sumdiag[2]={0.,0.};
Complex diag[2];
VectorWaveFunction interv;
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) {
// first diagram
if(diagon[0]) {
interv = _qqgvertex->evaluate(mt,5,_gluon,q1[ihel1],q2[ihel2]);
diag[0] = _qqgvertex->evaluate(mt,q4[ohel2],q3[ohel1],interv);
}
else diag[0]=0.;
// second diagram
if(diagon[1]) {
interv = _qqgvertex->evaluate(mt,5,_gluon,q1[ihel1],q3[ohel1]);
diag[1]=_qqgvertex->evaluate(mt,q4[ohel2],q2[ihel2],interv);
}
else diag[1]=0.;
// sum of diagrams
for(unsigned int ix=0;ix<2;++ix) sumdiag[ix] += norm(diag[ix]);
// total
output +=real(diag[0]*conj(diag[0])+diag[1]*conj(diag[1])
+2./3.*diag[0]*conj(diag[1]));
// store the me if needed
if(iflow!=0) _me(ihel1,ihel2,ohel1,ohel2)=diag[iflow-1];
}
}
}
}
//select a colour flow
_flow=1+UseRandom::rnd2(sumdiag[0],sumdiag[1]);
// select a diagram ensuring it is one of those in the selected colour flow
sumdiag[_flow%2]=0.;
_diagram=20+UseRandom::rnd2(sumdiag[0],sumdiag[1]);
// final part of colour and spin factors
// Energy2 mq2=sqr(getParticleData(6)->mass());
// double tau1=(tHat()-mq2)/sHat(),tau2=(uHat()-mq2)/sHat(),rho=4*mq2/sHat();
// cerr << "testing matrix element "
// << output/18./(4./9.*sqr(4.*pi*SM().alphaS(mt))*(sqr(tau1)+sqr(tau2)+0.5*rho))
// << "\n";
return output/18.;
}
void MEPP2QQ::getDiagrams() const {
// gg -> q qbar subprocesses
if(_process==0||_process==1||_process==2) {
// first t-channel
add(new_ptr((Tree2toNDiagram(3),_gluon,_antiquark[_quarkflavour-1],_gluon,
1,_quark[_quarkflavour-1], 2,_antiquark[_quarkflavour-1],-4)));
// interchange
add(new_ptr((Tree2toNDiagram(3),_gluon,_antiquark[_quarkflavour-1],_gluon,
2,_quark[_quarkflavour-1], 1,_antiquark[_quarkflavour-1],-5)));
// s-channel
add(new_ptr((Tree2toNDiagram(2),_gluon,_gluon, 1, _gluon,
3,_quark[_quarkflavour-1], 3, _antiquark[_quarkflavour-1], -6)));
}
// q g -> q g subprocesses
if(_process==0||_process==4) {
// s-channel
add(new_ptr((Tree2toNDiagram(2),_quark[_quarkflavour-1], _gluon,
1, _quark[_quarkflavour-1],
3, _quark[_quarkflavour-1], 3, _gluon,-10)));
// quark t-channel
add(new_ptr((Tree2toNDiagram(3),_quark[_quarkflavour-1],
_quark[_quarkflavour-1],_gluon,
2,_quark[_quarkflavour-1],1,_gluon,-11)));
// gluon t-channel
add(new_ptr((Tree2toNDiagram(3),_quark[_quarkflavour-1],_gluon,_gluon,
1,_quark[_quarkflavour-1],2,_gluon,-12)));
}
// qbar g -> qbar g subprocesses
if(_process==0||_process==5) {
// s-channel
add(new_ptr((Tree2toNDiagram(2),_antiquark[_quarkflavour-1], _gluon,
1, _antiquark[_quarkflavour-1],
3, _antiquark[_quarkflavour-1], 3, _gluon,-13)));
// quark t-channel
add(new_ptr((Tree2toNDiagram(3),_antiquark[_quarkflavour-1],
_antiquark[_quarkflavour-1],_gluon,
2,_antiquark[_quarkflavour-1],1,_gluon,-14)));
// gluon t-channel
add(new_ptr((Tree2toNDiagram(3),_antiquark[_quarkflavour-1],_gluon,_gluon,
1,_antiquark[_quarkflavour-1],2,_gluon,-15)));
}
// processes involving two quark lines
for(unsigned int iy=0;iy<_maxflavour;++iy) {
// q q -> q q subprocesses
if(_process==0||_process==6) {
// gluon t-channel
add(new_ptr((Tree2toNDiagram(3),_quark[_quarkflavour-1],_gluon,_quark[iy],
1,_quark[_quarkflavour-1],2,_quark[iy],-16)));
// exchange for identical quarks
if(_quarkflavour-1==iy)
add(new_ptr((Tree2toNDiagram(3),_quark[_quarkflavour-1],_gluon,_quark[iy],
2,_quark[_quarkflavour-1],1,_quark[iy],-17)));
}
// qbar qbar -> qbar qbar subprocesses
if(_process==0||_process==7) {
// gluon t-channel
add(new_ptr((Tree2toNDiagram(3),_antiquark[_quarkflavour-1],_gluon,_antiquark[iy],
1,_antiquark[_quarkflavour-1],2,_antiquark[iy],-18)));
// exchange for identical quarks
if(_quarkflavour-1==iy)
add(new_ptr((Tree2toNDiagram(3),_antiquark[_quarkflavour-1],_gluon,_antiquark[iy],
2,_antiquark[_quarkflavour-1],1,_antiquark[iy],-19)));
}
// q qbar -> q qbar
if(_process==0||_process==1||_process==8) {
// gluon s-channel
add(new_ptr((Tree2toNDiagram(2),_quark[iy], _antiquark[iy],
1, _gluon, 3, _quark[_quarkflavour-1],
3, _antiquark[_quarkflavour-1],-20)));
if(_process!=1) {
// gluon t-channel
add(new_ptr((Tree2toNDiagram(3),_quark[iy],_gluon,_antiquark[_quarkflavour-1],
1,_quark[iy],2,_antiquark[_quarkflavour-1],-21)));
// gluon t-channel
add(new_ptr((Tree2toNDiagram(3),_quark[_quarkflavour-1],_gluon,_antiquark[iy],
1,_quark[_quarkflavour-1],2,_antiquark[iy],-21)));
}
}
}
}
Selector<const ColourLines *>
MEPP2QQ::colourGeometries(tcDiagPtr diag) const {
// colour lines for gg to q qbar
static const ColourLines cggqq[4]={ColourLines("1 4, -1 -2 3, -3 -5"),
ColourLines("3 4, -3 -2 1, -1 -5"),
ColourLines("2 -1, 1 3 4, -2 -3 -5"),
ColourLines("1 -2, -1 -3 -5, 2 3 4")};
// colour lines for q g to q g
static const ColourLines cqgqg[4]={ColourLines("1 -2, 2 3 5, 4 -5"),
ColourLines("1 5, 3 4,-3 2 -5 "),
ColourLines("1 2 -3, 3 5, -5 -2 4"),
ColourLines("1 -2 5,3 2 4,-3 -5")};
// colour lines for qbar g -> qbar g
static const ColourLines cqbgqbg[4]={ColourLines("-1 2, -2 -3 -5, -4 5"),
ColourLines("-1 -5, -3 -4, 3 -2 5"),
ColourLines("-1 -2 3, -3 -5, 5 2 -4"),
ColourLines("-1 2 -5,-3 -2 -4, 3 5")};
// colour lines for q q -> q q
static const ColourLines cqqqq[2]={ColourLines("1 2 5,3 -2 4"),
ColourLines("1 2 4,3 -2 5")};
// colour lines for qbar qbar -> qbar qbar
static const ColourLines cqbqbqbqb[2]={ColourLines("-1 -2 -5,-3 2 -4"),
ColourLines("-1 -2 -4,-3 2 -5")};
// colour lines for q qbar -> q qbar
static const ColourLines cqqbqqb[2]={ColourLines("1 3 4,-2 -3 -5"),
ColourLines("1 2 -3,4 -2 -5")};
// select the colour flow (as all ready picked just insert answer)
Selector<const ColourLines *> sel;
switch(abs(diag->id())) {
// gg -> q qbar subprocess
case 4: case 5:
sel.insert(1.0, &cggqq[abs(diag->id())-4]);
break;
case 6:
sel.insert(1.0, &cggqq[1+_flow]);
break;
// q g -> q g subprocess
case 10: case 11:
sel.insert(1.0, &cqgqg[abs(diag->id())-10]);
break;
case 12:
sel.insert(1.0, &cqgqg[1+_flow]);
break;
// q g -> q g subprocess
case 13: case 14:
sel.insert(1.0, &cqbgqbg[abs(diag->id())-13]);
break;
case 15:
sel.insert(1.0, &cqbgqbg[1+_flow]);
break;
// q q -> q q subprocess
case 16: case 17:
sel.insert(1.0, &cqqqq[abs(diag->id())-16]);
break;
// qbar qbar -> qbar qbar subprocess
case 18: case 19:
sel.insert(1.0, &cqbqbqbqb[abs(diag->id())-18]);
break;
// q qbar -> q qbar subprocess
case 20: case 21:
sel.insert(1.0, &cqqbqqb[abs(diag->id())-20]);
break;
}
return sel;
}
double MEPP2QQ::me2() const {
// total matrix element
double me(0.);
// gg initiated processes
if(mePartonData()[0]->id()==ParticleID::g&&mePartonData()[1]->id()==ParticleID::g) {
VectorWaveFunction g1w(rescaledMomenta()[0],mePartonData()[0],incoming);
VectorWaveFunction g2w(rescaledMomenta()[1],mePartonData()[1],incoming);
SpinorBarWaveFunction qw(rescaledMomenta()[2],mePartonData()[2],outgoing);
SpinorWaveFunction qbarw(rescaledMomenta()[3],mePartonData()[3],outgoing);
vector<VectorWaveFunction> g1,g2;
vector<SpinorBarWaveFunction> q;
vector<SpinorWaveFunction> qbar;
for(unsigned int ix=0;ix<2;++ix) {
g1w.reset(2*ix);g1.push_back(g1w);
g2w.reset(2*ix);g2.push_back(g2w);
qw.reset(ix);q.push_back(qw);
qbarw.reset(ix);qbar.push_back(qbarw);
}
// calculate the matrix element
me=gg2qqbarME(g1,g2,q,qbar,0);
}
// quark first processes
else if(mePartonData()[0]->id()>0) {
// q g -> q g
if(mePartonData()[1]->id()==ParticleID::g) {
SpinorWaveFunction qinw(rescaledMomenta()[0],mePartonData()[0],incoming);
VectorWaveFunction g2w(rescaledMomenta()[1],mePartonData()[1],incoming);
SpinorBarWaveFunction qoutw(rescaledMomenta()[2],mePartonData()[2],outgoing);
VectorWaveFunction g4w(rescaledMomenta()[3],mePartonData()[3],outgoing);
vector<VectorWaveFunction> g2,g4;
vector<SpinorWaveFunction> qin;
vector<SpinorBarWaveFunction> qout;
for(unsigned int ix=0;ix<2;++ix) {
qinw.reset(ix);qin.push_back(qinw);
g2w.reset(2*ix);g2.push_back(g2w);
qoutw.reset(ix);qout.push_back(qoutw);
g4w.reset(2*ix);g4.push_back(g4w);
}
// calculate the matrix element
me = qg2qgME(qin,g2,qout,g4,0);
}
// q qbar to q qbar
else if(mePartonData()[1]->id()<0) {
SpinorWaveFunction q1w(rescaledMomenta()[0],mePartonData()[0],incoming);
SpinorBarWaveFunction q2w(rescaledMomenta()[1],mePartonData()[1],incoming);
SpinorBarWaveFunction q3w(rescaledMomenta()[2],mePartonData()[2],outgoing);
SpinorWaveFunction q4w(rescaledMomenta()[3],mePartonData()[3],outgoing);
vector<SpinorWaveFunction> q1,q4;
vector<SpinorBarWaveFunction> q2,q3;
for(unsigned int ix=0;ix<2;++ix) {
q1w.reset(ix);q1.push_back(q1w);
q2w.reset(ix);q2.push_back(q2w);
q3w.reset(ix);q3.push_back(q3w);
q4w.reset(ix);q4.push_back(q4w);
}
// calculate the matrix element
me = qqbar2qqbarME(q1,q2,q3,q4,0);
}
// q q -> q q
else if(mePartonData()[1]->id()>0) {
SpinorWaveFunction q1w(rescaledMomenta()[0],mePartonData()[0],incoming);
SpinorWaveFunction q2w(rescaledMomenta()[1],mePartonData()[1],incoming);
SpinorBarWaveFunction q3w(rescaledMomenta()[2],mePartonData()[2],outgoing);
SpinorBarWaveFunction q4w(rescaledMomenta()[3],mePartonData()[3],outgoing);
vector<SpinorWaveFunction> q1,q2;
vector<SpinorBarWaveFunction> q3,q4;
for(unsigned int ix=0;ix<2;++ix) {
q1w.reset(ix);q1.push_back(q1w);
q2w.reset(ix);q2.push_back(q2w);
q3w.reset(ix);q3.push_back(q3w);
q4w.reset(ix);q4.push_back(q4w);
}
// calculate the matrix element
me = qq2qqME(q1,q2,q3,q4,0);
}
}
// antiquark first processes
else if(mePartonData()[0]->id()<0) {
// qbar g -> qbar g
if(mePartonData()[1]->id()==ParticleID::g) {
SpinorBarWaveFunction qinw(rescaledMomenta()[0],mePartonData()[0],incoming);
VectorWaveFunction g2w(rescaledMomenta()[1],mePartonData()[1],incoming);
SpinorWaveFunction qoutw(rescaledMomenta()[2],mePartonData()[2],outgoing);
VectorWaveFunction g4w(rescaledMomenta()[3],mePartonData()[3],outgoing);
vector<VectorWaveFunction> g2,g4;
vector<SpinorBarWaveFunction> qin;
vector<SpinorWaveFunction> qout;
for(unsigned int ix=0;ix<2;++ix) {
qinw.reset(ix);qin.push_back(qinw);
g2w.reset(2*ix);g2.push_back(g2w);
qoutw.reset(ix);qout.push_back(qoutw);
g4w.reset(2*ix);g4.push_back(g4w);
}
// calculate the matrix element
me = qbarg2qbargME(qin,g2,qout,g4,0);
}
// qbar qbar -> qbar qbar
else if(mePartonData()[1]->id()<0) {
SpinorBarWaveFunction q1w(rescaledMomenta()[0],mePartonData()[0],incoming);
SpinorBarWaveFunction q2w(rescaledMomenta()[1],mePartonData()[1],incoming);
SpinorWaveFunction q3w(rescaledMomenta()[2],mePartonData()[2],outgoing);
SpinorWaveFunction q4w(rescaledMomenta()[3],mePartonData()[3],outgoing);
vector<SpinorBarWaveFunction> q1,q2;
vector<SpinorWaveFunction> q3,q4;
for(unsigned int ix=0;ix<2;++ix) {
q1w.reset(ix);q1.push_back(q1w);
q2w.reset(ix);q2.push_back(q2w);
q3w.reset(ix);q3.push_back(q3w);
q4w.reset(ix);q4.push_back(q4w);
}
// calculate the matrix element
me = qbarqbar2qbarqbarME(q1,q2,q3,q4,0);
}
}
else throw Exception() << "Unknown process in MEPP2QQ::me2()"
<< Exception::abortnow;
// return the answer
return me;
}
void MEPP2QQ::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]);
// identify the process and calculate the matrix element
if(hard[0]->id()==ParticleID::g&&hard[1]->id()==ParticleID::g) {
if(hard[2]->id()<0) swap(hard[2],hard[3]);
vector<VectorWaveFunction> g1,g2;
vector<SpinorBarWaveFunction> q;
vector<SpinorWaveFunction> qbar;
// off-shell wavefunctions for the spin correlations
VectorWaveFunction( g1,hard[0],incoming,false,true,true);
VectorWaveFunction( g2,hard[1],incoming,false,true,true);
SpinorBarWaveFunction(q ,hard[2],outgoing,true ,true);
SpinorWaveFunction( qbar,hard[3],outgoing,true ,true);
g1[1]=g1[2];g2[1]=g2[2];
// on-shell for matrix element
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);
VectorWaveFunction g1w(rescaledMomenta()[0],data[0],incoming);
VectorWaveFunction g2w(rescaledMomenta()[1],data[1],incoming);
SpinorBarWaveFunction qw(rescaledMomenta()[2],data[2],outgoing);
SpinorWaveFunction qbarw(rescaledMomenta()[3],data[3],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
g1w.reset(2*ix); g1 [ix] = g1w ;
g2w.reset(2*ix); g2 [ix] = g2w ;
qw.reset(ix); q [ix] = qw ;
qbarw.reset(ix); qbar[ix] = qbarw;
}
gg2qqbarME(g1,g2,q,qbar,_flow);
}
else if(hard[0]->id()==ParticleID::g||hard[1]->id()==ParticleID::g) {
if(hard[0]->id()==ParticleID::g) swap(hard[0],hard[1]);
if(hard[2]->id()==ParticleID::g) swap(hard[2],hard[3]);
// on-shell for matrix element
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);
vector<VectorWaveFunction> g2,g4;
VectorWaveFunction(g2,hard[1],incoming,false,true,true);
VectorWaveFunction(g4,hard[3],outgoing,true ,true,true);
VectorWaveFunction gin (rescaledMomenta()[1],data[1],incoming);
VectorWaveFunction gout(rescaledMomenta()[3],data[3],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
gin .reset(2*ix); g2 [ix] = gin ;
gout.reset(2*ix); g4 [ix] = gout;
}
// q g -> q g
if(hard[0]->id()>0) {
vector<SpinorWaveFunction> q1;
vector<SpinorBarWaveFunction> q3;
SpinorWaveFunction( q1,hard[0],incoming,false,true);
SpinorBarWaveFunction(q3,hard[2],outgoing,true ,true);
SpinorWaveFunction qin (rescaledMomenta()[0],data[0],incoming);
SpinorBarWaveFunction qout(rescaledMomenta()[2],data[2],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
qin .reset(ix); q1[ix] = qin ;
qout.reset(ix); q3[ix] = qout;
}
qg2qgME(q1,g2,q3,g4,_flow);
}
// qbar g -> qbar g
else {
vector<SpinorBarWaveFunction> q1;
vector<SpinorWaveFunction> q3;
SpinorBarWaveFunction(q1,hard[0],incoming,false,true);
SpinorWaveFunction( q3,hard[2],outgoing,true ,true);
SpinorBarWaveFunction qin (rescaledMomenta()[0],data[0],incoming);
SpinorWaveFunction qout(rescaledMomenta()[2],data[2],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
qin .reset(ix); q1[ix] = qin ;
qout.reset(ix); q3[ix] = qout;
}
qbarg2qbargME(q1,g2,q3,g4,_flow);
}
}
else if(hard[0]->id()>0||hard[1]->id()>0) {
// q q -> q q
if(hard[0]->id()>0&&hard[1]->id()>0) {
if(hard[2]->id()!=hard[0]->id()) swap(hard[2],hard[3]);
vector<SpinorWaveFunction> q1,q2;
vector<SpinorBarWaveFunction> q3,q4;
SpinorWaveFunction( q1,hard[0],incoming,false,true);
SpinorWaveFunction( q2,hard[1],incoming,false,true);
SpinorBarWaveFunction(q3,hard[2],outgoing,true ,true);
SpinorBarWaveFunction(q4,hard[3],outgoing,true ,true);
// on-shell for matrix element
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 q1w(rescaledMomenta()[0],data[0],incoming);
SpinorWaveFunction q2w(rescaledMomenta()[1],data[1],incoming);
SpinorBarWaveFunction q3w(rescaledMomenta()[2],data[2],outgoing);
SpinorBarWaveFunction q4w(rescaledMomenta()[3],data[3],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
q1w.reset(ix);q1[ix] = q1w;
q2w.reset(ix);q2[ix] = q2w;
q3w.reset(ix);q3[ix] = q3w;
q4w.reset(ix);q4[ix] = q4w;
}
qq2qqME(q1,q2,q3,q4,_flow);
}
// q qbar -> q qbar
else {
if(hard[0]->id()<0) swap(hard[0],hard[1]);
if(hard[2]->id()<0) swap(hard[2],hard[3]);
vector<SpinorWaveFunction> q1,q4;
vector<SpinorBarWaveFunction> q2,q3;
// off-shell for spin correlations
SpinorWaveFunction( q1,hard[0],incoming,false,true);
SpinorBarWaveFunction(q2,hard[1],incoming,false,true);
SpinorBarWaveFunction(q3,hard[2],outgoing,true ,true);
SpinorWaveFunction( q4,hard[3],outgoing,true ,true);
// on-shell for matrix element
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 q1w(rescaledMomenta()[0],data[0],incoming);
SpinorBarWaveFunction q2w(rescaledMomenta()[1],data[1],incoming);
SpinorBarWaveFunction q3w(rescaledMomenta()[2],data[2],outgoing);
SpinorWaveFunction q4w(rescaledMomenta()[3],data[3],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
q1w.reset(ix);q1[ix] = q1w;
q2w.reset(ix);q2[ix] = q2w;
q3w.reset(ix);q3[ix] = q3w;
q4w.reset(ix);q4[ix] = q4w;
}
qqbar2qqbarME(q1,q2,q3,q4,_flow);
}
}
else if (hard[0]->id()<0&&hard[1]->id()<0) {
if(hard[2]->id()!=hard[0]->id()) swap(hard[2],hard[3]);
vector<SpinorBarWaveFunction> q1,q2;
vector<SpinorWaveFunction> q3,q4;
SpinorBarWaveFunction(q1,hard[0],incoming,false,true);
SpinorBarWaveFunction(q2,hard[1],incoming,false,true);
SpinorWaveFunction( q3,hard[2],outgoing,true ,true);
SpinorWaveFunction( q4,hard[3],outgoing,true ,true);
// on-shell for matrix element
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);
SpinorBarWaveFunction q1w(rescaledMomenta()[0],data[0],incoming);
SpinorBarWaveFunction q2w(rescaledMomenta()[1],data[1],incoming);
SpinorWaveFunction q3w(rescaledMomenta()[2],data[2],outgoing);
SpinorWaveFunction q4w(rescaledMomenta()[3],data[3],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
q1w.reset(ix);q1[ix] = q1w;
q2w.reset(ix);q2[ix] = q2w;
q3w.reset(ix);q3[ix] = q3w;
q4w.reset(ix);q4[ix] = q4w;
}
qbarqbar2qbarqbarME(q1,q2,q3,q4,_flow);
}
else throw Exception() << "Unknown process in MEPP2QQ::constructVertex()"
<< Exception::runerror;
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(_me);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<4;++ix)
hard[ix]->spinInfo()->productionVertex(hardvertex);
}
diff --git a/MatrixElement/Hadron/MEPP2QQ.h b/MatrixElement/Hadron/MEPP2QQ.h
--- a/MatrixElement/Hadron/MEPP2QQ.h
+++ b/MatrixElement/Hadron/MEPP2QQ.h
@@ -1,392 +1,357 @@
// -*- C++ -*-
//
// MEPP2QQ.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_MEPP2QQ_H
#define HERWIG_MEPP2QQ_H
//
// This is the declaration of the MEPP2QQ class.
//
#include "Herwig/MatrixElement/HwMEBase.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVVVertex.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
namespace Herwig {
using namespace ThePEG;
using namespace ThePEG::Helicity;
/**
* The MEPP2QQ class implements the production of a heavy quark-antiquark
* pair via QCD.
*
* @see \ref MEPP2QQInterfaces "The interfaces"
* defined for MEPP2QQ.
*/
class MEPP2QQ: public HwMEBase {
public:
/**
* The default constructor.
*/
MEPP2QQ();
/** @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:
/**
* Members to calculate the matrix elements
*/
//@{
/**
* Matrix element for \f$gg\to q\bar{q}\f$
* @param g1 The wavefunctions for the first incoming gluon
* @param g2 The wavefunctions for the second incoming gluon
* @param q The wavefunction for the outgoing quark
* @param qbar The wavefunction for the outgoing antiquark
* @param flow The colour flow
*/
double gg2qqbarME(vector<VectorWaveFunction> &g1,vector<VectorWaveFunction> &g2,
vector<SpinorBarWaveFunction> & q,vector<SpinorWaveFunction> & qbar,
unsigned int flow) const;
/**
* Matrix element for \f$q\bar{q}\to q\bar{q}\f$
* @param q1 The wavefunction for the incoming quark
* @param q2 The wavefunction for the incoming antiquark
* @param q3 The wavefunction for the outgoing quark
* @param q4 The wavefunction for the outgoing antiquark
* @param flow The colour flow
*/
double qqbar2qqbarME(vector<SpinorWaveFunction> & q1,
vector<SpinorBarWaveFunction> & q2,
vector<SpinorBarWaveFunction> & q3,
vector<SpinorWaveFunction> & q4,
unsigned int flow) const;
/**
* Matrix element for \f$qq\to qq\f$
* @param q1 The wavefunction for the first incoming quark
* @param q2 The wavefunction for the second incoming quark
* @param q3 The wavefunction for the first outgoing quark
* @param q4 The wavefunction for the second outgoing quark
* @param flow The colour flow
*/
double qq2qqME(vector<SpinorWaveFunction> & q1, vector<SpinorWaveFunction> & q2,
vector<SpinorBarWaveFunction> & q3, vector<SpinorBarWaveFunction> & q4,
unsigned int flow) const;
/**
* Matrix element for \f$\bar{q}\bar{q}\to \bar{q}\bar{q}\f$
* @param q1 The wavefunction for the first incoming antiquark
* @param q2 The wavefunction for the second incoming antiquark
* @param q3 The wavefunction for the first outgoing antiquark
* @param q4 The wavefunction for the second outgoing antiquark
* @param flow The colour flow
*/
double qbarqbar2qbarqbarME(vector<SpinorBarWaveFunction> & q1,
vector<SpinorBarWaveFunction> & q2,
vector<SpinorWaveFunction> & q3,
vector<SpinorWaveFunction> & q4,
unsigned int flow) const;
/**
* Matrix element for \f$qg\to qg\f$
* @param qin The wavefunction for the incoming quark
* @param g2 The wavefunction for the incoming gluon
* @param qout The wavefunction for the outgoing quark
* @param g4 The wavefunction for the outgoing gluon
* @param flow The colour flow
*/
double qg2qgME(vector<SpinorWaveFunction> & qin,vector<VectorWaveFunction> &g2,
vector<SpinorBarWaveFunction> & qout,vector<VectorWaveFunction> &g4,
unsigned int flow) const;
/**
* Matrix elements for \f$\bar{q}g\to \bar{q}g\f$.
* @param qin The wavefunction for the incoming antiquark
* @param g2 The wavefunction for the incoming gluon
* @param qout The wavefunction for the outgoing antiquark
* @param g4 The wavefunction for the outgoing gluon
* @param flow The colour flow
*/
double qbarg2qbargME(vector<SpinorBarWaveFunction> & qin,
vector<VectorWaveFunction> &g2,
vector<SpinorWaveFunction> & qout,vector<VectorWaveFunction> &g4,
unsigned int flow) const;
//@}
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();
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<MEPP2QQ> initMEPP2QQ;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEPP2QQ & operator=(const MEPP2QQ &);
private:
/**
* Vertices needed to compute the diagrams
*/
//@{
/**
* \f$ggg\f$ vertex
*/
AbstractVVVVertexPtr _gggvertex;
/**
* \f$q\bar{q}g\f$ vertex
*/
AbstractFFVVertexPtr _qqgvertex;
//@}
/**
* Quark Flavour
*/
unsigned int _quarkflavour;
/**
* Processes to include
*/
unsigned int _process;
/**
* Option for the treatment of bottom and lighter
* quark masses
*/
unsigned int _bottomopt;
/**
* Option for the treatment of top quark masses
*/
unsigned int _topopt;
/**
* Maximum numbere of quark flavours to include
*/
unsigned int _maxflavour;
/**
* Colour flow
*/
mutable unsigned int _flow;
/**
* Diagram
*/
mutable unsigned int _diagram;
/**
* Matrix element
*/
mutable ProductionMatrixElement _me;
/**
* ParticleData objects of the partons
*/
//@{
/**
* The gluon
*/
PDPtr _gluon;
/**
* the quarks
*/
vector<PDPtr> _quark;
/**
* the antiquarks
*/
vector<PDPtr> _antiquark;
//@}
};
}
-#include "ThePEG/Utilities/ClassTraits.h"
-
-namespace ThePEG {
-
-/** @cond TRAITSPECIALIZATIONS */
-
-/** This template specialization informs ThePEG about the
- * base classes of MEPP2QQ. */
-template <>
-struct BaseClassTrait<Herwig::MEPP2QQ,1> {
- /** Typedef of the first base class of MEPP2QQ. */
- typedef Herwig::HwMEBase NthBase;
-};
-
-/** This template specialization informs ThePEG about the name of
- * the MEPP2QQ class and the shared object where it is defined. */
-template <>
-struct ClassTraits<Herwig::MEPP2QQ>
- : public ClassTraitsBase<Herwig::MEPP2QQ> {
- /** Return a platform-independent class name */
- static string className() { return "Herwig::MEPP2QQ"; }
- /**
- * The name of a file containing the dynamic library where the class
- * MEPP2QQ is implemented. It may also include several, space-separated,
- * libraries if the class MEPP2QQ 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_MEPP2QQ_H */
diff --git a/MatrixElement/Hadron/MEPP2QQHiggs.cc b/MatrixElement/Hadron/MEPP2QQHiggs.cc
--- a/MatrixElement/Hadron/MEPP2QQHiggs.cc
+++ b/MatrixElement/Hadron/MEPP2QQHiggs.cc
@@ -1,633 +1,636 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2QQH class.
//
#include "MEPP2QQHiggs.h"
+#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/Utilities/SimplePhaseSpace.h"
#include "Herwig/Utilities/Kinematics.h"
#include "ThePEG/Cuts/Cuts.h"
#include "Herwig/MatrixElement/HardVertex.h"
using namespace Herwig;
MEPP2QQHiggs::MEPP2QQHiggs() : quarkFlavour_(6), process_(0), shapeOpt_(2),
mh_(), wh_(), alpha_(1.1)
{}
-ClassDescription<MEPP2QQHiggs> MEPP2QQHiggs::initMEPP2QQHiggs;
-// Definition of the static class description member.
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEPP2QQHiggs,HwMEBase>
+describeHerwigMEPP2QQHiggs("Herwig::MEPP2QQHiggs", "HwMEHadron.so");
void MEPP2QQHiggs::Init() {
static ClassDocumentation<MEPP2QQHiggs> documentation
("The MEPP2QQHiggs class implements the matrix elements for the "
"production of the Higgs boson in association with a heavy quark-antiquark pair");
static Switch<MEPP2QQHiggs,unsigned int> interfaceQuarkType
("QuarkType",
"The type of quark",
&MEPP2QQHiggs::quarkFlavour_, 6, false, false);
static SwitchOption interfaceQuarkTypeBottom
(interfaceQuarkType,
"Bottom",
"Produce bottom-antibottom",
5);
static SwitchOption interfaceQuarkTypeTop
(interfaceQuarkType,
"Top",
"Produce top-antitop",
6);
static Switch<MEPP2QQHiggs,unsigned int> interfaceProcess
("Process",
"Which subprocesses to include",
&MEPP2QQHiggs::process_, 0, false, false);
static SwitchOption interfaceProcessAll
(interfaceProcess,
"All",
"Include all subprocesses",
0);
static SwitchOption interfaceProcess1
(interfaceProcess,
"gg",
"Include only gg -> QQbarH processes",
1);
static SwitchOption interfaceProcessqbarqbarqbarqbar
(interfaceProcess,
"qqbar",
"Include only qbar qbar -> QQbarH processes",
2);
static Switch<MEPP2QQHiggs,unsigned int> interfaceShapeOption
("ShapeScheme",
"Option for the treatment of the Higgs resonance shape",
&MEPP2QQHiggs::shapeOpt_, 2, false, false);
static SwitchOption interfaceStandardShapeFixed
(interfaceShapeOption,
"FixedBreitWigner",
"Breit-Wigner s-channel resonance",
1);
static SwitchOption interfaceStandardShapeRunning
(interfaceShapeOption,
"MassGenerator",
"Use the mass generator to give the shape",
2);
static SwitchOption interfaceStandardShapeOnShell
(interfaceShapeOption,
"OnShell",
"Produce an on-shell Higgs boson",
0);
static Parameter<MEPP2QQHiggs,double> interfaceAlpha
("Alpha",
"Power for the generation of the tranverse mass in the pT mapping",
&MEPP2QQHiggs::alpha_, 1.1, 0.0, 10.0,
false, false, Interface::limited);
}
Energy2 MEPP2QQHiggs::scale() const {
return sHat();
// return sqr(mePartonData()[2]->mass()+mePartonData()[3]->mass()+
// mePartonData()[4]->mass());
}
int MEPP2QQHiggs::nDim() const {
return 4 + int(shapeOpt_>0);
}
unsigned int MEPP2QQHiggs::orderInAlphaS() const {
return 2;
}
unsigned int MEPP2QQHiggs::orderInAlphaEW() const {
return 1;
}
IBPtr MEPP2QQHiggs::clone() const {
return new_ptr(*this);
}
IBPtr MEPP2QQHiggs::fullclone() const {
return new_ptr(*this);
}
void MEPP2QQHiggs::setKinematics() {
HwMEBase::setKinematics();
}
void MEPP2QQHiggs::persistentOutput(PersistentOStream & os) const {
os << quarkFlavour_ << process_ << shapeOpt_
<< ounit(mh_,GeV) << ounit(wh_,GeV) << hmass_
<< GGGVertex_ << QQGVertex_ << QQHVertex_
<< gluon_ << higgs_ << quark_ << antiquark_
<< alpha_;
}
void MEPP2QQHiggs::persistentInput(PersistentIStream & is, int) {
is >> quarkFlavour_ >> process_ >> shapeOpt_
>> iunit(mh_,GeV) >> iunit(wh_,GeV) >> hmass_
>> GGGVertex_ >> QQGVertex_ >> QQHVertex_
>> gluon_ >> higgs_ >> quark_ >> antiquark_
>> alpha_;
}
void MEPP2QQHiggs::doinit() {
HwMEBase::doinit();
// stuff for the higgs mass
higgs_=getParticleData(ParticleID::h0);
mh_ = higgs_->mass();
wh_ = higgs_->width();
if(higgs_->massGenerator()) {
hmass_=dynamic_ptr_cast<GenericMassGeneratorPtr>(higgs_->massGenerator());
}
if(shapeOpt_==2&&!hmass_)
throw InitException()
<< "If using the mass generator for the line shape in MEPP2QQHiggs::doinit()"
<< "the mass generator must be an instance of the GenericMassGenerator class"
<< Exception::runerror;
// get the vertex pointers from the SM object
tcHwSMPtr hwsm= dynamic_ptr_cast<tcHwSMPtr>(standardModel());
// do the initialisation
if(!hwsm) throw InitException() << "Wrong type of StandardModel object in "
<< "MEPP2QQHiggs::doinit() the Herwig"
<< " version must be used"
<< Exception::runerror;
GGGVertex_ = hwsm->vertexGGG();
QQGVertex_ = hwsm->vertexFFG();
QQHVertex_ = hwsm->vertexFFH();
// get the particle data objects
gluon_=getParticleData(ParticleID::g);
for(int ix=1;ix<=6;++ix) {
quark_.push_back( getParticleData( ix));
antiquark_.push_back(getParticleData(-ix));
}
}
bool MEPP2QQHiggs::generateKinematics(const double * r) {
jacobian(1.);
// CMS energy
Energy rs = sqrt(sHat());
// quark mass
Energy mq(quark_[quarkFlavour_-1]->mass());
// generate the higgs mass
Energy mh(mh_);
if(shapeOpt_!=0) {
Energy mhmax = min(rs-2.*mq,higgs_->massMax());
Energy mhmin = max(ZERO ,higgs_->massMin());
if(mhmax<=mhmin) return false;
double rhomin = atan2((sqr(mhmin)-sqr(mh_)), mh_*wh_);
double rhomax = atan2((sqr(mhmax)-sqr(mh_)), mh_*wh_);
mh = sqrt(mh_*wh_*tan(rhomin+r[4]*(rhomax-rhomin))+sqr(mh_));
jacobian(jacobian()*(rhomax-rhomin));
}
if(rs<mh+2.*mq) return false;
// limits for virtual quark mass
Energy2 mmin(sqr(mq+mh)),mmax(sqr(rs-mq));
double rhomin,rhomax;
if(alpha_==0.) {
rhomin = mmin/sqr(mq);
rhomax = mmax/sqr(mq);
}
else if(alpha_==1.) {
rhomax = log((mmax-sqr(mq))/sqr(mq));
rhomin = log((mmin-sqr(mq))/sqr(mq));
}
else {
rhomin = pow((mmax-sqr(mq))/sqr(mq),1.-alpha_);
rhomax = pow((mmin-sqr(mq))/sqr(mq),1.-alpha_);
jacobian(jacobian()/(alpha_-1.));
}
// branch for mass smoothing
Energy2 m132,m232;
Energy p1,p2;
// first branch
if(r[1]<=0.5) {
double rtemp = 2.*r[1];
double rho = rhomin+rtemp*(rhomax-rhomin);
if(alpha_==0)
m132 = sqr(mq)*rho;
else if(alpha_==1)
m132 = sqr(mq)*(exp(rho)+1.);
else
m132 = sqr(mq)*(pow(rho,1./(1.-alpha_))+1.);
Energy m13 = sqrt(m132);
try {
p1 = SimplePhaseSpace::getMagnitude(sHat(), m13, mq);
p2 = SimplePhaseSpace::getMagnitude(m132,mq,mh);
} catch ( ImpossibleKinematics ) {
return false;
}
Energy ptmin = lastCuts().minKT(mePartonData()[3]);
double ctmin = -1.0, ctmax = 1.0;
if ( ptmin > ZERO ) {
double ctm = 1.0 - sqr(ptmin/p1);
if ( ctm <= 0.0 ) return false;
ctmin = max(ctmin, -sqrt(ctm));
ctmax = min(ctmax, sqrt(ctm));
}
double cos1 = getCosTheta(ctmin,ctmax,r[0]);
double sin1(sqrt(1.-sqr(cos1)));
double phi1 = Constants::twopi*UseRandom::rnd();
Lorentz5Momentum p13(sin1*p1*cos(phi1),sin1*p1*sin(phi1),cos1*p1,
sqrt(sqr(p1)+m132),m13);
meMomenta()[3].setVect(Momentum3(-sin1*p1*cos(phi1),-sin1*p1*sin(phi1),-cos1*p1));
meMomenta()[3].setMass(mq);
meMomenta()[3].rescaleEnergy();
bool test=Kinematics::twoBodyDecay(p13,mq,mh,-1.+2*r[2],r[3]*Constants::twopi,
meMomenta()[2],meMomenta()[4]);
if(!test) return false;
m232 = (meMomenta()[3]+meMomenta()[4]).m2();
double D = 2./(pow(sqr(mq)/(m132-sqr(mq)),alpha_)+
pow(sqr(mq)/(m232-sqr(mq)),alpha_));
jacobian(0.5*jacobian()*rs/m13*sqr(mq)*D*(rhomax-rhomin)/sHat());
}
// second branch
else {
double rtemp = 2.*(r[1]-0.5);
double rho = rhomin+rtemp*(rhomax-rhomin);
if(alpha_==0)
m232 = sqr(mq)*rho;
else if(alpha_==1)
m232 = sqr(mq)*(exp(rho)+1.);
else
m232 = sqr(mq)*(pow(rho,1./(1.-alpha_))+1.);
Energy m23 = sqrt(m232);
try {
p1 = SimplePhaseSpace::getMagnitude(sHat(), m23, mq);
p2 = SimplePhaseSpace::getMagnitude(m232,mq,mh);
} catch ( ImpossibleKinematics ) {
return false;
}
Energy ptmin = lastCuts().minKT(mePartonData()[2]);
double ctmin = -1.0, ctmax = 1.0;
if ( ptmin > ZERO ) {
double ctm = 1.0 - sqr(ptmin/p1);
if ( ctm <= 0.0 ) return false;
ctmin = max(ctmin, -sqrt(ctm));
ctmax = min(ctmax, sqrt(ctm));
}
double cos1 = getCosTheta(ctmin,ctmax,r[0]);
double sin1(sqrt(1.-sqr(cos1)));
double phi1 = Constants::twopi*UseRandom::rnd();
Lorentz5Momentum p23(-sin1*p1*cos(phi1),-sin1*p1*sin(phi1),-cos1*p1,
sqrt(sqr(p1)+m232),m23);
meMomenta()[2].setVect(Momentum3(sin1*p1*cos(phi1),sin1*p1*sin(phi1),cos1*p1));
meMomenta()[2].setMass(mq);
meMomenta()[2].rescaleEnergy();
bool test=Kinematics::twoBodyDecay(p23,mq,mh,-1.+2*r[2],r[3]*Constants::twopi,
meMomenta()[3],meMomenta()[4]);
if(!test) return false;
m132 = (meMomenta()[2]+meMomenta()[4]).m2();
double D = 2./(pow(sqr(mq)/(m132-sqr(mq)),alpha_)+
pow(sqr(mq)/(m232-sqr(mq)),alpha_));
jacobian(0.5*jacobian()*rs/m23*sqr(mq)*D*(rhomax-rhomin)/sHat());
}
// calculate jacobian
jacobian(0.125*jacobian()*p1*p2/sHat());
// check cuts
vector<LorentzMomentum> out;
tcPDVector tout;
for(unsigned int ix=2;ix<5;++ix) {
out .push_back(meMomenta()[ix]);
tout.push_back(mePartonData()[ix]);
}
return lastCuts().passCuts(tout, out, mePartonData()[0], mePartonData()[1]);
}
CrossSection MEPP2QQHiggs::dSigHatDR() const {
using Constants::pi;
// jacobian factor for the higgs
InvEnergy2 bwfact;
Energy moff = meMomenta()[4].mass();
if(shapeOpt_==1) {
bwfact = mePartonData()[4]->generateWidth(moff)*moff/pi/
(sqr(sqr(moff)-sqr(mh_))+sqr(mh_*wh_));
}
else {
bwfact = hmass_->BreitWignerWeight(moff);
}
double jac1 = shapeOpt_==0 ?
1. : double(bwfact*(sqr(sqr(moff)-sqr(mh_))+sqr(mh_*wh_))/(mh_*wh_));
return sqr(hbarc)*me2()*jacobian()*jac1/sHat()/pow(Constants::twopi,3);
}
void MEPP2QQHiggs::getDiagrams() const {
tPDPtr Q = quark_[quarkFlavour_-1];
tPDPtr QB = antiquark_[quarkFlavour_-1];
// gg -> q qbar h0 subprocesses
if(process_==0||process_==1) {
// first t-channel
add(new_ptr((Tree2toNDiagram(3), gluon_, QB, gluon_,
1, Q, 4, Q , 2, QB, 4, higgs_, -1)));
add(new_ptr((Tree2toNDiagram(4), gluon_, QB, QB, gluon_,
1, Q, 3, QB, 2, higgs_, -2)));
add(new_ptr((Tree2toNDiagram(3),gluon_,QB,gluon_,
1, Q, 2, QB, 5, QB, 5, higgs_, -3)));
// interchange
add(new_ptr((Tree2toNDiagram(3),gluon_,Q,gluon_,
2, Q, 4, Q , 1, QB, 4, higgs_, -4)));
add(new_ptr((Tree2toNDiagram(4),gluon_,Q,Q,gluon_,
3, Q, 1, QB, 2, higgs_, -5)));
add(new_ptr((Tree2toNDiagram(3),gluon_,Q,gluon_,
2, Q, 1, QB, 5, QB, 5, higgs_, -6)));
// s-channel
add(new_ptr((Tree2toNDiagram(2),gluon_,gluon_, 1, gluon_,
3, Q, 4, Q, 3, QB, 4, higgs_, -7)));
add(new_ptr((Tree2toNDiagram(2),gluon_,gluon_, 1, gluon_,
3,Q, 3, QB, 5, QB, 5, higgs_, -8)));
}
// q qbar -> q qbar
if(process_==0||process_==2) {
for(unsigned int ix=1;ix<5;++ix) {
// gluon s-channel
add(new_ptr((Tree2toNDiagram(2),quark_[ix-1], antiquark_[ix-1],
1, gluon_, 3, Q, 4, Q , 3, QB, 4, higgs_, -9)));
add(new_ptr((Tree2toNDiagram(2),quark_[ix-1], antiquark_[ix-1],
1, gluon_, 3, Q, 3, QB, 5, QB, 5, higgs_, -10)));
}
}
}
double MEPP2QQHiggs::me2() const {
// total matrix element
double me(0.);
// gg initiated processes
if(mePartonData()[0]->id()==ParticleID::g) {
VectorWaveFunction g1w(meMomenta()[0],mePartonData()[0],incoming);
VectorWaveFunction g2w(meMomenta()[1],mePartonData()[1],incoming);
SpinorBarWaveFunction qw(meMomenta()[2],mePartonData()[2],outgoing);
SpinorWaveFunction qbarw(meMomenta()[3],mePartonData()[3],outgoing);
ScalarWaveFunction higgs(meMomenta()[4],mePartonData()[4],1.,outgoing);
vector<VectorWaveFunction> g1,g2;
vector<SpinorBarWaveFunction> q;
vector<SpinorWaveFunction> qbar;
for(unsigned int ix=0;ix<2;++ix) {
g1w.reset(2*ix);g1.push_back(g1w);
g2w.reset(2*ix);g2.push_back(g2w);
qw.reset(ix);q.push_back(qw);
qbarw.reset(ix);qbar.push_back(qbarw);
}
// calculate the matrix element
me=ggME(g1,g2,q,qbar,higgs,0);
}
// q qbar initiated
else {
SpinorWaveFunction q1w(meMomenta()[0],mePartonData()[0],incoming);
SpinorBarWaveFunction q2w(meMomenta()[1],mePartonData()[1],incoming);
SpinorBarWaveFunction q3w(meMomenta()[2],mePartonData()[2],outgoing);
SpinorWaveFunction q4w(meMomenta()[3],mePartonData()[3],outgoing);
ScalarWaveFunction higgs(meMomenta()[4],mePartonData()[4],1.,outgoing);
vector<SpinorWaveFunction> q1,q4;
vector<SpinorBarWaveFunction> q2,q3;
for(unsigned int ix=0;ix<2;++ix) {
q1w.reset(ix);q1.push_back(q1w);
q2w.reset(ix);q2.push_back(q2w);
q3w.reset(ix);q3.push_back(q3w);
q4w.reset(ix);q4.push_back(q4w);
}
// calculate the matrix element
me = qqME(q1,q2,q3,q4,higgs,0);
}
return me*sHat()*UnitRemoval::InvE2;
}
double MEPP2QQHiggs::ggME(vector<VectorWaveFunction> &g1,
vector<VectorWaveFunction> &g2,
vector<SpinorBarWaveFunction> & q,
vector<SpinorWaveFunction> & qbar,
ScalarWaveFunction & hwave,
unsigned int iflow) const {
// scale
Energy2 mt(scale());
Energy mass = q[0].mass();
// matrix element to be stored
if(iflow!=0) me_.reset(ProductionMatrixElement(PDT::Spin1,PDT::Spin1,
PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin0));
// calculate the matrix element
double output(0.),sumflow[2]={0.,0.};
double sumdiag[8]={0.,0.,0.,0.,0.,0.,0.,0.};
Complex diag[8],flow[2];
VectorWaveFunction interv;
SpinorWaveFunction inters,QBoff;
SpinorBarWaveFunction intersb,Qoff;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
interv = GGGVertex_->evaluate(mt,5,gluon_,g1[ihel1],g2[ihel2]);
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
Qoff = QQHVertex_->evaluate(mt,3,q[ohel1].particle(),
q[ohel1],hwave,mass);
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
QBoff = QQHVertex_->evaluate(mt,3,qbar[ohel2].particle(),
qbar[ohel2],hwave,mass);
// 1st diagram
inters = QQGVertex_->evaluate(mt,1,qbar[ohel2].particle(),
qbar[ohel2],g2[ihel2],mass);
diag[0] = QQGVertex_->evaluate(mt,inters,Qoff,g1[ihel1]);
// 2nd diagram
intersb = QQGVertex_->evaluate(mt,1,q[ohel1].particle(),
q[ohel1],g1[ihel1],mass);
diag[1] = QQHVertex_->evaluate(mt,inters,intersb,hwave);
// 3rd diagram
diag[2] = QQGVertex_->evaluate(mt,QBoff,intersb,g2[ihel2]);
// 4th diagram
inters = QQGVertex_->evaluate(mt,1,qbar[ohel2].particle(),
qbar[ohel2],g1[ihel1],mass);
diag[3] = QQGVertex_->evaluate(mt,inters,Qoff,g2[ihel2]);
// 5th diagram
intersb = QQGVertex_->evaluate(mt,1,q[ohel1].particle(),
q[ohel1],g2[ihel2],mass);
diag[4] = QQHVertex_->evaluate(mt,inters,intersb,hwave);
// 6th diagram
diag[5] = QQGVertex_->evaluate(mt,QBoff,intersb,g1[ihel1]);
// 7th diagram
diag[6] = QQGVertex_->evaluate(mt,qbar[ohel2],Qoff ,interv);
// 8th diagram
diag[7] = QQGVertex_->evaluate(mt,QBoff ,q[ohel1],interv);
// colour flows
flow[0]=diag[0]+diag[1]+diag[2]+(diag[6]+diag[7]);
flow[1]=diag[3]+diag[4]+diag[5]-(diag[6]+diag[7]);
// sums
for(unsigned int ix=0;ix<8;++ix) sumdiag[ix] += norm(diag[ix]);
for(unsigned int ix=0;ix<2;++ix) sumflow[ix] += norm(flow[ix]);
// total
output +=real(flow[0]*conj(flow[0])+flow[1]*conj(flow[1])
-0.25*flow[0]*conj(flow[1]));
// store the me if needed
if(iflow!=0) me_(2*ihel1,2*ihel2,ohel1,ohel2,0)=flow[iflow-1];
}
}
}
}
// select a colour flow
flow_ = 1 + UseRandom::rnd2(sumflow[0],sumflow[1]);
if(flow_==1) sumdiag[0]=sumdiag[1]=sumdiag[2]=0.;
else sumdiag[3]=sumdiag[4]=sumdiag[5]=0.;
// select a diagram from that flow
double prob = UseRandom::rnd();
for(unsigned int ix=0;ix<8;++ix) {
if(prob<=sumdiag[ix]) {
diagram_=1+ix;
break;
}
prob -= sumdiag[ix];
}
// final part of colour and spin factors
return output/48.;
}
double MEPP2QQHiggs::qqME(vector<SpinorWaveFunction> & q1,
vector<SpinorBarWaveFunction> & q2,
vector<SpinorBarWaveFunction> & q3,
vector<SpinorWaveFunction> & q4,
ScalarWaveFunction & hwave,
unsigned int iflow) const {
// scale
Energy2 mt(scale());
Energy mass = q3[0].mass();
// matrix element to be stored
if(iflow!=0) me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin0));
// calculate the matrix element
double output(0.),sumdiag[2]={0.,0.};
Complex diag[2];
VectorWaveFunction interv;
SpinorWaveFunction QBoff;
SpinorBarWaveFunction Qoff;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
interv = QQGVertex_->evaluate(mt,5,gluon_,q1[ihel1],q2[ihel2]);
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
Qoff = QQHVertex_->evaluate(mt,3,q3[ohel1].particle(),
q3[ohel1],hwave,mass);
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
QBoff = QQHVertex_->evaluate(mt,3,q4[ohel2].particle(),
q4[ohel2],hwave,mass);
// 1st diagram
diag[0] = QQGVertex_->evaluate(mt,q4[ohel2],Qoff,interv);
// 2nd diagram
diag[1] = QQGVertex_->evaluate(mt,QBoff,q3[ohel1],interv);
// sum of diagrams
for(unsigned int ix=0;ix<2;++ix) sumdiag[ix] += norm(diag[ix]);
diag[0] += diag[1];
output += norm(diag[0]);
if(iflow!=0) me_(ihel1,ihel2,ohel1,ohel2,0) = diag[0];
}
}
}
}
// only 1 colour flow
flow_=1;
// select a diagram
diagram_ = 9+UseRandom::rnd2(sumdiag[0],sumdiag[1]);
// final part of colour and spin factors
return output/18.;
}
Selector<const ColourLines *>
MEPP2QQHiggs::colourGeometries(tcDiagPtr diag) const {
// colour lines for gg -> Q Qbar H
static const ColourLines cgg[10]=
{ColourLines("1 4 5, -1 -2 3 , -3 -6 "),
ColourLines("1 5 , -1 -2 -3 4, -4 -6 "),
ColourLines("1 4 , -1 -2 3 , -3 -5 -6"),
ColourLines("3 4 5, 1 2 -3 , -1 -6 "),
ColourLines("4 5 , 1 2 3 -4, -1 -6"),
ColourLines("3 4 , 1 2 -3 , -1 -5 -6"),
ColourLines("1 3 4 5, -1 2, -2 -3 -6"),
ColourLines("2 3 4 5, 1 -2, -1 -3 -6"),
ColourLines("1 3 4, -1 2, -2 -3 -5 -6"),
ColourLines("2 3 4, 1 -2, -1 -3 -5 -6")};
// colour lines for q qbar -> Q Qbar H
static const ColourLines cqq[2]=
{ColourLines("1 3 4 5, -2 -3 -6"),
ColourLines("1 3 4 , -2 -3 -5 -6")};
// select the colour flow (as all ready picked just insert answer)
Selector<const ColourLines *> sel;
switch(abs(diag->id())) {
// gg -> q qbar subprocess
case 1: case 2: case 3: case 4: case 5: case 6:
sel.insert(1.0, &cgg[abs(diag->id())-1]);
break;
case 7:
sel.insert(1.0, &cgg[5 + flow_]);
break;
case 8:
sel.insert(1.0, &cgg[7 + flow_]);
break;
// q qbar -> q qbar subprocess
case 9: case 10:
sel.insert(1.0, &cqq[abs(diag->id())-9]);
break;
}
return sel;
}
Selector<MEBase::DiagramIndex>
MEPP2QQHiggs::diagrams(const DiagramVector & diags) const {
// select the diagram, this is easy for us as we have already done it
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i ) {
if(diags[i]->id()==-int(diagram_)) sel.insert(1.0, i);
else sel.insert(0., i);
}
return sel;
}
void MEPP2QQHiggs::constructVertex(tSubProPtr sub) {
// extract the particles in the hard process
ParticleVector hard;
hard.push_back(sub->incoming().first);
hard.push_back(sub->incoming().second);
for(unsigned int ix=0;ix<3;++ix) hard.push_back(sub->outgoing()[ix]);
// identify the process and calculate the matrix element
if(hard[0]->id()<0) swap(hard[0],hard[1]);
if(hard[2]->id()==ParticleID::h0) swap(hard[2],hard[4]);
if(hard[3]->id()==ParticleID::h0) swap(hard[3],hard[4]);
if(hard[2]->id()<0) swap(hard[2],hard[3]);
if(hard[0]->id()==ParticleID::g) {
vector<VectorWaveFunction> g1,g2;
vector<SpinorBarWaveFunction> q;
vector<SpinorWaveFunction> qbar;
// off-shell wavefunctions for the spin correlations
VectorWaveFunction( g1,hard[0],incoming,false,true,true);
VectorWaveFunction( g2,hard[1],incoming,false,true,true);
SpinorBarWaveFunction(q ,hard[2],outgoing,true ,true);
SpinorWaveFunction( qbar,hard[3],outgoing,true ,true);
ScalarWaveFunction hwave( hard[4],outgoing,true);
g1[1]=g1[2];g2[1]=g2[2];
ggME(g1,g2,q,qbar,hwave,flow_);
}
// q qbar -> Q Qbar Higgs
else {
vector<SpinorWaveFunction> q1,q4;
vector<SpinorBarWaveFunction> q2,q3;
// off-shell for spin correlations
SpinorWaveFunction( q1,hard[0],incoming,false,true);
SpinorBarWaveFunction(q2,hard[1],incoming,false,true);
SpinorBarWaveFunction(q3,hard[2],outgoing,true ,true);
SpinorWaveFunction( q4,hard[3],outgoing,true ,true);
ScalarWaveFunction hwave( hard[4],outgoing,true);
qqME(q1,q2,q3,q4,hwave,flow_);
}
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(me_);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<5;++ix)
hard[ix]->spinInfo()->productionVertex(hardvertex);
}
diff --git a/MatrixElement/Hadron/MEPP2QQHiggs.h b/MatrixElement/Hadron/MEPP2QQHiggs.h
--- a/MatrixElement/Hadron/MEPP2QQHiggs.h
+++ b/MatrixElement/Hadron/MEPP2QQHiggs.h
@@ -1,391 +1,356 @@
// -*- C++ -*-
#ifndef HERWIG_MEPP2QQHiggs_H
#define HERWIG_MEPP2QQHiggs_H
//
// This is the declaration of the MEPP2QQHiggs class.
//
#include "Herwig/MatrixElement/HwMEBase.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVVVertex.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/PDT/GenericMassGenerator.h"
namespace Herwig {
using namespace ThePEG;
/**
* The MEPP2QQHiggs class implements the matrix elements for
* \f$gg\to Q \bar Q h^0\f$ and \f$q\bar q\to Q \bar Q h^0\f$.
*
* @see \ref MEPP2QQHiggsInterfaces "The interfaces"
* defined for MEPP2QQHiggs.
*/
class MEPP2QQHiggs: public HwMEBase {
public:
/** @name Standard constructors and destructors. */
//@{
/**
* The default constructor.
*/
MEPP2QQHiggs();
//@}
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;
/**
* 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. If the function is
* overridden in a sub class the new function must call the base
* class one first.
*/
virtual void setKinematics();
/**
* 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;
/**
* Construct the vertex of spin correlations.
*/
virtual void constructVertex(tSubProPtr);
//@}
protected:
/**
* Members to calculate the matrix elements
*/
//@{
/**
* Matrix element for \f$gg\to Q\bar{Q}h^0\f$
* @param g1 The wavefunctions for the first incoming gluon
* @param g2 The wavefunctions for the second incoming gluon
* @param q The wavefunction for the outgoing quark
* @param qbar The wavefunction for the outgoing antiquark
* @param h The wavefunction for the outgoing Higgs boson
* @param flow The colour flow
*/
double ggME(vector<VectorWaveFunction> &g1,vector<VectorWaveFunction> &g2,
vector<SpinorBarWaveFunction> & q,vector<SpinorWaveFunction> & qbar,
ScalarWaveFunction & h,
unsigned int flow) const;
/**
* Matrix element for \f$q\bar{q}\to Q\bar{Q}h^0\f$
* @param q1 The wavefunction for the incoming quark
* @param q2 The wavefunction for the incoming antiquark
* @param q3 The wavefunction for the outgoing quark
* @param q4 The wavefunction for the outgoing antiquark
* @param h The wavefunction for the outgoing Higgs boson
* @param flow The colour flow
*/
double qqME(vector<SpinorWaveFunction> & q1,
vector<SpinorBarWaveFunction> & q2,
vector<SpinorBarWaveFunction> & q3,
vector<SpinorWaveFunction> & q4,
ScalarWaveFunction & h,
unsigned int flow) 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 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 static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<MEPP2QQHiggs> initMEPP2QQHiggs;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEPP2QQHiggs & operator=(const MEPP2QQHiggs &);
private:
/**
* Switches to control the subprocess
*/
//@{
/**
* Quark Flavour
*/
unsigned int quarkFlavour_;
/**
* Processes to include
*/
unsigned int process_;
//@}
/**
* Switches etc for the Higgs mass generation
*/
//@{
/**
* Defines the Higgs resonance shape
*/
unsigned int shapeOpt_;
/**
* On-shell mass for the higgs
*/
Energy mh_;
/**
* On-shell width for the higgs
*/
Energy wh_;
/**
* The mass generator for the Higgs
*/
GenericMassGeneratorPtr hmass_;
//@}
/**
* Vertices needed to compute the diagrams
*/
//@{
/**
* \f$ggg\f$ vertex
*/
AbstractVVVVertexPtr GGGVertex_;
/**
* \f$q\bar{q}g\f$ vertex
*/
AbstractFFVVertexPtr QQGVertex_;
/**
* \f$q\bar q h^0\f$ vertex
*/
AbstractFFSVertexPtr QQHVertex_;
//@}
/**
* ParticleData objects of the particles
*/
//@{
/**
* The gluon
*/
PDPtr gluon_;
/**
* The Higgs boson
*/
PDPtr higgs_;
/**
* the quarks
*/
vector<PDPtr> quark_;
/**
* the antiquarks
*/
vector<PDPtr> antiquark_;
//@}
/**
* Parameters for the phase-space generation
*/
//@{
/**
* Power for the phase-space mapping
*/
double alpha_;
//@}
/**
* Colour flow
*/
mutable unsigned int flow_;
/**
* Diagram
*/
mutable unsigned int diagram_;
/**
* Matrix element
*/
mutable ProductionMatrixElement me_;
};
}
-#include "ThePEG/Utilities/ClassTraits.h"
-
-namespace ThePEG {
-
-/** @cond TRAITSPECIALIZATIONS */
-
-/** This template specialization informs ThePEG about the
- * base classes of MEPP2QQHiggs. */
-template <>
-struct BaseClassTrait<Herwig::MEPP2QQHiggs,1> {
- /** Typedef of the first base class of MEPP2QQHiggs. */
- typedef Herwig::HwMEBase NthBase;
-};
-
-/** This template specialization informs ThePEG about the name of
- * the MEPP2QQHiggs class and the shared object where it is defined. */
-template <>
-struct ClassTraits<Herwig::MEPP2QQHiggs>
- : public ClassTraitsBase<Herwig::MEPP2QQHiggs> {
- /** Return a platform-independent class name */
- static string className() { return "Herwig::MEPP2QQHiggs"; }
- /**
- * The name of a file containing the dynamic library where the class
- * MEPP2QQHiggs is implemented. It may also include several, space-separated,
- * libraries if the class MEPP2QQHiggs 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_MEPP2QQHiggs_H */
diff --git a/MatrixElement/Hadron/MEPP2SingleTop.cc b/MatrixElement/Hadron/MEPP2SingleTop.cc
--- a/MatrixElement/Hadron/MEPP2SingleTop.cc
+++ b/MatrixElement/Hadron/MEPP2SingleTop.cc
@@ -1,656 +1,659 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2SingleTop class.
//
#include "MEPP2SingleTop.h"
+#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "Herwig/MatrixElement/HardVertex.h"
using namespace Herwig;
MEPP2SingleTop::MEPP2SingleTop() : process_(1), maxflavour_(5), topOption_(1),
wOption_(1)
{}
IBPtr MEPP2SingleTop::clone() const {
return new_ptr(*this);
}
IBPtr MEPP2SingleTop::fullclone() const {
return new_ptr(*this);
}
void MEPP2SingleTop::doinit() {
HwMEBase::doinit();
vector<unsigned int> massopt(2,0);
massopt[0] = topOption_;
if(process_==1) {
massopt[1]= 0;
}
else if(process_==2) {
massopt[1]= 1;
}
else if(process_==3) {
massopt[1]= wOption_;
}
massOption(massopt);
// mass option
rescalingOption(2);
// 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"
<< " MEPP2SingleTop::doinit()"
<< Exception::abortnow;
// get pointers to all required Vertex objects
FFWvertex_ = hwsm->vertexFFW();
FFGvertex_ = hwsm->vertexFFG();
}
void MEPP2SingleTop::persistentOutput(PersistentOStream & os) const {
os << process_ << FFWvertex_ << FFGvertex_ << maxflavour_
<< topOption_ << wOption_;
}
void MEPP2SingleTop::persistentInput(PersistentIStream & is, int) {
is >> process_ >> FFWvertex_ >> FFGvertex_ >> maxflavour_
>> topOption_ >> wOption_;
}
-ClassDescription<MEPP2SingleTop> MEPP2SingleTop::initMEPP2SingleTop;
-// Definition of the static class description member.
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEPP2SingleTop,HwMEBase>
+describeHerwigMEPP2SingleTop("Herwig::MEPP2SingleTop", "HwMEHadron.so");
void MEPP2SingleTop::Init() {
static ClassDocumentation<MEPP2SingleTop> documentation
("The MEPP2SingleTop class implements the production of "
"a single top quark.");
static Switch<MEPP2SingleTop,unsigned int> interfaceProcess
("Process",
"The process to generate",
&MEPP2SingleTop::process_, 1, false, false);
static SwitchOption interfaceProcesstChannel
(interfaceProcess,
"tChannel",
"Generate t-channel W exchange processes",
1);
static SwitchOption interfaceProcesssChannel
(interfaceProcess,
"sChannel",
"Generate s-channel W exchange processes",
2);
static SwitchOption interfaceProcesstW
(interfaceProcess,
"tW",
"Generate top production in association with a W boson",
3);
static Parameter<MEPP2SingleTop,int> interfaceMaximumFlavour
("MaximumFlavour",
"The maximum flavour of the non-top quarks",
&MEPP2SingleTop::maxflavour_, 5, 1, 5,
false, false, Interface::limited);
static Switch<MEPP2SingleTop,int> interfaceTopMassOption
("TopMassOption",
"Option for the treatment of the top quark masses",
&MEPP2SingleTop::topOption_, 1, false, false);
static SwitchOption interfaceTopMassOptionOnMassShell
(interfaceTopMassOption,
"OnMassShell",
"The top is produced on its mass shell",
1);
static SwitchOption interfaceTopMassOptionOffShell
(interfaceTopMassOption,
"OffShell",
"The top is generated off-shell using the mass and width generator.",
2);
static Switch<MEPP2SingleTop,int> interfaceWMassOption
("WMassOption",
"Option for the treatment of the top quark masses",
&MEPP2SingleTop::wOption_, 1, false, false);
static SwitchOption interfaceWMassOptionOnMassShell
(interfaceWMassOption,
"OnMassShell",
"The W is produced on its mass shell",
1);
static SwitchOption interfaceWMassOptionOffShell
(interfaceWMassOption,
"OffShell",
"The W is generated off-shell using the mass and width generator.",
2);
}
Energy2 MEPP2SingleTop::scale() const{
if(process_==2)
return sHat();
Energy2 s(0.5*sHat()),u(0.5*(uHat()-meMomenta()[3].mass2())),
t(0.5*(tHat()-meMomenta()[2].mass2()));
return 4.*s*t*u/(s*s+t*t+u*u);
}
unsigned int MEPP2SingleTop::orderInAlphaS() const {
return process_!=3 ? 0 : 1;
}
unsigned int MEPP2SingleTop::orderInAlphaEW() const {
return process_!=3 ? 2 : 1;
}
void MEPP2SingleTop::getDiagrams() const {
tcPDPtr g = getParticleData(ParticleID::g);
tcPDPtr Wp = getParticleData(ParticleID::Wplus );
tcPDPtr Wm = getParticleData(ParticleID::Wminus);
tcPDPtr tp = getParticleData(ParticleID::t);
tcPDPtr tb = tp->CC();
// light particles
typedef std::vector<pair<tcPDPtr,tcPDPtr> > Pairvector;
Pairvector lightPair;
switch(maxflavour_) {
case 5:
lightPair.push_back(make_pair(getParticleData(ParticleID::b),
getParticleData(ParticleID::cbar)));
lightPair.push_back(make_pair(getParticleData(ParticleID::b),
getParticleData(ParticleID::ubar)));
case 4:
lightPair.push_back(make_pair(getParticleData(ParticleID::s),
getParticleData(ParticleID::cbar)));
lightPair.push_back(make_pair(getParticleData(ParticleID::d),
getParticleData(ParticleID::cbar)));
case 3:
lightPair.push_back(make_pair(getParticleData(ParticleID::s),
getParticleData(ParticleID::ubar)));
case 2:
lightPair.push_back(make_pair(getParticleData(ParticleID::d),
getParticleData(ParticleID::ubar)));
default:
;
}
// top partner
vector<tcPDPtr> topPartner;
for(long ix=1;ix<=maxflavour_;ix+=2)
topPartner.push_back(getParticleData(ix));
// t-channel
if(process_==1) {
for (Pairvector::const_iterator light = lightPair.begin();
light != lightPair.end(); ++light) {
// lights
tcPDPtr qNeg1 = light->first;
tcPDPtr qNeg2 = light->second->CC();
tcPDPtr qPos1 = light->first ->CC();
tcPDPtr qPos2 = light->second;
if(SM().CKM(*qNeg2,*qNeg1)<1e-30) continue;
for(unsigned int ix=0;ix<topPartner.size();++ix) {
if(SM().CKM(*tp,*topPartner[ix])<1e-30) continue;
// diagrams
add(new_ptr((Tree2toNDiagram(3), topPartner[ix] ,
Wp, qNeg2, 1, tp, 2, qNeg1, -1)));
add(new_ptr((Tree2toNDiagram(3), topPartner[ix] ,
Wp, qPos1, 1, tp, 2, qPos2, -2)));
add(new_ptr((Tree2toNDiagram(3), topPartner[ix]->CC(),
Wm, qNeg1, 1, tb, 2, qNeg2, -3)));
add(new_ptr((Tree2toNDiagram(3), topPartner[ix]->CC(),
Wm, qPos2, 1, tb, 2, qPos1, -4)));
}
}
}
else if(process_==2) {
Pairvector::const_iterator light = lightPair.begin();
for (; light != lightPair.end(); ++light) {
// lights
tcPDPtr qNeg1 = light->first ;
tcPDPtr qNeg2 = light->second;
tcPDPtr qPos1 = qNeg2->CC();
tcPDPtr qPos2 = qNeg1->CC();
if(SM().CKM(*qPos1,*qNeg1)<1e-30) continue;
for(unsigned int ix=0;ix<topPartner.size();++ix) {
if(SM().CKM(*tp,*topPartner[ix])<1e-30) continue;
// diagrams
add(new_ptr((Tree2toNDiagram(2), qNeg1, qNeg2, 1, Wm,
3, tb, 3, topPartner[ix] , -11)));
add(new_ptr((Tree2toNDiagram(2), qPos1, qPos2, 1, Wp,
3, tp, 3, topPartner[ix]->CC(), -12)));
}
}
}
else if(process_==3) {
for(unsigned int ix=0;ix<topPartner.size();++ix) {
if(SM().CKM(*tp,*topPartner[ix])<1e-30) continue;
add(new_ptr((Tree2toNDiagram(2), topPartner[ix], g,
1, topPartner[ix], 3, tp, 3, Wm, -21)));
add(new_ptr((Tree2toNDiagram(3), topPartner[ix], tp, g,
3, tp, 1, Wm, -22)));
add(new_ptr((Tree2toNDiagram(2), topPartner[ix]->CC(), g,
1, topPartner[ix]->CC(), 3, tb, 3, Wp, -23)));
add(new_ptr((Tree2toNDiagram(3), topPartner[ix]->CC(), tb, g,
3, tb, 1, Wp, -24)));
}
}
else
assert(false);
}
Selector<MEBase::DiagramIndex>
MEPP2SingleTop::diagrams(const DiagramVector & diags) const {
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i ) {
// only one diagram for t- and s-channel processes
if ( abs(diags[i]->id()) <20 )
sel.insert(1.0, i);
else if ( abs(diags[i]->id()) <23 )
sel.insert(meInfo()[abs(diags[i]->id())-21],i);
else
sel.insert(meInfo()[abs(diags[i]->id())-23],i);
}
return sel;
}
Selector<const ColourLines *>
MEPP2SingleTop::colourGeometries(tcDiagPtr diag) const {
// t-channel
static ColourLines ct[4]={ColourLines(" 1 4, 3 5"),
ColourLines(" 1 4, -3 -5"),
ColourLines("-1 -4, 3 5"),
ColourLines("-1 -4, -3 -5")};
// s-channel
static ColourLines cs[2]={ColourLines("1 -2, -4 5"),
ColourLines("1 -2, 4 -5")};
// tW
static ColourLines ctw[4]={ColourLines(" 1 -2, 2 3 4"),
ColourLines(" 1 2 -3, 3 4"),
ColourLines("-1 2, -2 -3 -4"),
ColourLines("-1 -2 3, -3 -4")};
// select the right one
Selector<const ColourLines *> sel;
int id = abs(diag->id());
switch (id) {
case 1: case 2: case 3: case 4:
sel.insert(1.0, &ct[id-1]);
break;
case 11: case 12:
sel.insert(1.0, &cs[id-11]);
break;
case 21: case 22: case 23: case 24:
sel.insert(1.0, &ctw[id-21]);
break;
default:
assert(false);
};
return sel;
}
double MEPP2SingleTop::me2() const {
if(process_==1) {
vector<SpinorWaveFunction> f1,f2;
vector<SpinorBarWaveFunction> a1,a2;
SpinorWaveFunction sf1,sf2;
SpinorBarWaveFunction sa1,sa2;
if(mePartonData()[0]->id()>0) {
sf1 = SpinorWaveFunction (meMomenta()[0],mePartonData()[0],incoming);
sa1 = SpinorBarWaveFunction(meMomenta()[2],mePartonData()[2],outgoing);
}
else {
sa1 = SpinorBarWaveFunction(meMomenta()[0],mePartonData()[0],incoming);
sf1 = SpinorWaveFunction (meMomenta()[2],mePartonData()[2],outgoing);
}
if(mePartonData()[1]->id()>0) {
sf2 = SpinorWaveFunction (meMomenta()[1],mePartonData()[1],incoming);
sa2 = SpinorBarWaveFunction(meMomenta()[3],mePartonData()[3],outgoing);
}
else {
sa2 = SpinorBarWaveFunction(meMomenta()[1],mePartonData()[1],incoming);
sf2 = SpinorWaveFunction (meMomenta()[3],mePartonData()[3],outgoing);
}
for(unsigned int ix=0;ix<2;++ix) {
sf1.reset(ix); f1.push_back(sf1);
sf2.reset(ix); f2.push_back(sf2);
sa1.reset(ix); a1.push_back(sa1);
sa2.reset(ix); a2.push_back(sa2);
}
return tChannelME(f1,a1,f2,a2,false);
}
else if(process_==2) {
vector<SpinorWaveFunction> fin,aout;
vector<SpinorBarWaveFunction> ain,fout;
SpinorWaveFunction q (meMomenta()[0],mePartonData()[0],incoming);
SpinorBarWaveFunction qbar(meMomenta()[1],mePartonData()[1],incoming);
SpinorBarWaveFunction f;
SpinorWaveFunction fbar;
if(mePartonData()[2]->id()==ParticleID::t) {
f = SpinorBarWaveFunction(meMomenta()[2],mePartonData()[2],outgoing);
fbar = SpinorWaveFunction (meMomenta()[3],mePartonData()[3],outgoing);
}
else {
f = SpinorBarWaveFunction(meMomenta()[3],mePartonData()[3],outgoing);
fbar = SpinorWaveFunction (meMomenta()[2],mePartonData()[2],outgoing);
}
for(unsigned int ix=0;ix<2;++ix) {
q.reset(ix) ; fin.push_back(q);
qbar.reset(ix); ain.push_back(qbar);
f.reset(ix) ;fout.push_back(f);
fbar.reset(ix);aout.push_back(fbar);
}
return sChannelME(fin,ain,fout,aout,false);
}
else {
SpinorWaveFunction sf;
SpinorBarWaveFunction sa;
vector<SpinorWaveFunction> f1;
vector<SpinorBarWaveFunction> a1;
vector<VectorWaveFunction> gl,vec;
if(mePartonData()[0]->id()>0) {
sf = SpinorWaveFunction (meMomenta()[0],mePartonData()[0],incoming);
sa = SpinorBarWaveFunction(meMomenta()[2],mePartonData()[2],outgoing);
}
else {
sa = SpinorBarWaveFunction(meMomenta()[0],mePartonData()[0],incoming);
sf = SpinorWaveFunction (meMomenta()[2],mePartonData()[2],outgoing);
}
VectorWaveFunction gluon(meMomenta()[1],mePartonData()[1],incoming);
VectorWaveFunction wbos (meMomenta()[3],mePartonData()[3],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
sf.reset(ix); f1.push_back(sf);
sa.reset(ix); a1.push_back(sa);
gluon.reset(2*ix); gl.push_back(gluon);
wbos.reset(ix); vec.push_back(wbos);
}
wbos.reset(2);
vec.push_back(wbos);
return tWME(f1,gl,a1,vec,false);
}
}
double MEPP2SingleTop::sChannelME(vector<SpinorWaveFunction> & fin ,
vector<SpinorBarWaveFunction> & ain ,
vector<SpinorBarWaveFunction> & fout,
vector<SpinorWaveFunction> & aout,
bool calc) const {
// matrix element to be stored
ProductionMatrixElement newme(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half);
// positive or negative W boson
bool positive = mePartonData()[0]->iCharge() + mePartonData()[1]->iCharge() > 0;
tcPDPtr wBoson = positive ?
getParticleData(ParticleID::Wplus) : getParticleData(ParticleID::Wminus);
// sum over helicities to get the matrix element
double me = 0.;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
VectorWaveFunction inter = FFWvertex_->evaluate(scale(),1,wBoson,fin[ihel1],ain[ihel2]);
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
Complex diag = FFWvertex_->evaluate(scale(),aout[ohel2],fout[ohel1],inter);
// sum over helicities
me += norm(diag);
if(calc) {
if(fout[ohel1].id()==ParticleID::t)
newme(ihel1,ihel2,ohel1,ohel2) = diag;
else
newme(ihel1,ihel2,ohel2,ohel1) = diag;
}
}
}
}
}
// results
// spin and colour factor
double colspin=1./12.;
if(abs(fout[0].id())<=6) colspin*=3.;
if(calc) me_.reset(newme);
return me*colspin;
}
double MEPP2SingleTop::tChannelME(vector<SpinorWaveFunction> & f1,
vector<SpinorBarWaveFunction> & a1,
vector<SpinorWaveFunction> & f2,
vector<SpinorBarWaveFunction> & a2,
bool calc) const {
// matrix element to be stored
ProductionMatrixElement newme(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half);
tcPDPtr wBoson = getParticleData(ParticleID::Wplus);
// sum over helicities to get the matrix element
double me = 0.;
unsigned int ihel[4];
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
VectorWaveFunction inter = FFWvertex_->evaluate(scale(),3,wBoson,
f1[ihel1],a1[ohel1]);
ihel[0] = ihel1;
ihel[2] = ohel1;
if(f1[ihel1].direction()==outgoing) swap(ihel[0],ihel[2]);
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
Complex diag = FFWvertex_->evaluate(scale(),f2[ihel2],a2[ohel2],inter);
// sum over helicities
me += norm(diag);
ihel[1] = ihel2;
ihel[3] = ohel2;
if(f2[ihel2].direction()==outgoing) swap(ihel[1],ihel[3]);
if(calc)
newme(ihel[0],ihel[1],ihel[2],ihel[3]) = diag;
}
}
}
}
// results
// spin and colour factor
double colspin = 1./4.;
if(calc) me_.reset(newme);
// Energy mt = getParticleData(ParticleID::t)->mass();
// Energy mw = getParticleData(ParticleID::Wplus)->mass();
// double test1
// = 0.25*sqr(4.*Constants::pi*SM().alphaEM(scale())/SM().sin2ThetaW())*
// sHat()*(sHat()-sqr(mt))/sqr(tHat()-sqr(mw));
// double test2
// = 0.25*sqr(4.*Constants::pi*SM().alphaEM(scale())/SM().sin2ThetaW())*
// uHat()*(uHat()-sqr(mt))/sqr(tHat()-sqr(mw));
return me*colspin;
}
double MEPP2SingleTop::tWME(vector<SpinorWaveFunction> & fin,
vector<VectorWaveFunction> & gin,
vector<SpinorBarWaveFunction> & fout,
vector<VectorWaveFunction> & Wout,
bool calc) const {
if(calc) me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1,
PDT::Spin1Half,PDT::Spin1));
double me[3]={0.,0.,0.};
Complex diag[2];
Energy2 mt=scale();
for(unsigned int ihel=0;ihel<2;++ihel) {
for(unsigned int ghel=0;ghel<2;++ghel) {
for(unsigned int ohel=0;ohel<2;++ohel) {
for(unsigned int whel=0;whel<3;++whel) {
if(fin[ihel].direction()==incoming) {
// 1st diagram
SpinorWaveFunction inters =
FFGvertex_->evaluate(mt,5,mePartonData()[0],
fin[ihel],gin[ghel]);
diag[0]= FFWvertex_->evaluate(mt,inters,fout[ohel],Wout[whel]);
// 2nd diagram
SpinorBarWaveFunction interb =
FFGvertex_->evaluate(mt,3,mePartonData()[2],
fout[ohel],gin[ghel]);
diag[1]= FFWvertex_->evaluate(mt,fin[ihel],interb,Wout[whel]);
}
else {
// 1st diagram
SpinorBarWaveFunction interb =
FFGvertex_->evaluate(mt,5,mePartonData()[0],
fout[ihel],gin[ghel]);
diag[0]= FFWvertex_->evaluate(mt,fin[ohel],interb,Wout[whel]);
// 2nd diagram
SpinorWaveFunction inters =
FFGvertex_->evaluate(mt,3,mePartonData()[2],
fin[ohel],gin[ghel]);
diag[1]= FFWvertex_->evaluate(mt,inters,fout[ihel],Wout[whel]);
}
// diagram contributions
me[1] += norm(diag[0]);
me[2] += norm(diag[1]);
// total
diag[0] += diag[1];
me[0] += norm(diag[0]);
if(calc)
me_(ihel,ghel,ohel,whel) = 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);
return me[0];
}
void MEPP2SingleTop::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(mePartonData()[0]->id()!=hard[0]->id()) {
swap(hard[0],hard[1]);
}
if(mePartonData()[2]->id()!=hard[2]->id()) {
swap(hard[2],hard[3]);
}
// on-shell for matrix element
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);
if(process_==1) {
vector<SpinorWaveFunction> f1,f2;
vector<SpinorBarWaveFunction> a1,a2;
// off-shell wavefunctions for the spin correlations (and on shell for matrix elements)
SpinorWaveFunction sf1,sf2;
SpinorBarWaveFunction sa1,sa2;
if(hard[0]->id()>0) {
SpinorWaveFunction (f1,hard[0],incoming,false,true);
SpinorBarWaveFunction(a1,hard[2],outgoing,true,true);
sf1 = SpinorWaveFunction (rescaledMomenta()[0],data[0],incoming);
sa1 = SpinorBarWaveFunction(rescaledMomenta()[2],data[2],outgoing);
}
else {
SpinorBarWaveFunction(a1,hard[0],incoming,false,true);
SpinorWaveFunction (f1,hard[2],outgoing,true,true);
sa1 = SpinorBarWaveFunction(rescaledMomenta()[0],data[0],incoming);
sf1 = SpinorWaveFunction (rescaledMomenta()[2],data[2],outgoing);
}
if(hard[1]->id()>0) {
SpinorWaveFunction (f2,hard[1],incoming,false,true);
SpinorBarWaveFunction(a2,hard[3],outgoing,true,true);
sf2 = SpinorWaveFunction (rescaledMomenta()[1],data[1],incoming);
sa2 = SpinorBarWaveFunction(rescaledMomenta()[3],data[3],outgoing);
}
else {
SpinorBarWaveFunction(a2,hard[1],incoming,false,true);
SpinorWaveFunction (f2,hard[3],outgoing,true,true);
sa2 = SpinorBarWaveFunction(rescaledMomenta()[1],data[1],incoming);
sf2 = SpinorWaveFunction (rescaledMomenta()[3],data[3],outgoing);
}
for(unsigned int ix=0;ix<2;++ix) {
sf1.reset(ix); f1[ix] = sf1;
sf2.reset(ix); f2[ix] = sf2;
sa1.reset(ix); a1[ix] = sa1;
sa2.reset(ix); a2[ix] = sa2;
}
tChannelME(f1,a1,f2,a2,true);
}
else if(process_==2) {
vector<SpinorWaveFunction> fin,aout;
vector<SpinorBarWaveFunction> ain,fout;
SpinorWaveFunction (fin,hard[0],incoming,false,true);
SpinorBarWaveFunction(ain,hard[1],incoming,false,true);
SpinorWaveFunction q (rescaledMomenta()[0],data[0],incoming);
SpinorBarWaveFunction qbar(rescaledMomenta()[1],data[1],incoming);
SpinorBarWaveFunction f;
SpinorWaveFunction fbar;
if(hard[2]->id()==ParticleID::t) {
SpinorBarWaveFunction(fout,hard[2],outgoing,true,true);
SpinorWaveFunction (aout,hard[3],outgoing,true,true);
f = SpinorBarWaveFunction(rescaledMomenta()[2],data[2],outgoing);
fbar = SpinorWaveFunction (rescaledMomenta()[3],data[3],outgoing);
}
else {
SpinorBarWaveFunction(fout,hard[3],outgoing,true,true);
SpinorWaveFunction (aout,hard[2],outgoing,true,true);
f = SpinorBarWaveFunction(rescaledMomenta()[3],data[3],outgoing);
fbar = SpinorWaveFunction (rescaledMomenta()[2],data[2],outgoing);
}
for(unsigned int ix=0;ix<2;++ix) {
q.reset(ix) ; fin[ix] = q;
qbar.reset(ix); ain[ix] = qbar;
f.reset(ix) ;fout[ix] = f;
fbar.reset(ix);aout[ix] = fbar;
}
sChannelME(fin,ain,fout,aout,true);
}
else {
SpinorWaveFunction sf;
SpinorBarWaveFunction sa;
vector<SpinorWaveFunction> f1;
vector<SpinorBarWaveFunction> a1;
vector<VectorWaveFunction> gl,vec;
if(hard[0]->id()>0) {
SpinorWaveFunction (f1,hard[0],incoming,false,true);
SpinorBarWaveFunction(a1,hard[2],outgoing,true ,true);
sf = SpinorWaveFunction (rescaledMomenta()[0],data[0],incoming);
sa = SpinorBarWaveFunction(rescaledMomenta()[2],data[2],outgoing);
}
else {
SpinorBarWaveFunction(a1,hard[0],incoming,false,true);
SpinorWaveFunction (f1,hard[2],outgoing,true ,true);
sa = SpinorBarWaveFunction(rescaledMomenta()[0],data[0],incoming);
sf = SpinorWaveFunction (rescaledMomenta()[2],data[2],outgoing);
}
VectorWaveFunction(gl,hard[1],incoming,false,true ,true);
VectorWaveFunction(vec,hard[3],outgoing,true,false,true);
VectorWaveFunction gluon(rescaledMomenta()[1],data[1],incoming);
VectorWaveFunction wbos (rescaledMomenta()[3],data[3],outgoing);
gl[1]=gl[2];
for(unsigned int ix=0;ix<2;++ix) {
sf.reset(ix); f1[ix] = sf;
sa.reset(ix); a1[ix] = sa;
gluon.reset(2*ix); gl[ix] = gluon;
wbos.reset(ix); vec[ix] = wbos;
}
wbos.reset(2);
vec[2] = wbos;
tWME(f1,gl,a1,vec,true);
}
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(me_);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<4;++ix)
hard[ix]->spinInfo()->productionVertex(hardvertex);
}
diff --git a/MatrixElement/Hadron/MEPP2SingleTop.h b/MatrixElement/Hadron/MEPP2SingleTop.h
--- a/MatrixElement/Hadron/MEPP2SingleTop.h
+++ b/MatrixElement/Hadron/MEPP2SingleTop.h
@@ -1,290 +1,255 @@
// -*- C++ -*-
#ifndef HERWIG_MEPP2SingleTop_H
#define HERWIG_MEPP2SingleTop_H
//
// This is the declaration of the MEPP2SingleTop class.
//
#include "Herwig/MatrixElement/HwMEBase.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
namespace Herwig {
using namespace ThePEG;
/**
* The MEPP2SingleTop class implements the matrix element for the
* production of a single top quark.
*
* @see \ref MEPP2SingleTopInterfaces "The interfaces"
* defined for MEPP2SingleTop.
*/
class MEPP2SingleTop: public HwMEBase {
public:
/**
* The default constructor.
*/
MEPP2SingleTop();
/** @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:
/**
* Matrix Elements ofr the different processes
*/
//@{
/**
* Matrix element for \f$q\bar{q}\to W \to t\bar{f}\f$.
* @param fin Spinors for incoming quark
* @param ain Spinors for incoming antiquark
* @param fout Spinors for incoming quark
* @param aout Spinors for incoming antiquark
* @param me Whether or not to calculate the matrix element for spin correlations
*/
double sChannelME(vector<SpinorWaveFunction> & fin ,
vector<SpinorBarWaveFunction> & ain ,
vector<SpinorBarWaveFunction> & fout,
vector<SpinorWaveFunction> & aout,
bool me) const;
/**
* Matrix element for \f$qq\to t q\f$.
* @param f1 Spinors for incoming quark
* @param a1 Spinors for incoming antiquark
* @param f2 Spinors for incoming quark
* @param a2 Spinors for incoming antiquark
* @param me Whether or not to calculate the matrix element for spin correlations
*/
double tChannelME(vector<SpinorWaveFunction> & f1 ,
vector<SpinorBarWaveFunction> & a1 ,
vector<SpinorWaveFunction> & f2,
vector<SpinorBarWaveFunction> & a2,
bool me) const;
/**
* Matrix element for \f$qg\to t W\f$.
* @param fin Spinors for incoming quark
* @param gin Polarization vectors for the incoming gluon
* @param fout Spinors for outgoing quark
* @param Wout Polarization vectors for the outgoing W
* @param me Whether or not to calculate the matrix element for spin correlations
*/
double tWME(vector<SpinorWaveFunction> & fin,
vector<VectorWaveFunction> & gin,
vector<SpinorBarWaveFunction> & fout,
vector<VectorWaveFunction> & Wout,
bool me) const;
//@}
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 static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<MEPP2SingleTop> initMEPP2SingleTop;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEPP2SingleTop & operator=(const MEPP2SingleTop &);
private:
/**
* Vertices
*/
//@{
/**
* FFWVertex
*/
AbstractFFVVertexPtr FFWvertex_;
/**
* FFGVertex
*/
AbstractFFVVertexPtr FFGvertex_;
//@}
/**
* Which processes to include
*/
unsigned int process_;
/**
* Allowed flavours of the incoming quarks
*/
int maxflavour_;
/**
* Treatment of the top quark mass
*/
int topOption_;
/**
* Treatment of the W mass
*/
int wOption_;
/**
* The matrix element
*/
mutable ProductionMatrixElement me_;
};
}
-#include "ThePEG/Utilities/ClassTraits.h"
-
-namespace ThePEG {
-
-/** @cond TRAITSPECIALIZATIONS */
-
-/** This template specialization informs ThePEG about the
- * base classes of MEPP2SingleTop. */
-template <>
-struct BaseClassTrait<Herwig::MEPP2SingleTop,1> {
- /** Typedef of the first base class of MEPP2SingleTop. */
- typedef Herwig::HwMEBase NthBase;
-};
-
-/** This template specialization informs ThePEG about the name of
- * the MEPP2SingleTop class and the shared object where it is defined. */
-template <>
-struct ClassTraits<Herwig::MEPP2SingleTop>
- : public ClassTraitsBase<Herwig::MEPP2SingleTop> {
- /** Return a platform-independent class name */
- static string className() { return "Herwig::MEPP2SingleTop"; }
- /**
- * The name of a file containing the dynamic library where the class
- * MEPP2SingleTop is implemented. It may also include several, space-separated,
- * libraries if the class MEPP2SingleTop 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_MEPP2SingleTop_H */
diff --git a/MatrixElement/Hadron/MEPP2VGamma.cc b/MatrixElement/Hadron/MEPP2VGamma.cc
--- a/MatrixElement/Hadron/MEPP2VGamma.cc
+++ b/MatrixElement/Hadron/MEPP2VGamma.cc
@@ -1,379 +1,382 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2VGamma class.
//
#include "MEPP2VGamma.h"
+#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "Herwig/MatrixElement/HardVertex.h"
using namespace Herwig;
MEPP2VGamma::MEPP2VGamma() : process_(0), maxflavour_(5), massOption_(2)
{}
unsigned int MEPP2VGamma::orderInAlphaS() const {
return 0;
}
unsigned int MEPP2VGamma::orderInAlphaEW() const {
return 2;
}
-ClassDescription<MEPP2VGamma> MEPP2VGamma::initMEPP2VGamma;
-// Definition of the static class description member.
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEPP2VGamma,HwMEBase>
+describeHerwigMEPP2VGamma("Herwig::MEPP2VGamma", "HwMEHadron.so");
void MEPP2VGamma::Init() {
static ClassDocumentation<MEPP2VGamma> documentation
("The MEPP2VGamma class simulates the production of"
" W+/-gamma and Z0gamma in hadron-hadron collisions"
" using the 2->2 matrix elements");
static Switch<MEPP2VGamma,unsigned int> interfaceProcess
("Process",
"Which processes to include",
&MEPP2VGamma::process_, 0, false, false);
static SwitchOption interfaceProcessAll
(interfaceProcess,
"All",
"Include all the processes",
0);
static SwitchOption interfaceProcessWGamma
(interfaceProcess,
"WGamma",
"Only include W+/-gamma",
1);
static SwitchOption interfaceProcessZGamma
(interfaceProcess,
"ZGamma",
"Only include ZGamma",
2);
static Parameter<MEPP2VGamma,int> interfaceMaximumFlavour
("MaximumFlavour",
"The maximum flavour allowed for the incoming quarks",
&MEPP2VGamma::maxflavour_, 5, 2, 5,
false, false, Interface::limited);
static Switch<MEPP2VGamma,unsigned int> interfaceMassOption
("MassOption",
"Option for the treatment of the boson masses",
&MEPP2VGamma::massOption_, 1, false, false);
static SwitchOption interfaceMassOptionOnMassShell
(interfaceMassOption,
"OnMassShell",
"The boson is produced on its mass shell",
1);
static SwitchOption interfaceMassOption2
(interfaceMassOption,
"OffShell",
"The bosons are generated off-shell using the mass and width generator.",
2);
}
void MEPP2VGamma::persistentOutput(PersistentOStream & os) const {
os << FFPvertex_ << FFWvertex_ << FFZvertex_ << WWWvertex_
<< process_ << massOption_;
}
void MEPP2VGamma::persistentInput(PersistentIStream & is, int) {
is >> FFPvertex_ >> FFWvertex_ >> FFZvertex_ >> WWWvertex_
>> process_ >> massOption_;
}
Energy2 MEPP2VGamma::scale() const {
return sHat();
}
IBPtr MEPP2VGamma::clone() const {
return new_ptr(*this);
}
IBPtr MEPP2VGamma::fullclone() const {
return new_ptr(*this);
}
void MEPP2VGamma::doinit() {
HwMEBase::doinit();
// mass option
vector<unsigned int> mopt(2,1);
mopt[0]=massOption_;
massOption(mopt);
rescalingOption(2);
// 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"
<< " MEPP2VGamma::doinit()"
<< Exception::abortnow;
// get pointers to all required Vertex objects
FFZvertex_ = hwsm->vertexFFZ();
FFPvertex_ = hwsm->vertexFFP();
WWWvertex_ = hwsm->vertexWWW();
FFWvertex_ = hwsm->vertexFFW();
}
Selector<const ColourLines *>
MEPP2VGamma::colourGeometries(tcDiagPtr diag) const {
static ColourLines cs("1 -2");
static ColourLines ct("1 2 -3");
Selector<const ColourLines *> sel;
if(diag->id()<-2) sel.insert(1.0, &cs);
else sel.insert(1.0, &ct);
return sel;
}
void MEPP2VGamma::getDiagrams() const {
typedef std::vector<pair<tcPDPtr,tcPDPtr> > Pairvector;
tcPDPtr wPlus = getParticleData(ParticleID::Wplus );
tcPDPtr wMinus = getParticleData(ParticleID::Wminus);
tcPDPtr z0 = getParticleData(ParticleID::Z0 );
tcPDPtr gamma = getParticleData(ParticleID::gamma);
// W+/- gamma
if(process_==0||process_==1) {
// possible parents
Pairvector parentpair;
parentpair.reserve(6);
// don't even think of putting 'break' in here!
switch(maxflavour_) {
case 5:
parentpair.push_back(make_pair(getParticleData(ParticleID::b),
getParticleData(ParticleID::cbar)));
parentpair.push_back(make_pair(getParticleData(ParticleID::b),
getParticleData(ParticleID::ubar)));
case 4:
parentpair.push_back(make_pair(getParticleData(ParticleID::s),
getParticleData(ParticleID::cbar)));
parentpair.push_back(make_pair(getParticleData(ParticleID::d),
getParticleData(ParticleID::cbar)));
case 3:
parentpair.push_back(make_pair(getParticleData(ParticleID::s),
getParticleData(ParticleID::ubar)));
case 2:
parentpair.push_back(make_pair(getParticleData(ParticleID::d),
getParticleData(ParticleID::ubar)));
default:
;
}
// W+ gamma
for(unsigned int ix=0;ix<parentpair.size();++ix) {
add(new_ptr((Tree2toNDiagram(3), parentpair[ix].second->CC(),
parentpair[ix].first, parentpair[ix].first->CC(),
1, wPlus, 2, gamma, -1)));
add(new_ptr((Tree2toNDiagram(3), parentpair[ix].second->CC(),
parentpair[ix].second->CC() , parentpair[ix].first->CC(),
2, wPlus, 1, gamma, -2)));
add(new_ptr((Tree2toNDiagram(2), parentpair[ix].second->CC(),
parentpair[ix].first->CC(), 1, wPlus, 3, wPlus, 3, gamma, -3)));
}
// W- gamma
for(unsigned int ix=0;ix<parentpair.size();++ix) {
add(new_ptr((Tree2toNDiagram(3), parentpair[ix].first,
parentpair[ix].second->CC(),
parentpair[ix].second, 1, wMinus, 2, gamma, -1)));
add(new_ptr((Tree2toNDiagram(3), parentpair[ix].first, parentpair[ix].first ,
parentpair[ix].second, 2, wMinus, 1, gamma, -2)));
add(new_ptr((Tree2toNDiagram(2), parentpair[ix].first,
parentpair[ix].second, 1, wMinus, 3, wMinus, 3, gamma, -3)));
}
}
if(process_==0||process_==2) {
for(int ix=1;ix<=maxflavour_;++ix) {
tcPDPtr qk = getParticleData(ix);
tcPDPtr qb = qk->CC();
add(new_ptr((Tree2toNDiagram(3), qk, qk, qb, 1, z0, 2, gamma, -1)));
add(new_ptr((Tree2toNDiagram(3), qk, qk, qb, 2, z0, 1, gamma, -2)));
}
}
}
Selector<MEBase::DiagramIndex>
MEPP2VGamma::diagrams(const DiagramVector & diags) const {
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i )
sel.insert(meInfo()[abs(diags[i]->id()) - 1], i);
return sel;
}
double MEPP2VGamma::me2() const {
// setup momenta and particle data for the external wavefunctions
// incoming
SpinorWaveFunction em_in( meMomenta()[0],mePartonData()[0],incoming);
SpinorBarWaveFunction ep_in( meMomenta()[1],mePartonData()[1],incoming);
// outgoing
VectorWaveFunction v1_out(meMomenta()[2],mePartonData()[2],outgoing);
VectorWaveFunction v2_out(meMomenta()[3],mePartonData()[3],outgoing);
vector<SpinorWaveFunction> f1;
vector<SpinorBarWaveFunction> a1;
vector<VectorWaveFunction> v1,v2;
// calculate the wavefunctions
for(unsigned int ix=0;ix<3;++ix) {
if(ix<2) {
em_in.reset(ix);
f1.push_back(em_in);
ep_in.reset(ix);
a1.push_back(ep_in);
}
v1_out.reset(ix);
v1.push_back(v1_out);
if(ix!=1) {
v2_out.reset(ix);
v2.push_back(v2_out);
}
}
if(mePartonData()[2]->id()==ParticleID::Z0) {
return ZGammaME(f1,a1,v1,v2,false);
}
else {
return WGammaME(f1,a1,v1,v2,false);
}
}
double MEPP2VGamma::ZGammaME(vector<SpinorWaveFunction> & f1,
vector<SpinorBarWaveFunction> & a1,
vector<VectorWaveFunction> & v1,
vector<VectorWaveFunction> & v2,
bool calc) const {
double output(0.);
vector<double> me(3,0.0);
if(calc) 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<3;++ohel1) {
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
inter = FFZvertex_->evaluate(scale(),5,f1[ihel1].particle(),
f1[ihel1],v1[ohel1]);
diag[0] = FFPvertex_->evaluate(scale(),inter,a1[ihel2],v2[ohel2]);
inter = FFPvertex_->evaluate(scale(),5,f1[ihel1].particle(),
f1[ihel1] ,v2[ohel2]);
diag[1] = FFZvertex_->evaluate(scale(),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
if(calc) me_(ihel1,ihel2,ohel1,ohel2) = diag[0];
}
}
}
}
DVector save(3);
for (size_t i = 0; i < 3; ++i) {
save[i] = 0.25 * me[i];
}
meInfo(save);
return 0.25*output/3.;
}
double MEPP2VGamma::WGammaME(vector<SpinorWaveFunction> & f1,
vector<SpinorBarWaveFunction> & a1,
vector<VectorWaveFunction> & v1,
vector<VectorWaveFunction> & v2,
bool calc) const {
double output(0.);
vector<double> me(3,0.0);
if(calc) me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1,PDT::Spin1));
vector<Complex> diag(3,0.0);
SpinorWaveFunction inter;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
VectorWaveFunction interW =
FFWvertex_->evaluate(scale(),3,v1[0].particle(),
f1[ihel1],a1[ihel2]);
for(unsigned int ohel1=0;ohel1<3;++ohel1) {
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
// t-channel diagrams
inter = FFWvertex_->evaluate(scale(),5,a1[ihel1].particle(),
f1[ihel1],v1[ohel1]);
diag[0] = FFPvertex_->evaluate(scale(),inter,a1[ihel2],v2[ohel2]);
inter = FFPvertex_->evaluate(scale(),5,f1[ihel1].particle(),
f1[ihel1] ,v2[ohel2]);
diag[1] = FFWvertex_->evaluate(scale(),inter,a1[ihel2],v1[ohel1]);
// s-channel diagram
diag[2] = WWWvertex_->evaluate(scale(),interW,v1[ohel1],v2[ohel2]);
// individual diagrams
for (size_t ii=0; ii<3; ++ii) me[ii] += std::norm(diag[ii]);
// full matrix element
diag[0] += diag[1]+diag[2];
output += std::norm(diag[0]);
// storage of the matrix element for spin correlations
if(calc) me_(ihel1,ihel2,ohel1,ohel2) = diag[0];
}
}
}
}
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.25/3.;
// testing code
// int iu = abs(mePartonData()[0]->id());
// int id = abs(mePartonData()[1]->id());
// if(iu%2!=0) swap(iu,id);
// iu = (iu-2)/2;
// id = (id-1)/2;
// double ckm = SM().CKM(iu,id);
// InvEnergy4 dsigdt = Constants::pi*sqr(SM().alphaEM(scale()))
// /6./sqr(sHat())/SM().sin2ThetaW()*sqr(1./(1.+tHat()/uHat())-1./3.)*
// (sqr(tHat())+sqr(uHat())+2.*sqr(getParticleData(ParticleID::Wplus)->mass())*sHat())/
// tHat()/uHat();
// double test = 16.*ckm*Constants::pi*sqr(sHat())*dsigdt;
// cerr << "testing W gamma " << test << " " << output << " "
// << (test-output)/(test+output) << "\n";
return output;
}
void MEPP2VGamma::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]);
// order of particles
unsigned int order[4]={0,1,2,3};
if(hard[order[0]]->id()<0) swap(order[0],order[1]);
vector<SpinorWaveFunction> q;
vector<SpinorBarWaveFunction> qb;
SpinorWaveFunction (q ,hard[order[0]],incoming,false);
SpinorBarWaveFunction(qb,hard[order[1]],incoming,false);
vector<VectorWaveFunction> w1,w2;
if(hard[order[2]]->id()==ParticleID::gamma)
swap(order[2],order[3]);
VectorWaveFunction (w1,hard[order[2]],outgoing,true ,false);
VectorWaveFunction (w2,hard[order[3]],outgoing,true ,true );
w2[1]=w2[2];
// q qbar -> Z gamma
if(hard[order[2]]->id()==ParticleID::Z0) {
ZGammaME(q,qb,w1,w2,true);
}
// q qbar -> W gamma
else {
WGammaME(q,qb,w1,w2,true);
}
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(me_);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<4;++ix)
hard[order[ix]]->spinInfo()->productionVertex(hardvertex);
}
diff --git a/MatrixElement/Hadron/MEPP2VGamma.h b/MatrixElement/Hadron/MEPP2VGamma.h
--- a/MatrixElement/Hadron/MEPP2VGamma.h
+++ b/MatrixElement/Hadron/MEPP2VGamma.h
@@ -1,276 +1,241 @@
// -*- C++ -*-
#ifndef HERWIG_MEPP2VGamma_H
#define HERWIG_MEPP2VGamma_H
//
// This is the declaration of the MEPP2VGamma class.
//
#include "Herwig/MatrixElement/HwMEBase.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVVVertex.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
namespace Herwig {
using namespace ThePEG;
/**
* The MEPP2VGamma class implements the .
*
* @see \ref MEPP2VGammaInterfaces "The interfaces"
* defined for MEPP2VGamma.
*/
class MEPP2VGamma: public HwMEBase {
public:
/**
* The default constructor.
*/
MEPP2VGamma();
/** @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:
/**
* Matrix element for \f$f\bar{f}\to W^\pm \gamma\f$.
* @param f1 Spinors for the incoming fermion
* @param a1 Spinors for the incoming antifermion
* @param v1 \f$W^\pm\f$ wavefunction
* @param v2 \f$\gamma\f$ wavefunction
* @param me Whether or not to calculate the matrix element for spin correlations
*/
double WGammaME(vector<SpinorWaveFunction> & f1,
vector<SpinorBarWaveFunction> & a1,
vector<VectorWaveFunction> & v1,
vector<VectorWaveFunction> & v2,
bool me) const;
/**
* Matrix element for \f$f\bar{f}\to Z^0 \gamma\f$.
* @param f1 Spinors for the incoming fermion
* @param a1 Spinors for the incoming antifermion
* @param v1 \f$Z^0\f$ wavefunction
* @param v2 \f$\gamma\f$ wavefunction
* @param me Whether or not to calculate the matrix element for spin correlations
*/
double ZGammaME(vector<SpinorWaveFunction> & f1,
vector<SpinorBarWaveFunction> & a1,
vector<VectorWaveFunction> & v1,
vector<VectorWaveFunction> & v2,
bool me) const;
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 static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<MEPP2VGamma> initMEPP2VGamma;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEPP2VGamma & operator=(const MEPP2VGamma &);
private:
/**
* Vertices
*/
//@{
/**
* FFPVertex
*/
AbstractFFVVertexPtr FFPvertex_;
/**
* FFWVertex
*/
AbstractFFVVertexPtr FFWvertex_;
/**
* FFZVertex
*/
AbstractFFVVertexPtr FFZvertex_;
/**
* WWW Vertex
*/
AbstractVVVVertexPtr WWWvertex_;
//@}
/**
* Processes
*/
unsigned int process_;
/**
* Allowed flavours of the incoming quarks
*/
int maxflavour_;
/**
* Treatment of the the boson masses
*/
unsigned int massOption_;
/**
* The matrix element
*/
mutable ProductionMatrixElement me_;
};
}
-#include "ThePEG/Utilities/ClassTraits.h"
-
-namespace ThePEG {
-
-/** @cond TRAITSPECIALIZATIONS */
-
-/** This template specialization informs ThePEG about the
- * base classes of MEPP2VGamma. */
-template <>
-struct BaseClassTrait<Herwig::MEPP2VGamma,1> {
- /** Typedef of the first base class of MEPP2VGamma. */
- typedef Herwig::HwMEBase NthBase;
-};
-
-/** This template specialization informs ThePEG about the name of
- * the MEPP2VGamma class and the shared object where it is defined. */
-template <>
-struct ClassTraits<Herwig::MEPP2VGamma>
- : public ClassTraitsBase<Herwig::MEPP2VGamma> {
- /** Return a platform-independent class name */
- static string className() { return "Herwig::MEPP2VGamma"; }
- /**
- * The name of a file containing the dynamic library where the class
- * MEPP2VGamma is implemented. It may also include several, space-separated,
- * libraries if the class MEPP2VGamma 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_MEPP2VGamma_H */
diff --git a/MatrixElement/Hadron/MEPP2VV.cc b/MatrixElement/Hadron/MEPP2VV.cc
--- a/MatrixElement/Hadron/MEPP2VV.cc
+++ b/MatrixElement/Hadron/MEPP2VV.cc
@@ -1,540 +1,543 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2VV class.
//
#include "MEPP2VV.h"
+#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "Herwig/MatrixElement/HardVertex.h"
using namespace Herwig;
MEPP2VV::MEPP2VV() : process_(0), maxflavour_(5), massOption_(2)
{}
unsigned int MEPP2VV::orderInAlphaS() const {
return 0;
}
unsigned int MEPP2VV::orderInAlphaEW() const {
return 2;
}
-ClassDescription<MEPP2VV> MEPP2VV::initMEPP2VV;
-// Definition of the static class description member.
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEPP2VV,HwMEBase>
+describeHerwigMEPP2VV("Herwig::MEPP2VV", "HwMEHadron.so");
void MEPP2VV::Init() {
static ClassDocumentation<MEPP2VV> documentation
("The MEPP2VV class simulates the production of W+W-, "
"W+/-Z0 and Z0Z0 in hadron-hadron collisions using the 2->2"
" matrix elements");
static Switch<MEPP2VV,unsigned int> interfaceProcess
("Process",
"Which processes to include",
&MEPP2VV::process_, 0, false, false);
static SwitchOption interfaceProcessAll
(interfaceProcess,
"All",
"Include all the processes",
0);
static SwitchOption interfaceProcessWW
(interfaceProcess,
"WW",
"Only include W+W-",
1);
static SwitchOption interfaceProcessWZ
(interfaceProcess,
"WZ",
"Only include W+/-Z",
2);
static SwitchOption interfaceProcessZZ
(interfaceProcess,
"ZZ",
"Only include ZZ",
3);
static SwitchOption interfaceProcessWpZ
(interfaceProcess,
"WpZ",
"Only include W+ Z",
4);
static SwitchOption interfaceProcessWmZ
(interfaceProcess,
"WmZ",
"Only include W- Z",
5);
static Parameter<MEPP2VV,int> interfaceMaximumFlavour
("MaximumFlavour",
"The maximum flavour allowed for the incoming quarks",
&MEPP2VV::maxflavour_, 5, 2, 5,
false, false, Interface::limited);
static Switch<MEPP2VV,unsigned int> interfaceMassOption
("MassOption",
"Option for the treatment of the boson masses",
&MEPP2VV::massOption_, 1, false, false);
static SwitchOption interfaceMassOptionOnMassShell
(interfaceMassOption,
"OnMassShell",
"The boson is produced on its mass shell",
1);
static SwitchOption interfaceMassOption2
(interfaceMassOption,
"OffShell",
"The bosons are generated off-shell using the mass and width generator.",
2);
}
void MEPP2VV::persistentOutput(PersistentOStream & os) const {
os << FFPvertex_ << FFWvertex_ << FFZvertex_ << WWWvertex_
<< process_ << massOption_ << maxflavour_;
}
void MEPP2VV::persistentInput(PersistentIStream & is, int) {
is >> FFPvertex_ >> FFWvertex_ >> FFZvertex_ >> WWWvertex_
>> process_ >> massOption_ >> maxflavour_;
}
Energy2 MEPP2VV::scale() const {
return sHat();
}
IBPtr MEPP2VV::clone() const {
return new_ptr(*this);
}
IBPtr MEPP2VV::fullclone() const {
return new_ptr(*this);
}
void MEPP2VV::doinit() {
HwMEBase::doinit();
// mass option
massOption(vector<unsigned int>(2,massOption_));
rescalingOption(2);
// 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"
<< " MEPP2VV::doinit()"
<< Exception::abortnow;
// get pointers to all required Vertex objects
FFZvertex_ = hwsm->vertexFFZ();
FFPvertex_ = hwsm->vertexFFP();
WWWvertex_ = hwsm->vertexWWW();
FFWvertex_ = hwsm->vertexFFW();
}
double MEPP2VV::getCosTheta(double ctmin, double ctmax, const double r) {
double rand = r;
Energy2 m12 = sqr(meMomenta()[2].mass());
Energy2 m22 = sqr(meMomenta()[3].mass());
Energy2 D1 = sHat()-m12-m22;
Energy4 lambda = sqr(D1) - 4*m12*m22;
double D = D1 / sqrt(lambda);
if(mePartonData()[2]->id()==ParticleID::Z0&&
mePartonData()[3]->id()==ParticleID::Z0) {
double prob = 0.5;
double costh;
double fraction1 = (D-ctmax)/(D-ctmin);
double fraction2 = (D+ctmin)/(D+ctmax);
if(rand<=prob) {
rand /=prob;
costh = D - (D - ctmin) * pow(fraction1, rand);
}
else {
rand = (rand-prob)/(1.-prob);
costh =-D + (D + ctmax) * pow(fraction2, rand);
}
jacobian(1./(prob /((costh - D) * log(fraction1))-
(1.-prob)/((costh + D) * log(fraction2))));
return costh;
}
else {
double fraction = (D-ctmax)/(D-ctmin);
double costh = D - (D - ctmin) * pow(fraction, rand);
jacobian((costh - D) * log(fraction));
return costh;
}
}
Selector<const ColourLines *>
MEPP2VV::colourGeometries(tcDiagPtr diag) const {
static ColourLines cs("1 -2");
static ColourLines ct("1 2 -3");
Selector<const ColourLines *> sel;
if(abs(diag->partons()[2]->id())==24&&abs(diag->partons()[3]->id())==24) {
if(diag->id()<=-4) sel.insert(1.0, &cs);
else sel.insert(1.0, &ct);
}
else if(abs(diag->partons()[2]->id())==24&&diag->partons()[3]->id()==23) {
if(diag->id()==-3) sel.insert(1.0, &cs);
else sel.insert(1.0, &ct);
}
else {
sel.insert(1.0, &ct);
}
return sel;
}
void MEPP2VV::getDiagrams() const {
typedef std::vector<pair<tcPDPtr,tcPDPtr> > Pairvector;
tcPDPtr wPlus = getParticleData(ParticleID::Wplus );
tcPDPtr wMinus = getParticleData(ParticleID::Wminus);
tcPDPtr z0 = getParticleData(ParticleID::Z0 );
tcPDPtr gamma = getParticleData(ParticleID::gamma);
// W+ W-
if(process_==0||process_==1) {
for(int ix=1;ix<=maxflavour_;++ix) {
tcPDPtr qk = getParticleData(ix);
tcPDPtr w1 = ix%2==0 ? wPlus : wMinus;
tcPDPtr w2 = ix%2!=0 ? wPlus : wMinus;
for(int iy=1;iy<=maxflavour_;++iy) {
if(abs(ix-iy)%2!=0) continue;
tcPDPtr qb = getParticleData(-iy);
// s channel photon
add(new_ptr((Tree2toNDiagram(2), qk, qb, 1, gamma, 3, w1, 3, w2, -4)));
// s-channel Z
add(new_ptr((Tree2toNDiagram(2), qk, qb, 1, z0, 3, w1, 3, w2, -5)));
// t-channel
if(ix%2==0) {
int idiag=0;
for(int iz=1;iz<=5;iz+=2) {
--idiag;
tcPDPtr tc = getParticleData(iz);
add(new_ptr((Tree2toNDiagram(3), qk, tc, qb, 1, w1, 2, w2, idiag)));
}
}
else {
int idiag=0;
for(int iz=2;iz<=6;iz+=2) {
--idiag;
tcPDPtr tc = getParticleData(iz);
add(new_ptr((Tree2toNDiagram(3), qk, tc, qb, 1, w1, 2, w2, idiag)));
}
}
}
}
}
// W+/- Z
if(process_==0||process_==2||process_==4||process_==5) {
// possible parents
Pairvector parentpair;
parentpair.reserve(6);
// don't even think of putting 'break' in here!
switch(maxflavour_) {
case 5:
parentpair.push_back(make_pair(getParticleData(ParticleID::b),
getParticleData(ParticleID::cbar)));
parentpair.push_back(make_pair(getParticleData(ParticleID::b),
getParticleData(ParticleID::ubar)));
case 4:
parentpair.push_back(make_pair(getParticleData(ParticleID::s),
getParticleData(ParticleID::cbar)));
parentpair.push_back(make_pair(getParticleData(ParticleID::d),
getParticleData(ParticleID::cbar)));
case 3:
parentpair.push_back(make_pair(getParticleData(ParticleID::s),
getParticleData(ParticleID::ubar)));
case 2:
parentpair.push_back(make_pair(getParticleData(ParticleID::d),
getParticleData(ParticleID::ubar)));
default:
;
}
// W+ Z
if(process_==0||process_==2||process_==4) {
for(unsigned int ix=0;ix<parentpair.size();++ix) {
add(new_ptr((Tree2toNDiagram(3), parentpair[ix].second->CC(),
parentpair[ix].first, parentpair[ix].first->CC(),
1, wPlus, 2, z0, -1)));
add(new_ptr((Tree2toNDiagram(3), parentpair[ix].second->CC(),
parentpair[ix].second->CC() , parentpair[ix].first->CC(),
2, wPlus, 1, z0, -2)));
add(new_ptr((Tree2toNDiagram(2), parentpair[ix].second->CC(),
parentpair[ix].first->CC(), 1, wPlus, 3, wPlus, 3, z0, -3)));
}
}
// W- Z
if(process_==0||process_==2||process_==5) {
for(unsigned int ix=0;ix<parentpair.size();++ix) {
add(new_ptr((Tree2toNDiagram(3), parentpair[ix].first,
parentpair[ix].second->CC(),
parentpair[ix].second, 1, wMinus, 2, z0, -1)));
add(new_ptr((Tree2toNDiagram(3), parentpair[ix].first,
parentpair[ix].first , parentpair[ix].second, 2, wMinus, 1, z0, -2)));
add(new_ptr((Tree2toNDiagram(2), parentpair[ix].first,
parentpair[ix].second, 1, wMinus, 3, wMinus, 3, z0, -3)));
}
}
}
// Z Z
if(process_==0||process_==3) {
for(int ix=1;ix<=maxflavour_;++ix) {
tcPDPtr qk = getParticleData(ix);
tcPDPtr qb = qk->CC();
add(new_ptr((Tree2toNDiagram(3), qk, qk, qb, 1, z0, 2, z0, -1)));
add(new_ptr((Tree2toNDiagram(3), qk, qk, qb, 2, z0, 1, z0, -2)));
}
}
}
Selector<MEBase::DiagramIndex>
MEPP2VV::diagrams(const DiagramVector & diags) const {
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i )
sel.insert(meInfo()[abs(diags[i]->id())-1], i);
return sel;
}
double MEPP2VV::me2() const {
// setup momenta and particle data for the external wavefunctions
// incoming
SpinorWaveFunction em_in( meMomenta()[0],mePartonData()[0],incoming);
SpinorBarWaveFunction ep_in( meMomenta()[1],mePartonData()[1],incoming);
// outgoing
VectorWaveFunction v1_out(meMomenta()[2],mePartonData()[2],outgoing);
VectorWaveFunction v2_out(meMomenta()[3],mePartonData()[3],outgoing);
vector<SpinorWaveFunction> f1;
vector<SpinorBarWaveFunction> a1;
vector<VectorWaveFunction> v1,v2;
// calculate the wavefunctions
for(unsigned int ix=0;ix<3;++ix) {
if(ix<2) {
em_in.reset(ix);
f1.push_back(em_in);
ep_in.reset(ix);
a1.push_back(ep_in);
}
v1_out.reset(ix);
v1.push_back(v1_out);
v2_out.reset(ix);
v2.push_back(v2_out);
}
if(mePartonData()[2]->id()==ParticleID::Z0&&
mePartonData()[3]->id()==ParticleID::Z0) {
return ZZME(f1,a1,v1,v2,false);
}
else if(abs(mePartonData()[2]->id())==ParticleID::Wplus&&
abs(mePartonData()[3]->id())==ParticleID::Wplus) {
return WWME(f1,a1,v1,v2,false);
}
else {
return WZME(f1,a1,v1,v2,false);
}
}
double MEPP2VV::WWME(vector<SpinorWaveFunction> & f1,
vector<SpinorBarWaveFunction> & a1,
vector<VectorWaveFunction> & v1,
vector<VectorWaveFunction> & v2,
bool calc) const {
double output(0.);
vector<double> me(5,0.0);
if(calc) me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1,PDT::Spin1));
// particle data for the t-channel intermediate
tcPDPtr tc[3];
if(f1[0].particle()->id()%2==0) {
for (int ix=0;ix<3;++ix) tc[ix] = getParticleData(1+2*ix);
}
else {
for (int ix=0;ix<3;++ix) tc[ix] = getParticleData(2+2*ix);
}
tcPDPtr gamma = getParticleData(ParticleID::gamma);
tcPDPtr z0 = getParticleData(ParticleID::Z0);
vector<Complex> diag(5,0.0);
VectorWaveFunction interP,interZ;
bool sChannel =
f1[0].particle()->id() == -a1[0].particle()->id();
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
if(sChannel) {
interP = FFPvertex_->evaluate(scale(),3,gamma,f1[ihel1],a1[ihel2]);
interZ = FFZvertex_->evaluate(scale(),3,z0 ,f1[ihel1],a1[ihel2]);
}
for(unsigned int ohel1=0;ohel1<3;++ohel1) {
for(unsigned int ohel2=0;ohel2<3;++ohel2) {
// s-channel photon
diag[3] = sChannel ?
WWWvertex_->evaluate(scale(),interP,v2[ohel2],v1[ohel1]) : 0.;
// s-channel Z0
diag[4] = sChannel ?
WWWvertex_->evaluate(scale(),interZ,v2[ohel2],v1[ohel1]) : 0.;
// t-channel
for(unsigned int ix=0;ix<3;++ix) {
SpinorWaveFunction inter =
FFWvertex_->evaluate(scale(),(abs(tc[ix]->id())!=6 ? 5 : 1),
tc[ix],f1[ihel1],v1[ohel1]);
diag[ix] =
FFWvertex_->evaluate(scale(),inter,a1[ihel2],v2[ohel2]);
}
// individual diagrams
for (size_t ii=0; ii<5; ++ii) me[ii] += std::norm(diag[ii]);
// full matrix element
diag[0] += diag[1]+diag[2]+diag[3]+diag[4];
output += std::norm(diag[0]);
// storage of the matrix element for spin correlations
if(calc) me_(ihel1,ihel2,ohel1,ohel2) = diag[0];
}
}
}
}
DVector save(5);
for (size_t i = 0; i < 5; ++i) {
save[i] = 0.25 * me[i];
}
meInfo(save);
return 0.25*output/3.;
}
double MEPP2VV::WZME(vector<SpinorWaveFunction> & f1,
vector<SpinorBarWaveFunction> & a1,
vector<VectorWaveFunction> & v1,
vector<VectorWaveFunction> & v2,
bool calc) const {
double output(0.);
vector<double> me(5,0.0);
if(calc) me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1,PDT::Spin1));
vector<Complex> diag(3,0.0);
SpinorWaveFunction inter;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
VectorWaveFunction interW =
FFWvertex_->evaluate(scale(),3,v1[0].particle(),
f1[ihel1],a1[ihel2]);
for(unsigned int ohel1=0;ohel1<3;++ohel1) {
for(unsigned int ohel2=0;ohel2<3;++ohel2) {
// t-channel diagrams
inter = FFWvertex_->evaluate(scale(),5,a1[ihel1].particle(),
f1[ihel1],v1[ohel1]);
diag[0] = FFZvertex_->evaluate(scale(),inter,a1[ihel2],v2[ohel2]);
inter = FFZvertex_->evaluate(scale(),5,f1[ihel1].particle(),
f1[ihel1] ,v2[ohel2]);
diag[1] = FFWvertex_->evaluate(scale(),inter,a1[ihel2],v1[ohel1]);
// s-channel diagram
diag[2] = WWWvertex_->evaluate(scale(),interW,v1[ohel1],v2[ohel2]);
// individual diagrams
for (size_t ii=0; ii<3; ++ii) me[ii] += std::norm(diag[ii]);
// full matrix element
diag[0] += diag[1]+diag[2];
output += std::norm(diag[0]);
// storage of the matrix element for spin correlations
if(calc) me_(ihel1,ihel2,ohel1,ohel2) = diag[0];
}
}
}
}
DVector save(5);
for (size_t i = 0; i < 5; ++i) {
save[i] = 0.25 * me[i];
}
meInfo(save);
return 0.25*output/3.;
}
double MEPP2VV::ZZME(vector<SpinorWaveFunction> & f1,
vector<SpinorBarWaveFunction> & a1,
vector<VectorWaveFunction> & v1,
vector<VectorWaveFunction> & v2,
bool calc) const {
double output(0.);
vector<double> me(5,0.0);
if(calc) 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<3;++ohel1) {
for(unsigned int ohel2=0;ohel2<3;++ohel2) {
inter = FFZvertex_->evaluate(scale(),5,f1[ihel1].particle(),
f1[ihel1],v1[ohel1]);
diag[0] = FFZvertex_->evaluate(scale(),inter,a1[ihel2],v2[ohel2]);
inter = FFZvertex_->evaluate(scale(),5,f1[ihel1].particle(),
f1[ihel1] ,v2[ohel2]);
diag[1] = FFZvertex_->evaluate(scale(),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
if(calc) me_(ihel1,ihel2,ohel1,ohel2) = diag[0];
}
}
}
}
// identical particle factor
output /= 2.;
DVector save(5);
for (size_t i = 0; i < 5; ++i) {
save[i] = 0.25 * me[i];
}
meInfo(save);
return 0.25*output/3.;
}
void MEPP2VV::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]);
// order of particles
unsigned int order[4]={0,1,2,3};
if(hard[order[0]]->id()<0) swap(order[0],order[1]);
vector<SpinorWaveFunction> q;
vector<SpinorBarWaveFunction> qb;
SpinorWaveFunction (q ,hard[order[0]],incoming,false);
SpinorBarWaveFunction(qb,hard[order[1]],incoming,false);
vector<VectorWaveFunction> w1,w2;
// q qbar -> Z Z
if(hard[order[2]]->id()==ParticleID::Z0&&
hard[order[3]]->id()==ParticleID::Z0) {
VectorWaveFunction (w1,hard[order[2]],outgoing,true ,false);
VectorWaveFunction (w2,hard[order[3]],outgoing,true ,false);
ZZME(q,qb,w1,w2,true);
}
// q qbar -> W W
else if(abs(hard[order[2]]->id())==ParticleID::Wplus&&
abs(hard[order[3]]->id())==ParticleID::Wplus) {
if((hard[order[0]]->id()%2==1&&hard[order[2]]->id()==ParticleID::Wplus)||
(hard[order[0]]->id()%2==0&&hard[order[2]]->id()==ParticleID::Wminus))
swap(order[2],order[3]);
VectorWaveFunction (w1,hard[order[2]],outgoing,true ,false);
VectorWaveFunction (w2,hard[order[3]],outgoing,true ,false);
WWME(q,qb,w1,w2,true);
}
// q qbar -> W Z
else {
if(abs(hard[order[2]]->id())!=ParticleID::Wplus)
swap(order[2],order[3]);
VectorWaveFunction (w1,hard[order[2]],outgoing,true ,false);
VectorWaveFunction (w2,hard[order[3]],outgoing,true ,false);
WZME(q,qb,w1,w2,true);
}
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(me_);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<4;++ix)
hard[order[ix]]->spinInfo()->productionVertex(hardvertex);
}
diff --git a/MatrixElement/Hadron/MEPP2VV.h b/MatrixElement/Hadron/MEPP2VV.h
--- a/MatrixElement/Hadron/MEPP2VV.h
+++ b/MatrixElement/Hadron/MEPP2VV.h
@@ -1,303 +1,268 @@
// -*- C++ -*-
#ifndef HERWIG_MEPP2VV_H
#define HERWIG_MEPP2VV_H
//
// This is the declaration of the MEPP2VV class.
//
#include "Herwig/MatrixElement/HwMEBase.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVVVertex.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
namespace Herwig {
using namespace ThePEG;
/**
* The MEPP2VV class implements the production of \f$W^+W^-\f$,
* \f$W^\pm Z^0\f$ and \f$Z^0Z^o\f$ in hadron-hadron collisions.
*
* @see \ref MEPP2VVInterfaces "The interfaces"
* defined for MEPP2VV.
*/
class MEPP2VV: public HwMEBase {
public:
/**
* The default constructor.
*/
MEPP2VV();
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;
/**
* Return the process being run (WW/ZZ/WZ).
*/
virtual int process() const { return process_; }
/**
* 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;
/**
* Used internally by generateKinematics, after calculating the
* limits on cos(theta).
*/
virtual double getCosTheta(double cthmin, double cthmax, const double r);
/**
* 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:
/**
* Matrix element for \f$f\bar{f}\to W^+W^-\f$.
* @param f1 Spinors for the incoming fermion
* @param a1 Spinors for the incoming antifermion
* @param v1 The first outgoing W polarization vectors
* @param v2 The second outgoing W polarization vectors
* @param me Whether or not to calculate the matrix element for spin correlations
*/
double WWME(vector<SpinorWaveFunction> & f1,
vector<SpinorBarWaveFunction> & a1,
vector<VectorWaveFunction> & v1,
vector<VectorWaveFunction> & v2,
bool me) const;
/**
* Matrix element for \f$f\bar{f}\to W^\pm Z^0\f$.
* @param f1 Spinors for the incoming fermion
* @param a1 Spinors for the incoming antifermion
* @param v1 The outgoing W polarization vectors
* @param v2 The outgoing Z polarization vectors
* @param me Whether or not to calculate the matrix element for spin correlations
*/
double WZME(vector<SpinorWaveFunction> & f1,
vector<SpinorBarWaveFunction> & a1,
vector<VectorWaveFunction> & v1,
vector<VectorWaveFunction> & v2,
bool me) const;
/**
* Matrix element for \f$f\bar{f}\to Z^0Z^0\f$.
* @param f1 Spinors for the incoming fermion
* @param a1 Spinors for the incoming antifermion
* @param v1 The first outgoing Z polarization vectors
* @param v2 The second outgoing Z polarization vectors
* @param me Whether or not to calculate the matrix element for spin correlations
*/
double ZZME(vector<SpinorWaveFunction> & f1,
vector<SpinorBarWaveFunction> & a1,
vector<VectorWaveFunction> & v1,
vector<VectorWaveFunction> & v2,
bool me) const;
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 static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<MEPP2VV> initMEPP2VV;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEPP2VV & operator=(const MEPP2VV &);
private:
/**
* Vertices
*/
//@{
/**
* FFPVertex
*/
AbstractFFVVertexPtr FFPvertex_;
/**
* FFWVertex
*/
AbstractFFVVertexPtr FFWvertex_;
/**
* FFZVertex
*/
AbstractFFVVertexPtr FFZvertex_;
/**
* WWW Vertex
*/
AbstractVVVVertexPtr WWWvertex_;
//@}
/**
* Processes
*/
unsigned int process_;
/**
* Allowed flavours of the incoming quarks
*/
int maxflavour_;
/**
* Treatment of the the boson masses
*/
unsigned int massOption_;
/**
* The matrix element
*/
mutable ProductionMatrixElement me_;
};
}
-#include "ThePEG/Utilities/ClassTraits.h"
-
-namespace ThePEG {
-
-/** @cond TRAITSPECIALIZATIONS */
-
-/** This template specialization informs ThePEG about the
- * base classes of MEPP2VV. */
-template <>
-struct BaseClassTrait<Herwig::MEPP2VV,1> {
- /** Typedef of the first base class of MEPP2VV. */
- typedef Herwig::HwMEBase NthBase;
-};
-
-/** This template specialization informs ThePEG about the name of
- * the MEPP2VV class and the shared object where it is defined. */
-template <>
-struct ClassTraits<Herwig::MEPP2VV>
- : public ClassTraitsBase<Herwig::MEPP2VV> {
- /** Return a platform-independent class name */
- static string className() { return "Herwig::MEPP2VV"; }
- /**
- * The name of a file containing the dynamic library where the class
- * MEPP2VV is implemented. It may also include several, space-separated,
- * libraries if the class MEPP2VV 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_MEPP2VV_H */
diff --git a/MatrixElement/Hadron/MEPP2WH.cc b/MatrixElement/Hadron/MEPP2WH.cc
--- a/MatrixElement/Hadron/MEPP2WH.cc
+++ b/MatrixElement/Hadron/MEPP2WH.cc
@@ -1,150 +1,153 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2WH class.
//
#include "MEPP2WH.h"
+#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
using namespace Herwig;
MEPP2WH::MEPP2WH() : _plusminus(0)
{}
-ClassDescription<MEPP2WH> MEPP2WH::initMEPP2WH;
-// Definition of the static class description member.
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEPP2WH,MEfftoVH>
+describeHerwigMEPP2WH("Herwig::MEPP2WH", "HwMEHadron.so");
void MEPP2WH::persistentOutput(PersistentOStream & os) const {
os << _plusminus;
}
void MEPP2WH::persistentInput(PersistentIStream & is, int) {
is >> _plusminus;
}
void MEPP2WH::Init() {
static ClassDocumentation<MEPP2WH> documentation
("The MEPP2WH class implements the matrix element for the Bjorken"
" process q qbar -> WH");
static Switch<MEPP2WH,unsigned int> interfacePlusMinus
("Wcharge",
"Which intermediate W bosons to include",
&MEPP2WH::_plusminus, 0, false, false);
static SwitchOption interfacePlusMinusAll
(interfacePlusMinus,
"Both",
"Include W+ and W-",
0);
static SwitchOption interfacePlusMinusPlus
(interfacePlusMinus,
"Plus",
"Only include W+",
1);
static SwitchOption interfacePlusMinusMinus
(interfacePlusMinus,
"Minus",
"Only include W-",
2);
}
void MEPP2WH::getDiagrams() const {
// which intgermediates to include
bool wplus =_plusminus==0||_plusminus==1;
bool wminus=_plusminus==0||_plusminus==2;
tPDPtr higgs = getParticleData(ParticleID::h0);
// possible parents
vector<PDPair> parentpair;
parentpair.reserve(6);
// don't even think of putting 'break' in here!
switch(maxFlavour()) {
case 5:
parentpair.push_back(make_pair(getParticleData(ParticleID::b),
getParticleData(ParticleID::cbar)));
parentpair.push_back(make_pair(getParticleData(ParticleID::b),
getParticleData(ParticleID::ubar)));
case 4:
parentpair.push_back(make_pair(getParticleData(ParticleID::s),
getParticleData(ParticleID::cbar)));
parentpair.push_back(make_pair(getParticleData(ParticleID::d),
getParticleData(ParticleID::cbar)));
case 3:
parentpair.push_back(make_pair(getParticleData(ParticleID::s),
getParticleData(ParticleID::ubar)));
case 2:
parentpair.push_back(make_pair(getParticleData(ParticleID::d),
getParticleData(ParticleID::ubar)));
default:
;
}
// possible children
typedef Selector<tDMPtr> DecaySelector;
// for W+
DecaySelector wpdec = getParticleData(ParticleID::Wplus)->decaySelector();
vector<PDPair> wpdecays;
for(DecaySelector::const_iterator cit=wpdec.begin();cit!=wpdec.end();++cit) {
if(cit->second->orderedProducts().size()!=2) continue;
if(cit->second->orderedProducts()[0]->id()>0)
wpdecays.push_back(make_pair(cit->second->orderedProducts()[0],
cit->second->orderedProducts()[1]));
else
wpdecays.push_back(make_pair(cit->second->orderedProducts()[1],
cit->second->orderedProducts()[0]));
}
// for W-
DecaySelector wmdec = getParticleData(ParticleID::Wminus)->decaySelector();
vector<PDPair> wmdecays;
for(DecaySelector::const_iterator cit=wmdec.begin();cit!=wmdec.end();++cit) {
if(cit->second->orderedProducts().size()!=2) continue;
if(cit->second->orderedProducts()[0]->id()>0)
wmdecays.push_back(make_pair(cit->second->orderedProducts()[0],
cit->second->orderedProducts()[1]));
else
wmdecays.push_back(make_pair(cit->second->orderedProducts()[1],
cit->second->orderedProducts()[0]));
}
vector<PDPair>::const_iterator parent = parentpair.begin();
for (; parent != parentpair.end(); ++parent) {
// W- modes
if(wminus) {
for(unsigned int ix=0;ix<wmdecays.size();++ix) {
add(new_ptr((Tree2toNDiagram(2), parent->first, parent->second,
1, WMinus(), 3, higgs, 3, WMinus(),
5, wmdecays[ix].first,5, wmdecays[ix].second,-1)));
}
}
// W+ modes
if(wplus) {
for(unsigned int ix=0;ix<wpdecays.size();++ix) {
add(new_ptr((Tree2toNDiagram(2), parent->second->CC(), parent->first->CC(),
1, WPlus(), 3, higgs, 3, WPlus(), 5, wpdecays[ix].first,
5, wpdecays[ix].second, -1)));
}
}
}
}
void MEPP2WH::doinit() {
// get the vedrtex pointers from the SM object
tcHwSMPtr hwsm= dynamic_ptr_cast<tcHwSMPtr>(standardModel());
if(!hwsm)
throw InitException() << "Wrong type of StandardModel object in "
<< "MEPP2WH::doinit() the Herwig"
<< " version must be used"
<< Exception::runerror;
// set the vertex
setWWHVertex(hwsm->vertexWWH());
higgs(getParticleData(ParticleID::h0));
MEfftoVH::doinit();
}
diff --git a/MatrixElement/Hadron/MEPP2WH.h b/MatrixElement/Hadron/MEPP2WH.h
--- a/MatrixElement/Hadron/MEPP2WH.h
+++ b/MatrixElement/Hadron/MEPP2WH.h
@@ -1,154 +1,119 @@
// -*- C++ -*-
#ifndef HERWIG_MEPP2WH_H
#define HERWIG_MEPP2WH_H
//
// This is the declaration of the MEPP2WH class.
//
#include "Herwig/MatrixElement/MEfftoVH.h"
namespace Herwig {
using namespace ThePEG;
/**
* The MEPP2WH class provides the matrix elements for the production of
* the \f$W^\pm\f$ boson in association with the Higgs in hadron collisions.
*
* @see \ref MEPP2WHInterfaces "The interfaces"
* defined for MEPP2WH.
*/
class MEPP2WH: public MEfftoVH {
public:
/**
* Default constructor
*/
MEPP2WH();
/** @name Virtual functions required by the MEBase class. */
//@{
/**
* Add all possible diagrams with the add() function.
*/
virtual void getDiagrams() 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 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();
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<MEPP2WH> initMEPP2WH;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEPP2WH & operator=(const MEPP2WH &);
private:
/**
* Which intermediate \f$W^\pm\f$ bosons to include
*/
unsigned int _plusminus;
};
}
-#include "ThePEG/Utilities/ClassTraits.h"
-
-namespace ThePEG {
-
-/** @cond TRAITSPECIALIZATIONS */
-
-/** This template specialization informs ThePEG about the
- * base classes of MEPP2WH. */
-template <>
-struct BaseClassTrait<Herwig::MEPP2WH,1> {
- /** Typedef of the first base class of MEPP2WH. */
- typedef Herwig::MEfftoVH NthBase;
-};
-
-/** This template specialization informs ThePEG about the name of
- * the MEPP2WH class and the shared object where it is defined. */
-template <>
-struct ClassTraits<Herwig::MEPP2WH>
- : public ClassTraitsBase<Herwig::MEPP2WH> {
- /** Return a platform-independent class name */
- static string className() { return "Herwig::MEPP2WH"; }
- /**
- * The name of a file containing the dynamic library where the class
- * MEPP2WH is implemented. It may also include several, space-separated,
- * libraries if the class MEPP2WH 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_MEPP2WH_H */
diff --git a/MatrixElement/Hadron/MEPP2WJet.cc b/MatrixElement/Hadron/MEPP2WJet.cc
--- a/MatrixElement/Hadron/MEPP2WJet.cc
+++ b/MatrixElement/Hadron/MEPP2WJet.cc
@@ -1,835 +1,838 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2WJet class.
//
#include "MEPP2WJet.h"
+#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "ThePEG/Utilities/SimplePhaseSpace.h"
#include "ThePEG/Cuts/Cuts.h"
#include "Herwig/MatrixElement/HardVertex.h"
using namespace Herwig;
MEPP2WJet::MEPP2WJet() : _process(0), _maxflavour(5), _plusminus(0),
_wdec(0), _widthopt(1)
{}
void MEPP2WJet::doinit() {
HwMEBase::doinit();
_wplus = getParticleData(ThePEG::ParticleID::Wplus );
_wminus = getParticleData(ThePEG::ParticleID::Wminus);
// cast the SM pointer to the Herwig SM pointer
ThePEG::Ptr<Herwig::StandardModel>::transient_const_pointer
hwsm=ThePEG::dynamic_ptr_cast< ThePEG::Ptr<Herwig::StandardModel>
::transient_const_pointer>(standardModel());
// do the initialisation
if(!hwsm)
throw InitException() << "Must be Herwig::StandardModel in MEPP2WJet::doinit()"
<< Exception::runerror;
// set the vertex pointers
_theFFWVertex = hwsm->vertexFFW();
_theQQGVertex = hwsm->vertexFFG();
}
-ClassDescription<MEPP2WJet> MEPP2WJet::initMEPP2WJet;
-// Definition of the static class description member.
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEPP2WJet,HwMEBase>
+describeHerwigMEPP2WJet("Herwig::MEPP2WJet", "HwMEHadron.so");
void MEPP2WJet::Init() {
static ClassDocumentation<MEPP2WJet> documentation
("The MEPP2WJet class implements the matrix element for W + jet production");
static Parameter<MEPP2WJet,unsigned int> interfaceMaxFlavour
( "MaxFlavour",
"The heaviest incoming quark flavour this matrix element is allowed to handle "
"(if applicable).",
&MEPP2WJet::_maxflavour, 5, 0, 8, false, false, true);
static Switch<MEPP2WJet,unsigned int> interfaceProcess
("Process",
"Which subprocesses to include",
&MEPP2WJet::_process, 0, false, false);
static SwitchOption interfaceProcessAll
(interfaceProcess,
"All",
"Include all subprocesses",
0);
static SwitchOption interfaceProcessqqbar
(interfaceProcess,
"qqbar",
"Only include q qbar -> W g process",
1);
static SwitchOption interfaceProcessqg
(interfaceProcess,
"qg",
"Only include the q g -> W q process",
2);
static SwitchOption interfaceProcessqbarg
(interfaceProcess,
"qbarg",
"Only include the qbar g -> W qbar process",
3);
static Switch<MEPP2WJet,unsigned int> interfacePlusMinus
("Wcharge",
"Which intermediate W bosons to include",
&MEPP2WJet::_plusminus, 0, false, false);
static SwitchOption interfacePlusMinusAll
(interfacePlusMinus,
"Both",
"Include W+ and W-",
0);
static SwitchOption interfacePlusMinusPlus
(interfacePlusMinus,
"Plus",
"Only include W+",
1);
static SwitchOption interfacePlusMinusMinus
(interfacePlusMinus,
"Minus",
"Only include W-",
2);
static Switch<MEPP2WJet,unsigned int> interfaceWDecay
("WDecay",
"Which processes to include",
&MEPP2WJet::_wdec, 0, false, false);
static SwitchOption interfaceWDecayAll
(interfaceWDecay,
"All",
"Include all SM fermions as outgoing particles",
0);
static SwitchOption interfaceWDecayQuarks
(interfaceWDecay,
"Quarks",
"Only include outgoing quarks",
1);
static SwitchOption interfaceWDecayLeptons
(interfaceWDecay,
"Leptons",
"All include outgoing leptons",
2);
static SwitchOption interfaceWDecayElectron
(interfaceWDecay,
"Electron",
"Only include outgoing e nu_e",
3);
static SwitchOption interfaceWDecayMuon
(interfaceWDecay,
"Muon",
"Only include outgoing mu nu_mu",
4);
static SwitchOption interfaceWDecayTau
(interfaceWDecay,
"Tau",
"Only include outgoing tauu nu_tau",
5);
static SwitchOption interfaceWDecayUpDown
(interfaceWDecay,
"UpDown",
"Only include outgoing u dbar/ d ubar",
6);
static SwitchOption interfaceWDecayUpStrange
(interfaceWDecay,
"UpStrange",
"Only include outgoing u sbar/ s ubar",
7);
static SwitchOption interfaceWDecayUpBottom
(interfaceWDecay,
"UpBottom",
"Only include outgoing u bbar/ b ubar",
8);
static SwitchOption interfaceWDecayCharmDown
(interfaceWDecay,
"CharmDown",
"Only include outgoing c dbar/ d cbar",
9);
static SwitchOption interfaceWDecayCharmStrange
(interfaceWDecay,
"CharmStrange",
"Only include outgoing c sbar/ s cbar",
10);
static SwitchOption interfaceWDecayCharmBottom
(interfaceWDecay,
"CharmBottom",
"Only include outgoing c bbar/ b cbar",
11);
static Switch<MEPP2WJet,unsigned int> interfaceWidthOption
("WidthOption",
"The option for handling the width of the off-shell W boson",
&MEPP2WJet::_widthopt, 1, false, false);
static SwitchOption interfaceWidthOptionFixedDenominator
(interfaceWidthOption,
"FixedDenominator",
"Use a fixed with in the W propagator but the full matrix element"
" in the numerator",
1);
static SwitchOption interfaceWidthOptionAllRunning
(interfaceWidthOption,
"AllRunning",
"Use a running width in the W propagator and the full matrix "
"element in the numerator",
2);
}
void MEPP2WJet::getDiagrams() const {
// which intgermediates to include
bool wplus = _plusminus==0 || _plusminus==1;
bool wminus = _plusminus==0 || _plusminus==2;
// possible incoming and outgoing particles
typedef std::vector<pair<long,long> > Pairvector;
// possible parents
Pairvector parentpair;
parentpair.reserve(6);
// don't even think of putting 'break' in here!
switch(_maxflavour) {
case 5:
parentpair.push_back(make_pair(ParticleID::b, ParticleID::cbar));
parentpair.push_back(make_pair(ParticleID::b, ParticleID::ubar));
case 4:
parentpair.push_back(make_pair(ParticleID::s, ParticleID::cbar));
parentpair.push_back(make_pair(ParticleID::d, ParticleID::cbar));
case 3:
parentpair.push_back(make_pair(ParticleID::s, ParticleID::ubar));
case 2:
parentpair.push_back(make_pair(ParticleID::d, ParticleID::ubar));
default:
;
}
// possible children
Pairvector childpair;
childpair.reserve(9);
childpair.push_back(make_pair(ParticleID::eminus, ParticleID::nu_ebar));
childpair.push_back(make_pair(ParticleID::muminus, ParticleID::nu_mubar));
childpair.push_back(make_pair(ParticleID::tauminus, ParticleID::nu_taubar));
childpair.push_back(make_pair(ParticleID::d, ParticleID::ubar));
childpair.push_back(make_pair(ParticleID::s, ParticleID::ubar));
childpair.push_back(make_pair(ParticleID::b, ParticleID::ubar));
childpair.push_back(make_pair(ParticleID::d, ParticleID::cbar));
childpair.push_back(make_pair(ParticleID::s, ParticleID::cbar));
childpair.push_back(make_pair(ParticleID::b, ParticleID::cbar));
// gluon for diagrams
tcPDPtr g = getParticleData(ParticleID::g);
// loop over the children
bool lepton,quark;
Pairvector::const_iterator child = childpair.begin();
for (; child != childpair.end(); ++child) {
// allowed leptonic decay
lepton=child->first>10&&
(_wdec==0||_wdec==2||
(abs(child->first)-5)/2==int(_wdec));
// allowed quark decay
quark =abs(child->second)<10&&
(_wdec==0||_wdec==1||
(abs(child->second)==2&&(abs(child->first)+11)/2==int(_wdec))||
(abs(child->second)==4&&(abs(child->first)+17)/2==int(_wdec)));
// if decay not allowed skip
if(!(quark||lepton)) continue;
// decay products
tcPDPtr lNeg1 = getParticleData(child->first);
tcPDPtr lNeg2 = getParticleData(child->second);
tcPDPtr lPos1 = lNeg2->CC();
tcPDPtr lPos2 = lNeg1->CC();
Pairvector::const_iterator parent = parentpair.begin();
for (; parent != parentpair.end(); ++parent) {
// parents
tcPDPtr qNeg1 = getParticleData(parent->first);
tcPDPtr qNeg2 = getParticleData(parent->second);
tcPDPtr qPos1 = qNeg2->CC();
tcPDPtr qPos2 = qNeg1->CC();
// diagrams
// q qbar annhilation processes
if(_process==0||_process==1) {
// q qbar -> W- g
if(wminus) {
add(new_ptr((Tree2toNDiagram(3), qNeg1, qNeg2, qNeg2, 1, _wminus,
2, g, 4, lNeg1, 4, lNeg2, -1)));
add(new_ptr((Tree2toNDiagram(3), qNeg1, qNeg1, qNeg2, 2, _wminus,
1, g, 4, lNeg1, 4, lNeg2, -2)));
}
// q qbar -> W+ g
if(wplus) {
add(new_ptr((Tree2toNDiagram(3), qPos1, qPos2, qPos2, 1, _wplus,
2, g, 4, lPos1, 4, lPos2, -3)));
add(new_ptr((Tree2toNDiagram(3), qPos1, qPos1, qPos2, 2, _wplus,
1, g, 4, lPos1, 4, lPos2, -4)));
}
}
// q g compton
if(_process==0||_process==2) {
if(wminus) {
add(new_ptr((Tree2toNDiagram(3), qNeg1, qPos1, g , 1, _wminus,
2, qPos1, 4, lNeg1, 4, lNeg2, -5)));
add(new_ptr((Tree2toNDiagram(2), qNeg1, g, 1, qNeg1, 3, _wminus,
3, qPos1, 4, lNeg1, 4, lNeg2, -6)));
}
if(wplus) {
add(new_ptr((Tree2toNDiagram(3), qPos1, qNeg1, g, 1, _wplus,
2, qNeg1, 4, lPos1, 4, lPos2, -7)));
add(new_ptr((Tree2toNDiagram(2), qPos1, g, 1, qNeg1, 3, _wplus,
3, qNeg1, 4, lPos1, 4, lPos2, -8)));
}
}
// qbar g compton
if(_process==0||_process==3) {
if(wminus) {
add(new_ptr((Tree2toNDiagram(3), qNeg2, qPos2, g, 1, _wminus,
2, qPos2, 4, lNeg1, 4, lNeg2, -9 )));
add(new_ptr((Tree2toNDiagram(2), qNeg2, g, 1, qNeg2, 3, _wminus,
3, qPos2, 4, lNeg1, 4, lNeg2, -10)));
}
if(wplus) {
add(new_ptr((Tree2toNDiagram(3), qPos2, qNeg2, g, 1, _wplus,
2, qNeg2, 4, lPos1, 4, lPos2, -11)));
add(new_ptr((Tree2toNDiagram(2), qPos2, g, 1, qPos2, 3, _wplus,
3, qNeg2, 4, lPos1, 4, lPos2, -12)));
}
}
}
}
}
unsigned int MEPP2WJet::orderInAlphaS() const {
return 1;
}
unsigned int MEPP2WJet::orderInAlphaEW() const {
return 2;
}
void MEPP2WJet::persistentOutput(PersistentOStream & os) const {
os << _theFFWVertex << _theQQGVertex << _wplus << _widthopt
<< _wminus << _process << _maxflavour << _plusminus << _wdec;
}
void MEPP2WJet::persistentInput(PersistentIStream & is, int) {
is >> _theFFWVertex >> _theQQGVertex >> _wplus >> _widthopt
>> _wminus >> _process >> _maxflavour >> _plusminus >> _wdec;
}
int MEPP2WJet::nDim() const {
return 5;
}
Selector<const ColourLines *>
MEPP2WJet::colourGeometries(tcDiagPtr diag) const {
// colour lines for q qbar -> W g
static const ColourLines cqqbar[4]={ColourLines("1 -2 5,-3 -5"),
ColourLines("1 5, -5 2 -3"),
ColourLines("1 -2 5,-3 -5,6 -7"),
ColourLines("1 5, -5 2 -3,6 -7")};
// colour lines for q g -> W q
static const ColourLines cqg [4]={ColourLines("1 2 -3,3 5"),
ColourLines("1 -2,2 3 5"),
ColourLines("1 2 -3,3 5,6 -7"),
ColourLines("1 -2,2 3 5,6 -7")};
// colour lines for qbar q -> W qbar
static const ColourLines cqbarg[4]={ColourLines("-1 -2 3,-3 -5"),
ColourLines("-1 2,-2 -3 -5"),
ColourLines("-1 -2 3,-3 -5,6 -7"),
ColourLines("-1 2,-2 -3 -5,6 -7")};
// select the correct line
unsigned int icol = mePartonData()[3]->coloured() ? 2 : 0;
Selector<const ColourLines *> sel;
switch(abs(diag->id())) {
case 1 : case 3:
sel.insert(1.0, &cqqbar[icol]);
break;
case 2 : case 4:
sel.insert(1.0, &cqqbar[icol+1]);
break;
case 5 : case 7:
sel.insert(1.0, &cqg[icol]);
break;
case 6 : case 8:
sel.insert(1.0, &cqg[icol+1]);
break;
case 9 : case 11:
sel.insert(1.0, &cqbarg[icol]);
break;
case 10 : case 12:
sel.insert(1.0, &cqbarg[icol+1]);
break;
}
return sel;
}
Selector<MEBase::DiagramIndex>
MEPP2WJet::diagrams(const DiagramVector & diags) const {
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i ) {
int id=abs(diags[i]->id());
if (id <= 2 ) sel.insert(meInfo()[id- 1],i);
else if(id <= 4 ) sel.insert(meInfo()[id- 3],i);
else if(id <= 6 ) sel.insert(meInfo()[id- 5],i);
else if(id <= 8 ) sel.insert(meInfo()[id- 7],i);
else if(id <= 10) sel.insert(meInfo()[id- 9],i);
else if(id <= 12) sel.insert(meInfo()[id-11],i);
}
return sel;
}
Energy2 MEPP2WJet::scale() const {
return _scale;
}
CrossSection MEPP2WJet::dSigHatDR() const {
return me2()*jacobian()/(16.0*sqr(Constants::pi)*sHat())*sqr(hbarc);
}
bool MEPP2WJet::generateKinematics(const double * r) {
// initialize jacobian
jacobian(1.);
// cms energy
Energy ecm=sqrt(sHat());
// find the right W pointer
tcPDPtr wdata = mePartonData()[3]->iCharge()+mePartonData()[4]->iCharge() > 0 ?
_wplus :_wminus;
// first generate the mass of the off-shell gauge boson
// minimum mass of the
tcPDVector ptemp;
ptemp.push_back(mePartonData()[3]);
ptemp.push_back(mePartonData()[4]);
Energy2 minMass2 = max(lastCuts().minSij(mePartonData()[3],mePartonData()[4]),
lastCuts().minS(ptemp));
// minimum pt of the jet
Energy ptmin = max(lastCuts().minKT(mePartonData()[2]),
lastCuts().minKT(wdata));
// maximum mass of the gauge boson so pt is possible
Energy2 maxMass2 = min(ecm*(ecm-2.*ptmin),lastCuts().maxS(ptemp));
if(maxMass2<=ZERO||minMass2<ZERO) return false;
// also impose the limits from the ParticleData object
minMass2 = max(minMass2,sqr(wdata->massMin()));
maxMass2 = min(maxMass2,sqr(wdata->massMax()));
// return if not kinematically possible
if(minMass2>maxMass2) return false;
// generation of the mass
Energy M(wdata->mass()),Gamma(wdata->width());
Energy2 M2(sqr(M)),MG(M*Gamma);
double rhomin = atan2((minMass2-M2),MG);
double rhomax = atan2((maxMass2-M2),MG);
_mw2=M2+MG*tan(rhomin+r[1]*(rhomax-rhomin));
Energy mw=sqrt(_mw2);
// jacobian
jacobian(jacobian()*(sqr(_mw2-M2)+sqr(MG))/MG*(rhomax-rhomin)/sHat());
// set the masses of the outgoing particles in the 2-2 scattering
meMomenta()[2].setMass(ZERO);
Lorentz5Momentum pw(mw);
// generate the polar angle of the hard scattering
double ctmin(-1.0), ctmax(1.0);
Energy q(ZERO);
try {
q = SimplePhaseSpace::getMagnitude(sHat(), meMomenta()[2].mass(),mw);
}
catch ( ImpossibleKinematics ) {
return false;
}
Energy2 pq = sqrt(sHat())*q;
if ( ptmin > ZERO ) {
double ctm = 1.0 - sqr(ptmin/q);
if ( ctm <= 0.0 ) return false;
ctmin = max(ctmin, -sqrt(ctm));
ctmax = min(ctmax, sqrt(ctm));
}
if ( ctmin >= ctmax ) return false;
double cth = getCosTheta(ctmin, ctmax, r[0]);
// momenta of particle in hard scattering
Energy pt = q*sqrt(1.0-sqr(cth));
double phi=2.0*Constants::pi*r[2];
meMomenta()[2].setVect(Momentum3( pt*sin(phi), pt*cos(phi), q*cth));
pw.setVect( Momentum3(-pt*sin(phi),-pt*cos(phi),-q*cth));
meMomenta()[2].rescaleEnergy();
pw.rescaleEnergy();
// set the scale
_scale = _mw2+sqr(pt);
// generate the momenta of the W decay products
meMomenta()[3].setMass(mePartonData()[3]->mass());
meMomenta()[4].setMass(mePartonData()[4]->mass());
Energy q2 = ZERO;
try {
q2 = SimplePhaseSpace::getMagnitude(_mw2, meMomenta()[3].mass(),
meMomenta()[4].mass());
} catch ( ImpossibleKinematics ) {
return false;
}
double cth2 =-1.+2.*r[3];
double phi2=Constants::twopi*r[4];
Energy pt2 =q2*sqrt(1.-sqr(cth2));
Lorentz5Momentum pl[2]={Lorentz5Momentum( pt2*cos(phi2), pt2*sin(phi2), q2*cth2,ZERO,
meMomenta()[3].mass()),
Lorentz5Momentum(-pt2*cos(phi2),-pt2*sin(phi2),-q2*cth2,ZERO,
meMomenta()[4].mass())};
pl[0].rescaleEnergy();
pl[1].rescaleEnergy();
Boost boostv(pw.boostVector());
pl[0].boost(boostv);
pl[1].boost(boostv);
meMomenta()[3] = pl[0];
meMomenta()[4] = pl[1];
// check passes all the cuts
vector<LorentzMomentum> out(3);
out[0] = meMomenta()[2];
out[1] = meMomenta()[3];
out[2] = meMomenta()[4];
tcPDVector tout(3);
tout[0] = mePartonData()[2];
tout[1] = mePartonData()[3];
tout[2] = mePartonData()[4];
if ( !lastCuts().passCuts(tout, out, mePartonData()[0], mePartonData()[1]) )
return false;
// jacobian
jacobian((pq/sHat())*Constants::pi*jacobian()/8./sqr(Constants::pi)*q2/mw);
return true;
}
double MEPP2WJet::me2() const {
InvEnergy2 output(ZERO);
// construct spinors for the leptons (always the same)
vector<SpinorBarWaveFunction> lm;
vector<SpinorWaveFunction> lp;
SpinorBarWaveFunction lmout(meMomenta()[3],mePartonData()[3],outgoing);
SpinorWaveFunction lpout(meMomenta()[4],mePartonData()[4],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
lmout.reset(ix);lm.push_back(lmout);
lpout.reset(ix);lp.push_back(lpout);
}
// q g to q W
if(mePartonData()[0]->id()<=6&&mePartonData()[0]->id()>0&&
mePartonData()[1]->id()==ParticleID::g) {
// polarization states for the particles
vector<SpinorWaveFunction> fin;
vector<VectorWaveFunction> gin;
vector<SpinorBarWaveFunction> fout;
SpinorWaveFunction qin (meMomenta()[0],mePartonData()[0],incoming);
VectorWaveFunction glin(meMomenta()[1],mePartonData()[1],incoming);
SpinorBarWaveFunction qout(meMomenta()[2],mePartonData()[2],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
qin.reset(ix) ; fin.push_back(qin);
glin.reset(2*ix); gin.push_back(glin);
qout.reset(ix);fout.push_back(qout);
}
output=qgME(fin,gin,fout,lm,lp);
}
// qbar g to qbar W
else if(mePartonData()[0]->id()>=-6&&mePartonData()[0]->id()<0&&
mePartonData()[1]->id()==ParticleID::g) {
vector<SpinorBarWaveFunction> ain;
vector<VectorWaveFunction> gin;
vector<SpinorWaveFunction> aout;
SpinorBarWaveFunction qbin (meMomenta()[0],mePartonData()[0],incoming);
VectorWaveFunction glin (meMomenta()[1],mePartonData()[1],incoming);
SpinorWaveFunction qbout(meMomenta()[2],mePartonData()[2],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
qbin.reset(ix) ; ain.push_back(qbin);
glin.reset(2*ix) ; gin.push_back(glin);
qbout.reset(ix);aout.push_back(qbout);
}
output=qbargME(ain,gin,aout,lm,lp);
}
// q qbar to g W
else {
vector<SpinorWaveFunction> fin;
vector<SpinorBarWaveFunction> ain;
vector<VectorWaveFunction> gout;
SpinorWaveFunction qin (meMomenta()[0],mePartonData()[0],incoming);
SpinorBarWaveFunction qbin(meMomenta()[1],mePartonData()[1],incoming);
VectorWaveFunction glout(meMomenta()[2],mePartonData()[2],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
qin.reset(ix) ; fin.push_back(qin);
qbin.reset(ix) ; ain.push_back(qbin);
glout.reset(2*ix); gout.push_back(glout);
}
output=qqbarME(fin,ain,gout,lm,lp);
}
return output*sHat();
}
InvEnergy2 MEPP2WJet::qqbarME(vector<SpinorWaveFunction> & fin,
vector<SpinorBarWaveFunction> & ain,
vector<VectorWaveFunction> & gout,
vector<SpinorBarWaveFunction> & lm,
vector<SpinorWaveFunction> & lp,
bool calc) const {
// if calculation spin corrections construct the me
if(calc) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1,PDT::Spin1Half,
PDT::Spin1Half));
// some integers
unsigned int ihel1,ihel2,ohel1,ohel2,ohel3;
// find the right W pointer
tcPDPtr wdata = mePartonData()[3]->iCharge()+mePartonData()[4]->iCharge() > 0
? _wplus :_wminus;
// compute the W current for speed
VectorWaveFunction bcurr[2][2];
for(ohel2=0;ohel2<2;++ohel2) {
for(ohel3=0;ohel3<2;++ohel3) {
bcurr[ohel2][ohel3] = _theFFWVertex->evaluate(_mw2,_widthopt,wdata,
lp[ohel3],lm[ohel2]);
}
}
double me[3]={0.,0.,0.};
Complex diag[2];
SpinorWaveFunction inters;
SpinorBarWaveFunction interb;
for(ihel1=0;ihel1<2;++ihel1) {
for(ihel2=0;ihel2<2;++ihel2) {
for(ohel1=0;ohel1<2;++ohel1) {
// intermediates for the diagrams
inters=_theQQGVertex->evaluate(_scale,5,mePartonData()[0],
fin[ihel1],gout[ohel1]);
interb=_theQQGVertex->evaluate(_scale,5,mePartonData()[1],
ain[ihel2],gout[ohel1]);
for(ohel2=0;ohel2<2;++ohel2) {
for(ohel3=0;ohel3<2;++ohel3) {
diag[0] = _theFFWVertex->evaluate(_mw2,fin[ihel1],interb,
bcurr[ohel2][ohel3]);
diag[1] = _theFFWVertex->evaluate(_mw2,inters,ain[ihel2],
bcurr[ohel2][ohel3]);
// diagram contributions
me[1] += norm(diag[0]);
me[2] += norm(diag[1]);
// total
diag[0] += diag[1];
me[0] += norm(diag[0]);
if(calc) _me(ihel1,ihel2,2*ohel1,ohel2,ohel3) = diag[0];
}
}
}
}
}
// results
// initial state spin and colour average
double colspin=1./9./4.;
// and C_F N_c from matrix element
colspin *= 4.;
// colour factor for the W decay
if(mePartonData()[3]->coloured()) colspin*=3.;
DVector save;
for(unsigned int ix=0;ix<3;++ix) {
me[ix]*=colspin;
if(ix>0) save.push_back(me[ix]);
}
meInfo(save);
return me[0] * UnitRemoval::InvE2;
}
InvEnergy2 MEPP2WJet::qgME(vector<SpinorWaveFunction> & fin,
vector<VectorWaveFunction> & gin,
vector<SpinorBarWaveFunction> & fout,
vector<SpinorBarWaveFunction> & lm,
vector<SpinorWaveFunction> & lp,
bool calc) const {
// if calculation spin corrections construct the me
if(calc) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1,
PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half));
// find the right W pointer
tcPDPtr wdata = mePartonData()[3]->iCharge()+mePartonData()[4]->iCharge() > 0 ?
_wplus :_wminus;
// some integers
unsigned int ihel1,ihel2,ohel1,ohel2,ohel3;
// compute the leptonic W current for speed
VectorWaveFunction bcurr[2][2];
for(ohel2=0;ohel2<2;++ohel2) {
for(ohel3=0;ohel3<2;++ohel3) {
bcurr[ohel2][ohel3] = _theFFWVertex->evaluate(_mw2,_widthopt,wdata,
lp[ohel3],lm[ohel2]);
}
}
// compute the matrix elements
double me[3]={0.,0.,0.};
Complex diag[2];
SpinorWaveFunction inters;
SpinorBarWaveFunction interb;
for(ihel1=0;ihel1<2;++ihel1) {
for(ihel2=0;ihel2<2;++ihel2) {
for(ohel1=0;ohel1<2;++ohel1) {
// intermediates for the diagrams
interb=_theQQGVertex->evaluate(_scale,5,mePartonData()[2],
fout[ohel1],gin[ihel2]);
inters=_theQQGVertex->evaluate(_scale,5,mePartonData()[0],
fin[ihel1],gin[ihel2]);
for(ohel2=0;ohel2<2;++ohel2) {
for(ohel3=0;ohel3<2;++ohel3) {
diag[0]=_theFFWVertex->evaluate(_mw2,fin[ihel1],interb,
bcurr[ohel2][ohel3]);
diag[1]=_theFFWVertex->evaluate(_mw2,inters,fout[ohel1],
bcurr[ohel2][ohel3]);
// diagram contributions
me[1] += norm(diag[0]);
me[2] += norm(diag[1]);
// total
diag[0] += diag[1];
me[0] += norm(diag[0]);
if(calc) _me(ihel1,2*ihel2,ohel1,ohel2,ohel3) = diag[0];
}
}
}
}
}
// results
// initial state spin and colour average
double colspin=1./24./4.;
// and C_F N_c from matrix element
colspin *=4.;
// colour factor for the W decay
if(mePartonData()[3]->coloured()) colspin*=3.;
DVector save;
for(unsigned int ix=0;ix<3;++ix) {
me[ix]*=colspin;
if(ix>0) save.push_back(me[ix]);
}
meInfo(save);
return me[0] * UnitRemoval::InvE2;
}
InvEnergy2 MEPP2WJet::qbargME(vector<SpinorBarWaveFunction> & fin,
vector<VectorWaveFunction> & gin,
vector<SpinorWaveFunction> & fout,
vector<SpinorBarWaveFunction> & lm,
vector<SpinorWaveFunction> & lp,
bool calc) const {
// if calculation spin corrections construct the me
if(calc) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1,
PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half));
// find the right W pointer
tcPDPtr wdata = mePartonData()[3]->iCharge()+mePartonData()[4]->iCharge() > 0 ?
_wplus :_wminus;
// some integers
unsigned int ihel1,ihel2,ohel1,ohel2,ohel3;
// compute the leptonic W current for speed
VectorWaveFunction bcurr[2][2];
for(ohel2=0;ohel2<2;++ohel2) {
for(ohel3=0;ohel3<2;++ohel3) {
bcurr[ohel2][ohel3] = _theFFWVertex->evaluate(_mw2,_widthopt,wdata,
lp[ohel3],lm[ohel2]);
}
}
// compute the matrix elements
double me[3]={0.,0.,0.};
Complex diag[2];
SpinorWaveFunction inters;
SpinorBarWaveFunction interb;
for(ihel1=0;ihel1<2;++ihel1) {
for(ihel2=0;ihel2<2;++ihel2) {
for(ohel1=0;ohel1<2;++ohel1) {
// intermediates for the diagrams
inters=_theQQGVertex->evaluate(_scale,5,mePartonData()[2],
fout[ohel1],gin[ihel2]);
interb=_theQQGVertex->evaluate(_scale,5,mePartonData()[0],
fin[ihel1],gin[ihel2]);
for(ohel2=0;ohel2<2;++ohel2) {
for(ohel3=0;ohel3<2;++ohel3) {
diag[0]= _theFFWVertex->evaluate(_mw2,inters,fin[ihel1],
bcurr[ohel2][ohel3]);
diag[1]= _theFFWVertex->evaluate(_mw2,fout[ohel1],interb,
bcurr[ohel2][ohel3]);
// diagram contributions
me[1] += norm(diag[0]);
me[2] += norm(diag[1]);
// total
diag[0] += diag[1];
me[0] += norm(diag[0]);
if(calc) _me(ihel1,2*ihel2,ohel1,ohel2,ohel3) = diag[0];
}
}
}
}
}
// results
// initial state spin and colour average
double colspin=1./24./4.;
// and C_F N_c from matrix element
colspin *= 4.;
// colour factor for the W decay
if(mePartonData()[3]->coloured()) colspin*=3.;
DVector save;
for(unsigned int ix=0;ix<3;++ix) {
me[ix]*=colspin;
if(ix>0) save.push_back(me[ix]);
}
meInfo(save);
return me[0] * UnitRemoval::InvE2;
}
void MEPP2WJet::constructVertex(tSubProPtr sub) {
// extract the particles in the hard process
ParticleVector hard(5);
// incoming
hard[0]=sub->incoming().first;
hard[1]=sub->incoming().second;
if((hard[0]->id()<0&&hard[1]->id()<=6)||
hard[0]->id()==ParticleID::g) swap(hard[0],hard[1]);
// outgoing
for(unsigned int ix=0;ix<3;++ix) {
unsigned int iloc;
PPtr mother=sub->outgoing()[ix]->parents()[0];
if(mother&&abs(mother->id())==ParticleID::Wplus) {
if(sub->outgoing()[ix]->id()>0) iloc=3;
else iloc=4;
}
else iloc=2;
hard[iloc]=sub->outgoing()[ix];
}
// wavefunctions for the W decay products
vector<SpinorBarWaveFunction> lm;
vector<SpinorWaveFunction> lp;
SpinorBarWaveFunction(lm,hard[3],outgoing,true,true);
SpinorWaveFunction (lp,hard[4],outgoing,true,true);
// identify hard process and calculate matrix element
// q g to q W
if(hard[0]->id()<=6&&hard[0]->id()>0&&hard[1]->id()==ParticleID::g) {
vector<SpinorWaveFunction> fin;
vector<VectorWaveFunction> gin;
vector<SpinorBarWaveFunction> fout;
SpinorWaveFunction (fin ,hard[0],incoming,false,true);
VectorWaveFunction (gin ,hard[1],incoming,false,true,true);
SpinorBarWaveFunction (fout,hard[2],outgoing,true ,true);
gin[1]=gin[2];
qgME(fin,gin,fout,lm,lp,true);
}
// qbar g to qbar W
else if(hard[0]->id()>=-6&&hard[0]->id()<0&&hard[1]->id()==ParticleID::g) {
vector<SpinorBarWaveFunction> ain;
vector<VectorWaveFunction> gin;
vector<SpinorWaveFunction> aout;
SpinorBarWaveFunction(ain ,hard[0],incoming,false,true);
VectorWaveFunction (gin ,hard[1],incoming,false,true,true);
SpinorWaveFunction (aout,hard[2],outgoing,true ,true);
gin[1]=gin[2];
qbargME(ain,gin,aout,lm,lp,true);
}
// q qbar to g W
else {
vector<SpinorWaveFunction> fin;
vector<SpinorBarWaveFunction> ain;
vector<VectorWaveFunction> gout;
SpinorWaveFunction (fin ,hard[0],incoming,false,true);
SpinorBarWaveFunction(ain ,hard[1],incoming,false,true);
VectorWaveFunction (gout,hard[2],outgoing,true ,true,true);
gout[1]=gout[2];
qqbarME(fin,ain,gout,lm,lp,true);
}
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(_me);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<5;++ix)
(hard[ix]->spinInfo())->productionVertex(hardvertex);
}
diff --git a/MatrixElement/Hadron/MEPP2WJet.h b/MatrixElement/Hadron/MEPP2WJet.h
--- a/MatrixElement/Hadron/MEPP2WJet.h
+++ b/MatrixElement/Hadron/MEPP2WJet.h
@@ -1,357 +1,322 @@
// -*- C++ -*-
#ifndef HERWIG_MEPP2WJet_H
#define HERWIG_MEPP2WJet_H
//
// This is the declaration of the MEPP2WJet class.
//
#include "Herwig/MatrixElement/HwMEBase.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.fh"
namespace Herwig {
using namespace ThePEG;
using namespace ThePEG::Helicity;
/**
* The MEPP2WJet class implements the matrix element for the production of
* a W boson and a jet including the decay of the W.
*
* @see \ref MEPP2WJetInterfaces "The interfaces"
* defined for MEPP2WJet.
*/
class MEPP2WJet: public HwMEBase {
public:
/**
* The default constructor.
*/
MEPP2WJet();
/** @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;
/**
* 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:
/**
* Matrix elements for the different subprocesses
*/
//@{
/**
* Matrix element for \f$q\bar{q}\to W^\pm g\f$.
* @param fin Spinors for incoming quark
* @param ain Spinors for incoming antiquark
* @param gout Polarization vectors for the outgoing gluon
* @param lm Spinors for outgoing lepton
* @param lp Spinors for outgoing antilepton
* @param me Whether or not to calculate the matrix element for spin correlations
**/
InvEnergy2 qqbarME(vector<SpinorWaveFunction> & fin,
vector<SpinorBarWaveFunction> & ain,
vector<VectorWaveFunction> & gout,
vector<SpinorBarWaveFunction> & lm,
vector<SpinorWaveFunction> & lp,
bool me=false) const;
/**
* Matrix element for \f$qg\to W^\pm q\f$.
* @param fin Spinors for incoming quark
* @param gin Polarization vectors for the incoming gluon
* @param fout Spinors for outgoing quark
* @param lm Spinors for outgoing lepton
* @param lp Spinors for outgoing antilepton
* @param me Whether or not to calculate the matrix element for spin correlations
**/
InvEnergy2 qgME(vector<SpinorWaveFunction> & fin,
vector<VectorWaveFunction> & gin,
vector<SpinorBarWaveFunction> & fout,
vector<SpinorBarWaveFunction> & lm,
vector<SpinorWaveFunction> & lp,
bool me=false) const;
/**
* Matrix element for \f$\bar{q}g\to W^\pm\bar{q}\f$.
* @param fin Spinors for incoming antiquark
* @param gin Polarization vectors for the incoming gluon
* @param fout Spinors for outgoing antiquark
* @param lm Spinors for outgoing lepton
* @param lp Spinors for outgoing antilepton
* @param me Whether or not to calculate the matrix element for spin correlations
**/
InvEnergy2 qbargME(vector<SpinorBarWaveFunction> & fin,
vector<VectorWaveFunction> & gin,
vector<SpinorWaveFunction> & fout,
vector<SpinorBarWaveFunction> & lm,
vector<SpinorWaveFunction> & lp,
bool me=false) const;
//@}
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();
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<MEPP2WJet> initMEPP2WJet;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEPP2WJet & operator=(const MEPP2WJet &);
private:
/**
* Vertices for the helicity amplitude calculation
*/
//@{
/**
* Pointer to the W vertex
*/
AbstractFFVVertexPtr _theFFWVertex;
/**
* Pointer to the \f$qqg\f$ vertex
*/
AbstractFFVVertexPtr _theQQGVertex;
//@}
/**
* @name Pointers to the W ParticleData objects
*/
//@{
/**
* The \f$W^+\f$ data pointer
*/
tcPDPtr _wplus;
/**
* The \f$W^-\f$ data pointer
*/
tcPDPtr _wminus;
//@}
/**
* @name Switches to control the particles in the hard process
*/
//@{
/**
* Subprocesses to include
*/
unsigned int _process;
/**
* Allowed flavours for the incoming quarks
*/
unsigned int _maxflavour;
/**
* Which charge states to include
*/
unsigned int _plusminus;
/**
* W decay modes
*/
unsigned int _wdec;
/**
* Option for the treatment of the W off-shell effects
*/
unsigned int _widthopt;
//@}
/**
* Matrix element for spin correlations
*/
mutable ProductionMatrixElement _me;
/**
* Storage of the scale to avoid the need to recalculate
*/
Energy2 _scale;
/**
* Storage of the off-shell W mass to avoid the need to recalculate
*/
Energy2 _mw2;
};
}
-#include "ThePEG/Utilities/ClassTraits.h"
-
-namespace ThePEG {
-
-/** @cond TRAITSPECIALIZATIONS */
-
-/** This template specialization informs ThePEG about the
- * base classes of MEPP2WJet. */
-template <>
-struct BaseClassTrait<Herwig::MEPP2WJet,1> {
- /** Typedef of the first base class of MEPP2WJet. */
- typedef Herwig::HwMEBase NthBase;
-};
-
-/** This template specialization informs ThePEG about the name of
- * the MEPP2WJet class and the shared object where it is defined. */
-template <>
-struct ClassTraits<Herwig::MEPP2WJet>
- : public ClassTraitsBase<Herwig::MEPP2WJet> {
- /** Return a platform-independent class name */
- static string className() { return "Herwig::MEPP2WJet"; }
- /**
- * The name of a file containing the dynamic library where the class
- * MEPP2WJet is implemented. It may also include several, space-separated,
- * libraries if the class MEPP2WJet 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_MEPP2WJet_H */
diff --git a/MatrixElement/Hadron/MEPP2ZH.cc b/MatrixElement/Hadron/MEPP2ZH.cc
--- a/MatrixElement/Hadron/MEPP2ZH.cc
+++ b/MatrixElement/Hadron/MEPP2ZH.cc
@@ -1,76 +1,79 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2ZH class.
//
#include "MEPP2ZH.h"
+#include "ThePEG/Utilities/DescribeClass.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/PDT/DecayMode.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
using namespace Herwig;
MEPP2ZH::MEPP2ZH()
{}
void MEPP2ZH::getDiagrams() const {
// find possible Z decays
typedef Selector<tDMPtr> DecaySelector;
DecaySelector Zdec = Z0()->decaySelector();
vector<PDPair> Zdecays;
for(DecaySelector::const_iterator cit=Zdec.begin();cit!=Zdec.end();++cit) {
if(cit->second->orderedProducts().size()!=2) continue;
if(cit->second->orderedProducts()[0]->id()>0)
Zdecays.push_back(make_pair(cit->second->orderedProducts()[0],
cit->second->orderedProducts()[1]));
else
Zdecays.push_back(make_pair(cit->second->orderedProducts()[1],
cit->second->orderedProducts()[0]));
}
// create the diagrams
for ( int ix=1; ix<=int(maxFlavour()); ++ix ) {
tcPDPtr q = getParticleData(ix);
tcPDPtr qbar = q->CC();
for(unsigned int iz=0;iz<Zdecays.size();++iz) {
add(new_ptr((Tree2toNDiagram(2), q, qbar,
1, Z0(), 3, higgs(), 3, Z0(),
5, Zdecays[iz].first,5, Zdecays[iz].second,-1)));
}
}
}
void MEPP2ZH::persistentOutput(PersistentOStream & ) const {
}
void MEPP2ZH::persistentInput(PersistentIStream & , int) {
}
-ClassDescription<MEPP2ZH> MEPP2ZH::initMEPP2ZH;
-// Definition of the static class description member.
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEPP2ZH,MEfftoVH>
+describeHerwigMEPP2ZH("Herwig::MEPP2ZH", "HwMEHadron.so");
void MEPP2ZH::Init() {
static ClassDocumentation<MEPP2ZH> documentation
("The MEPP2ZH class implements the matrix element for q qbar -> Z H");
}
void MEPP2ZH::doinit() {
// get the vedrtex pointers from the SM object
tcHwSMPtr hwsm= dynamic_ptr_cast<tcHwSMPtr>(standardModel());
if(!hwsm)
throw InitException() << "Wrong type of StandardModel object in "
<< "MEeeto2ZH::doinit() the Herwig"
<< " version must be used"
<< Exception::runerror;
// set the vertex
setWWHVertex(hwsm->vertexWWH());
higgs(getParticleData(ParticleID::h0));
MEfftoVH::doinit();
}
diff --git a/MatrixElement/Hadron/MEPP2ZH.h b/MatrixElement/Hadron/MEPP2ZH.h
--- a/MatrixElement/Hadron/MEPP2ZH.h
+++ b/MatrixElement/Hadron/MEPP2ZH.h
@@ -1,152 +1,117 @@
// -*- C++ -*-
#ifndef HERWIG_MEPP2ZH_H
#define HERWIG_MEPP2ZH_H
//
// This is the declaration of the MEPP2ZH class.
//
#include "Herwig/MatrixElement/MEfftoVH.h"
namespace Herwig {
using namespace ThePEG;
/**
* The MEPP2ZH class implements the matrix element
* for \f$q\bar{q}\to Z^0h^0\f$.
*
* @see \ref MEPP2ZHInterfaces "The interfaces"
* defined for MEPP2ZH.
*/
class MEPP2ZH: public MEfftoVH {
public:
/**
* The default constructor.
*/
MEPP2ZH();
/** @name Virtual functions required by the MEBase class. */
//@{
/**
* Add all possible diagrams with the add() function.
*/
virtual void getDiagrams() 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 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();
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<MEPP2ZH> initMEPP2ZH;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEPP2ZH & operator=(const MEPP2ZH &);
private:
/**
* The allowed flavours of the incoming quarks
*/
int _maxflavour;
};
}
-#include "ThePEG/Utilities/ClassTraits.h"
-
-namespace ThePEG {
-
-/** @cond TRAITSPECIALIZATIONS */
-
-/** This template specialization informs ThePEG about the
- * base classes of MEPP2ZH. */
-template <>
-struct BaseClassTrait<Herwig::MEPP2ZH,1> {
- /** Typedef of the first base class of MEPP2ZH. */
- typedef Herwig::MEfftoVH NthBase;
-};
-
-/** This template specialization informs ThePEG about the name of
- * the MEPP2ZH class and the shared object where it is defined. */
-template <>
-struct ClassTraits<Herwig::MEPP2ZH>
- : public ClassTraitsBase<Herwig::MEPP2ZH> {
- /** Return a platform-independent class name */
- static string className() { return "Herwig::MEPP2ZH"; }
- /**
- * The name of a file containing the dynamic library where the class
- * MEPP2ZH is implemented. It may also include several, space-separated,
- * libraries if the class MEPP2ZH 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_MEPP2ZH_H */
diff --git a/MatrixElement/Hadron/MEPP2ZJet.cc b/MatrixElement/Hadron/MEPP2ZJet.cc
--- a/MatrixElement/Hadron/MEPP2ZJet.cc
+++ b/MatrixElement/Hadron/MEPP2ZJet.cc
@@ -1,858 +1,861 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2ZJet class.
//
#include "MEPP2ZJet.h"
+#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "ThePEG/Utilities/SimplePhaseSpace.h"
#include "ThePEG/Cuts/Cuts.h"
#include "Herwig/MatrixElement/HardVertex.h"
using namespace Herwig;
MEPP2ZJet::MEPP2ZJet() : _process(0), _maxflavour(5), _zdec(0),
_gammaZ(0), _widthopt(1), _pprob(0.5)
{}
void MEPP2ZJet::doinit() {
HwMEBase::doinit();
_z0 = getParticleData(ThePEG::ParticleID::Z0 );
_gamma = getParticleData(ThePEG::ParticleID::gamma);
// cast the SM pointer to the Herwig SM pointer
ThePEG::Ptr<Herwig::StandardModel>::transient_const_pointer
hwsm=ThePEG::dynamic_ptr_cast< ThePEG::Ptr<Herwig::StandardModel>
::transient_const_pointer>(standardModel());
// do the initialisation
if(!hwsm)
throw InitException() << "Must be Herwig::StandardModel in MEPP2ZJet::doinit()"
<< Exception::runerror;
// set the vertex pointers
_theFFZVertex = hwsm->vertexFFZ();
_theFFPVertex = hwsm->vertexFFP();
_theQQGVertex = hwsm->vertexFFG();
}
-ClassDescription<MEPP2ZJet> MEPP2ZJet::initMEPP2ZJet;
-// Definition of the static class description member.
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEPP2ZJet,HwMEBase>
+describeHerwigMEPP2ZJet("Herwig::MEPP2ZJet", "HwMEHadron.so");
void MEPP2ZJet::Init() {
static ClassDocumentation<MEPP2ZJet> documentation
("The MEPP2ZJet class implements the matrix element for Z/gamma+ jet production");
static Parameter<MEPP2ZJet,int> interfaceMaxFlavour
( "MaxFlavour",
"The heaviest incoming quark flavour this matrix element is allowed to handle "
"(if applicable).",
&MEPP2ZJet::_maxflavour, 5, 0, 8, false, false, true);
static Switch<MEPP2ZJet,int> interfaceZDecay
("ZDecay",
"Which process to included",
&MEPP2ZJet::_zdec, 0, false, false);
static SwitchOption interfaceZDecayAll
(interfaceZDecay,
"All",
"Include all SM fermions as outgoing particles",
0);
static SwitchOption interfaceZDecayQuarks
(interfaceZDecay,
"Quarks",
"All include the quarks as outgoing particles",
1);
static SwitchOption interfaceZDecayLeptons
(interfaceZDecay,
"Leptons",
"Only include the leptons as outgoing particles",
2);
static SwitchOption interfaceZDecayChargedLeptons
(interfaceZDecay,
"ChargedLeptons",
"Only include the charged leptons as outgoing particles",
3);
static SwitchOption interfaceZDecayNeutrinos
(interfaceZDecay,
"Neutrinos",
"Only include the neutrinos as outgoing particles",
4);
static SwitchOption interfaceZDecayElectron
(interfaceZDecay,
"Electron",
"Only include e+e- as outgoing particles",
5);
static SwitchOption interfaceZDecayMuon
(interfaceZDecay,
"Muon",
"Only include mu+mu- as outgoing particles",
6);
static SwitchOption interfaceZDecayTau
(interfaceZDecay,
"Tau",
"Only include tau+tau- as outgoing particles",
7);
static SwitchOption interfaceZDecayNu_e
(interfaceZDecay,
"Nu_e",
"Only include nu_e ne_ebar as outgoing particles",
8);
static SwitchOption interfaceZDecaynu_mu
(interfaceZDecay,
"Nu_mu",
"Only include nu_mu nu_mubar as outgoing particles",
9);
static SwitchOption interfaceZDecaynu_tau
(interfaceZDecay,
"Nu_tau",
"Only include nu_tau nu_taubar as outgoing particles",
10);
static SwitchOption interfaceZDecayDown
(interfaceZDecay,
"Down",
"Only include d dbar as outgoing particles",
11);
static SwitchOption interfaceZDecayUp
(interfaceZDecay,
"Up",
"Only include u ubar as outgoing particles",
12);
static SwitchOption interfaceZDecayStrange
(interfaceZDecay,
"Strange",
"Only include s sbar as outgoing particles",
13);
static SwitchOption interfaceZDecayCharm
(interfaceZDecay,
"Charm",
"Only include c cbar as outgoing particles",
14);
static SwitchOption interfaceZDecayBottom
(interfaceZDecay,
"Bottom",
"Only include b bbar as outgoing particles",
15);
static SwitchOption interfaceZDecayTop
(interfaceZDecay,
"Top",
"Only include t tbar as outgoing particles",
16);
static Switch<MEPP2ZJet,unsigned int> interfaceProcess
("Process",
"Which subprocesses to include",
&MEPP2ZJet::_process, 0, false, false);
static SwitchOption interfaceProcessAll
(interfaceProcess,
"All",
"Include all subprocesses",
0);
static SwitchOption interfaceProcessqqbar
(interfaceProcess,
"qqbar",
"Only include q qbar -> Z/gamma g process",
1);
static SwitchOption interfaceProcessqg
(interfaceProcess,
"qg",
"Only include the q g -> Z/gamma q process",
2);
static SwitchOption interfaceProcessqbarg
(interfaceProcess,
"qbarg",
"Only include the qbar g -> Z/gamma qbar process",
3);
static Parameter<MEPP2ZJet,double> interfacePhotonProbablity
("PhotonProbablity",
"Probability for using the \\f$1/s^2\\f$ piece for the"
" generation of the gauge boson mass",
&MEPP2ZJet::_pprob, 0.5, 0.0, 1.0,
false, false, Interface::limited);
static Switch<MEPP2ZJet,unsigned int> interfaceGammaZ
("GammaZ",
"Which terms to include",
&MEPP2ZJet::_gammaZ, 0, false, false);
static SwitchOption interfaceGammaZAll
(interfaceGammaZ,
"All",
"Include both gamma and Z terms",
0);
static SwitchOption interfaceGammaZGamma
(interfaceGammaZ,
"Gamma",
"Only include the photon",
1);
static SwitchOption interfaceGammaZZ
(interfaceGammaZ,
"Z",
"Only include the Z",
2);
static Switch<MEPP2ZJet,unsigned int> interfaceWidthOption
("WidthOption",
"The option for handling the width of the off-shell W boson",
&MEPP2ZJet::_widthopt, 1, false, false);
static SwitchOption interfaceWidthOptionFixedDenominator
(interfaceWidthOption,
"FixedDenominator",
"Use a fxied with in the W propagator but the full matrix element"
" in the numerator",
1);
static SwitchOption interfaceWidthOptionAllRunning
(interfaceWidthOption,
"AllRunning",
"Use a running width in the W propagator and the full matrix "
"element in the numerator",
2);
}
void MEPP2ZJet::getDiagrams() const {
// which intermediates to include
bool gamma = _gammaZ==0 || _gammaZ==1;
bool Z0 = _gammaZ==0 || _gammaZ==2;
// pointer for gluon
tcPDPtr g = getParticleData(ParticleID::g);
bool quark,lepton;
for ( int ix=1; ix<17; ++ix ) {
// increment counter to switch between quarks and leptons
if(ix==7) ix+=4;
// is it a valid quark process
quark=ix<=6&&(_zdec==0||_zdec==1||_zdec-10==ix);
// is it a valid lepton process
lepton=ix>=11&&ix<=16&&
(_zdec==0||_zdec==2||(_zdec==3&&ix%2==1)||
(_zdec==4&&ix%2==0)||(ix%2==0&&(ix-10)/2==_zdec-7)||
(ix%2==1&&(ix-9)/2==_zdec-4));
// if not a validf process continue
if(!(quark||lepton)) continue;
// pointer for Z decay products
tcPDPtr lm = getParticleData(ix);
tcPDPtr lp = lm->CC();
for (int i = 1; i <= _maxflavour; ++i ) {
tcPDPtr q = getParticleData(i);
tcPDPtr qb = q->CC();
// q qbar -> Z g -> l+l- g
if(_process==0||_process==1) {
if(gamma) add(new_ptr((Tree2toNDiagram(3), q, q, qb, 1, _gamma,
2, g, 4, lm, 4, lp, -1)));
if(Z0) add(new_ptr((Tree2toNDiagram(3), q, q, qb, 1, _z0,
2, g, 4, lm, 4, lp, -2)));
if(gamma) add(new_ptr((Tree2toNDiagram(3), q, q, qb, 2, _gamma,
1, g, 4, lm, 4, lp, -3)));
if(Z0) add(new_ptr((Tree2toNDiagram(3), q, q, qb, 2, _z0,
1, g, 4, lm, 4, lp, -4)));
}
// q g -> Z q -> l+l- qbar
if(_process==0||_process==2) {
if(gamma) add(new_ptr((Tree2toNDiagram(3), q, q, g, 1, _gamma,
2, q, 4, lm, 4, lp, -5)));
if(Z0) add(new_ptr((Tree2toNDiagram(3), q, q, g, 1, _z0,
2, q, 4, lm, 4, lp, -6)));
if(gamma) add(new_ptr((Tree2toNDiagram(2), q, g, 1, q, 3, _gamma,
3, q, 4, lm, 4, lp, -7)));
if(Z0) add(new_ptr((Tree2toNDiagram(2), q, g, 1, q, 3, _z0,
3, q, 4, lm, 4, lp, -8)));
}
// qbar g -> Z qbar -> l+l- qbar
if(_process==0||_process==3) {
if(gamma) add(new_ptr((Tree2toNDiagram(3), qb, qb, g, 1, _gamma,
2, qb, 4, lm, 4, lp, -9 )));
if(Z0) add(new_ptr((Tree2toNDiagram(3), qb, qb, g, 1, _z0,
2, qb, 4, lm, 4, lp, -10)));
if(gamma) add(new_ptr((Tree2toNDiagram(2), qb, g, 1, qb, 3, _gamma,
3, qb, 4, lm, 4, lp, -11)));
if(Z0) add(new_ptr((Tree2toNDiagram(2), qb, g, 1, qb, 3, _z0,
3, qb, 4, lm, 4, lp, -12)));
}
}
}
}
unsigned int MEPP2ZJet::orderInAlphaS() const {
return 1;
}
unsigned int MEPP2ZJet::orderInAlphaEW() const {
return 2;
}
void MEPP2ZJet::persistentOutput(PersistentOStream & os) const {
os << _theFFZVertex << _theFFPVertex << _theQQGVertex << _z0 << _widthopt
<< _gamma << _process << _maxflavour << _zdec << _pprob << _gammaZ;
}
void MEPP2ZJet::persistentInput(PersistentIStream & is, int) {
is >> _theFFZVertex >> _theFFPVertex >> _theQQGVertex >> _z0 >> _widthopt
>> _gamma >> _process >> _maxflavour >> _zdec >> _pprob >> _gammaZ;
}
int MEPP2ZJet::nDim() const {
return 5;
}
Selector<const ColourLines *>
MEPP2ZJet::colourGeometries(tcDiagPtr diag) const {
// colour lines for q qbar -> Z g
static const ColourLines cqqbar[4]={ColourLines("1 2 5,-3 -5"),
ColourLines("1 5,-5 2 -3"),
ColourLines("1 2 5,-3 -5, 6 -7"),
ColourLines("1 5,-5 2 -3, 6 -7")};
// colour lines for q g -> Z q
static const ColourLines cqg [4]={ColourLines("1 2 -3,3 5"),
ColourLines("1 -2,2 3 5"),
ColourLines("1 2 -3,3 5, 6 -7"),
ColourLines("1 -2,2 3 5, 6 -7")};
// colour lines for qbar q -> Z qbar
static const ColourLines cqbarg[4]={ColourLines("-1 -2 3,-3 -5"),
ColourLines("-1 2,-2 -3 -5"),
ColourLines("-1 -2 3,-3 -5, 6 -7"),
ColourLines("-1 2,-2 -3 -5, 6 -7")};
// select the correct line
unsigned int icol = mePartonData()[3]->coloured() ? 2 : 0;
Selector<const ColourLines *> sel;
switch(abs(diag->id())) {
case 1 : case 2:
sel.insert(1.0, &cqqbar[icol]);
break;
case 3 : case 4:
sel.insert(1.0, &cqqbar[icol+1]);
break;
case 5 : case 6:
sel.insert(1.0, &cqg[icol]);
break;
case 7 : case 8:
sel.insert(1.0, &cqg[icol+1]);
break;
case 9 : case 10:
sel.insert(1.0, &cqbarg[icol]);
break;
case 11 : case 12:
sel.insert(1.0, &cqbarg[icol+1]);
break;
}
return sel;
}
Selector<MEBase::DiagramIndex>
MEPP2ZJet::diagrams(const DiagramVector & diags) const {
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i ) {
int id=abs(diags[i]->id());
if (id <= 4 ) sel.insert(meInfo()[id-1],i);
else if(id <= 8 ) sel.insert(meInfo()[id-5],i);
else if(id <= 12) sel.insert(meInfo()[id-9],i);
}
return sel;
}
Energy2 MEPP2ZJet::scale() const {
return _scale;
}
CrossSection MEPP2ZJet::dSigHatDR() const {
return me2()*jacobian()/(16.0*sqr(Constants::pi)*sHat())*sqr(hbarc);
}
bool MEPP2ZJet::generateKinematics(const double * r) {
// initialize jacobian
jacobian(1.);
// cms energy
Energy ecm=sqrt(sHat());
// first generate the mass of the off-shell gauge boson
// minimum mass of the
tcPDVector ptemp;
ptemp.push_back(mePartonData()[3]);
ptemp.push_back(mePartonData()[4]);
Energy2 minMass2 = max(lastCuts().minSij(mePartonData()[3],mePartonData()[4]),
lastCuts().minS(ptemp));
// minimum pt of the jet
Energy ptmin = max(lastCuts().minKT(mePartonData()[2]),
lastCuts().minKT(_z0));
// maximum mass of the gauge boson so pt is possible
Energy2 maxMass2 = min(ecm*(ecm-2.*ptmin),lastCuts().maxS(ptemp));
if(maxMass2<=ZERO||minMass2<ZERO) return false;
// also impose the limits from the ParticleData object
minMass2 = max(minMass2,sqr(_z0->massMin()));
maxMass2 = min(maxMass2,sqr(_z0->massMax()));
// also impose the limits from the ParticleData object
if(maxMass2<minMass2) return false;
// generation of the mass
Energy M(_z0->mass()),Gamma(_z0->width());
Energy2 M2(sqr(M)),MG(M*Gamma);
double rhomin = atan2((minMass2-M2),MG);
double rhomax = atan2((maxMass2-M2),MG);
if(r[1]<_pprob) {
double rand=r[1]/_pprob;
_mz2=minMass2*maxMass2/(minMass2+rand*(maxMass2-minMass2));
}
else {
double rand=(r[1]-_pprob)/(1.-_pprob);
_mz2=M2+MG*tan(rhomin+rand*(rhomax-rhomin));
}
Energy mz=sqrt(_mz2);
InvEnergy2 emjac1 = _pprob*minMass2*maxMass2/(maxMass2-minMass2)/sqr(_mz2);
InvEnergy2 emjac2 = (1.-_pprob)*MG/(rhomax-rhomin)/(sqr(_mz2-M2)+sqr(MG));
// jacobian
jacobian(jacobian()/sHat()/(emjac1+emjac2));
// set the masses of the outgoing particles to 2-2 scattering
meMomenta()[2].setMass(ZERO);
Lorentz5Momentum pz(mz);
// generate the polar angle of the hard scattering
double ctmin(-1.0), ctmax(1.0);
Energy q(ZERO);
try {
q = SimplePhaseSpace::getMagnitude(sHat(), meMomenta()[2].mass(),mz);
}
catch ( ImpossibleKinematics ) {
return false;
}
Energy2 pq = sqrt(sHat())*q;
if ( ptmin > ZERO ) {
double ctm = 1.0 - sqr(ptmin/q);
if ( ctm <= 0.0 ) return false;
ctmin = max(ctmin, -sqrt(ctm));
ctmax = min(ctmax, sqrt(ctm));
}
if ( ctmin >= ctmax ) return false;
double cth = getCosTheta(ctmin, ctmax, r[0]);
Energy pt = q*sqrt(1.0-sqr(cth));
double phi = 2.0*Constants::pi*r[2];
meMomenta()[2].setVect(Momentum3( pt*sin(phi), pt*cos(phi), q*cth));
pz.setVect( Momentum3(-pt*sin(phi),-pt*cos(phi),-q*cth));
meMomenta()[2].rescaleEnergy();
pz.rescaleEnergy();
// set the scale
_scale = _mz2+sqr(pt);
// generate the momenta of the Z decay products
meMomenta()[3].setMass(mePartonData()[3]->mass());
meMomenta()[4].setMass(mePartonData()[4]->mass());
Energy q2 = ZERO;
try {
q2 = SimplePhaseSpace::getMagnitude(_mz2, meMomenta()[3].mass(),
meMomenta()[4].mass());
} catch ( ImpossibleKinematics ) {
return false;
}
double cth2 =-1.+2.*r[3];
double phi2=Constants::twopi*r[4];
Energy pt2 =q2*sqrt(1.-sqr(cth2));
Lorentz5Momentum pl[2]={Lorentz5Momentum( pt2*cos(phi2), pt2*sin(phi2), q2*cth2,ZERO,
meMomenta()[3].mass()),
Lorentz5Momentum(-pt2*cos(phi2),-pt2*sin(phi2),-q2*cth2,ZERO,
meMomenta()[4].mass())};
pl[0].rescaleEnergy();
pl[1].rescaleEnergy();
Boost boostv(pz.boostVector());
pl[0].boost(boostv);
pl[1].boost(boostv);
meMomenta()[3] = pl[0];
meMomenta()[4] = pl[1];
// check passes all the cuts
vector<LorentzMomentum> out(3);
tcPDVector tout(3);
for(unsigned int ix=0;ix<3;++ix) {
out[ ix] = meMomenta()[ix+2];
tout[ix] = mePartonData()[ix+2];
}
if ( !lastCuts().passCuts(tout, out, mePartonData()[0], mePartonData()[1]) )
return false;
// jacobian
jacobian((pq/sHat())*Constants::pi*jacobian()/8./sqr(Constants::pi)*q2/mz);
return true;
}
double MEPP2ZJet::me2() const {
InvEnergy2 output(ZERO);
// construct spinors for the leptons (always the same)
vector<SpinorBarWaveFunction> lm;
vector<SpinorWaveFunction> lp;
SpinorBarWaveFunction lmout(meMomenta()[3],mePartonData()[3],outgoing);
SpinorWaveFunction lpout(meMomenta()[4],mePartonData()[4],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
lmout.reset(ix);lm.push_back(lmout);
lpout.reset(ix);lp.push_back(lpout);
}
// q g to q Z
if(mePartonData()[0]->id()<=6&&mePartonData()[0]->id()>0&&
mePartonData()[1]->id()==ParticleID::g) {
// polarization states for the particles
vector<SpinorWaveFunction> fin;
vector<VectorWaveFunction> gin;
vector<SpinorBarWaveFunction> fout;
SpinorWaveFunction qin (meMomenta()[0],mePartonData()[0],incoming);
VectorWaveFunction glin(meMomenta()[1],mePartonData()[1],incoming);
SpinorBarWaveFunction qout(meMomenta()[2],mePartonData()[2],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
qin.reset(ix) ; fin.push_back(qin);
glin.reset(2*ix); gin.push_back(glin);
qout.reset(ix);fout.push_back(qout);
}
output=qgME(fin,gin,fout,lm,lp);
}
// qbar g to qbar Z
else if(mePartonData()[0]->id()>=-6&&mePartonData()[0]->id()<0&&
mePartonData()[1]->id()==ParticleID::g) {
vector<SpinorBarWaveFunction> ain;
vector<VectorWaveFunction> gin;
vector<SpinorWaveFunction> aout;
SpinorBarWaveFunction qbin (meMomenta()[0],mePartonData()[0],incoming);
VectorWaveFunction glin (meMomenta()[1],mePartonData()[1],incoming);
SpinorWaveFunction qbout(meMomenta()[2],mePartonData()[2],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
qbin .reset(ix ); ain .push_back(qbin );
glin .reset(2*ix); gin .push_back(glin );
qbout.reset(ix ); aout.push_back(qbout);
}
output=qbargME(ain,gin,aout,lm,lp);
}
// q qbar to g Z
else {
vector<SpinorWaveFunction> fin;
vector<SpinorBarWaveFunction> ain;
vector<VectorWaveFunction> gout;
SpinorWaveFunction qin (meMomenta()[0],mePartonData()[0],incoming);
SpinorBarWaveFunction qbin(meMomenta()[1],mePartonData()[1],incoming);
VectorWaveFunction glout(meMomenta()[2],mePartonData()[2],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
qin.reset(ix) ; fin.push_back(qin);
qbin.reset(ix) ; ain.push_back(qbin);
glout.reset(2*ix); gout.push_back(glout);
}
output=qqbarME(fin,ain,gout,lm,lp);
}
return output*sHat();
}
InvEnergy2 MEPP2ZJet::qqbarME(vector<SpinorWaveFunction> & fin,
vector<SpinorBarWaveFunction> & ain,
vector<VectorWaveFunction> & gout,
vector<SpinorBarWaveFunction> & lm,
vector<SpinorWaveFunction> & lp,
bool calc) const {
// if calculation spin corrections construct the me
if(calc) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1,PDT::Spin1Half,
PDT::Spin1Half));
// diagrams to include
bool gamma = _gammaZ==0 || _gammaZ==1;
bool Z0 = _gammaZ==0 || _gammaZ==2;
// some integers
unsigned int ihel1,ihel2,ohel1,ohel2,ohel3;
// compute the leptonic photon and Z currents for speed
VectorWaveFunction bcurr[2][2][2];
for(ohel2=0;ohel2<2;++ohel2) {
for(ohel3=0;ohel3<2;++ohel3) {
// photon current
if(gamma) bcurr[0][ohel2][ohel3]=
_theFFPVertex->evaluate(_mz2,1,_gamma,lp[ohel3],lm[ohel2]);
// Z current
if(Z0) bcurr[1][ohel2][ohel3]=
_theFFZVertex->evaluate(_mz2,_widthopt,_z0,lp[ohel3],lm[ohel2]);
}
}
// compute the matrix elements
double me[5]={0.,0.,0.,0.,0.};
Complex diag[4];
SpinorWaveFunction inters;
SpinorBarWaveFunction interb;
for(ihel1=0;ihel1<2;++ihel1) {
for(ihel2=0;ihel2<2;++ihel2) {
for(ohel1=0;ohel1<2;++ohel1) {
// intermediates for the diagrams
inters=_theQQGVertex->evaluate(_scale,5,mePartonData()[0],
fin[ihel1],gout[ohel1]);
interb=_theQQGVertex->evaluate(_scale,5,mePartonData()[1],
ain[ihel2],gout[ohel1]);
for(ohel2=0;ohel2<2;++ohel2) {
for(ohel3=0;ohel3<2;++ohel3) {
diag[0] = gamma ?
_theFFPVertex->evaluate(_mz2,fin[ihel1],interb,
bcurr[0][ohel2][ohel3]) : 0.;
diag[1]= Z0 ?
_theFFZVertex->evaluate(_mz2,fin[ihel1],interb,
bcurr[1][ohel2][ohel3]) : 0.;
diag[2]= gamma ?
_theFFPVertex->evaluate(_mz2,inters,ain[ihel2],
bcurr[0][ohel2][ohel3]) : 0.;
diag[3]= Z0 ?
_theFFZVertex->evaluate(_mz2,inters,ain[ihel2],
bcurr[1][ohel2][ohel3]) : 0.;
// diagram contributions
me[1] += norm(diag[0]);
me[2] += norm(diag[1]);
me[3] += norm(diag[2]);
me[4] += norm(diag[3]);
// total
diag[0] += diag[1] + diag[2] + diag[3];
me[0] += norm(diag[0]);
if(calc) _me(ihel1,ihel2,2*ohel1,ohel2,ohel3) = diag[0];
}
}
}
}
}
// results
// initial state spin and colour average
double colspin = 1./9./4.;
// and C_F N_c from matrix element
colspin *= 4.;
// and for Z decay products
if(mePartonData()[3]->coloured()) colspin *= 3.;
DVector save;
for(unsigned int ix=0;ix<5;++ix) {
me[ix] *= colspin;
if(ix>0) save.push_back(me[ix]);
}
meInfo(save);
return me[0]*UnitRemoval::InvE2;
}
InvEnergy2 MEPP2ZJet::qgME(vector<SpinorWaveFunction> & fin,
vector<VectorWaveFunction> & gin,
vector<SpinorBarWaveFunction> & fout,
vector<SpinorBarWaveFunction> & lm,
vector<SpinorWaveFunction> & lp,
bool calc) const {
// diagrams to include
bool gamma = _gammaZ==0 || _gammaZ==1;
bool Z0 = _gammaZ==0 || _gammaZ==2;
// if calculation spin corrections construct the me
if(calc) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1,
PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half));
// some integers
unsigned int ihel1,ihel2,ohel1,ohel2,ohel3;
// compute the leptonic photon and Z currents for speed
VectorWaveFunction bcurr[2][2][2];
for(ohel2=0;ohel2<2;++ohel2) {
for(ohel3=0;ohel3<2;++ohel3) {
// photon current
if(gamma) bcurr[0][ohel2][ohel3]=
_theFFPVertex->evaluate(_mz2,1,_gamma,lp[ohel3],lm[ohel2]);
// Z current
if(Z0) bcurr[1][ohel2][ohel3]=
_theFFZVertex->evaluate(_mz2,_widthopt,_z0,lp[ohel3],lm[ohel2]);
}
}
// compute the matrix elements
double me[5]={0.,0.,0.,0.,0.};
Complex diag[4];
SpinorWaveFunction inters;
SpinorBarWaveFunction interb;
Energy2 _scale=scale();
for(ihel1=0;ihel1<2;++ihel1) {
for(ihel2=0;ihel2<2;++ihel2) {
for(ohel1=0;ohel1<2;++ohel1) {
// intermediates for the diagrams
interb=_theQQGVertex->evaluate(_scale,5,mePartonData()[2],
fout[ohel1],gin[ihel2]);
inters=_theQQGVertex->evaluate(_scale,5,mePartonData()[0],
fin[ihel1],gin[ihel2]);
for(ohel2=0;ohel2<2;++ohel2) {
for(ohel3=0;ohel3<2;++ohel3) {
diag[0]=gamma ?
_theFFPVertex->evaluate(_mz2,fin[ihel1],interb,
bcurr[0][ohel2][ohel3]) : 0.;
diag[1]=Z0 ?
_theFFZVertex->evaluate(_mz2,fin[ihel1],interb,
bcurr[1][ohel2][ohel3]) : 0.;
diag[2]=gamma ?
_theFFPVertex->evaluate(_mz2,inters,fout[ohel1],
bcurr[0][ohel2][ohel3]) : 0.;
diag[3]=Z0 ?
_theFFZVertex->evaluate(_mz2,inters,fout[ohel1],
bcurr[1][ohel2][ohel3]) : 0.;
// diagram contributions
me[1] += norm(diag[0]);
me[2] += norm(diag[1]);
me[3] += norm(diag[2]);
me[4] += norm(diag[3]);
// total
diag[0] += diag[1] + diag[2] + diag[3];
me[0] += norm(diag[0]);
if(calc) _me(ihel1,2*ihel2,ohel1,ohel2,ohel3) = diag[0];
}
}
}
}
}
// results
// initial state spin and colour average
double colspin = 1./24./4.;
// and C_F N_c from matrix element
colspin *= 4.;
// and for Z decay products
if(mePartonData()[3]->coloured()) colspin *= 3.;
DVector save;
for(unsigned int ix=0;ix<5;++ix) {
me[ix] *= colspin;
if(ix>0) save.push_back(me[ix]);
}
meInfo(save);
return me[0]*UnitRemoval::InvE2;
}
InvEnergy2 MEPP2ZJet::qbargME(vector<SpinorBarWaveFunction> & fin,
vector<VectorWaveFunction> & gin,
vector<SpinorWaveFunction> & fout,
vector<SpinorBarWaveFunction> & lm,
vector<SpinorWaveFunction> & lp,
bool calc) const {
// diagrams to include
bool gamma = _gammaZ==0 || _gammaZ==1;
bool Z0 = _gammaZ==0 || _gammaZ==2;
// if calculation spin corrections construct the me
if(calc) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1,
PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half));
// some integers
unsigned int ihel1,ihel2,ohel1,ohel2,ohel3;
// compute the leptonic photon and Z currents for speed
VectorWaveFunction bcurr[2][2][2];
for(ohel2=0;ohel2<2;++ohel2) {
for(ohel3=0;ohel3<2;++ohel3) {
// photon current
if(gamma) bcurr[0][ohel2][ohel3]=
_theFFPVertex->evaluate(_mz2,1,_gamma,lp[ohel3],lm[ohel2]);
// Z current
if(Z0) bcurr[1][ohel2][ohel3]=
_theFFZVertex->evaluate(_mz2,_widthopt,_z0,lp[ohel3],lm[ohel2]);
}
}
// compute the matrix elements
double me[5]={0.,0.,0.,0.,0.};
Complex diag[4];
SpinorWaveFunction inters;
SpinorBarWaveFunction interb;
Energy2 _scale=scale();
for(ihel1=0;ihel1<2;++ihel1) {
for(ihel2=0;ihel2<2;++ihel2) {
for(ohel1=0;ohel1<2;++ohel1) {
// intermediates for the diagrams
inters=_theQQGVertex->evaluate(_scale,5,mePartonData()[2],
fout[ohel1],gin[ihel2]);
interb=_theQQGVertex->evaluate(_scale,5,mePartonData()[0],
fin[ihel1],gin[ihel2]);
for(ohel2=0;ohel2<2;++ohel2) {
for(ohel3=0;ohel3<2;++ohel3) {
diag[0]= gamma ?
_theFFPVertex->evaluate(_mz2,inters,fin[ihel1],
bcurr[0][ohel2][ohel3]) : 0.;
diag[1]= Z0 ?
_theFFZVertex->evaluate(_mz2,inters,fin[ihel1],
bcurr[1][ohel2][ohel3]) : 0.;
diag[2]= gamma ?
_theFFPVertex->evaluate(_mz2,fout[ohel1],interb,
bcurr[0][ohel2][ohel3]) : 0.;
diag[3]= Z0 ?
_theFFZVertex->evaluate(_mz2,fout[ohel1],interb,
bcurr[1][ohel2][ohel3]) : 0.;
// diagram contributions
me[1] += norm(diag[0]);
me[2] += norm(diag[1]);
me[3] += norm(diag[2]);
me[4] += norm(diag[3]);
// total
diag[0] += diag[1] + diag[2] + diag[3];
me[0] += norm(diag[0]);
if(calc) _me(ihel1,2*ihel2,ohel1,ohel2,ohel3) = diag[0];
}
}
}
}
}
// results
// initial state spin and colour average
double colspin = 1./24./4.;
// and C_F N_c from matrix element
colspin *= 4.;
// and for Z decay products
if(mePartonData()[3]->coloured()) colspin*=3.;
DVector save;
for(unsigned int ix=0;ix<5;++ix) {
me[ix] *= colspin;
if(ix>0) save.push_back(me[ix]);
}
meInfo(save);
return me[0]*UnitRemoval::InvE2;
}
void MEPP2ZJet::constructVertex(tSubProPtr sub) {
// extract the particles in the hard process
ParticleVector hard(5);
// incoming
hard[0]=sub->incoming().first;
hard[1]=sub->incoming().second;
if((hard[0]->id()<0&&hard[1]->id()<=6)||
hard[0]->id()==ParticleID::g) swap(hard[0],hard[1]);
// outgoing
for(unsigned int ix=0;ix<3;++ix) {
unsigned int iloc;
PPtr mother=sub->outgoing()[ix]->parents()[0];
if(mother&&(mother->id()==ParticleID::gamma||mother->id()==ParticleID::Z0)) {
if(sub->outgoing()[ix]->id()>0) iloc=3;
else iloc=4;
}
else iloc=2;
hard[iloc]=sub->outgoing()[ix];
}
// wavefunctions for the Z decay products
vector<SpinorBarWaveFunction> lm;
vector<SpinorWaveFunction> lp;
SpinorBarWaveFunction(lm,hard[3],outgoing,true,true);
SpinorWaveFunction (lp,hard[4],outgoing,true,true);
// identify hard process and calculate matrix element
// q g to q Z
if(hard[0]->id()<=6&&hard[0]->id()>0&&hard[1]->id()==ParticleID::g) {
vector<SpinorWaveFunction> fin;
vector<VectorWaveFunction> gin;
vector<SpinorBarWaveFunction> fout;
SpinorWaveFunction (fin ,hard[0],incoming,false,true);
VectorWaveFunction (gin ,hard[1],incoming,false,true,true);
SpinorBarWaveFunction (fout,hard[2],outgoing,true ,true);
gin[1]=gin[2];
qgME(fin,gin,fout,lm,lp,true);
}
// qbar g to qbar Z
else if(hard[0]->id()>=-6&&hard[0]->id()<0&&hard[1]->id()==ParticleID::g) {
vector<SpinorBarWaveFunction> ain;
vector<VectorWaveFunction> gin;
vector<SpinorWaveFunction> aout;
SpinorBarWaveFunction(ain ,hard[0],incoming,false,true);
VectorWaveFunction (gin ,hard[1],incoming,false,true,true);
SpinorWaveFunction (aout,hard[2],outgoing,true ,true);
gin[1]=gin[2];
qbargME(ain,gin,aout,lm,lp,true);
}
// q qbar to g Z
else {
vector<SpinorWaveFunction> fin;
vector<SpinorBarWaveFunction> ain;
vector<VectorWaveFunction> gout;
SpinorWaveFunction (fin ,hard[0],incoming,false,true);
SpinorBarWaveFunction(ain ,hard[1],incoming,false,true);
VectorWaveFunction (gout,hard[2],outgoing,true ,true,true);
gout[1]=gout[2];
qqbarME(fin,ain,gout,lm,lp,true);
}
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(_me);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<5;++ix)
(hard[ix]->spinInfo())->productionVertex(hardvertex);
}
diff --git a/MatrixElement/Hadron/MEPP2ZJet.h b/MatrixElement/Hadron/MEPP2ZJet.h
--- a/MatrixElement/Hadron/MEPP2ZJet.h
+++ b/MatrixElement/Hadron/MEPP2ZJet.h
@@ -1,364 +1,329 @@
// -*- C++ -*-
#ifndef HERWIG_MEPP2ZJet_H
#define HERWIG_MEPP2ZJet_H
//
// This is the declaration of the MEPP2ZJet class.
//
#include "Herwig/MatrixElement/HwMEBase.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.fh"
namespace Herwig {
using namespace ThePEG;
using namespace ThePEG::Helicity;
/**
* The MEPP2ZJet class implements the matrix element for the production
* of a Z boson + a jet including the decay of the Z including \f$Z/\gamma\f$
* interference
*
* @see \ref MEPP2ZJetInterfaces "The interfaces"
* defined for MEPP2ZJet.
*/
class MEPP2ZJet: public HwMEBase {
public:
/**
* The default constructor.
*/
MEPP2ZJet();
/** @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;
/**
* 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:
/**
* Matrix elements for the different subprocesses
*/
//@{
/**
* Matrix element for \f$q\bar{q}\to Z/\gamma g\f$.
* @param fin Spinors for incoming quark
* @param ain Spinors for incoming antiquark
* @param gout Polarization vectors for the outgoing gluon
* @param lm Spinors for outgoing lepton
* @param lp Spinors for outgoing antilepton
* @param me Whether or not to calculate the matrix element for spin correlations
**/
InvEnergy2 qqbarME(vector<SpinorWaveFunction> & fin,
vector<SpinorBarWaveFunction> & ain,
vector<VectorWaveFunction> & gout,
vector<SpinorBarWaveFunction> & lm, vector<SpinorWaveFunction> & lp,
bool me=false) const;
/**
* Matrix element for \f$qg\to Z/\gamma q\f$.
* @param fin Spinors for incoming quark
* @param gin Polarization vectors for the incoming gluon
* @param fout Spinors for outgoing quark
* @param lm Spinors for outgoing lepton
* @param lp Spinors for outgoing antilepton
* @param me Whether or not to calculate the matrix element for spin correlations
**/
InvEnergy2 qgME(vector<SpinorWaveFunction> & fin,vector<VectorWaveFunction> & gin,
vector<SpinorBarWaveFunction> & fout,
vector<SpinorBarWaveFunction> & lm, vector<SpinorWaveFunction> & lp,
bool me=false) const;
/**
* Matrix element for \f$\bar{q}g\to Z/\gamma\bar{q}\f$.
* @param fin Spinors for incoming antiquark
* @param gin Polarization vectors for the incoming gluon
* @param fout Spinors for outgoing antiquark
* @param lm Spinors for outgoing lepton
* @param lp Spinors for outgoing antilepton
* @param me Whether or not to calculate the matrix element for spin correlations
**/
InvEnergy2 qbargME(vector<SpinorBarWaveFunction> & fin,
vector<VectorWaveFunction> & gin,
vector<SpinorWaveFunction> & fout,
vector<SpinorBarWaveFunction> & lm, vector<SpinorWaveFunction> & lp,
bool me=false) const;
//@}
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();
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<MEPP2ZJet> initMEPP2ZJet;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEPP2ZJet & operator=(const MEPP2ZJet &);
private:
/**
* Vertices for the helicity amplitude calculation
*/
//@{
/**
* Pointer to the Z vertex
*/
AbstractFFVVertexPtr _theFFZVertex;
/**
* Pointer to the photon vertex
*/
AbstractFFVVertexPtr _theFFPVertex;
/**
* Pointer to the \f$qqg\f$ vertex
*/
AbstractFFVVertexPtr _theQQGVertex;
//@}
/**
* @name Pointers to the \f$Z^0\f$ and \f$\gamma\f$ ParticleData objects
*/
//@{
/**
* Pointer to the Z ParticleData object
*/
tcPDPtr _z0;
/**
* Pointer to the photon ParticleData object
*/
tcPDPtr _gamma;
//@}
/**
* @name Switches to control the particles in the hard process
*/
//@{
/**
* Subprocesses to include
*/
unsigned int _process;
/**
* Allowed flavours for the incoming quarks
*/
int _maxflavour;
/**
* Control over which Z decay modes to include
*/
int _zdec;
/**
* Which terms to include
*/
unsigned int _gammaZ;
/**
* Option for the treatment of the W off-shell effects
*/
unsigned int _widthopt;
//@}
/**
* Probability of selecting \f$1/s^2\f$ for the jacobian
* transformation of the boson mass
*/
double _pprob;
/**
* Matrix element for spin correlations
*/
mutable ProductionMatrixElement _me;
/**
* Storage of the scale to avoid the need to recalculate
*/
Energy2 _scale;
/**
* Storage of the off-shell Z mass to avoid the need to recalculate
*/
Energy2 _mz2;
};
}
-#include "ThePEG/Utilities/ClassTraits.h"
-
-namespace ThePEG {
-
-/** @cond TRAITSPECIALIZATIONS */
-
-/** This template specialization informs ThePEG about the
- * base classes of MEPP2ZJet. */
-template <>
-struct BaseClassTrait<Herwig::MEPP2ZJet,1> {
- /** Typedef of the first base class of MEPP2ZJet. */
- typedef Herwig::HwMEBase NthBase;
-};
-
-/** This template specialization informs ThePEG about the name of
- * the MEPP2ZJet class and the shared object where it is defined. */
-template <>
-struct ClassTraits<Herwig::MEPP2ZJet>
- : public ClassTraitsBase<Herwig::MEPP2ZJet> {
- /** Return a platform-independent class name */
- static string className() { return "Herwig::MEPP2ZJet"; }
- /**
- * The name of a file containing the dynamic library where the class
- * MEPP2ZJet is implemented. It may also include several, space-separated,
- * libraries if the class MEPP2ZJet 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_MEPP2ZJet_H */
diff --git a/MatrixElement/Hadron/MEQCD2to2.cc b/MatrixElement/Hadron/MEQCD2to2.cc
--- a/MatrixElement/Hadron/MEQCD2to2.cc
+++ b/MatrixElement/Hadron/MEQCD2to2.cc
@@ -1,1179 +1,1182 @@
// -*- C++ -*-
//
// MEQCD2to2.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEQCD2to2 class.
//
#include "MEQCD2to2.h"
+#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Utilities/SimplePhaseSpace.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "ThePEG/Cuts/Cuts.h"
#include "Herwig/MatrixElement/HardVertex.h"
using namespace Herwig;MEQCD2to2::MEQCD2to2():_maxflavour(5),_process(0) {
massOption(vector<unsigned int>(2,0));
}
void MEQCD2to2::rebind(const TranslationMap & trans)
{
_ggggvertex = trans.translate(_ggggvertex);
_gggvertex = trans.translate( _gggvertex);
_qqgvertex = trans.translate( _qqgvertex);
_gluon = trans.translate( _gluon);
for(unsigned int ix=0;ix<_quark.size();++ix)
{_quark[ix]=trans.translate(_quark[ix]);}
for(unsigned int ix=0;ix<_antiquark.size();++ix)
{_antiquark[ix]=trans.translate(_quark[ix]);}
HwMEBase::rebind(trans);
}
IVector MEQCD2to2::getReferences() {
IVector ret = HwMEBase::getReferences();
ret.push_back(_ggggvertex);
ret.push_back(_gggvertex);
ret.push_back(_qqgvertex);
ret.push_back(_gluon);
for(unsigned int ix=0;ix<_quark.size();++ix)
{ret.push_back(_quark[ix]);}
for(unsigned int ix=0;ix<_antiquark.size();++ix)
{ret.push_back(_antiquark[ix]);}
return ret;
}
void MEQCD2to2::doinit() {
// call the base class
HwMEBase::doinit();
// get the vedrtex pointers from the SM object
tcHwSMPtr hwsm= dynamic_ptr_cast<tcHwSMPtr>(standardModel());
// do the initialisation
if(hwsm) {
_qqgvertex = hwsm->vertexFFG();
_gggvertex = hwsm->vertexGGG();
_ggggvertex = hwsm->vertexGGGG();
}
else throw InitException() << "Wrong type of StandardModel object in "
<< "MEQCD2to2::doinit() the Herwig version must be used"
<< Exception::runerror;
// get the particle data objects
_gluon=getParticleData(ParticleID::g);
for(int ix=1;ix<=int(_maxflavour);++ix) {
_quark.push_back( getParticleData( ix));
_antiquark.push_back(getParticleData(-ix));
}
}
Energy2 MEQCD2to2::scale() const {
Energy2 s(sHat()),u(uHat()),t(tHat());
return 2.*s*t*u/(s*s+t*t+u*u);
}
void MEQCD2to2::persistentOutput(PersistentOStream & os) const {
os << _ggggvertex << _gggvertex << _qqgvertex << _maxflavour
<< _process << _gluon << _quark << _antiquark;
}
void MEQCD2to2::persistentInput(PersistentIStream & is, int) {
is >> _ggggvertex >> _gggvertex >> _qqgvertex >> _maxflavour
>> _process >> _gluon >> _quark >> _antiquark;
}
unsigned int MEQCD2to2::orderInAlphaS() const {
return 2;
}
unsigned int MEQCD2to2::orderInAlphaEW() const {
return 0;
}
-ClassDescription<MEQCD2to2> MEQCD2to2::initMEQCD2to2;
-// Definition of the static class description member.
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEQCD2to2,HwMEBase>
+describeHerwigMEQCD2to2("Herwig::MEQCD2to2", "HwMEHadron.so");
void MEQCD2to2::Init() {
static ClassDocumentation<MEQCD2to2> documentation
("The MEQCD2to2 class implements the QCD 2->2 processes in hadron-hadron"
" collisions");
static Parameter<MEQCD2to2,unsigned int> interfaceMaximumFlavour
("MaximumFlavour",
"The maximum flavour of the quarks in the process",
&MEQCD2to2::_maxflavour, 5, 1, 5,
false, false, Interface::limited);
static Switch<MEQCD2to2,unsigned int> interfaceProcess
("Process",
"Which subprocesses to include",
&MEQCD2to2::_process, 0, false, false);
static SwitchOption interfaceProcessAll
(interfaceProcess,
"All",
"Include all subprocesses",
0);
static SwitchOption interfaceProcess1
(interfaceProcess,
"gg2gg",
"Include only gg->gg subprocesses",
1);
static SwitchOption interfaceProcess2
(interfaceProcess,
"gg2qqbar",
"Include only gg -> q qbar processes",
2);
static SwitchOption interfaceProcessqqbargg
(interfaceProcess,
"qqbar2gg",
"Include only q qbar -> gg processes",
3);
static SwitchOption interfaceProcessqgqg
(interfaceProcess,
"qg2qg",
"Include only q g -> q g processes",
4);
static SwitchOption interfaceProcessqbargqbarg
(interfaceProcess,
"qbarg2qbarg",
"Include only qbar g -> qbar g processes",
5);
static SwitchOption interfaceProcessqqqq
(interfaceProcess,
"qq2qq",
"Include only q q -> q q processes",
6);
static SwitchOption interfaceProcessqbarqbarqbarqbar
(interfaceProcess,
"qbarqbar2qbarqbar",
"Include only qbar qbar -> qbar qbar processes",
7);
static SwitchOption interfaceProcessqqbarqqbar
(interfaceProcess,
"qqbar2qqbar",
"Include only q qbar -> q qbar processes",
8);
}
Selector<MEBase::DiagramIndex>
MEQCD2to2::diagrams(const DiagramVector & diags) const {
// select the diagram, this is easy for us as we have already done it
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i ) {
if(diags[i]->id()==-int(_diagram)) sel.insert(1.0, i);
else sel.insert(0., i);
}
return sel;
}
double MEQCD2to2::gg2qqbarME(vector<VectorWaveFunction> &g1,
vector<VectorWaveFunction> &g2,
vector<SpinorBarWaveFunction> & q,
vector<SpinorWaveFunction> & qbar,
unsigned int iflow) const {
// scale
Energy2 mt(scale());
// matrix element to be stored
if(iflow!=0) _me.reset(ProductionMatrixElement(PDT::Spin1,PDT::Spin1,
PDT::Spin1Half,PDT::Spin1Half));
// calculate the matrix element
double output(0.),sumdiag[3]={0.,0.,0.},sumflow[2]={0.,0.};
Complex diag[3],flow[2];
VectorWaveFunction interv;
SpinorWaveFunction inters;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
interv=_gggvertex->evaluate(mt,5,_gluon,g1[ihel1],g2[ihel2]);
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
//first t-channel diagram
inters =_qqgvertex->evaluate(mt,5,qbar[ohel2].particle(),
qbar[ohel2],g2[ihel2]);
diag[0]=_qqgvertex->evaluate(mt,inters,q[ohel1],g1[ihel1]);
//second t-channel diagram
inters =_qqgvertex->evaluate(mt,5,qbar[ohel2].particle(),
qbar[ohel2],g1[ihel1]);
diag[1]=_qqgvertex->evaluate(mt,inters,q[ohel1],g2[ihel2]);
// s-channel diagram
diag[2]=_qqgvertex->evaluate(mt,qbar[ohel2],q[ohel1],interv);
// colour flows
flow[0]=diag[0]+diag[2];
flow[1]=diag[1]-diag[2];
// sums
for(unsigned int ix=0;ix<3;++ix) sumdiag[ix] += norm(diag[ix]);
for(unsigned int ix=0;ix<2;++ix) sumflow[ix] += norm(flow[ix]);
// total
output +=real(flow[0]*conj(flow[0])+flow[1]*conj(flow[1])
-0.25*flow[0]*conj(flow[1]));
// store the me if needed
if(iflow!=0) _me(2*ihel1,2*ihel2,ohel1,ohel2)=flow[iflow-1];
}
}
}
}
// test code vs me from ESW
//Energy2 u(uHat()),t(tHat()),s(sHat());
//double alphas(4.*pi*SM().alphaS(mt));
//cerr << "testing matrix element "
// << 48.*(1./6./u/t-3./8./s/s)*(t*t+u*u)*sqr(alphas)/output << endl;
// select a colour flow
_flow=1+UseRandom::rnd2(sumflow[0],sumflow[1]);
// select a diagram ensuring it is one of those in the selected colour flow
sumdiag[_flow%2]=0.;
_diagram=4+UseRandom::rnd3(sumdiag[0],sumdiag[1],sumdiag[2]);
// final part of colour and spin factors
return output/48.;
}
double MEQCD2to2::qqbar2ggME(vector<SpinorWaveFunction> & q,
vector<SpinorBarWaveFunction> & qbar,
vector<VectorWaveFunction> &g1,
vector<VectorWaveFunction> &g2,
unsigned int iflow) const {
// scale
Energy2 mt(scale());
// matrix element to be stored
if(iflow!=0) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1,PDT::Spin1));
// calculate the matrix element
double output(0.),sumdiag[3]={0.,0.,0.},sumflow[2]={0.,0.};
Complex diag[3],flow[2];
VectorWaveFunction interv;
SpinorWaveFunction inters;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
interv=_qqgvertex->evaluate(mt,5,_gluon,q[ihel1],qbar[ihel2]);
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
// first t-channel diagram
inters=_qqgvertex->evaluate(mt,5,q[ihel1].particle()->CC(),
q[ihel1],g1[ohel1]);
diag[0]=_qqgvertex->evaluate(mt,inters,qbar[ihel2],g2[ohel2]);
// second t-channel diagram
inters=_qqgvertex->evaluate(mt,5,q[ihel1].particle()->CC(),
q[ihel1],g2[ohel2]);
diag[1]=_qqgvertex->evaluate(mt,inters,qbar[ihel2],g1[ohel1]);
// s-channel diagram
diag[2]=_gggvertex->evaluate(mt,g1[ohel1],g2[ohel2],interv);
// colour flows
flow[0]=diag[0]-diag[2];
flow[1]=diag[1]+diag[2];
// sums
for(unsigned int ix=0;ix<3;++ix) sumdiag[ix] += norm(diag[ix]);
for(unsigned int ix=0;ix<2;++ix) sumflow[ix] += norm(flow[ix]);
// total
output +=real(flow[0]*conj(flow[0])+flow[1]*conj(flow[1])
-0.25*flow[0]*conj(flow[1]));
// store the me if needed
if(iflow!=0) _me(ihel1,ihel2,2*ohel1,2*ohel2)=flow[iflow-1];
}
}
}
}
// test code vs me from ESW
//Energy2 u(uHat()),t(tHat()),s(sHat());
//double alphas(4.*pi*SM().alphaS(mt));
//cerr << "testing matrix element "
// << 27./2.*0.5*(32./27./u/t-8./3./s/s)*(t*t+u*u)*sqr(alphas)/output << endl;
//select a colour flow
_flow=1+UseRandom::rnd2(sumflow[0],sumflow[1]);
// select a diagram ensuring it is one of those in the selected colour flow
sumdiag[_flow%2]=0.;
_diagram=7+UseRandom::rnd3(sumdiag[0],sumdiag[1],sumdiag[2]);
// final part of colour and spin factors
return 2.*output/27.;
}
double MEQCD2to2::qg2qgME(vector<SpinorWaveFunction> & qin,
vector<VectorWaveFunction> &g2,
vector<SpinorBarWaveFunction> & qout,
vector<VectorWaveFunction> &g4,
unsigned int iflow) const {
// scale
Energy2 mt(scale());
// matrix element to be stored
if(iflow!=0) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1,
PDT::Spin1Half,PDT::Spin1));
// calculate the matrix element
double output(0.),sumdiag[3]={0.,0.,0.},sumflow[2]={0.,0.};
Complex diag[3],flow[2];
VectorWaveFunction interv;
SpinorWaveFunction inters,inters2;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
inters=_qqgvertex->evaluate(mt,5,qin[ihel1].particle()->CC(),
qin[ihel1],g2[ihel2]);
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
// s-channel diagram
diag[0]=_qqgvertex->evaluate(mt,inters,qout[ohel1],g4[ohel2]);
// first t-channel
inters2=_qqgvertex->evaluate(mt,5,qin[ihel1].particle()->CC(),
qin[ihel1],g4[ohel2]);
diag[1]=_qqgvertex->evaluate(mt,inters2,qout[ohel1],g2[ihel2]);
// second t-channel
interv=_qqgvertex->evaluate(mt,5,_gluon,qin[ihel1],qout[ohel1]);
diag[2]=_gggvertex->evaluate(mt,g2[ihel2],g4[ohel2],interv);
// colour flows
flow[0]=diag[0]-diag[2];
flow[1]=diag[1]+diag[2];
// sums
for(unsigned int ix=0;ix<3;++ix) sumdiag[ix] += norm(diag[ix]);
for(unsigned int ix=0;ix<2;++ix) sumflow[ix] += norm(flow[ix]);
// total
output +=real(flow[0]*conj(flow[0])+flow[1]*conj(flow[1])
-0.25*flow[0]*conj(flow[1]));
// store the me if needed
if(iflow!=0) _me(ihel1,2*ihel2,ohel1,2*ohel2)=flow[iflow-1];
}
}
}
}
// test code vs me from ESW
//Energy2 u(uHat()),t(tHat()),s(sHat());
//double alphas(4.*pi*SM().alphaS(mt));
//cerr << "testing matrix element "
// << 18./output*(-4./9./s/u+1./t/t)*(s*s+u*u)*sqr(alphas) << endl;
//select a colour flow
_flow=1+UseRandom::rnd2(sumflow[0],sumflow[1]);
// select a diagram ensuring it is one of those in the selected colour flow
sumdiag[_flow%2]=0.;
_diagram=10+UseRandom::rnd3(sumdiag[0],sumdiag[1],sumdiag[2]);
// final part of colour and spin factors
return output/18.;
}
double MEQCD2to2::gg2ggME(vector<VectorWaveFunction> &g1,vector<VectorWaveFunction> &g2,
vector<VectorWaveFunction> &g3,vector<VectorWaveFunction> &g4,
unsigned int iflow) const {
// colour factors for different flows
static const double c1 = 4.*( sqr(9.)/8.-3.*9./8.+1.-0.75/9.);
static const double c2 = 4.*(-0.25*9. +1.-0.75/9.);
// scale
Energy2 mt(scale());
// // matrix element to be stored
if(iflow!=0) _me.reset(ProductionMatrixElement(PDT::Spin1,PDT::Spin1,
PDT::Spin1,PDT::Spin1));
// calculate the matrix element
double output(0.),sumdiag[3]={0.,0.,0.},sumflow[3]={0.,0.,0.};
Complex diag[3],flow[3];
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) {
// s-channel diagram
diag[0]=_ggggvertex->evaluate(mt,1,g3[ohel1],g1[ihel1],
g4[ohel2],g2[ihel2]);
// t-channel
diag[1]=_ggggvertex->evaluate(mt,1,g1[ihel1],g2[ihel2],
g3[ohel1],g4[ohel2]);
// u-channel
diag[2]=_ggggvertex->evaluate(mt,1,g2[ihel2],g1[ihel1],
g3[ohel1],g4[ohel2]);
// colour flows
flow[0] = diag[0]-diag[2];
flow[1] = -diag[0]-diag[1];
flow[2] = diag[1]+diag[2];
// sums
for(unsigned int ix=0;ix<3;++ix) {
sumdiag[ix] += norm(diag[ix]);
sumflow[ix] += norm(flow[ix]);
}
// total
output += c1*(norm(flow[0])+norm(flow[1])+norm(flow[2]))
+2.*c2*real(flow[0]*conj(flow[1])+flow[0]*conj(flow[2])+
flow[1]*conj(flow[2]));
// store the me if needed
if(iflow!=0) _me(2*ihel1,2*ihel2,2*ohel1,2*ohel2)=flow[iflow-1];
}
}
}
}
// spin, colour and identical particle factorsxs
output /= 4.*64.*2.;
// test code vs me from ESW
// Energy2 u(uHat()),t(tHat()),s(sHat());
// using Constants::pi;
// double alphas(4.*pi*SM().alphaS(mt));
// cerr << "testing matrix element "
// << 1./output*9./4.*(3.-t*u/s/s-s*u/t/t-s*t/u/u)*sqr(alphas) << endl;
// select a colour flow
_flow=1+UseRandom::rnd3(sumflow[0],sumflow[1],sumflow[2]);
// and diagram
if(_flow==1) _diagram = 1+2*UseRandom::rnd2(sumdiag[0],sumdiag[2]);
else if(_flow==2) _diagram = 1+ UseRandom::rnd2(sumdiag[0],sumdiag[1]);
else if(_flow==3) _diagram = 2+ UseRandom::rnd2(sumdiag[1],sumdiag[2]);
// final part of colour and spin factors
return output;
}
double MEQCD2to2::qbarg2qbargME(vector<SpinorBarWaveFunction> & qin,
vector<VectorWaveFunction> &g2,
vector<SpinorWaveFunction> & qout,
vector<VectorWaveFunction> &g4,
unsigned int iflow) const {
// scale
Energy2 mt(scale());
// matrix element to be stored
if(iflow!=0) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1,
PDT::Spin1Half,PDT::Spin1));
// calculate the matrix element
double output(0.),sumdiag[3]={0.,0.,0.},sumflow[2]={0.,0.};
Complex diag[3],flow[2];
VectorWaveFunction interv;
SpinorBarWaveFunction inters,inters2;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
inters=_qqgvertex->evaluate(mt,5,qin[ihel1].particle()->CC(),
qin[ihel1],g2[ihel2]);
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
// s-channel diagram
diag[0]=_qqgvertex->evaluate(mt,qout[ohel1],inters,g4[ohel2]);
// first t-channel
inters2=_qqgvertex->evaluate(mt,5,qin[ihel1].particle()->CC(),
qin[ihel1],g4[ohel2]);
diag[1]=_qqgvertex->evaluate(mt,qout[ohel1],inters2,g2[ihel2]);
// second t-channel
interv=_qqgvertex->evaluate(mt,5,_gluon,qout[ohel1],qin[ihel1]);
diag[2]=_gggvertex->evaluate(mt,g2[ihel2],g4[ohel2],interv);
// colour flows
flow[0]=diag[0]+diag[2];
flow[1]=diag[1]-diag[2];
// sums
for(unsigned int ix=0;ix<3;++ix) sumdiag[ix] += norm(diag[ix]);
for(unsigned int ix=0;ix<2;++ix) sumflow[ix] += norm(flow[ix]);
// total
output +=real(flow[0]*conj(flow[0])+flow[1]*conj(flow[1])
-0.25*flow[0]*conj(flow[1]));
// store the me if needed
if(iflow!=0) _me(ihel1,2*ihel2,ohel1,2*ohel2)=flow[iflow-1];
}
}
}
}
// test code vs me from ESW
//Energy2 u(uHat()),t(tHat()),s(sHat());
//double alphas(4.*pi*SM().alphaS(mt));
//cerr << "testing matrix element "
// << 18./output*(-4./9./s/u+1./t/t)*(s*s+u*u)*sqr(alphas) << endl;
//select a colour flow
_flow=1+UseRandom::rnd2(sumflow[0],sumflow[1]);
// select a diagram ensuring it is one of those in the selected colour flow
sumdiag[_flow%2]=0.;
_diagram=13+UseRandom::rnd3(sumdiag[0],sumdiag[1],sumdiag[2]);
// final part of colour and spin factors
return output/18.;
}
double MEQCD2to2::qq2qqME(vector<SpinorWaveFunction> & q1,
vector<SpinorWaveFunction> & q2,
vector<SpinorBarWaveFunction> & q3,
vector<SpinorBarWaveFunction> & q4,
unsigned int iflow) const {
// identify special case of identical quarks
bool identical(q1[0].id()==q2[0].id());
// scale
Energy2 mt(scale());
// matrix element to be stored
if(iflow!=0) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half));
// calculate the matrix element
double output(0.),sumdiag[2]={0.,0.};
Complex diag[2];
VectorWaveFunction interv;
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) {
// first diagram
interv = _qqgvertex->evaluate(mt,5,_gluon,q1[ihel1],q3[ohel1]);
diag[0] = _qqgvertex->evaluate(mt,q2[ihel2],q4[ohel2],interv);
// second diagram if identical
if(identical) {
interv = _qqgvertex->evaluate(mt,5,_gluon,q1[ihel1],q4[ohel2]);
diag[1]=_qqgvertex->evaluate(mt,q2[ihel2],q3[ohel1],interv);
}
else diag[1]=0.;
// sum of diagrams
for(unsigned int ix=0;ix<2;++ix) sumdiag[ix] += norm(diag[ix]);
// total
output +=real(diag[0]*conj(diag[0])+diag[1]*conj(diag[1])
+2./3.*diag[0]*conj(diag[1]));
// store the me if needed
if(iflow!=0) _me(ihel1,ihel2,ohel1,ohel2)=diag[iflow-1];
}
}
}
}
// identical particle symmetry factor if needed
if(identical) output*=0.5;
// test code vs me from ESW
//Energy2 u(uHat()),t(tHat()),s(sHat());
//double alphas(4.*pi*SM().alphaS(mt));
//if(identical)
// {cerr << "testing matrix element A "
// << 18./output*0.5*(4./9.*((s*s+u*u)/t/t+(s*s+t*t)/u/u)
// -8./27.*s*s/u/t)*sqr(alphas) << endl;}
//else
// {cerr << "testing matrix element B "
// << 18./output*(4./9.*(s*s+u*u)/t/t)*sqr(alphas) << endl;}
//select a colour flow
_flow=1+UseRandom::rnd2(sumdiag[0],sumdiag[1]);
// select a diagram ensuring it is one of those in the selected colour flow
sumdiag[_flow%2]=0.;
_diagram=16+UseRandom::rnd2(sumdiag[0],sumdiag[1]);
// final part of colour and spin factors
return output/18.;
}
double MEQCD2to2::qbarqbar2qbarqbarME(vector<SpinorBarWaveFunction> & q1,
vector<SpinorBarWaveFunction> & q2,
vector<SpinorWaveFunction> & q3,
vector<SpinorWaveFunction> & q4,
unsigned int iflow) const {
// identify special case of identical quarks
bool identical(q1[0].id()==q2[0].id());
// scale
Energy2 mt(scale());
// matrix element to be stored
if(iflow!=0)
{_me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half));}
// calculate the matrix element
double output(0.),sumdiag[2]={0.,0.};
Complex diag[2];
VectorWaveFunction interv;
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) {
// first diagram
interv = _qqgvertex->evaluate(mt,5,_gluon,q3[ohel1],q1[ihel1]);
diag[0] = _qqgvertex->evaluate(mt,q4[ohel2],q2[ihel2],interv);
// second diagram if identical
if(identical) {
interv = _qqgvertex->evaluate(mt,5,_gluon,q4[ohel2],q1[ihel1]);
diag[1]=_qqgvertex->evaluate(mt,q3[ohel1],q2[ihel2],interv);
}
else diag[1]=0.;
// sum of diagrams
for(unsigned int ix=0;ix<2;++ix) sumdiag[ix] += norm(diag[ix]);
// total
output +=real(diag[0]*conj(diag[0])+diag[1]*conj(diag[1])
+2./3.*diag[0]*conj(diag[1]));
// store the me if needed
if(iflow!=0) _me(ihel1,ihel2,ohel1,ohel2)=diag[iflow-1];
}
}
}
}
// identical particle symmetry factor if needed
if(identical){output*=0.5;}
// test code vs me from ESW
// Energy2 u(uHat()),t(tHat()),s(sHat());
// double alphas(4.*pi*SM().alphaS(mt));
// if(identical)
// {cerr << "testing matrix element A "
// << 18./output*0.5*(4./9.*((s*s+u*u)/t/t+(s*s+t*t)/u/u)
// -8./27.*s*s/u/t)*sqr(alphas) << endl;}
// else
// {cerr << "testing matrix element B "
// << 18./output*(4./9.*(s*s+u*u)/t/t)*sqr(alphas) << endl;}
//select a colour flow
_flow=1+UseRandom::rnd2(sumdiag[0],sumdiag[1]);
// select a diagram ensuring it is one of those in the selected colour flow
sumdiag[_flow%2]=0.;
_diagram=18+UseRandom::rnd2(sumdiag[0],sumdiag[1]);
// final part of colour and spin factors
return output/18.;
}
double MEQCD2to2::qqbar2qqbarME(vector<SpinorWaveFunction> & q1,
vector<SpinorBarWaveFunction> & q2,
vector<SpinorBarWaveFunction> & q3,
vector<SpinorWaveFunction> & q4,
unsigned int iflow) const {
// type of process
bool diagon[2]={q1[0].id()== -q2[0].id(),
q1[0].id()== -q3[0].id()};
// scale
Energy2 mt(scale());
// matrix element to be stored
if(iflow!=0) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half));
// calculate the matrix element
double output(0.),sumdiag[2]={0.,0.};
Complex diag[2];
VectorWaveFunction interv;
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) {
// first diagram
if(diagon[0]) {
interv = _qqgvertex->evaluate(mt,5,_gluon,q1[ihel1],q2[ihel2]);
diag[0] = _qqgvertex->evaluate(mt,q4[ohel2],q3[ohel1],interv);
}
else diag[0]=0.;
// second diagram
if(diagon[1]) {
interv = _qqgvertex->evaluate(mt,5,_gluon,q1[ihel1],q3[ohel1]);
diag[1]=_qqgvertex->evaluate(mt,q4[ohel2],q2[ihel2],interv);
}
else diag[1]=0.;
// sum of diagrams
for(unsigned int ix=0;ix<2;++ix) sumdiag[ix] += norm(diag[ix]);
// total
output +=real(diag[0]*conj(diag[0])+diag[1]*conj(diag[1])
+2./3.*diag[0]*conj(diag[1]));
// store the me if needed
if(iflow!=0){_me(ihel1,ihel2,ohel1,ohel2)=diag[iflow-1];}
}
}
}
}
// test code vs me from ESW
// Energy2 u(uHat()),t(tHat()),s(sHat());
// double alphas(4.*pi*SM().alphaS(mt));
// if(diagon[0]&&diagon[1]) {
// cerr << "testing matrix element A "
// << q1[0].id() << " " << q2[0].id() << " -> "
// << q3[0].id() << " " << q4[0].id() << " "
// << 18./output*0.5*(4./9.*((s*s+u*u)/t/t+(u*u+t*t)/s/s)
// -8./27.*u*u/s/t)*sqr(alphas) << endl;
// }
// else if(diagon[0]) {
// cerr << "testing matrix element B "
// << q1[0].id() << " " << q2[0].id() << " -> "
// << q3[0].id() << " " << q4[0].id() << " "
// << 18./output*(4./9.*(t*t+u*u)/s/s)*sqr(alphas) << endl;
// }
// else if(diagon[1]) {
// cerr << "testing matrix element C "
// << q1[0].id() << " " << q2[0].id() << " -> "
// << q3[0].id() << " " << q4[0].id() << " "
// << 18./output*(4./9.*(s*s+u*u)/t/t)*sqr(alphas) << endl;
// }
//select a colour flow
_flow=1+UseRandom::rnd2(sumdiag[0],sumdiag[1]);
// select a diagram ensuring it is one of those in the selected colour flow
sumdiag[_flow%2]=0.;
_diagram=20+UseRandom::rnd2(sumdiag[0],sumdiag[1]);
// final part of colour and spin factors
return output/18.;
}
void MEQCD2to2::getDiagrams() const {
// gg-> gg subprocess
if(_process==0||_process==1) {
// s-channel
add(new_ptr((Tree2toNDiagram(2),_gluon,_gluon, 1, _gluon,
3,_gluon, 3, _gluon, -1)));
// first t-channel
add(new_ptr((Tree2toNDiagram(3),_gluon,_gluon,_gluon,
1,_gluon, 2,_gluon,-2)));
// second t-channel
add(new_ptr((Tree2toNDiagram(3),_gluon,_gluon,_gluon,
2,_gluon, 1,_gluon,-3)));
}
// processes involving one quark line
for(unsigned int ix=0;ix<_maxflavour;++ix) {
// gg -> q qbar subprocesses
if(_process==0||_process==2) {
// first t-channel
add(new_ptr((Tree2toNDiagram(3),_gluon,_antiquark[ix],_gluon,
1,_quark[ix], 2,_antiquark[ix],-4)));
// interchange
add(new_ptr((Tree2toNDiagram(3),_gluon,_antiquark[ix],_gluon,
2,_quark[ix], 1,_antiquark[ix],-5)));
// s-channel
add(new_ptr((Tree2toNDiagram(2),_gluon,_gluon, 1, _gluon,
3,_quark[ix], 3, _antiquark[ix], -6)));
}
// q qbar -> g g subprocesses
if(_process==0||_process==3) {
// first t-channel
add(new_ptr((Tree2toNDiagram(3),_quark[ix],_antiquark[ix],_antiquark[ix],
1,_gluon, 2,_gluon,-7)));
// second t-channel
add(new_ptr((Tree2toNDiagram(3),_quark[ix],_antiquark[ix],_antiquark[ix],
2,_gluon, 1,_gluon,-8)));
// s-channel
add(new_ptr((Tree2toNDiagram(2),_quark[ix], _antiquark[ix],
1, _gluon, 3, _gluon, 3, _gluon,-9)));
}
// q g -> q g subprocesses
if(_process==0||_process==4) {
// s-channel
add(new_ptr((Tree2toNDiagram(2),_quark[ix], _gluon,
1, _quark[ix], 3, _quark[ix], 3, _gluon,-10)));
// quark t-channel
add(new_ptr((Tree2toNDiagram(3),_quark[ix],_quark[ix],_gluon,
2,_quark[ix],1,_gluon,-11)));
// gluon t-channel
add(new_ptr((Tree2toNDiagram(3),_quark[ix],_gluon,_gluon,
1,_quark[ix],2,_gluon,-12)));
}
// qbar g -> qbar g subprocesses
if(_process==0||_process==5) {
// s-channel
add(new_ptr((Tree2toNDiagram(2),_antiquark[ix], _gluon,
1, _antiquark[ix], 3, _antiquark[ix], 3, _gluon,-13)));
// quark t-channel
add(new_ptr((Tree2toNDiagram(3),_antiquark[ix],_antiquark[ix],_gluon,
2,_antiquark[ix],1,_gluon,-14)));
// gluon t-channel
add(new_ptr((Tree2toNDiagram(3),_antiquark[ix],_gluon,_gluon,
1,_antiquark[ix],2,_gluon,-15)));
}
// processes involving two quark lines
for(unsigned int iy=ix;iy<_maxflavour;++iy) {
// q q -> q q subprocesses
if(_process==0||_process==6) {
// gluon t-channel
add(new_ptr((Tree2toNDiagram(3),_quark[ix],_gluon,_quark[iy],
1,_quark[ix],2,_quark[iy],-16)));
// exchange for identical quarks
if(ix==iy)
add(new_ptr((Tree2toNDiagram(3),_quark[ix],_gluon,_quark[iy],
2,_quark[ix],1,_quark[iy],-17)));
}
// qbar qbar -> qbar qbar subprocesses
if(_process==0||_process==7) {
// gluon t-channel
add(new_ptr((Tree2toNDiagram(3),_antiquark[ix],_gluon,_antiquark[iy],
1,_antiquark[ix],2,_antiquark[iy],-18)));
// exchange for identical quarks
if(ix==iy)
add(new_ptr((Tree2toNDiagram(3),_antiquark[ix],_gluon,_antiquark[iy],
2,_antiquark[ix],1,_antiquark[iy],-19)));
}
}
for(unsigned int iy=0;iy<_maxflavour;++iy) {
// q qbar -> q qbar
if(_process==0||_process==8) {
// gluon s-channel
add(new_ptr((Tree2toNDiagram(2),_quark[ix], _antiquark[ix],
1, _gluon, 3, _quark[iy], 3, _antiquark[iy],-20)));
// gluon t-channel
add(new_ptr((Tree2toNDiagram(3),_quark[ix],_gluon,_antiquark[iy],
1,_quark[ix],2,_antiquark[iy],-21)));
}
}
}
}
Selector<const ColourLines *>
MEQCD2to2::colourGeometries(tcDiagPtr diag) const {
// colour lines for gg to gg
static const ColourLines cgggg[12]={ColourLines("1 -2, -1 -3 -5, 5 -4, 2 3 4"),// A_2 s
ColourLines("-1 2, 1 3 5, -5 4, -2 -3 -4"),// A_1 s
ColourLines("1 5, -1 -2 3, -3 -4, -5 2 4"),// A_1 u
ColourLines("-1 -5, 1 2 -3, 3 4, 5 -2 -4"),// A_2 u
ColourLines("1 -2, -1 -3 -4, 4 -5, 2 3 5"),// B_2 s
ColourLines("-1 2, 1 3 4, -4 5, -2 -3 -5"),// B_1 s
ColourLines("1 4, -1 -2 3, -3 -5, -4 2 5"),// B_1 t
ColourLines("-1 -4, 1 2 -3, 3 5, 4 -2 -5"),// B_2 t
ColourLines("1 4, -1 -2 -5, 3 5, -3 2 -4"),// C_1 t
ColourLines("-1 -4, 1 2 5, -3 -5, 3 -2 4"),// C_2 t
ColourLines("1 5, -1 -2 -4, 3 4, -3 2 -5"),// C_1 u
ColourLines("-1 -5, 1 2 4, -3 -4, 3 -2 5") // C_2 u
};
// colour lines for gg to q qbar
static const ColourLines cggqq[4]={ColourLines("1 4, -1 -2 3, -3 -5"),
ColourLines("3 4, -3 -2 1, -1 -5"),
ColourLines("2 -1, 1 3 4, -2 -3 -5"),
ColourLines("1 -2, -1 -3 -5, 2 3 4")};
// colour lines for q qbar to gg
static const ColourLines cqqgg[4]={ColourLines("1 4, -4 -2 5, -3 -5"),
ColourLines("1 5, -3 -4, 4 -2 -5"),
ColourLines("1 3 4, -4 5, -2 -3 -5"),
ColourLines("1 3 5, -5 4, -2 -3 -4")};
// colour lines for q g to q g
static const ColourLines cqgqg[4]={ColourLines("1 -2, 2 3 5, 4 -5"),
ColourLines("1 5, 3 4,-3 2 -5 "),
ColourLines("1 2 -3, 3 5, -5 -2 4"),
ColourLines("1 -2 5,3 2 4,-3 -5")};
// colour lines for qbar g -> qbar g
static const ColourLines cqbgqbg[4]={ColourLines("-1 2, -2 -3 -5, -4 5"),
ColourLines("-1 -5, -3 -4, 3 -2 5"),
ColourLines("-1 -2 3, -3 -5, 5 2 -4"),
ColourLines("-1 2 -5,-3 -2 -4, 3 5")};
// colour lines for q q -> q q
static const ColourLines cqqqq[2]={ColourLines("1 2 5,3 -2 4"),
ColourLines("1 2 4,3 -2 5")};
// colour lines for qbar qbar -> qbar qbar
static const ColourLines cqbqbqbqb[2]={ColourLines("-1 -2 -5,-3 2 -4"),
ColourLines("-1 -2 -4,-3 2 -5")};
// colour lines for q qbar -> q qbar
static const ColourLines cqqbqqb[2]={ColourLines("1 3 4,-2 -3 -5"),
ColourLines("1 2 -3,4 -2 -5")};
// select the colour flow (as all ready picked just insert answer)
Selector<const ColourLines *> sel;
switch(abs(diag->id())) {
// gg -> gg subprocess
case 1:
if(_flow==1) {
sel.insert(0.5, &cgggg[0]);
sel.insert(0.5, &cgggg[1]);
}
else {
sel.insert(0.5, &cgggg[4]);
sel.insert(0.5, &cgggg[5]);
}
break;
case 2:
if(_flow==2) {
sel.insert(0.5, &cgggg[6]);
sel.insert(0.5, &cgggg[7]);
}
else {
sel.insert(0.5, &cgggg[8]);
sel.insert(0.5, &cgggg[9]);
}
break;
case 3:
if(_flow==1) {
sel.insert(0.5, &cgggg[2]);
sel.insert(0.5, &cgggg[3]);
}
else {
sel.insert(0.5, &cgggg[10]);
sel.insert(0.5, &cgggg[11]);
}
break;
// gg -> q qbar subprocess
case 4: case 5:
sel.insert(1.0, &cggqq[abs(diag->id())-4]);
break;
case 6:
sel.insert(1.0, &cggqq[1+_flow]);
break;
// q qbar -> gg subprocess
case 7: case 8:
sel.insert(1.0, &cqqgg[abs(diag->id())-7]);
break;
case 9:
sel.insert(1.0, &cqqgg[1+_flow]);
break;
// q g -> q g subprocess
case 10: case 11:
sel.insert(1.0, &cqgqg[abs(diag->id())-10]);
break;
case 12:
sel.insert(1.0, &cqgqg[1+_flow]);
break;
// q g -> q g subprocess
case 13: case 14:
sel.insert(1.0, &cqbgqbg[abs(diag->id())-13]);
break;
case 15:
sel.insert(1.0, &cqbgqbg[1+_flow]);
break;
// q q -> q q subprocess
case 16: case 17:
sel.insert(1.0, &cqqqq[abs(diag->id())-16]);
break;
// qbar qbar -> qbar qbar subprocess
case 18: case 19:
sel.insert(1.0, &cqbqbqbqb[abs(diag->id())-18]);
break;
// q qbar -> q qbar subprocess
case 20: case 21:
sel.insert(1.0, &cqqbqqb[abs(diag->id())-20]);
break;
}
return sel;
}
double MEQCD2to2::me2() const {
// total matrix element
double me(0.);
// gg initiated processes
if(mePartonData()[0]->id()==ParticleID::g&&mePartonData()[1]->id()==ParticleID::g) {
// gg -> gg
if(mePartonData()[2]->id()==ParticleID::g) {
VectorWaveFunction g1w(meMomenta()[0],mePartonData()[0],incoming);
VectorWaveFunction g2w(meMomenta()[1],mePartonData()[1],incoming);
VectorWaveFunction g3w(meMomenta()[2],mePartonData()[2],outgoing);
VectorWaveFunction g4w(meMomenta()[3],mePartonData()[3],outgoing);
vector<VectorWaveFunction> g1,g2,g3,g4;
for(unsigned int ix=0;ix<2;++ix) {
g1w.reset(2*ix);g1.push_back(g1w);
g2w.reset(2*ix);g2.push_back(g2w);
g3w.reset(2*ix);g3.push_back(g3w);
g4w.reset(2*ix);g4.push_back(g4w);
}
// calculate the matrix element
me = gg2ggME(g1,g2,g3,g4,0);
}
// gg -> q qbar
else {
VectorWaveFunction g1w(meMomenta()[0],mePartonData()[0],incoming);
VectorWaveFunction g2w(meMomenta()[1],mePartonData()[1],incoming);
SpinorBarWaveFunction qw(meMomenta()[2],mePartonData()[2],outgoing);
SpinorWaveFunction qbarw(meMomenta()[3],mePartonData()[3],outgoing);
vector<VectorWaveFunction> g1,g2;
vector<SpinorBarWaveFunction> q;
vector<SpinorWaveFunction> qbar;
for(unsigned int ix=0;ix<2;++ix) {
g1w.reset(2*ix);g1.push_back(g1w);
g2w.reset(2*ix);g2.push_back(g2w);
qw.reset(ix);q.push_back(qw);
qbarw.reset(ix);qbar.push_back(qbarw);
}
// calculate the matrix element
me=gg2qqbarME(g1,g2,q,qbar,0);
}
}
// quark first processes
else if(mePartonData()[0]->id()>0) {
// q g -> q g
if(mePartonData()[1]->id()==ParticleID::g) {
SpinorWaveFunction qinw(meMomenta()[0],mePartonData()[0],incoming);
VectorWaveFunction g2w(meMomenta()[1],mePartonData()[1],incoming);
SpinorBarWaveFunction qoutw(meMomenta()[2],mePartonData()[2],outgoing);
VectorWaveFunction g4w(meMomenta()[3],mePartonData()[3],outgoing);
vector<VectorWaveFunction> g2,g4;
vector<SpinorWaveFunction> qin;
vector<SpinorBarWaveFunction> qout;
for(unsigned int ix=0;ix<2;++ix) {
qinw.reset(ix);qin.push_back(qinw);
g2w.reset(2*ix);g2.push_back(g2w);
qoutw.reset(ix);qout.push_back(qoutw);
g4w.reset(2*ix);g4.push_back(g4w);
}
// calculate the matrix element
me = qg2qgME(qin,g2,qout,g4,0);
}
else if(mePartonData()[1]->id()<0) {
// q qbar initiated processes( q qbar -> gg)
if(mePartonData()[2]->id()==ParticleID::g) {
SpinorWaveFunction qw(meMomenta()[0],mePartonData()[0],incoming);
SpinorBarWaveFunction qbarw(meMomenta()[1],mePartonData()[1],incoming);
VectorWaveFunction g1w(meMomenta()[2],mePartonData()[2],outgoing);
VectorWaveFunction g2w(meMomenta()[3],mePartonData()[3],outgoing);
vector<VectorWaveFunction> g1,g2;
vector<SpinorWaveFunction> q;
vector<SpinorBarWaveFunction> qbar;
for(unsigned int ix=0;ix<2;++ix) {
qw.reset(ix);q.push_back(qw);
qbarw.reset(ix);qbar.push_back(qbarw);
g1w.reset(2*ix);g1.push_back(g1w);
g2w.reset(2*ix);g2.push_back(g2w);
}
// calculate the matrix element
me = qqbar2ggME(q,qbar,g1,g2,0);
}
// q qbar to q qbar
else {
SpinorWaveFunction q1w(meMomenta()[0],mePartonData()[0],incoming);
SpinorBarWaveFunction q2w(meMomenta()[1],mePartonData()[1],incoming);
SpinorBarWaveFunction q3w(meMomenta()[2],mePartonData()[2],outgoing);
SpinorWaveFunction q4w(meMomenta()[3],mePartonData()[3],outgoing);
vector<SpinorWaveFunction> q1,q4;
vector<SpinorBarWaveFunction> q2,q3;
for(unsigned int ix=0;ix<2;++ix) {
q1w.reset(ix);q1.push_back(q1w);
q2w.reset(ix);q2.push_back(q2w);
q3w.reset(ix);q3.push_back(q3w);
q4w.reset(ix);q4.push_back(q4w);
}
// calculate the matrix element
me = qqbar2qqbarME(q1,q2,q3,q4,0);
}
}
// q q -> q q
else if(mePartonData()[1]->id()>0) {
SpinorWaveFunction q1w(meMomenta()[0],mePartonData()[0],incoming);
SpinorWaveFunction q2w(meMomenta()[1],mePartonData()[1],incoming);
SpinorBarWaveFunction q3w(meMomenta()[2],mePartonData()[2],outgoing);
SpinorBarWaveFunction q4w(meMomenta()[3],mePartonData()[3],outgoing);
vector<SpinorWaveFunction> q1,q2;
vector<SpinorBarWaveFunction> q3,q4;
for(unsigned int ix=0;ix<2;++ix) {
q1w.reset(ix);q1.push_back(q1w);
q2w.reset(ix);q2.push_back(q2w);
q3w.reset(ix);q3.push_back(q3w);
q4w.reset(ix);q4.push_back(q4w);
}
// calculate the matrix element
me = qq2qqME(q1,q2,q3,q4,0);
}
}
// antiquark first processes
else if(mePartonData()[0]->id()<0) {
// qbar g -> qbar g
if(mePartonData()[1]->id()==ParticleID::g) {
SpinorBarWaveFunction qinw(meMomenta()[0],mePartonData()[0],incoming);
VectorWaveFunction g2w(meMomenta()[1],mePartonData()[1],incoming);
SpinorWaveFunction qoutw(meMomenta()[2],mePartonData()[2],outgoing);
VectorWaveFunction g4w(meMomenta()[3],mePartonData()[3],outgoing);
vector<VectorWaveFunction> g2,g4;
vector<SpinorBarWaveFunction> qin;
vector<SpinorWaveFunction> qout;
for(unsigned int ix=0;ix<2;++ix) {
qinw.reset(ix);qin.push_back(qinw);
g2w.reset(2*ix);g2.push_back(g2w);
qoutw.reset(ix);qout.push_back(qoutw);
g4w.reset(2*ix);g4.push_back(g4w);
}
// calculate the matrix element
me = qbarg2qbargME(qin,g2,qout,g4,0);
}
// qbar qbar -> qbar qbar
else if(mePartonData()[1]->id()<0) {
SpinorBarWaveFunction q1w(meMomenta()[0],mePartonData()[0],incoming);
SpinorBarWaveFunction q2w(meMomenta()[1],mePartonData()[1],incoming);
SpinorWaveFunction q3w(meMomenta()[2],mePartonData()[2],outgoing);
SpinorWaveFunction q4w(meMomenta()[3],mePartonData()[3],outgoing);
vector<SpinorBarWaveFunction> q1,q2;
vector<SpinorWaveFunction> q3,q4;
for(unsigned int ix=0;ix<2;++ix) {
q1w.reset(ix);q1.push_back(q1w);
q2w.reset(ix);q2.push_back(q2w);
q3w.reset(ix);q3.push_back(q3w);
q4w.reset(ix);q4.push_back(q4w);
}
// calculate the matrix element
me = qbarqbar2qbarqbarME(q1,q2,q3,q4,0);
}
}
else throw Exception() << "Unknown process in MEQCD2to2::me2()"
<< Exception::abortnow;
// return the answer
return me;
}
void MEQCD2to2::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]);
// order of particles
unsigned int order[4]={0,1,2,3};
// identify the process and calculate the matrix element
if(hard[0]->id()==ParticleID::g&&hard[1]->id()==ParticleID::g) {
// gg -> gg
if(hard[2]->id()==ParticleID::g) {
vector<VectorWaveFunction> g1,g2,g3,g4;
VectorWaveFunction(g1,hard[0],incoming,false,true,true);
VectorWaveFunction(g2,hard[1],incoming,false,true,true);
VectorWaveFunction(g3,hard[2],outgoing,true ,true,true);
VectorWaveFunction(g4,hard[3],outgoing,true ,true,true);
g1[1]=g1[2];g2[1]=g2[2];g3[1]=g3[2];g4[1]=g4[2];
gg2ggME(g1,g2,g3,g4,_flow);
}
// gg -> q qbar
else {
if(hard[2]->id()<0) swap(order[2],order[3]);
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);
SpinorBarWaveFunction(q ,hard[order[2]],outgoing,true ,true);
SpinorWaveFunction( qbar,hard[order[3]],outgoing,true ,true);
g1[1]=g1[2];g2[1]=g2[2];
gg2qqbarME(g1,g2,q,qbar,_flow);
}
}
else if(hard[0]->id()==ParticleID::g||hard[1]->id()==ParticleID::g) {
if(hard[0]->id()==ParticleID::g) swap(order[0],order[1]);
if(hard[2]->id()==ParticleID::g) swap(order[2],order[3]);
// q g -> q g
if(hard[order[0]]->id()>0) {
vector<VectorWaveFunction> g2,g4;
vector<SpinorWaveFunction> qin;
vector<SpinorBarWaveFunction> qout;
SpinorWaveFunction( qin,hard[order[0]],incoming,false,true);
VectorWaveFunction( g2,hard[order[1]],incoming,false,true,true);
SpinorBarWaveFunction(qout,hard[order[2]],outgoing,true ,true);
VectorWaveFunction( g4,hard[order[3]],outgoing,true ,true,true);
g2[1]=g2[2];g4[1]=g4[2];
qg2qgME(qin,g2,qout,g4,_flow);
}
// qbar g -> qbar g
else {
vector<VectorWaveFunction> g2,g4;
vector<SpinorBarWaveFunction> qin;
vector<SpinorWaveFunction> qout;
SpinorBarWaveFunction( qin,hard[order[0]],incoming,false,true);
VectorWaveFunction( g2,hard[order[1]],incoming,false,true,true);
SpinorWaveFunction( qout,hard[order[2]],outgoing,true ,true);
VectorWaveFunction( g4,hard[order[3]],outgoing,true ,true,true);
g2[1]=g2[2];g4[1]=g4[2];
qbarg2qbargME(qin,g2,qout,g4,_flow);
}
}
else if(hard[0]->id()>0||hard[1]->id()>0) {
if(hard[2]->id()==ParticleID::g) {
if(hard[0]->id()<0) swap(order[0],order[1]);
vector<SpinorBarWaveFunction> qbar;
vector<SpinorWaveFunction> q;
vector<VectorWaveFunction> g3,g4;
SpinorWaveFunction( q ,hard[order[0]],incoming,false,true);
SpinorBarWaveFunction(qbar,hard[order[1]],incoming,false,true);
VectorWaveFunction( g3,hard[ 2 ],outgoing,true ,true,true);
VectorWaveFunction( g4,hard[ 3 ],outgoing,true ,true,true);
g3[1]=g3[2];g4[1]=g4[2];
qqbar2ggME(q,qbar,g3,g4,_flow);
}
// q q -> q q
else if(hard[0]->id()>0&&hard[1]->id()>0) {
if(hard[2]->id()!=hard[0]->id()) swap(order[2],order[3]);
vector<SpinorWaveFunction> q1,q2;
vector<SpinorBarWaveFunction> q3,q4;
SpinorWaveFunction( q1,hard[order[0]],incoming,false,true);
SpinorWaveFunction( q2,hard[order[1]],incoming,false,true);
SpinorBarWaveFunction(q3,hard[order[2]],outgoing,true ,true);
SpinorBarWaveFunction(q4,hard[order[3]],outgoing,true ,true);
qq2qqME(q1,q2,q3,q4,_flow);
}
// q qbar -> q qbar
else {
if(hard[0]->id()<0) swap(order[0],order[1]);
if(hard[2]->id()<0) swap(order[2],order[3]);
vector<SpinorWaveFunction> q1,q4;
vector<SpinorBarWaveFunction> q2,q3;
SpinorWaveFunction( q1,hard[order[0]],incoming,false,true);
SpinorBarWaveFunction(q2,hard[order[1]],incoming,false,true);
SpinorBarWaveFunction(q3,hard[order[2]],outgoing,true ,true);
SpinorWaveFunction( q4,hard[order[3]],outgoing,true ,true);
qqbar2qqbarME(q1,q2,q3,q4,_flow);
}
}
else if (hard[0]->id()<0&&hard[1]->id()<0) {
if(hard[2]->id()!=hard[0]->id()) swap(order[2],order[3]);
vector<SpinorBarWaveFunction> q1,q2;
vector<SpinorWaveFunction> q3,q4;
SpinorBarWaveFunction(q1,hard[order[0]],incoming,false,true);
SpinorBarWaveFunction(q2,hard[order[1]],incoming,false,true);
SpinorWaveFunction( q3,hard[order[2]],outgoing,true ,true);
SpinorWaveFunction( q4,hard[order[3]],outgoing,true ,true);
qbarqbar2qbarqbarME(q1,q2,q3,q4,_flow);
}
else throw Exception() << "Unknown process in MEQCD2to2::constructVertex()"
<< Exception::runerror;
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(_me);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<4;++ix)
hard[order[ix]]->spinInfo()->productionVertex(hardvertex);
}
diff --git a/MatrixElement/Hadron/MEQCD2to2.h b/MatrixElement/Hadron/MEQCD2to2.h
--- a/MatrixElement/Hadron/MEQCD2to2.h
+++ b/MatrixElement/Hadron/MEQCD2to2.h
@@ -1,405 +1,370 @@
// -*- C++ -*-
//
// MEQCD2to2.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_MEQCD2to2_H
#define HERWIG_MEQCD2to2_H
//
// This is the declaration of the MEQCD2to2 class.
//
#include "Herwig/MatrixElement/HwMEBase.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVVVVertex.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
namespace Herwig {
using namespace ThePEG;
using namespace ThePEG::Helicity;
/**
* The MEQCD2to2 class provides the matrix elements for \f$2\to2\f$
* QCD scattering processes in hadron-hadron collisions.
*
* @see \ref MEQCD2to2Interfaces "The interfaces"
* defined for MEQCD2to2.
*/
class MEQCD2to2: public HwMEBase {
public:
/**
* The default constructor.
*/
MEQCD2to2();
/** @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:
/**
* Members to calculate the matrix elements
*/
//@{
/**
* Matrix element for \f$gg\to gg\f$.
* @param g1 The wavefunctions for the first incoming gluon
* @param g2 The wavefunctions for the second incoming gluon
* @param g3 The wavefunctions for the first outgoing gluon
* @param g4 The wavefunctions for the second outgoing gluon
* @param flow The colour flow
*/
double gg2ggME(vector<VectorWaveFunction> &g1,vector<VectorWaveFunction> &g2,
vector<VectorWaveFunction> &g3,vector<VectorWaveFunction> &g4,
unsigned int flow) const;
/**
* Matrix element for \f$gg\to q\bar{q}\f$
* @param g1 The wavefunctions for the first incoming gluon
* @param g2 The wavefunctions for the second incoming gluon
* @param q The wavefunction for the outgoing quark
* @param qbar The wavefunction for the outgoing antiquark
* @param flow The colour flow
*/
double gg2qqbarME(vector<VectorWaveFunction> &g1,vector<VectorWaveFunction> &g2,
vector<SpinorBarWaveFunction> & q,vector<SpinorWaveFunction> & qbar,
unsigned int flow) const;
/**
* Matrix element for \f$q\bar{q}\to gg\f$
* @param q The wavefunction for the incoming quark
* @param qbar The wavefunction for the incoming antiquark
* @param g1 The wavefunctions for the first outgoing gluon
* @param g2 The wavefunctions for the second outgoing gluon
* @param flow The colour flow
*/
double qqbar2ggME(vector<SpinorWaveFunction> & q,vector<SpinorBarWaveFunction> & qbar,
vector<VectorWaveFunction> &g1,vector<VectorWaveFunction> &g2,
unsigned int flow) const;
/**
* Matrix element for \f$qg\to qg\f$
* @param qin The wavefunction for the incoming quark
* @param g2 The wavefunction for the incoming gluon
* @param qout The wavefunction for the outgoing quark
* @param g4 The wavefunction for the outgoing gluon
* @param flow The colour flow
*/
double qg2qgME(vector<SpinorWaveFunction> & qin,vector<VectorWaveFunction> &g2,
vector<SpinorBarWaveFunction> & qout,vector<VectorWaveFunction> &g4,
unsigned int flow) const;
/**
* Matrix elements for \f$\bar{q}g\to \bar{q}g\f$.
* @param qin The wavefunction for the incoming antiquark
* @param g2 The wavefunction for the incoming gluon
* @param qout The wavefunction for the outgoing antiquark
* @param g4 The wavefunction for the outgoing gluon
* @param flow The colour flow
*/
double qbarg2qbargME(vector<SpinorBarWaveFunction> & qin,
vector<VectorWaveFunction> &g2,
vector<SpinorWaveFunction> & qout,vector<VectorWaveFunction> &g4,
unsigned int flow) const;
/**
* Matrix element for \f$qq\to qq\f$
* @param q1 The wavefunction for the first incoming quark
* @param q2 The wavefunction for the second incoming quark
* @param q3 The wavefunction for the first outgoing quark
* @param q4 The wavefunction for the second outgoing quark
* @param flow The colour flow
*/
double qq2qqME(vector<SpinorWaveFunction> & q1, vector<SpinorWaveFunction> & q2,
vector<SpinorBarWaveFunction> & q3, vector<SpinorBarWaveFunction> & q4,
unsigned int flow) const;
/**
* Matrix element for \f$\bar{q}\bar{q}\to \bar{q}\bar{q}\f$
* @param q1 The wavefunction for the first incoming antiquark
* @param q2 The wavefunction for the second incoming antiquark
* @param q3 The wavefunction for the first outgoing antiquark
* @param q4 The wavefunction for the second outgoing antiquark
* @param flow The colour flow
*/
double qbarqbar2qbarqbarME(vector<SpinorBarWaveFunction> & q1,
vector<SpinorBarWaveFunction> & q2,
vector<SpinorWaveFunction> & q3,
vector<SpinorWaveFunction> & q4,
unsigned int flow) const;
/**
* Matrix element for \f$q\bar{q}\to q\bar{q}\f$
* @param q1 The wavefunction for the incoming quark
* @param q2 The wavefunction for the incoming antiquark
* @param q3 The wavefunction for the outgoing quark
* @param q4 The wavefunction for the outgoing antiquark
* @param flow The colour flow
*/
double qqbar2qqbarME(vector<SpinorWaveFunction> & q1,
vector<SpinorBarWaveFunction> & q2,
vector<SpinorBarWaveFunction> & q3,
vector<SpinorWaveFunction> & q4,
unsigned int flow) const;
//@}
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();
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<MEQCD2to2> initMEQCD2to2;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEQCD2to2 & operator=(const MEQCD2to2 &);
private:
/**
* Vertices needed to compute the diagrams
*/
//@{
/**
* \f$gggg\f$ vertex
*/
AbstractVVVVVertexPtr _ggggvertex;
/**
* \f$ggg\f$ vertex
*/
AbstractVVVVertexPtr _gggvertex;
/**
* \f$q\bar{q}g\f$ vertex
*/
AbstractFFVVertexPtr _qqgvertex;
//@}
/**
* Maximum numbere of quark flavours to include
*/
unsigned int _maxflavour;
/**
* Processes to include
*/
unsigned int _process;
/**
* Colour flow
*/
mutable unsigned int _flow;
/**
* Diagram
*/
mutable unsigned int _diagram;
/**
* Matrix element
*/
mutable ProductionMatrixElement _me;
/**
* ParticleData objects of the partons
*/
//@{
/**
* The gluon
*/
PDPtr _gluon;
/**
* the quarks
*/
vector<PDPtr> _quark;
/**
* the antiquarks
*/
vector<PDPtr> _antiquark;
//@}
};
}
-#include "ThePEG/Utilities/ClassTraits.h"
-
-namespace ThePEG {
-
-/** @cond TRAITSPECIALIZATIONS */
-
-/** This template specialization informs ThePEG about the
- * base classes of MEQCD2to2. */
-template <>
-struct BaseClassTrait<Herwig::MEQCD2to2,1> {
- /** Typedef of the first base class of MEQCD2to2. */
- typedef Herwig::HwMEBase NthBase;
-};
-
-/** This template specialization informs ThePEG about the name of
- * the MEQCD2to2 class and the shared object where it is defined. */
-template <>
-struct ClassTraits<Herwig::MEQCD2to2>
- : public ClassTraitsBase<Herwig::MEQCD2to2> {
- /** Return a platform-independent class name */
- static string className() { return "Herwig::MEQCD2to2"; }
- /**
- * The name of a file containing the dynamic library where the class
- * MEQCD2to2 is implemented. It may also include several, space-separated,
- * libraries if the class MEQCD2to2 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_MEQCD2to2_H */
diff --git a/MatrixElement/Hadron/MEQCD2to2Fast.cc b/MatrixElement/Hadron/MEQCD2to2Fast.cc
--- a/MatrixElement/Hadron/MEQCD2to2Fast.cc
+++ b/MatrixElement/Hadron/MEQCD2to2Fast.cc
@@ -1,429 +1,432 @@
// -*- C++ -*-
//
// MEQCD2to2Fast.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEQCD2to2Fast class.
//
#include "MEQCD2to2Fast.h"
+#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Utilities/SimplePhaseSpace.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "ThePEG/Cuts/Cuts.h"
using namespace Herwig;
IBPtr MEQCD2to2Fast::clone() const {
return new_ptr(*this);
}
IBPtr MEQCD2to2Fast::fullclone() const {
return new_ptr(*this);
}
Energy2 MEQCD2to2Fast::scale() const {
Energy2 s(sHat()),u(uHat()),t(tHat());
return 2.*s*t*u/(s*s+t*t+u*u);
}
void MEQCD2to2Fast::persistentOutput(PersistentOStream & os) const {
os << _maxflavour << _process << _strictFlavourScheme;
}
void MEQCD2to2Fast::persistentInput(PersistentIStream & is, int) {
is >> _maxflavour >> _process >> _strictFlavourScheme;
}
unsigned int MEQCD2to2Fast::orderInAlphaS() const {
return 2;
}
unsigned int MEQCD2to2Fast::orderInAlphaEW() const {
return 0;
}
-ClassDescription<MEQCD2to2Fast> MEQCD2to2Fast::initMEQCD2to2Fast;
-// Definition of the static class description member.
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEQCD2to2Fast,HwMEBase>
+describeHerwigMEQCD2to2Fast("Herwig::MEQCD2to2Fast", "HwMEHadronFast.so");
void MEQCD2to2Fast::Init() {
static ClassDocumentation<MEQCD2to2Fast> documentation
("The MEQCD2to2Fast class implements the QCD 2->2 processes in hadron-hadron"
" collisions");
static Parameter<MEQCD2to2Fast,unsigned int> interfaceMaximumFlavour
("MaximumFlavour",
"The maximum flavour of the quarks in the process",
&MEQCD2to2Fast::_maxflavour, 5, 1, 5,
false, false, Interface::limited);
static Switch<MEQCD2to2Fast,unsigned int> interfaceProcess
("Process",
"Which subprocesses to include",
&MEQCD2to2Fast::_process, 0, false, false);
static SwitchOption interfaceProcessAll
(interfaceProcess,
"All",
"Include all subprocesses",
0);
static SwitchOption interfaceProcess1
(interfaceProcess,
"gg2gg",
"Include only gg->gg subprocesses",
1);
static SwitchOption interfaceProcess2
(interfaceProcess,
"gg2qqbar",
"Include only gg -> q qbar processes",
2);
static SwitchOption interfaceProcessqqbargg
(interfaceProcess,
"qqbar2gg",
"Include only q qbar -> gg processes",
3);
static SwitchOption interfaceProcessqgqg
(interfaceProcess,
"qg2qg",
"Include only q g -> q g processes",
4);
static SwitchOption interfaceProcessqbargqbarg
(interfaceProcess,
"qbarg2qbarg",
"Include only qbar g -> qbar g processes",
5);
static SwitchOption interfaceProcessqqqq
(interfaceProcess,
"qq2qq",
"Include only q q -> q q processes",
6);
static SwitchOption interfaceProcessqbarqbarqbarqbar
(interfaceProcess,
"qbarqbar2qbarqbar",
"Include only qbar qbar -> qbar qbar processes",
7);
static SwitchOption interfaceProcessqqbarqqbar
(interfaceProcess,
"qqbar2qqbar",
"Include only q qbar -> q qbar processes",
8);
static Switch<MEQCD2to2Fast,bool> interfaceStrictFlavourScheme
("StrictFlavourScheme",
"Switch to not include massive initial state quarks.",
&MEQCD2to2Fast::_strictFlavourScheme, false, false, false);
static SwitchOption interfaceStrictFlavourSchemeYes
(interfaceStrictFlavourScheme,
"Yes",
"Do not include massive initial states.",
true);
static SwitchOption interfaceStrictFlavourSchemeNo
(interfaceStrictFlavourScheme,
"No",
"Allow massive initial states.",
false);
}
Selector<MEBase::DiagramIndex>
MEQCD2to2Fast::diagrams(const DiagramVector & diags) const {
// select the diagram, this is easy for us as we have already done it
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i ) {
if(diags[i]->id()==-int(_diagram)) sel.insert(1.0, i);
else sel.insert(0., i);
}
return sel;
}
void MEQCD2to2Fast::getDiagrams() const {
// get the particle data objects
PDPtr gluon=getParticleData(ParticleID::g);
vector<PDPtr> quark,antiquark;
for(int ix=1;ix<=int(_maxflavour);++ix) {
quark.push_back( getParticleData( ix));
antiquark.push_back(getParticleData(-ix));
}
// gg-> gg subprocess
if(_process==0||_process==1) {
// s-channel
add(new_ptr((Tree2toNDiagram(2),gluon,gluon, 1, gluon,
3,gluon, 3, gluon, -1)));
// first t-channel
add(new_ptr((Tree2toNDiagram(3),gluon,gluon,gluon,
1,gluon, 2,gluon,-2)));
// second t-channel
add(new_ptr((Tree2toNDiagram(3),gluon,gluon,gluon,
2,gluon, 1,gluon,-3)));
}
// processes involving one quark line
for(unsigned int ix=0;ix<_maxflavour;++ix) {
// gg -> q qbar subprocesses
if(_process==0||_process==2) {
// first t-channel
add(new_ptr((Tree2toNDiagram(3),gluon,antiquark[ix],gluon,
1,quark[ix], 2,antiquark[ix],-4)));
// interchange
add(new_ptr((Tree2toNDiagram(3),gluon,antiquark[ix],gluon,
2,quark[ix], 1,antiquark[ix],-5)));
// s-channel
add(new_ptr((Tree2toNDiagram(2),gluon,gluon, 1, gluon,
3,quark[ix], 3, antiquark[ix], -6)));
}
// q qbar -> g g subprocesses
if((_process==0||_process==3) && (quark[ix]->hardProcessMass() == ZERO || !_strictFlavourScheme)) {
// first t-channel
add(new_ptr((Tree2toNDiagram(3),quark[ix],antiquark[ix],antiquark[ix],
1,gluon, 2,gluon,-7)));
// second t-channel
add(new_ptr((Tree2toNDiagram(3),quark[ix],antiquark[ix],antiquark[ix],
2,gluon, 1,gluon,-8)));
// s-channel
add(new_ptr((Tree2toNDiagram(2),quark[ix], antiquark[ix],
1, gluon, 3, gluon, 3, gluon,-9)));
}
// q g -> q g subprocesses
if((_process==0||_process==4) && (quark[ix]->hardProcessMass() == ZERO || !_strictFlavourScheme)) {
// s-channel
add(new_ptr((Tree2toNDiagram(2),quark[ix], gluon,
1, quark[ix], 3, quark[ix], 3, gluon,-10)));
// quark t-channel
add(new_ptr((Tree2toNDiagram(3),quark[ix],quark[ix],gluon,
2,quark[ix],1,gluon,-11)));
// gluon t-channel
add(new_ptr((Tree2toNDiagram(3),quark[ix],gluon,gluon,
1,quark[ix],2,gluon,-12)));
}
// qbar g -> qbar g subprocesses
if((_process==0||_process==5) && (antiquark[ix]->hardProcessMass() == ZERO || !_strictFlavourScheme)) {
// s-channel
add(new_ptr((Tree2toNDiagram(2),antiquark[ix], gluon,
1, antiquark[ix], 3, antiquark[ix], 3, gluon,-13)));
// quark t-channel
add(new_ptr((Tree2toNDiagram(3),antiquark[ix],antiquark[ix],gluon,
2,antiquark[ix],1,gluon,-14)));
// gluon t-channel
add(new_ptr((Tree2toNDiagram(3),antiquark[ix],gluon,gluon,
1,antiquark[ix],2,gluon,-15)));
}
// processes involving two quark lines
for(unsigned int iy=ix;iy<_maxflavour;++iy) {
// q q -> q q subprocesses
if((_process==0||_process==6) &&
((quark[ix]->hardProcessMass() == ZERO && quark[iy]->hardProcessMass() == ZERO) || !_strictFlavourScheme)) {
// gluon t-channel
add(new_ptr((Tree2toNDiagram(3),quark[ix],gluon,quark[iy],
1,quark[ix],2,quark[iy],-16)));
// exchange for identical quarks
if(ix==iy)
add(new_ptr((Tree2toNDiagram(3),quark[ix],gluon,quark[iy],
2,quark[ix],1,quark[iy],-17)));
}
// qbar qbar -> qbar qbar subprocesses
if((_process==0||_process==7) &&
((antiquark[ix]->hardProcessMass() == ZERO && antiquark[iy]->hardProcessMass() == ZERO) || !_strictFlavourScheme)) {
// gluon t-channel
add(new_ptr((Tree2toNDiagram(3),antiquark[ix],gluon,antiquark[iy],
1,antiquark[ix],2,antiquark[iy],-18)));
// exchange for identical quarks
if(ix==iy)
add(new_ptr((Tree2toNDiagram(3),antiquark[ix],gluon,antiquark[iy],
2,antiquark[ix],1,antiquark[iy],-19)));
}
}
for(unsigned int iy=0;iy<_maxflavour;++iy) {
// q qbar -> q qbar
if(_process==0||_process==8) {
// gluon s-channel
if ( quark[ix]->hardProcessMass() == ZERO || !_strictFlavourScheme )
add(new_ptr((Tree2toNDiagram(2),quark[ix], antiquark[ix],
1, gluon, 3, quark[iy], 3, antiquark[iy],-20)));
// gluon t-channel
if ( (quark[ix]->hardProcessMass() == ZERO && antiquark[iy]->hardProcessMass() == ZERO) ||
!_strictFlavourScheme )
add(new_ptr((Tree2toNDiagram(3),quark[ix],gluon,antiquark[iy],
1,quark[ix],2,antiquark[iy],-21)));
}
}
}
}
Selector<const ColourLines *>
MEQCD2to2Fast::colourGeometries(tcDiagPtr diag) const {
// colour lines for gg to gg
static const ColourLines cgggg[12]={ColourLines("1 -2, -1 -3 -5, 5 -4, 2 3 4"),// A_2 s
ColourLines("-1 2, 1 3 5, -5 4, -2 -3 -4"),// A_1 s
ColourLines("1 5, -1 -2 3, -3 -4, -5 2 4"),// A_1 u
ColourLines("-1 -5, 1 2 -3, 3 4, 5 -2 -4"),// A_2 u
ColourLines("1 -2, -1 -3 -4, 4 -5, 2 3 5"),// B_2 s
ColourLines("-1 2, 1 3 4, -4 5, -2 -3 -5"),// B_1 s
ColourLines("1 4, -1 -2 3, -3 -5, -4 2 5"),// B_1 t
ColourLines("-1 -4, 1 2 -3, 3 5, 4 -2 -5"),// B_2 t
ColourLines("1 4, -1 -2 -5, 3 5, -3 2 -4"),// C_1 t
ColourLines("-1 -4, 1 2 5, -3 -5, 3 -2 4"),// C_2 t
ColourLines("1 5, -1 -2 -4, 3 4, -3 2 -5"),// C_1 u
ColourLines("-1 -5, 1 2 4, -3 -4, 3 -2 5") // C_2 u
};
// colour lines for gg to q qbar
static const ColourLines cggqq[4]={ColourLines("1 4, -1 -2 3, -3 -5"),
ColourLines("3 4, -3 -2 1, -1 -5"),
ColourLines("2 -1, 1 3 4, -2 -3 -5"),
ColourLines("1 -2, -1 -3 -5, 2 3 4")};
// colour lines for q qbar to gg
static const ColourLines cqqgg[4]={ColourLines("1 4, -4 -2 5, -3 -5"),
ColourLines("1 5, -3 -4, 4 -2 -5"),
ColourLines("1 3 4, -4 5, -2 -3 -5"),
ColourLines("1 3 5, -5 4, -2 -3 -4")};
// colour lines for q g to q g
static const ColourLines cqgqg[4]={ColourLines("1 -2, 2 3 5, 4 -5"),
ColourLines("1 5, 3 4,-3 2 -5 "),
ColourLines("1 2 -3, 3 5, -5 -2 4"),
ColourLines("1 -2 5,3 2 4,-3 -5")};
// colour lines for qbar g -> qbar g
static const ColourLines cqbgqbg[4]={ColourLines("-1 2, -2 -3 -5, -4 5"),
ColourLines("-1 -5, -3 -4, 3 -2 5"),
ColourLines("-1 -2 3, -3 -5, 5 2 -4"),
ColourLines("-1 2 -5,-3 -2 -4, 3 5")};
// colour lines for q q -> q q
static const ColourLines cqqqq[2]={ColourLines("1 2 5,3 -2 4"),
ColourLines("1 2 4,3 -2 5")};
// colour lines for qbar qbar -> qbar qbar
static const ColourLines cqbqbqbqb[2]={ColourLines("-1 -2 -5,-3 2 -4"),
ColourLines("-1 -2 -4,-3 2 -5")};
// colour lines for q qbar -> q qbar
static const ColourLines cqqbqqb[2]={ColourLines("1 3 4,-2 -3 -5"),
ColourLines("1 2 -3,4 -2 -5")};
// select the colour flow (as all ready picked just insert answer)
Selector<const ColourLines *> sel;
switch(abs(diag->id())) {
// gg -> gg subprocess
case 1:
if(_flow==1) {
sel.insert(0.5, &cgggg[0]);
sel.insert(0.5, &cgggg[1]);
}
else {
sel.insert(0.5, &cgggg[4]);
sel.insert(0.5, &cgggg[5]);
}
break;
case 2:
if(_flow==2) {
sel.insert(0.5, &cgggg[6]);
sel.insert(0.5, &cgggg[7]);
}
else {
sel.insert(0.5, &cgggg[8]);
sel.insert(0.5, &cgggg[9]);
}
break;
case 3:
if(_flow==1) {
sel.insert(0.5, &cgggg[2]);
sel.insert(0.5, &cgggg[3]);
}
else {
sel.insert(0.5, &cgggg[10]);
sel.insert(0.5, &cgggg[11]);
}
break;
// gg -> q qbar subprocess
case 4: case 5:
sel.insert(1.0, &cggqq[abs(diag->id())-4]);
break;
case 6:
sel.insert(1.0, &cggqq[1+_flow]);
break;
// q qbar -> gg subprocess
case 7: case 8:
sel.insert(1.0, &cqqgg[abs(diag->id())-7]);
break;
case 9:
sel.insert(1.0, &cqqgg[1+_flow]);
break;
// q g -> q g subprocess
case 10: case 11:
sel.insert(1.0, &cqgqg[abs(diag->id())-10]);
break;
case 12:
sel.insert(1.0, &cqgqg[1+_flow]);
break;
// q g -> q g subprocess
case 13: case 14:
sel.insert(1.0, &cqbgqbg[abs(diag->id())-13]);
break;
case 15:
sel.insert(1.0, &cqbgqbg[1+_flow]);
break;
// q q -> q q subprocess
case 16: case 17:
sel.insert(1.0, &cqqqq[abs(diag->id())-16]);
break;
// qbar qbar -> qbar qbar subprocess
case 18: case 19:
sel.insert(1.0, &cqbqbqbqb[abs(diag->id())-18]);
break;
// q qbar -> q qbar subprocess
case 20: case 21:
sel.insert(1.0, &cqqbqqb[abs(diag->id())-20]);
break;
}
return sel;
}
double MEQCD2to2Fast::me2() const {
// total matrix element
double me(0.);
// gg initiated processes
if(mePartonData()[0]->id()==ParticleID::g&&mePartonData()[1]->id()==ParticleID::g) {
// gg -> gg
if(mePartonData()[2]->id()==ParticleID::g) me = gg2ggME();
// gg -> q qbar
else me=gg2qqbarME();
}
// quark first processes
else if(mePartonData()[0]->id()>0) {
// q g -> q g
if(mePartonData()[1]->id()==ParticleID::g) me = qg2qgME();
else if(mePartonData()[1]->id()<0) {
// q qbar initiated processes( q qbar -> gg)
if(mePartonData()[2]->id()==ParticleID::g) me = qqbar2ggME();
// q qbar to q qbar
else me = qqbar2qqbarME();
}
// q q -> q q
else if(mePartonData()[1]->id()>0) me = qq2qqME();
}
// antiquark first processes
else if(mePartonData()[0]->id()<0) {
// qbar g -> qbar g
if(mePartonData()[1]->id()==ParticleID::g) me = qbarg2qbargME();
// qbar qbar -> qbar qbar
else if(mePartonData()[1]->id()<0) me = qbarqbar2qbarqbarME();
}
else {
throw Exception() << "Unknown process in MEQCD2to2Fast::me2()"
<< Exception::abortnow;
}
// multpliy by alpha_S^2 and return answer
double alphas(4.*Constants::pi*SM().alphaS(scale()));
return me*sqr(alphas);
}
void MEQCD2to2Fast::doinit() {
if ( _strictFlavourScheme )
massOption(vector<unsigned int>(2,1));
HwMEBase::doinit();
}
diff --git a/MatrixElement/Hadron/MEQCD2to2Fast.h b/MatrixElement/Hadron/MEQCD2to2Fast.h
--- a/MatrixElement/Hadron/MEQCD2to2Fast.h
+++ b/MatrixElement/Hadron/MEQCD2to2Fast.h
@@ -1,382 +1,347 @@
// -*- C++ -*-
//
// MEQCD2to2Fast.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_MEQCD2to2Fast_H
#define HERWIG_MEQCD2to2Fast_H
//
// This is the declaration of the MEQCD2to2Fast class.
//
#include "Herwig/MatrixElement/HwMEBase.h"
#include "ThePEG/Repository/UseRandom.h"
namespace Herwig {
using namespace ThePEG;
using namespace ThePEG::Helicity;
/**
* The MEQCD2to2Fast class implements the matrix elements for
* QCD \f$2\to2\f$ scattering processes using hard coded formulae and
* as such can not include spin correlations. It is designed to be a faster
* replacement for MEQCD2to2 for use in the underlying event.
*
* @see \ref MEQCD2to2FastInterfaces "The interfaces"
* defined for MEQCD2to2Fast.
*/
class MEQCD2to2Fast: public HwMEBase {
public:
/**
* The default constructor.
*/
MEQCD2to2Fast() :_maxflavour(5),_process(0),_strictFlavourScheme(false) {
massOption(vector<unsigned int>(2,0));
}
/** @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;
//@}
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:
/**
* Members to calculate the matrix elements
*/
//@{
/**
* Matrix element for \f$gg\to gg\f$.
*/
double gg2ggME() const {
Energy2 u(uHat()),t(tHat()),s(sHat());
double output = 9./4.*(3.-t*u/s/s-s*u/t/t-s*t/u/u);
double flow[3]={(1.-u*t/s/s-s*t/u/u+t*t/s/u),
(1.-t*u/s/s-s*u/t/t+u*u/s/t),
(1.-t*s/u/u-u*s/t/t+s*s/u/t)};
_flow = 1+UseRandom::rnd3(flow[0],flow[1],flow[2]);
double diag[3]={(sqr(u)+sqr(t))/sqr(s),
(sqr(s)+sqr(u))/sqr(t),
(sqr(s)+sqr(t))/sqr(u)};
if(_flow==1) diag[1]=0;
else if(_flow==2) diag[2]=0;
else if(_flow==3) diag[0]=0;
_diagram=1+UseRandom::rnd3(diag[0],diag[1],diag[2]);
return output;
}
/**
* Matrix element for \f$gg\to q\bar{q}\f$
*/
double gg2qqbarME() const {
Energy2 u(uHat()),t(tHat()),s(sHat());
Energy4 u2(sqr(u)),t2(sqr(t)),s2(sqr(s));
double output =(1./6./u/t-3./8./s2)*(t2+u2);
double flow[2]={u2/(u2+t2),t2/(u2+t2)};
_flow = 1+UseRandom::rnd2(flow[0],flow[1]);
_diagram=3+_flow;
return output;
}
/**
* Matrix element for \f$q\bar{q}\to gg\f$
*/
double qqbar2ggME() const {
Energy2 u(uHat()),t(tHat()),s(sHat());
Energy4 s2(sqr(s)),u2(sqr(u)),t2(sqr(t));
double output = 0.5*(32./27./u/t-8./3./s2)*(t2+u2);
double flow[2] = {u2/(u2+t2),t2/(t2+u2)};
_flow=1+UseRandom::rnd2(flow[0],flow[1]);
_diagram=6+_flow;
return output;
}
/**
* Matrix element for \f$qg\to qg\f$
*/
double qg2qgME() const {
Energy2 u(uHat()),t(tHat()),s(sHat());
Energy4 s2(sqr(s)),u2(sqr(u)),t2(sqr(t));
double output = (-4./9./s/u+1./t2)*(s2+u2);
double flow[2]={u2/(s2+u2),s2/(s2+u2)};
_flow=1+UseRandom::rnd2(flow[0],flow[1]);
_diagram=9+_flow;
return output;
}
/**
* Matrix elements for \f$\bar{q}g\to \bar{q}g\f$.
*/
double qbarg2qbargME() const {
// scale
Energy2 u(uHat()),t(tHat()),s(sHat());
Energy4 u2(sqr(u)),s2(sqr(s)); // t2(sqr(t))
double flow[2]={u2/(s2+u2),s2/(s2+u2)};
_flow=1+UseRandom::rnd2(flow[0],flow[1]);
_diagram=12+_flow;
return (-4./9./s/u+1./t/t)*(s*s+u*u);
}
/**
* Matrix element for \f$qq\to qq\f$
*/
double qq2qqME() const {
Energy2 u(uHat()),t(tHat());
Energy4 s2(sqr(sHat())),u2(sqr(u)),t2(sqr(t));
double output;
if(mePartonData()[0]->id()==mePartonData()[1]->id()) {
output = 0.5*(4./9.*((s2+u2)/t2+(s2+t2)/u2)
-8./27.*s2/u/t);
double flow[2]={(s2+u2)/t2,(s2+t2)/u2};
_flow=1+UseRandom::rnd2(flow[0],flow[1]);
}
else {
output = 4./9.*(s2+u2)/t2;
_flow=2;
}
_diagram = 15+_flow;
return output;
}
/**
* Matrix element for \f$\bar{q}\bar{q}\to \bar{q}\bar{q}\f$
*/
double qbarqbar2qbarqbarME() const {
Energy2 u(uHat()),t(tHat());
Energy4 u2(sqr(u)),t2(sqr(t)),s2(sqr(sHat()));
double output;
if(mePartonData()[0]->id()==mePartonData()[1]->id()) {
output = 0.5*(4./9.*((s2+u2)/t2+(s2+t2)/u2)
-8./27.*s2/u/t);
double flow[2]={(s2+u2)/t2,(s2+t2)/u2};
_flow=1+UseRandom::rnd2(flow[0],flow[1]);
}
else {
output = 4./9.*(s2+u2)/t2;
_flow = 2;
}
_diagram = 17+_flow;
// final part of colour and spin factors
return output;
}
/**
* Matrix element for \f$q\bar{q}\to q\bar{q}\f$
*/
double qqbar2qqbarME() const {
// type of process
bool diagon[2]={mePartonData()[0]->id()== -mePartonData()[1]->id(),
mePartonData()[0]->id()== mePartonData()[2]->id()};
// scale
Energy2 u(uHat()),t(tHat()),s(sHat());
Energy4 s2(sqr(s)),t2(sqr(t)),u2(sqr(u));
double output;
if(diagon[0]&&diagon[1]) {
output= (4./9.*((s2+u2)/t2+(u2+t2)/s2)
-8./27.*u2/s/t);
double flow[2]={(t2+u2)/s2,(s2+u2)/t2};
_flow=1+UseRandom::rnd2(flow[0],flow[1]);
}
else if(diagon[0]) {
output = (4./9.*(t2+u2)/s2);
_flow=1;
}
else {
output = (4./9.*(s2+u2)/t2);
_flow=2;
}
_diagram=19+_flow;
return output;
}
//@}
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
protected:
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<MEQCD2to2Fast> initMEQCD2to2Fast;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEQCD2to2Fast & operator=(const MEQCD2to2Fast &);
private:
/**
* Maximum numbere of quark flavours to include
*/
unsigned int _maxflavour;
/**
* Processes to include
*/
unsigned int _process;
/**
* Colour flow
*/
mutable unsigned int _flow;
/**
* Diagram
*/
mutable unsigned int _diagram;
/**
* Exclude contributions with massive incominbg quarks
*/
bool _strictFlavourScheme;
};
}
-#include "ThePEG/Utilities/ClassTraits.h"
-
-namespace ThePEG {
-
-/** @cond TRAITSPECIALIZATIONS */
-
-/** This template specialization informs ThePEG about the
- * base classes of MEQCD2to2Fast. */
-template <>
-struct BaseClassTrait<Herwig::MEQCD2to2Fast,1> {
- /** Typedef of the first base class of MEQCD2to2Fast. */
- typedef Herwig::HwMEBase NthBase;
-};
-
-/** This template specialization informs ThePEG about the name of
- * the MEQCD2to2Fast class and the shared object where it is defined. */
-template <>
-struct ClassTraits<Herwig::MEQCD2to2Fast>
- : public ClassTraitsBase<Herwig::MEQCD2to2Fast> {
- /** Return a platform-independent class name */
- static string className() { return "Herwig::MEQCD2to2Fast"; }
- /**
- * The name of a file containing the dynamic library where the class
- * MEQCD2to2Fast is implemented. It may also include several, space-separated,
- * libraries if the class MEQCD2to2Fast 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 "HwMEHadronFast.so"; }
-};
-
-/** @endcond */
-
-}
-
#endif /* HERWIG_MEQCD2to2Fast_H */
diff --git a/MatrixElement/Hadron/MEqq2W2ff.cc b/MatrixElement/Hadron/MEqq2W2ff.cc
--- a/MatrixElement/Hadron/MEqq2W2ff.cc
+++ b/MatrixElement/Hadron/MEqq2W2ff.cc
@@ -1,354 +1,357 @@
// -*- C++ -*-
//
// MEqq2W2ff.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEqq2W2ff class.
//
#include "MEqq2W2ff.h"
+#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/StandardModel/StandardModelBase.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "Herwig/MatrixElement/HardVertex.h"
#include <cassert>
using namespace Herwig;
MEqq2W2ff::MEqq2W2ff() : _maxflavour(5), _plusminus(0), _process(0) {
massOption(vector<unsigned int>(2,1));
}
void MEqq2W2ff::doinit() {
DrellYanBase::doinit();
_wp=getParticleData(ThePEG::ParticleID::Wplus);
_wm=getParticleData(ThePEG::ParticleID::Wminus);
// cast the SM pointer to the Herwig SM pointer
tcHwSMPtr hwsm=ThePEG::dynamic_ptr_cast<tcHwSMPtr>(standardModel());
// do the initialisation
if(hwsm)
_theFFWVertex = hwsm->vertexFFW();
else
throw InitException() << "Must be the Herwig StandardModel class in "
<< "MEqq2W2ff::doinit" << Exception::abortnow;
}
void MEqq2W2ff::getDiagrams() const {
// which intgermediates to include
bool wplus =_plusminus==0||_plusminus==1;
bool wminus=_plusminus==0||_plusminus==2;
// possible incoming and outgoing particles
typedef std::vector<pair<long,long> > Pairvector;
// possible parents
Pairvector parentpair;
parentpair.reserve(6);
// don't even think of putting 'break' in here!
switch(_maxflavour) {
case 5:
parentpair.push_back(make_pair(ParticleID::b, ParticleID::cbar));
parentpair.push_back(make_pair(ParticleID::b, ParticleID::ubar));
case 4:
parentpair.push_back(make_pair(ParticleID::s, ParticleID::cbar));
parentpair.push_back(make_pair(ParticleID::d, ParticleID::cbar));
case 3:
parentpair.push_back(make_pair(ParticleID::s, ParticleID::ubar));
case 2:
parentpair.push_back(make_pair(ParticleID::d, ParticleID::ubar));
default:
;
}
// possible children
Pairvector childpair;
childpair.reserve(9);
childpair.push_back(make_pair(ParticleID::eminus, ParticleID::nu_ebar));
childpair.push_back(make_pair(ParticleID::muminus, ParticleID::nu_mubar));
childpair.push_back(make_pair(ParticleID::tauminus, ParticleID::nu_taubar));
childpair.push_back(make_pair(ParticleID::d, ParticleID::ubar));
childpair.push_back(make_pair(ParticleID::s, ParticleID::ubar));
childpair.push_back(make_pair(ParticleID::b, ParticleID::ubar));
childpair.push_back(make_pair(ParticleID::d, ParticleID::cbar));
childpair.push_back(make_pair(ParticleID::s, ParticleID::cbar));
childpair.push_back(make_pair(ParticleID::b, ParticleID::cbar));
// loop over the children
bool lepton,quark;
Pairvector::const_iterator child = childpair.begin();
for (; child != childpair.end(); ++child) {
assert(child->first > 0 && child->second < 0);
// allowed leptonic decay
lepton = child->first > 10 && (_process==0
|| _process==2
|| (child->first - 5)/2 == int(_process));
// allowed quark decay
quark = child->first < 10 && (_process==0
|| _process==1
|| (child->second == -2 && (child->first + 11)/2 == int(_process))
|| (child->second == -4 && (child->first + 17)/2 == int(_process))
);
// if decay not allowed skip
if(!(quark || lepton)) continue;
// decay products
tcPDPtr lNeg1 = getParticleData(child->first);
tcPDPtr lNeg2 = getParticleData(child->second);
tcPDPtr lPos1 = lNeg2->CC();
tcPDPtr lPos2 = lNeg1->CC();
Pairvector::const_iterator parent = parentpair.begin();
for (; parent != parentpair.end(); ++parent) {
// parents
tcPDPtr qNeg1 = getParticleData(parent->first);
tcPDPtr qNeg2 = getParticleData(parent->second);
tcPDPtr qPos1 = qNeg2->CC();
tcPDPtr qPos2 = qNeg1->CC();
// diagrams
if(wminus) add(new_ptr((Tree2toNDiagram(2),
qNeg1, qNeg2,
1, _wm,
3, lNeg1, 3, lNeg2, -1)));
if(wplus) add(new_ptr((Tree2toNDiagram(2),
qPos1, qPos2,
1, _wp,
3, lPos1, 3, lPos2, -2)));
}
}
}
Energy2 MEqq2W2ff::scale() const {
return sHat();
}
double MEqq2W2ff::me2() const {
vector<SpinorWaveFunction> fin,aout;
vector<SpinorBarWaveFunction> ain,fout;
SpinorWaveFunction q (meMomenta()[0],mePartonData()[0],incoming);
SpinorBarWaveFunction qbar(meMomenta()[1],mePartonData()[1],incoming);
SpinorBarWaveFunction f (meMomenta()[2],mePartonData()[2],outgoing);
SpinorWaveFunction fbar(meMomenta()[3],mePartonData()[3],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
q.reset(ix) ; fin.push_back(q);
qbar.reset(ix); ain.push_back(qbar);
f.reset(ix) ;fout.push_back(f);
fbar.reset(ix);aout.push_back(fbar);
}
return qqbarME(fin,ain,fout,aout,false);
}
unsigned int MEqq2W2ff::orderInAlphaS() const {
return 0;
}
unsigned int MEqq2W2ff::orderInAlphaEW() const {
return 2;
}
Selector<MEBase::DiagramIndex>
MEqq2W2ff::diagrams(const DiagramVector &) const {
Selector<DiagramIndex> sel;
sel.insert(1.0, 0);
return sel;
}
Selector<const ColourLines *>
MEqq2W2ff::colourGeometries(tcDiagPtr) const {
static const ColourLines c1("1 -2");
static const ColourLines c2("1 -2,4 -5");
Selector<const ColourLines *> sel;
if(abs(mePartonData()[2]->id())<=6) sel.insert(1.0, &c2);
else sel.insert(1.0, &c1);
return sel;
}
void MEqq2W2ff::persistentOutput(PersistentOStream & os) const {
os << _maxflavour << _plusminus << _process << _theFFWVertex << _wp << _wm;
}
void MEqq2W2ff::persistentInput(PersistentIStream & is, int) {
is >> _maxflavour >> _plusminus >> _process >> _theFFWVertex >> _wp >> _wm;
}
-ClassDescription<MEqq2W2ff> MEqq2W2ff::initMEqq2W2ff;
-// Definition of the static class description member.
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEqq2W2ff,DrellYanBase>
+describeHerwigMEqq2W2ff("Herwig::MEqq2W2ff", "HwMEHadron.so");
void MEqq2W2ff::Init() {
static ClassDocumentation<MEqq2W2ff> documentation
("The MEqq2W2ff class implements the matrix element for"
"q qbar to Standard Model fermions via W exchange using helicity amplitude"
"techniques");
static Parameter<MEqq2W2ff,unsigned int> interfaceMaxFlavour
( "MaxFlavour",
"The heaviest incoming quark flavour this matrix element is allowed to handle "
"(if applicable).",
&MEqq2W2ff::_maxflavour, 5, 0, 5, false, false, true);
static Switch<MEqq2W2ff,unsigned int> interfacePlusMinus
("Wcharge",
"Which intermediate W bosons to include",
&MEqq2W2ff::_plusminus, 0, false, false);
static SwitchOption interfacePlusMinusAll
(interfacePlusMinus,
"Both",
"Include W+ and W-",
0);
static SwitchOption interfacePlusMinusPlus
(interfacePlusMinus,
"Plus",
"Only include W+",
1);
static SwitchOption interfacePlusMinusMinus
(interfacePlusMinus,
"Minus",
"Only include W-",
2);
static Switch<MEqq2W2ff,unsigned int> interfaceProcess
("Process",
"Which processes to include",
&MEqq2W2ff::_process, 0, false, false);
static SwitchOption interfaceProcessAll
(interfaceProcess,
"All",
"Include all SM fermions as outgoing particles",
0);
static SwitchOption interfaceProcessQuarks
(interfaceProcess,
"Quarks",
"Only include outgoing quarks",
1);
static SwitchOption interfaceProcessLeptons
(interfaceProcess,
"Leptons",
"All include outgoing leptons",
2);
static SwitchOption interfaceProcessElectron
(interfaceProcess,
"Electron",
"Only include outgoing e nu_e",
3);
static SwitchOption interfaceProcessMuon
(interfaceProcess,
"Muon",
"Only include outgoing mu nu_mu",
4);
static SwitchOption interfaceProcessTau
(interfaceProcess,
"Tau",
"Only include outgoing tauu nu_tau",
5);
static SwitchOption interfaceProcessUpDown
(interfaceProcess,
"UpDown",
"Only include outgoing u dbar/ d ubar",
6);
static SwitchOption interfaceProcessUpStrange
(interfaceProcess,
"UpStrange",
"Only include outgoing u sbar/ s ubar",
7);
static SwitchOption interfaceProcessUpBottom
(interfaceProcess,
"UpBottom",
"Only include outgoing u bbar/ b ubar",
8);
static SwitchOption interfaceProcessCharmDown
(interfaceProcess,
"CharmDown",
"Only include outgoing c dbar/ d cbar",
9);
static SwitchOption interfaceProcessCharmStrange
(interfaceProcess,
"CharmStrange",
"Only include outgoing c sbar/ s cbar",
10);
static SwitchOption interfaceProcessCharmBottom
(interfaceProcess,
"CharmBottom",
"Only include outgoing c bbar/ b cbar",
11);
}
double MEqq2W2ff::qqbarME(vector<SpinorWaveFunction> & fin ,
vector<SpinorBarWaveFunction> & ain ,
vector<SpinorBarWaveFunction> & fout,
vector<SpinorWaveFunction> & aout,
bool calc) const {
// matrix element to be stored
ProductionMatrixElement newme(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half);
// positive or negative W boson
bool positive = mePartonData()[0]->iCharge()
+ mePartonData()[1]->iCharge() > 0;
unsigned int ihel1,ihel2,ohel1,ohel2;
// sum over helicities to get the matrix element
double me = 0.;
VectorWaveFunction inter;
for(ihel1=0;ihel1<2;++ihel1) {
for(ihel2=0;ihel2<2;++ihel2) {
for(ohel1=0;ohel1<2;++ohel1) {
for(ohel2=0;ohel2<2;++ohel2) {
Complex diag = 0.0;
if (positive) {
// the Wp exchange
inter = _theFFWVertex->evaluate(scale(),1,_wp,fin[ihel1],ain[ihel2]);
diag = _theFFWVertex->evaluate(scale(),aout[ohel2],fout[ohel1],inter);
}
else {
// the Wm exchange
inter = _theFFWVertex->evaluate(scale(),1,_wm,fin[ihel1],ain[ihel2]);
diag = _theFFWVertex->evaluate(scale(),aout[ohel2],fout[ohel1],inter);
}
// sum over helicities
me += real(diag*conj(diag));
if(calc) newme(ihel1,ihel2,ohel1,ohel2) = diag;
}
}
}
}
// results
// spin and colour factor
double colspin=1./12.;
if(abs(fout[0].id())<=6) colspin*=3.;
if(calc) _me.reset(newme);
return me*colspin;
}
void MEqq2W2ff::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]);
// order of particles
unsigned int order[4]={0,1,2,3};
if(hard[0]->id()<0){order[0]=1;order[1]=0;}
if(hard[2]->id()<0){order[2]=3;order[3]=2;}
vector<SpinorWaveFunction> fin,aout;
vector<SpinorBarWaveFunction> ain,fout;
SpinorWaveFunction( fin ,hard[order[0]],incoming,false,true);
SpinorBarWaveFunction(ain ,hard[order[1]],incoming,false,true);
SpinorBarWaveFunction(fout,hard[order[2]],outgoing,true ,true);
SpinorWaveFunction( aout,hard[order[3]],outgoing,true ,true);
qqbarME(fin,ain,fout,aout,true);
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(_me);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<4;++ix)
hard[order[ix]]->spinInfo()->productionVertex(hardvertex);
}
diff --git a/MatrixElement/Hadron/MEqq2W2ff.h b/MatrixElement/Hadron/MEqq2W2ff.h
--- a/MatrixElement/Hadron/MEqq2W2ff.h
+++ b/MatrixElement/Hadron/MEqq2W2ff.h
@@ -1,268 +1,237 @@
// -*- C++ -*-
//
// MEqq2W2ff.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_MEqq2W2ff_H
#define HERWIG_MEqq2W2ff_H
//
// This is the declaration of the MEqq2W2ff class.
//
#include "Herwig/MatrixElement/DrellYanBase.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.fh"
namespace Herwig {
using namespace ThePEG;
using namespace ThePEG::Helicity;
/**
* The MEqq2W2ff class implements the matrix element for \f$q\bar{q'}\to W^\pm\f$
* including the decay of the \f$W^\pm\f$ to Standard Model fermions.
*
* @see \ref MEqq2W2ffInterfaces "The interfaces"
* defined for MEqq2W2ff.
*/
class MEqq2W2ff: public DrellYanBase {
public:
/**
* The default constructor.
*/
MEqq2W2ff();
/** @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:
/**
* Matrix element for \f$q\bar{q}\to \gamma/Z \to f\bar{f}\f$.
* @param fin Spinors for incoming quark
* @param ain Spinors for incoming antiquark
* @param fout Spinors for incoming quark
* @param aout Spinors for incoming antiquark
* @param me Whether or not to calculate the matrix element for spin correlations
*/
double qqbarME(vector<SpinorWaveFunction> & fin ,
vector<SpinorBarWaveFunction> & ain ,
vector<SpinorBarWaveFunction> & fout,
vector<SpinorWaveFunction> & aout,
bool me) const;
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();
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<MEqq2W2ff> initMEqq2W2ff;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEqq2W2ff & operator=(const MEqq2W2ff &);
private:
/**
* Pointer to the W vertex
*/
AbstractFFVVertexPtr _theFFWVertex;
/**
* Pointers to the intermediates resonances
*/
//@{
/**
* Pointer to the \f$W^+\f$
*/
tcPDPtr _wp;
/**
* Pointer to the \f$W^-\f$
*/
tcPDPtr _wm;
//@}
/**
* Switches to control the particles in the hard process
*/
//@{
/**
* The allowed flavours of the incoming quarks
*/
unsigned int _maxflavour;
/**
* Which intermediate \f$W^\pm\f$ bosons to include
*/
unsigned int _plusminus;
/**
* Which decay products of the \f$W^\pm\f$ to include
*/
unsigned int _process;
//@}
/**
* Matrix element for spin correlations
*/
ProductionMatrixElement _me;
};
}
-#include "ThePEG/Utilities/ClassTraits.h"
-
-namespace ThePEG {
-
-/** @cond TRAITSPECIALIZATIONS */
-
-/** This template specialization informs ThePEG about the
- * base classes of MEqq2W2ff. */
-template <>
-struct BaseClassTrait<Herwig::MEqq2W2ff,1> {
- /** Typedef of the first base class of MEqq2W2ff. */
- typedef Herwig::DrellYanBase NthBase;
-};
-
-/** This template specialization informs ThePEG about the name of
- * the MEqq2W2ff class and the shared object where it is defined. */
-template <>
-struct ClassTraits<Herwig::MEqq2W2ff>
- : public ClassTraitsBase<Herwig::MEqq2W2ff> {
- /** Return a platform-independent class name */
- static string className() { return "Herwig::MEqq2W2ff"; }
- /** Return the name(s) of the shared library (or libraries) be loaded to get
- * access to the MEqq2W2ff class and any other class on which it depends
- * (except the base class). */
- static string library() { return "HwMEHadron.so"; }
-};
-
-/** @endcond */
-
-}
-
#endif /* HERWIG_MEqq2W2ff_H */
diff --git a/MatrixElement/Hadron/MEqq2gZ2ff.cc b/MatrixElement/Hadron/MEqq2gZ2ff.cc
--- a/MatrixElement/Hadron/MEqq2gZ2ff.cc
+++ b/MatrixElement/Hadron/MEqq2gZ2ff.cc
@@ -1,376 +1,379 @@
// -*- C++ -*-
//
// MEqq2gZ2ff.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEqq2gZ2ff class.
//
#include "MEqq2gZ2ff.h"
+#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "Herwig/MatrixElement/HardVertex.h"
using namespace Herwig;
MEqq2gZ2ff::MEqq2gZ2ff() : _minflavour(1), _maxflavour(5),
_gammaZ(0), _process(0), spinCorrelations_(true) {
massOption(vector<unsigned int>(2,1));
}
void MEqq2gZ2ff::doinit() {
DrellYanBase::doinit();
_z0=getParticleData(ThePEG::ParticleID::Z0);
_gamma=getParticleData(ThePEG::ParticleID::gamma);
// cast the SM pointer to the Herwig SM pointer
tcHwSMPtr hwsm=ThePEG::dynamic_ptr_cast<tcHwSMPtr>(standardModel());
// do the initialisation
if(hwsm) {
_theFFZVertex = hwsm->vertexFFZ();
_theFFPVertex = hwsm->vertexFFP();
}
else
throw InitException() << "Must be the Herwig StandardModel class in "
<< "MEqq2gZ2ff::doinit" << Exception::abortnow;
}
void MEqq2gZ2ff::getDiagrams() const {
// which intermediates to include
bool gamma = _gammaZ==0 || _gammaZ==1;
bool Z0 = _gammaZ==0 || _gammaZ==2;
// loop over the processes we need
for ( int ix=1; ix<17; ++ix ) {
// increment counter to switch between quarks and leptons
if(ix==7) ix+=4;
// is it a valid quark process
bool quark = ix<=6 && (_process==0 || _process==1 || _process-10==ix);
// is it a valid lepton process
bool lepton= ix>=11 && ix<=16
&& (_process==0
|| _process==2
|| (_process==3 && ix%2==1)
|| (_process==4 && ix%2==0)
|| (ix%2==0 && (ix-10)/2==_process-7)
|| (ix%2==1 && (ix-9)/2 ==_process-4)
);
// if not a valid process continue
if(!(quark||lepton)) continue;
tcPDPtr lm = getParticleData(ix);
tcPDPtr lp = lm->CC();
for(int i = _minflavour; i <= _maxflavour; ++i) {
tcPDPtr q = getParticleData(i);
tcPDPtr qb = q->CC();
if(Z0) add(new_ptr((Tree2toNDiagram(2), q, qb, 1, _z0 , 3, lm, 3, lp, -1)));
if(gamma) add(new_ptr((Tree2toNDiagram(2), q, qb, 1, _gamma, 3, lm, 3, lp, -2)));
}
}
}
Energy2 MEqq2gZ2ff::scale() const {
return sHat();
}
double MEqq2gZ2ff::me2() const {
vector<SpinorWaveFunction> fin,aout;
vector<SpinorBarWaveFunction> ain,fout;
SpinorWaveFunction q(meMomenta()[0],mePartonData()[0],incoming);
SpinorBarWaveFunction qbar(meMomenta()[1],mePartonData()[1],incoming);
SpinorBarWaveFunction f(meMomenta()[2],mePartonData()[2],outgoing);
SpinorWaveFunction fbar(meMomenta()[3],mePartonData()[3],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
q.reset(ix) ; fin.push_back(q);
qbar.reset(ix); ain.push_back(qbar);
f.reset(ix) ;fout.push_back(f);
fbar.reset(ix);aout.push_back(fbar);
}
return qqbarME(fin,ain,fout,aout,false);
}
unsigned int MEqq2gZ2ff::orderInAlphaS() const {
return 0;
}
unsigned int MEqq2gZ2ff::orderInAlphaEW() const {
return 2;
}
Selector<MEBase::DiagramIndex>
MEqq2gZ2ff::diagrams(const DiagramVector & diags) const {
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i ) {
if ( diags[i]->id() == -1 ) sel.insert(meInfo()[0], i);
else if ( diags[i]->id() == -2 ) sel.insert(meInfo()[1], i);
}
return sel;
}
Selector<const ColourLines *>
MEqq2gZ2ff::colourGeometries(tcDiagPtr) const {
static const ColourLines c1("1 -2");
static const ColourLines c2("1 -2,4 -5");
Selector<const ColourLines *> sel;
if(abs(mePartonData()[2]->id())<=6) sel.insert(1.0, &c2);
else sel.insert(1.0, &c1);
return sel;
}
void MEqq2gZ2ff::persistentOutput(PersistentOStream & os) const {
os << _minflavour << _maxflavour << _gammaZ << _process
<< _theFFZVertex << _theFFPVertex
<< _gamma << _z0 << spinCorrelations_;
}
void MEqq2gZ2ff::persistentInput(PersistentIStream & is, int) {
is >> _minflavour >> _maxflavour >> _gammaZ >> _process
>> _theFFZVertex >> _theFFPVertex
>> _gamma >> _z0 >> spinCorrelations_;
}
-ClassDescription<MEqq2gZ2ff> MEqq2gZ2ff::initMEqq2gZ2ff;
-// Definition of the static class description member.
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEqq2gZ2ff,DrellYanBase>
+describeHerwigMEqq2gZ2ff("Herwig::MEqq2gZ2ff", "HwMEHadron.so");
void MEqq2gZ2ff::Init() {
static ClassDocumentation<MEqq2gZ2ff> documentation
("The MEqq2gZ2ff class implements the matrix element for"
"q qbar to Standard Model fermions via Z and photon exchange using"
" helicity amplitude techniques");
static Parameter<MEqq2gZ2ff,int> interfaceMaxFlavour
("MaxFlavour",
"The maximum incoming quark flavour this matrix element is allowed to handle",
&MEqq2gZ2ff::_maxflavour, 5, 1, 5,
false, false, Interface::limited);
static Parameter<MEqq2gZ2ff,int> interfaceMinFlavour
("MinFlavour",
"The minimum incoming quark flavour this matrix element is allowed to handle",
&MEqq2gZ2ff::_minflavour, 1, 1, 5,
false, false, Interface::limited);
static Switch<MEqq2gZ2ff,unsigned int> interfaceGammaZ
("GammaZ",
"Which terms to include",
&MEqq2gZ2ff::_gammaZ, 0, false, false);
static SwitchOption interfaceGammaZAll
(interfaceGammaZ,
"All",
"Include both gamma and Z terms",
0);
static SwitchOption interfaceGammaZGamma
(interfaceGammaZ,
"Gamma",
"Only include the photon",
1);
static SwitchOption interfaceGammaZZ
(interfaceGammaZ,
"Z",
"Only include the Z",
2);
static Switch<MEqq2gZ2ff,int> interfaceProcess
("Process",
"Which process to included",
&MEqq2gZ2ff::_process, 0, false, false);
static SwitchOption interfaceProcessAll
(interfaceProcess,
"All",
"Include all SM fermions as outgoing particles",
0);
static SwitchOption interfaceProcessQuarks
(interfaceProcess,
"Quarks",
"All include the quarks as outgoing particles",
1);
static SwitchOption interfaceProcessLeptons
(interfaceProcess,
"Leptons",
"Only include the leptons as outgoing particles",
2);
static SwitchOption interfaceProcessChargedLeptons
(interfaceProcess,
"ChargedLeptons",
"Only include the charged leptons as outgoing particles",
3);
static SwitchOption interfaceProcessNeutrinos
(interfaceProcess,
"Neutrinos",
"Only include the neutrinos as outgoing particles",
4);
static SwitchOption interfaceProcessElectron
(interfaceProcess,
"Electron",
"Only include e+e- as outgoing particles",
5);
static SwitchOption interfaceProcessMuon
(interfaceProcess,
"Muon",
"Only include mu+mu- as outgoing particles",
6);
static SwitchOption interfaceProcessTau
(interfaceProcess,
"Tau",
"Only include tau+tau- as outgoing particles",
7);
static SwitchOption interfaceProcessNu_e
(interfaceProcess,
"Nu_e",
"Only include nu_e ne_ebar as outgoing particles",
8);
static SwitchOption interfaceProcessnu_mu
(interfaceProcess,
"Nu_mu",
"Only include nu_mu nu_mubar as outgoing particles",
9);
static SwitchOption interfaceProcessnu_tau
(interfaceProcess,
"Nu_tau",
"Only include nu_tau nu_taubar as outgoing particles",
10);
static SwitchOption interfaceProcessDown
(interfaceProcess,
"Down",
"Only include d dbar as outgoing particles",
11);
static SwitchOption interfaceProcessUp
(interfaceProcess,
"Up",
"Only include u ubar as outgoing particles",
12);
static SwitchOption interfaceProcessStrange
(interfaceProcess,
"Strange",
"Only include s sbar as outgoing particles",
13);
static SwitchOption interfaceProcessCharm
(interfaceProcess,
"Charm",
"Only include c cbar as outgoing particles",
14);
static SwitchOption interfaceProcessBottom
(interfaceProcess,
"Bottom",
"Only include b bbar as outgoing particles",
15);
static SwitchOption interfaceProcessTop
(interfaceProcess,
"Top",
"Only include t tbar as outgoing particles",
16);
static Switch<MEqq2gZ2ff,bool> interfaceSpinCorrelations
("SpinCorrelations",
"Which on/off spin correlations in the hard process",
&MEqq2gZ2ff::spinCorrelations_, true, false, false);
static SwitchOption interfaceSpinCorrelationsYes
(interfaceSpinCorrelations,
"Yes",
"Switch correlations on",
true);
static SwitchOption interfaceSpinCorrelationsNo
(interfaceSpinCorrelations,
"No",
"Switch correlations off",
false);
}
double MEqq2gZ2ff::qqbarME(vector<SpinorWaveFunction> & fin ,
vector<SpinorBarWaveFunction> & ain ,
vector<SpinorBarWaveFunction> & fout,
vector<SpinorWaveFunction> & aout,
bool calc) const {
// scale
Energy2 mb2(scale());
// matrix element to be stored
ProductionMatrixElement menew(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half);
// which intermediates to include
bool gamma=_gammaZ==0||_gammaZ==1;
bool Z0 =_gammaZ==0||_gammaZ==2;
// declare the variables we need
unsigned int ihel1,ihel2,ohel1,ohel2;
VectorWaveFunction inter[2],test;
double me[3]={0.,0.,0.};
Complex diag1,diag2;
// sum over helicities to get the matrix element
for(ihel1=0;ihel1<2;++ihel1) {
for(ihel2=0;ihel2<2;++ihel2) {
// intermediate for Z
if(Z0) inter[0]=_theFFZVertex->evaluate(mb2,1,_z0 ,fin[ihel1],ain[ihel2]);
// intermediate for photon
if(gamma) inter[1]=_theFFPVertex->evaluate(mb2,1,_gamma,fin[ihel1],ain[ihel2]);
for(ohel1=0;ohel1<2;++ohel1) {
for(ohel2=0;ohel2<2;++ohel2) {
// first the Z exchange diagram
diag1 = Z0 ?
_theFFZVertex->evaluate(mb2,aout[ohel2],fout[ohel1],inter[0]) : 0.;
// first the photon exchange diagram
diag2 = gamma ?
_theFFPVertex->evaluate(mb2,aout[ohel2],fout[ohel1],inter[1]) : 0.;
// add up squares of individual terms
me[1] += real(diag1*conj(diag1));
me[2] += real(diag2*conj(diag2));
// the full thing including interference
diag1 +=diag2;
me[0] += real(diag1*conj(diag1));
if(calc) menew(ihel1,ihel2,ohel1,ohel2) = diag1;
}
}
}
}
// spin and colour factor
double colspin=1./12.;
if(abs(fout[0].id())<=6) colspin*=3.;
// results
// factor 12 from 4 helicity and 3 colour
for(int ix=0;ix<3;++ix){me[ix]*=colspin;}
DVector save;
save.push_back(me[1]);
save.push_back(me[2]);
meInfo(save);
if(calc) _me.reset(menew);
return me[0];
}
void MEqq2gZ2ff::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]);
// order of particles
unsigned int order[4]={0,1,2,3};
if(hard[0]->id()<0){order[0]=1;order[1]=0;}
if(hard[2]->id()<0){order[2]=3;order[3]=2;}
vector<SpinorWaveFunction> fin,aout;
vector<SpinorBarWaveFunction> ain,fout;
SpinorWaveFunction( fin ,hard[order[0]],incoming,false,true);
SpinorBarWaveFunction(ain ,hard[order[1]],incoming,false,true);
SpinorBarWaveFunction(fout,hard[order[2]],outgoing,true ,true);
SpinorWaveFunction( aout,hard[order[3]],outgoing,true ,true);
qqbarME(fin,ain,fout,aout,true);
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(_me);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<4;++ix)
hard[order[ix]]->spinInfo()->productionVertex(hardvertex);
}
diff --git a/MatrixElement/Hadron/MEqq2gZ2ff.h b/MatrixElement/Hadron/MEqq2gZ2ff.h
--- a/MatrixElement/Hadron/MEqq2gZ2ff.h
+++ b/MatrixElement/Hadron/MEqq2gZ2ff.h
@@ -1,289 +1,258 @@
// -*- C++ -*-
//
// MEqq2gZ2ff.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_MEqq2gZ2ff_H
#define HERWIG_MEqq2gZ2ff_H
//
// This is the declaration of the MEqq2gZ2ff class.
//
#include "Herwig/MatrixElement/DrellYanBase.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.fh"
namespace Herwig {
using namespace ThePEG;
using namespace ThePEG::Helicity;
/**
* The MEqq2gZ2ff class implements the products of Standard Model
* fermion antifermion pairs via the \f$Z^0\f$ resonance including
* photon interference terms.
*
* @see \ref MEqq2gZ2ffInterfaces "The interfaces"
* defined for MEqq2gZ2ff.
*/
class MEqq2gZ2ff: public DrellYanBase {
public:
/**
* The default constructor.
*/
MEqq2gZ2ff();
/** @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:
/**
* Matrix element for \f$q\bar{q}\to \gamma/Z \to f\bar{f}\f$.
* @param fin Spinors for incoming quark
* @param ain Spinors for incoming antiquark
* @param fout Spinors for incoming quark
* @param aout Spinors for incoming antiquark
* @param me Whether or not to calculate the matrix element for spin correlations
*/
double qqbarME(vector<SpinorWaveFunction> & fin ,
vector<SpinorBarWaveFunction> & ain ,
vector<SpinorBarWaveFunction> & fout,
vector<SpinorWaveFunction> & aout,
bool me) const;
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();
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<MEqq2gZ2ff> initMEqq2gZ2ff;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEqq2gZ2ff & operator=(const MEqq2gZ2ff &);
private:
/**
* Pointer to the vertices for the helicity calculations
*/
//@{
/**
* Pointer to the Z vertex
*/
AbstractFFVVertexPtr _theFFZVertex;
/**
* Pointer to the photon vertex
*/
AbstractFFVVertexPtr _theFFPVertex;
//@}
/**
* Pointers to the intermediate resonances
*/
//@{
/**
* Pointer to the Z ParticleData object
*/
tcPDPtr _z0;
/**
* Pointer to the photon ParticleData object
*/
tcPDPtr _gamma;
//@}
/**
* Switches to control the particles in the hard process
*/
//@{
/**
* Minimum allowed flavour for the incoming quarks
*/
int _minflavour;
/**
* Maximum allowed flavour for the incoming quarks
*/
int _maxflavour;
/**
* Whether to include both \f$Z^0\f$ and \f$\gamma\f$ or only one
*/
unsigned int _gammaZ;
/**
* Which processes to include
*/
int _process;
//@}
/**
* Matrix element for spin correlations
*/
ProductionMatrixElement _me;
/**
* 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 MEqq2gZ2ff. */
-template <>
-struct BaseClassTrait<Herwig::MEqq2gZ2ff,1> {
- /** Typedef of the first base class of MEqq2gZ2ff. */
- typedef Herwig::DrellYanBase NthBase;
-};
-
-/** This template specialization informs ThePEG about the name of
- * the MEqq2gZ2ff class and the shared object where it is defined. */
-template <>
-struct ClassTraits<Herwig::MEqq2gZ2ff>
- : public ClassTraitsBase<Herwig::MEqq2gZ2ff> {
- /** Return a platform-independent class name */
- static string className() { return "Herwig::MEqq2gZ2ff"; }
- /** Return the name(s) of the shared library (or libraries) be loaded to get
- * access to the MEqq2gZ2ff class and any other class on which it depends
- * (except the base class). */
- static string library() { return "HwMEHadron.so"; }
-};
-
-/** @endcond */
-
-}
-
#endif /* HERWIG_MEqq2gZ2ff_H */

File Metadata

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

Event Timeline