Page MenuHomeHEPForge

No OneTemporary

diff --git a/MatrixElement/Powheg/MEqq2gZ2ffPowhegQED.cc b/MatrixElement/Powheg/MEqq2gZ2ffPowhegQED.cc
--- a/MatrixElement/Powheg/MEqq2gZ2ffPowhegQED.cc
+++ b/MatrixElement/Powheg/MEqq2gZ2ffPowhegQED.cc
@@ -1,3292 +1,3294 @@
// -*- C++ -*-
// This is the implementation of the non-inlined, non-templated member
// functions of the MEqq2gZ2ffPowhegQED class.
//
#include "MEqq2gZ2ffPowhegQED.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "Herwig++/Models/StandardModel/StandardModel.h"
#include "ThePEG/PDF/BeamParticleData.h"
#include "Herwig++/Utilities/Maths.h"
#include "Herwig++/MatrixElement/HardVertex.h"
#include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h"
#include <numeric>
using namespace Herwig;
/**
* Typedef for BeamParticleData
*/
typedef Ptr<BeamParticleData>::transient_const_pointer tcBeamPtr;
MEqq2gZ2ffPowhegQED::MEqq2gZ2ffPowhegQED()
: corrections_(1), QEDContributions_(0), incomingPhotons_(true),
contrib_(1), power_(0.6), zPow_(0.5), yPow_(0.9),
alphaS_(0.118), alphaEM_(1./137.), fixedCouplings_(false),
supressionFunction_(0),
lambda2_(10000.*GeV2),QCDRadiationType_(-1),
preqqbarqQCD_(10.), preqqbarqbarQCD_(10.),
preqgQCD_(10.),pregqbarQCD_(10.),
preqqbarqQED_(50.), preqqbarqbarQED_(50.),
preqgQED_(10.),pregqbarQED_(10.), preFFQED_(6.),
preIFQED_(10.),
minpTQCD_(2.*GeV),
minpTQEDII_(1.*GeV),minpTQEDIF_(1.*GeV),minpTQEDFF_(1.*GeV),
process_(2), maxFlavour_(5) {
vector<unsigned int> mopt(2,1);
massOption(mopt);
}
unsigned int MEqq2gZ2ffPowhegQED::orderInAlphaS() const {
return 0;
}
unsigned int MEqq2gZ2ffPowhegQED::orderInAlphaEW() const {
return 2;
}
IBPtr MEqq2gZ2ffPowhegQED::clone() const {
return new_ptr(*this);
}
IBPtr MEqq2gZ2ffPowhegQED::fullclone() const {
return new_ptr(*this);
}
Energy2 MEqq2gZ2ffPowhegQED::scale() const {
return sqr(Z0_->mass());
//return sHat();
}
int MEqq2gZ2ffPowhegQED::nDim() const {
return HwMEBase::nDim() + ( contrib_>=1 && contrib_<=3 ? 3 : 0 );
}
bool MEqq2gZ2ffPowhegQED::generateKinematics(const double * r) {
if(contrib_>=1&&contrib_<=3) {
zTilde_ = r[nDim()-1];
vTilde_ = r[nDim()-2];
phi_ = Constants::twopi*r[nDim()-3];
}
jacobian(1.0);
return HwMEBase::generateKinematics(r);
}
CrossSection MEqq2gZ2ffPowhegQED::dSigHatDR() const {
// old technique
CrossSection preFactor =
jacobian()/(16.0*sqr(Constants::pi)*sHat())*sqr(hbarc);
loME_ = me2();
if(contrib_<4) return NLOWeight()*preFactor;
// folding technique to ensure positive
double wgt(0.);
unsigned int ntry(0);
do {
// radiative variables
zTilde_ = UseRandom::rnd();
vTilde_ = UseRandom::rnd();
phi_ = Constants::twopi*UseRandom::rnd();
wgt += NLOWeight();
++ntry;
}
while (wgt<0.&&ntry<100);
if(wgt<0.) return ZERO;
return wgt*preFactor/double(ntry);
}
double MEqq2gZ2ffPowhegQED::loME(const cPDVector & particles,
const vector<Lorentz5Momentum> & momenta,
bool first) const {
vector<SpinorWaveFunction> fin,aout;
vector<SpinorBarWaveFunction> ain,fout;
SpinorWaveFunction q(momenta[0],particles[0],incoming);
SpinorBarWaveFunction qbar(momenta[1],particles[1],incoming);
SpinorBarWaveFunction f(momenta[2],particles[2],outgoing);
SpinorWaveFunction fbar(momenta[3],particles[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,first);
}
double MEqq2gZ2ffPowhegQED::qqbarME(vector<SpinorWaveFunction> & fin ,
vector<SpinorBarWaveFunction> & ain ,
vector<SpinorBarWaveFunction> & fout,
vector<SpinorWaveFunction> & aout,
bool first) const {
// scale for the process
const Energy2 q2(scale());
ProductionMatrixElement menew(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half);
VectorWaveFunction inter[2];
double me[3]={0.,0.,0.};
// sum over helicities to get the matrix element
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
// intermediate for Z
inter[0]=oneLoopVertex_->evaluate(q2,1,Z0_ ,fin[ihel1],ain[ihel2]);
// intermediate for photon
inter[1]=oneLoopVertex_->evaluate(q2,1,gamma_,fin[ihel1],ain[ihel2]);
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
// first the Z exchange diagram
Complex diag1 = oneLoopVertex_->
evaluate(q2,aout[ohel2],fout[ohel1],inter[0]);
// first the photon exchange diagram
Complex diag2 = oneLoopVertex_->
evaluate(q2,aout[ohel2],fout[ohel1],inter[1]);
// add up squares of individual terms
me[1] += norm(diag1);
me[2] += norm(diag2);
// the full thing including interference
diag1 += diag2;
me[0] += norm(diag1);
menew(ihel1,ihel2,ohel1,ohel2) = diag1;
}
}
}
}
// spin and colour factor
double colspin=1./12.;
if(abs(fout[0].id())<=6) colspin*=3.;
for(int ix=0;ix<3;++ix)
me[ix]*=colspin;
if(first) {
DVector save;
save.push_back(me[1]);
save.push_back(me[2]);
meInfo(save);
me_.reset(menew);
}
return me[0];
}
Selector<const ColourLines *>
MEqq2gZ2ffPowhegQED::colourGeometries(tcDiagPtr) const {
static const ColourLines c1("1 -2");
Selector<const ColourLines *> sel;
sel.insert(1.0, &c1);
return sel;
}
void MEqq2gZ2ffPowhegQED::getDiagrams() const {
// loop over the processes we need
for ( int ix=11; ix<17; ++ix ) {
// is it a valid lepton process
bool lepton=
( 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(!lepton) continue;
tcPDPtr lm = getParticleData(ix);
tcPDPtr lp = lm->CC();
for(int i = 1; i <= maxFlavour_; ++i) {
tcPDPtr q = getParticleData(i);
tcPDPtr qb = q->CC();
add(new_ptr((Tree2toNDiagram(2), q, qb, 1, Z0_ , 3, lm, 3, lp, -1)));
add(new_ptr((Tree2toNDiagram(2), q, qb, 1, gamma_, 3, lm, 3, lp, -2)));
}
}
}
Selector<MEBase::DiagramIndex>
MEqq2gZ2ffPowhegQED::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;
}
double MEqq2gZ2ffPowhegQED::me2() const {
// clear looptools cache if needed
if(contrib_!=0&&(corrections_==3||corrections_==5))
oneLoopVertex_->clearCache();
// compute the spinors
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);
}
// scale for the process
const Energy2 q2(scale());
// wavefunctions and box corrections
// for EW correction if needed
VectorWaveFunction FS_Z[2][2],FS_A[2][2];
VectorWaveFunction IS_Z[2][2],IS_A[2][2];
vector<vector<complex<InvEnergy2 > > > boxCoeff;
if(contrib_!=0&&(corrections_==3||corrections_==5)) {
// compute final-state vertex correction
oneLoopVertex_->setOrder(1);
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
FS_Z[ohel1][ohel2] = oneLoopVertex_->
evaluate(q2,1,Z0_ ,aout[ohel2],fout[ohel1]);
FS_A[ohel1][ohel2] = oneLoopVertex_->
evaluate(q2,1,gamma_,aout[ohel2],fout[ohel1]);
}
}
// compute initial-state vertex correction
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
IS_Z[ihel1][ihel2] = oneLoopVertex_->
evaluate(q2,1,Z0_ ,fin[ihel1],ain[ihel2]);
IS_A[ihel1][ihel2] = oneLoopVertex_->
evaluate(q2,1,gamma_,fin[ihel1],ain[ihel2]);
}
}
oneLoopVertex_->setOrder(0);
// coefficients for the box diagrams
boxCoeff = oneLoopVertex_->
neutralCurrentFBox(mePartonData()[0],mePartonData()[1],
mePartonData()[2],mePartonData()[3],
sHat(),tHat(),uHat());
}
// momentum difference for genuine NLO QED FS structure
LorentzPolarizationVector momDiff =
(rescaledMomenta()[2]-rescaledMomenta()[3])/2./
(rescaledMomenta()[2].mass()+rescaledMomenta()[3].mass());
// storage of ME
ProductionMatrixElement menew(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half);
// intermediate wavefunctions
VectorWaveFunction inter_LO_AA ,inter_LO_ZZ ;
VectorWaveFunction inter_NLO_AA,inter_NLO_AZ,
inter_NLO_ZA,inter_NLO_ZZ;
// sum over helicities to get the matrix element
double loSum(0.),EWSum(0.),QEDSum(0.);
double dsum[2]={0.,0.};
// incoming helicities
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
// LO intermediates
// intermediate for Z
inter_LO_ZZ = oneLoopVertex_->evaluate(q2,1,Z0_ ,fin[ihel1],ain[ihel2]);
// intermediate for photon
inter_LO_AA = oneLoopVertex_->evaluate(q2,1,gamma_,fin[ihel1],ain[ihel2]);
// stuff for EW correction if needed
LorentzPolarizationVectorE leftQuark,rightQuark;
if(contrib_!=0&&(corrections_==3||corrections_==5)) {
// intermediates including self energy corrections
inter_NLO_AA = oneLoopVertex_->selfEnergyCorrection(gamma_,inter_LO_AA);
inter_NLO_AZ = oneLoopVertex_->selfEnergyCorrection(Z0_ ,inter_LO_AA);
inter_NLO_ZA = oneLoopVertex_->selfEnergyCorrection(gamma_,inter_LO_ZZ);
inter_NLO_ZZ = oneLoopVertex_->selfEnergyCorrection(Z0_ ,inter_LO_ZZ);
// currents for the box diagrams
leftQuark = fin[ihel1].dimensionedWave().
leftCurrent(ain[ihel2].dimensionedWave());
rightQuark = fin[ihel1].dimensionedWave().
rightCurrent(ain[ihel2].dimensionedWave());
}
// scalars for QED correction if needed
Complex scalar1(0.),scalar2(0.);
if(contrib_!=0&&(corrections_==2||corrections_==5)) {
scalar1 = inter_LO_ZZ.wave().dot(momDiff);
scalar2 = inter_LO_AA.wave().dot(momDiff);
}
// outgoing helicities
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
// LO piece
// first the Z exchange diagram
Complex diag1 = oneLoopVertex_->
evaluate(q2,aout[ohel2],fout[ohel1],inter_LO_ZZ);
// first the photon exchange diagram
Complex diag2 = oneLoopVertex_->
evaluate(q2,aout[ohel2],fout[ohel1],inter_LO_AA);
Complex lo = diag1 + diag2;
loSum += norm(lo);
// add up squares of individual terms
dsum[0] += norm(diag1);
dsum[1] += norm(diag2);
menew(ihel1,ihel2,ohel1,ohel2) = lo;
// genuine EW piece
if(contrib_!=0&&(corrections_==3||corrections_==5)) {
// self energy piece
Complex diag3 = oneLoopVertex_->
evaluate(q2,aout[ohel2],fout[ohel1],inter_NLO_AA);
Complex diag4 = oneLoopVertex_->
evaluate(q2,aout[ohel2],fout[ohel1],inter_NLO_AZ);
Complex diag5 = oneLoopVertex_->
evaluate(q2,aout[ohel2],fout[ohel1],inter_NLO_ZA);
Complex diag6 = oneLoopVertex_->
evaluate(q2,aout[ohel2],fout[ohel1],inter_NLO_ZZ);
Complex self = diag3 + diag4 + diag5 + diag6;
// vertex corrections
Complex diag7 = oneLoopVertex_->
evaluate(q2,aout[ohel2],fout[ohel1],IS_Z[ihel1][ihel2]);
Complex diag8 = oneLoopVertex_->
evaluate(q2,aout[ohel2],fout[ohel1],IS_A[ihel1][ihel2]);
Complex diag9 = oneLoopVertex_->
evaluate(q2,fin [ihel1],ain [ihel2],FS_Z[ohel1][ohel2]);
Complex diag10 = oneLoopVertex_->
evaluate(q2,fin [ihel1],ain [ihel2],FS_A[ohel1][ohel2]);
Complex vertex = diag7 + diag8 + diag9 + diag10;
// box diagrams
// currents
LorentzPolarizationVectorE leftLepton =
aout[ohel2].dimensionedWave().leftCurrent (fout[ohel1].dimensionedWave());
LorentzPolarizationVectorE rightLepton =
aout[ohel2].dimensionedWave().rightCurrent(fout[ohel1].dimensionedWave());
Complex box = -Complex(0.,1.)*
( leftQuark.dot( leftLepton)*boxCoeff[0][0] +
leftQuark.dot(rightLepton)*boxCoeff[0][1] +
rightQuark.dot( leftLepton)*boxCoeff[1][0] +
rightQuark.dot(rightLepton)*boxCoeff[1][1]);
// sum of the corrections
Complex loop = vertex + self + box;
EWSum += real(loop*conj(lo)+lo*conj(loop));
}
// QED FS corrections
if(contrib_!=0&&(corrections_==2||corrections_==5)) {
LorentzPolarizationVector left =
aout[ohel2].wave(). leftCurrent(fout[ohel1].wave());
LorentzPolarizationVector right =
aout[ohel2].wave().rightCurrent(fout[ohel1].wave());
Complex scalar =
aout[ohel2].wave().scalar(fout[ohel1].wave());
// nlo specific pieces
Complex diag3 =
Complex(0.,1.)*oneLoopVertex_->norm()*
(oneLoopVertex_->right()*( left.dot(inter_LO_ZZ.wave())) +
oneLoopVertex_-> left()*(right.dot(inter_LO_ZZ.wave())) -
( oneLoopVertex_-> left()+oneLoopVertex_->right())*scalar1*scalar);
diag3 += Complex(0.,1.)*oneLoopVertex_->norm()*
(oneLoopVertex_->right()*( left.dot(inter_LO_AA.wave())) +
oneLoopVertex_-> left()*(right.dot(inter_LO_AA.wave())) -
( oneLoopVertex_-> left()+oneLoopVertex_->right())*scalar2*scalar);
// nlo piece
QEDSum += real(diag1*conj(diag3) + diag3*conj(diag1));
}
}
}
}
}
// spin and colour factor
double colSpin=1./12.;
if(abs(mePartonData()[2]->id())<=6) colSpin *= 3.;
loSum *= colSpin;
EWSum *= colSpin;
QEDSum *= colSpin;
for(unsigned int ix=0;ix<2;++ix) dsum[ix] *= colSpin;
// test of EW correction (if needed)
// cerr << "testing in EW " << loME_ << " " << loSum << " " << EWSum << "\n";
// oneLoopVertex_->neutralCurrentEWME(mePartonData()[0],mePartonData()[1],
// mePartonData()[2],mePartonData()[3],
// sHat(),tHat(),uHat());
// save the stuff for diagram selection
DVector save;
save.push_back(dsum[0]);
save.push_back(dsum[1]);
meInfo(save);
me_.reset(menew);
// save the higher order pieces
f2term_ = QEDSum;
EWterm_ = EWSum/loSum;
// return LO result
return loSum;
}
void MEqq2gZ2ffPowhegQED::persistentOutput(PersistentOStream & os) const {
os << corrections_ << incomingPhotons_ << contrib_ << power_ << gluon_
<< fixedCouplings_ << alphaS_ << alphaEM_ << yPow_ << zPow_
<< supressionFunction_ << ounit(lambda2_,GeV2)
<< preqqbarqQCD_ << preqqbarqbarQCD_ << preqgQCD_ << pregqbarQCD_
<< preqqbarqQED_ << preqqbarqbarQED_ << preqgQED_ << pregqbarQED_
<< preFFQED_ << preIFQED_ << prefactorQCD_ << prefactorQED_
<< ounit(minpTQCD_,GeV)
<< ounit(minpTQEDII_,GeV) << ounit(minpTQEDIF_,GeV) << ounit(minpTQEDFF_,GeV)
<< alphaQCD_ << alphaQED_
<< FFGVertex_ << oneLoopVertex_ << QCDRadiationType_
<< Z0_ << gamma_ << process_ << maxFlavour_ << QEDContributions_;
}
void MEqq2gZ2ffPowhegQED::persistentInput(PersistentIStream & is, int) {
is >> corrections_ >> incomingPhotons_ >> contrib_ >> power_ >> gluon_
>> fixedCouplings_ >> alphaS_ >> alphaEM_ >> yPow_ >> zPow_
>> supressionFunction_ >> iunit(lambda2_,GeV2)
>> preqqbarqQCD_ >> preqqbarqbarQCD_ >> preqgQCD_ >> pregqbarQCD_
>> preqqbarqQED_ >> preqqbarqbarQED_ >> preqgQED_ >> pregqbarQED_
>> preFFQED_ >> preIFQED_ >> prefactorQCD_ >> prefactorQED_
>> iunit(minpTQCD_,GeV)
>> iunit(minpTQEDII_,GeV) >> iunit(minpTQEDIF_,GeV) >> iunit(minpTQEDFF_,GeV)
>> alphaQCD_ >> alphaQED_
>> FFGVertex_ >> oneLoopVertex_ >> QCDRadiationType_
>> Z0_ >> gamma_ >> process_ >> maxFlavour_ >> QEDContributions_;
}
void MEqq2gZ2ffPowhegQED::doinit() {
HwMEBase::doinit();
// get the ParticleData objects
Z0_ = getParticleData(ThePEG::ParticleID::Z0);
gamma_ = getParticleData(ThePEG::ParticleID::gamma);
gluon_ = getParticleData(ParticleID::g);
// prefactors for overestimate for real emission
// QCD
prefactorQCD_.push_back(preqqbarqQCD_);
prefactorQCD_.push_back(preqqbarqbarQCD_);
prefactorQCD_.push_back(preqgQCD_);
prefactorQCD_.push_back(pregqbarQCD_);
// QED
prefactorQED_.push_back(preqqbarqQED_);
prefactorQED_.push_back(preqqbarqbarQED_);
prefactorQED_.push_back(preqgQED_);
prefactorQED_.push_back(pregqbarQED_);
// cast the SM pointer to the Herwig SM pointer
tcHwSMPtr hwsm=ThePEG::dynamic_ptr_cast<tcHwSMPtr>(standardModel());
if(!hwsm)
throw InitException() << "Must be the Herwig++ SusyBase class in "
<< "MEqq2gZ2ffPowhegQED::doinit"
<< Exception::abortnow;
// extract the vertices
FFGVertex_ = hwsm->vertexFFG();
}
void MEqq2gZ2ffPowhegQED::doinitrun() {
oneLoopVertex_->initrun();
HwMEBase::doinitrun();
}
ClassDescription<MEqq2gZ2ffPowhegQED> MEqq2gZ2ffPowhegQED::initMEqq2gZ2ffPowhegQED;
// Definition of the static class description member.
void MEqq2gZ2ffPowhegQED::Init() {
static ClassDocumentation<MEqq2gZ2ffPowhegQED> documentation
("The MEqq2gZ2ffPowhegQED class implements the strong and QED corrections"
" to the Drell-Yan process");
static Switch<MEqq2gZ2ffPowhegQED,unsigned int> interfaceCorrections
("Corrections",
"Which corrections to include",
&MEqq2gZ2ffPowhegQED::corrections_, 1, false, false);
static SwitchOption interfaceCorrectionsQCD
(interfaceCorrections,
"QCD",
"Only include the QCD corrections",
1);
static SwitchOption interfaceCorrectionsQED
(interfaceCorrections,
"QED",
"Only include the QED corrections",
2);
static SwitchOption interfaceCorrectionsEW
(interfaceCorrections,
"EW",
"Only include the EW corrections",
3);
static SwitchOption interfaceCorrectionsQCDandQED
(interfaceCorrections,
"QCDandQED",
"Include both QED and QCD corrections",
4);
static SwitchOption interfaceCorrectionsAll
(interfaceCorrections,
"All",
"Include QED, QCD and EW corrections",
5);
static Switch<MEqq2gZ2ffPowhegQED,bool> interfaceIncomingPhotons
("IncomingPhotons",
"Whether or not to include incoming photons",
&MEqq2gZ2ffPowhegQED::incomingPhotons_, true, false, false);
static SwitchOption interfaceIncomingPhotonsYes
(interfaceIncomingPhotons,
"Yes",
"Include them",
true);
static SwitchOption interfaceIncomingPhotonsNo
(interfaceIncomingPhotons,
"No",
"Don't include them",
false);
static Switch<MEqq2gZ2ffPowhegQED,unsigned int> interfaceContribution
("Contribution",
"Which contributions to the cross section to include",
&MEqq2gZ2ffPowhegQED::contrib_, 1, false, false);
static SwitchOption interfaceContributionLeadingOrder
(interfaceContribution,
"LeadingOrder",
"Just generate the leading order cross section",
0);
static SwitchOption interfaceContributionPositiveNLO
(interfaceContribution,
"PositiveNLO",
"Generate the positive contribution to the full NLO cross section",
1);
static SwitchOption interfaceContributionNegativeNLO
(interfaceContribution,
"NegativeNLO",
"Generate the negative contribution to the full NLO cross section",
2);
static SwitchOption interfaceContributionReal
(interfaceContribution,
"Real",
"Generate the high pT real emission only",
3);
static SwitchOption interfaceContributionTotalNLO
(interfaceContribution,
"TotalNLO",
"Generate the full NLO cross section using folding",
4);
static Parameter<MEqq2gZ2ffPowhegQED,double> interfaceSamplingPower
("SamplingPower",
"Power for the sampling of xp",
&MEqq2gZ2ffPowhegQED::power_, 0.6, 0.0, 1.,
false, false, Interface::limited);
static Switch<MEqq2gZ2ffPowhegQED,bool> interfaceFixedAlphaS
("FixedAlpha",
"Use a fixed value of alpha_S and alpha_EM",
&MEqq2gZ2ffPowhegQED::fixedCouplings_, false, false, false);
static SwitchOption interfaceFixedAlphaSYes
(interfaceFixedAlphaS,
"Yes",
"Use fixed alpha_S and alpha_EM",
true);
static SwitchOption interfaceFixedAlphaSNo
(interfaceFixedAlphaS,
"No",
"Use running alpha_S and alpha_EM",
false);
static Parameter<MEqq2gZ2ffPowhegQED,double> interfaceAlphaS
("AlphaS",
"The fixed value of alpha_S to use",
&MEqq2gZ2ffPowhegQED::alphaS_, 0., 0., 1.,
false, false, Interface::limited);
static Parameter<MEqq2gZ2ffPowhegQED,double> interfaceAlphaEM
("AlphaEM",
"The fixed value of alpha_EM to use",
&MEqq2gZ2ffPowhegQED::alphaEM_, 1./137., 0., 1.,
false, false, Interface::limited);
static Switch<MEqq2gZ2ffPowhegQED,unsigned int> interfaceSupressionFunction
("SupressionFunction",
"Choice of the supression function",
&MEqq2gZ2ffPowhegQED::supressionFunction_, 0, false, false);
static SwitchOption interfaceSupressionFunctionNone
(interfaceSupressionFunction,
"None",
"Default POWHEG approach",
0);
static SwitchOption interfaceSupressionFunctionThetaFunction
(interfaceSupressionFunction,
"ThetaFunction",
"Use theta functions at scale Lambda",
1);
static SwitchOption interfaceSupressionFunctionSmooth
(interfaceSupressionFunction,
"Smooth",
"Supress high pT by pt^2/(pt^2+lambda^2)",
2);
static Parameter<MEqq2gZ2ffPowhegQED,Energy2> interfaceSupressionScale
("SupressionScale",
"The square of the scale for the supression function",
&MEqq2gZ2ffPowhegQED::lambda2_, GeV2, 10000.0*GeV2, 0.0*GeV2, 0*GeV2,
false, false, Interface::lowerlim);
static Parameter<MEqq2gZ2ffPowhegQED,double> interfaceQQbarQPreFactorQCD
("QQbarQPreFactorQCD",
"Prefactor for the sampling on qqbar -> X g with radiation from q",
&MEqq2gZ2ffPowhegQED::preqqbarqQCD_, 20.0, 0.0, 1000.0,
false, false, Interface::limited);
static Parameter<MEqq2gZ2ffPowhegQED,double> interfaceQQbarQbarPreFactorQCD
("QQbarQbarPreFactorQCD",
"Prefactor for the sampling on qqbar -> X g with radiation from qbar",
&MEqq2gZ2ffPowhegQED::preqqbarqbarQCD_, 20.0, 0.0, 1000.0,
false, false, Interface::limited);
static Parameter<MEqq2gZ2ffPowhegQED,double> interfaceQGPreFactorQCD
("QGPreFactorQCD",
"The prefactor for the qg->Xq channel",
&MEqq2gZ2ffPowhegQED::preqgQCD_, 20.0, 0.0, 1000.0,
false, false, Interface::limited);
static Parameter<MEqq2gZ2ffPowhegQED,double> interfaceQbarGPreFactorQCD
("QbarGPreFactorQCD",
"The prefactor for the qbarg->Xqbar channel",
&MEqq2gZ2ffPowhegQED::pregqbarQCD_, 20.0, 0.0, 1000.0,
false, false, Interface::limited);
static Parameter<MEqq2gZ2ffPowhegQED,double> interfaceQQbarQPreFactorQED
("QQbarQPreFactorQED",
"Prefactor for the sampling on qqbar -> X g with radiation from q",
&MEqq2gZ2ffPowhegQED::preqqbarqQED_, 20.0, 0.0, 1000.0,
false, false, Interface::limited);
static Parameter<MEqq2gZ2ffPowhegQED,double> interfaceQQbarQbarPreFactorQED
("QQbarQbarPreFactorQED",
"Prefactor for the sampling on qqbar -> X g with radiation from qbar",
&MEqq2gZ2ffPowhegQED::preqqbarqbarQED_, 20.0, 0.0, 1000.0,
false, false, Interface::limited);
static Parameter<MEqq2gZ2ffPowhegQED,double> interfaceQGPreFactorQED
("QGPreFactorQED",
"The prefactor for the qg->Xq channel",
&MEqq2gZ2ffPowhegQED::preqgQED_, 20.0, 0.0, 1000.0,
false, false, Interface::limited);
static Parameter<MEqq2gZ2ffPowhegQED,double> interfaceQbarGPreFactorQED
("QbarGPreFactorQED",
"The prefactor for the qbarg->Xqbar channel",
&MEqq2gZ2ffPowhegQED::pregqbarQED_, 20.0, 0.0, 1000.0,
false, false, Interface::limited);
static Parameter<MEqq2gZ2ffPowhegQED,double> interfaceFinalStatePreFactorQED
("FinalStatePreFactorQED",
"The prefactor for final-state QED radiation",
&MEqq2gZ2ffPowhegQED::preFFQED_, 6.0, 0.0, 100.0,
false, false, Interface::limited);
static Parameter<MEqq2gZ2ffPowhegQED,double> interfaceInitialFinalStatePreFactorQED
("InitialFinalStatePreFactorQED",
"The prefactor for inital- and final-state QED interference",
&MEqq2gZ2ffPowhegQED::preIFQED_, 1.0, 0.0, 100.0,
false, false, Interface::limited);
static Parameter<MEqq2gZ2ffPowhegQED,Energy> interfaceMinimumpTQCD
("MinimumpTQCD",
"The minimum pT for the hard QCD emission",
&MEqq2gZ2ffPowhegQED::minpTQCD_, GeV, 1.0*GeV, 0.0*GeV, 10.0*GeV,
false, false, Interface::limited);
static Parameter<MEqq2gZ2ffPowhegQED,Energy> interfaceMinimumpTQEDII
("MinimumpTQEDII",
"The minimum pT for the hard QED emission (initial-initial)",
&MEqq2gZ2ffPowhegQED::minpTQEDII_, GeV, 1.0*GeV, 0.0*GeV, 10.0*GeV,
false, false, Interface::limited);
static Parameter<MEqq2gZ2ffPowhegQED,Energy> interfaceMinimumpTQEDIF
("MinimumpTQEDIF",
"The minimum pT for the hard QED emission (initial-final)",
&MEqq2gZ2ffPowhegQED::minpTQEDIF_, GeV, 1.0*GeV, 0.0*GeV, 10.0*GeV,
false, false, Interface::limited);
static Parameter<MEqq2gZ2ffPowhegQED,Energy> interfaceMinimumpTQEDFF
("MinimumpTQEDFF",
"The minimum pT for the hard QED emission (final-final)",
&MEqq2gZ2ffPowhegQED::minpTQEDFF_, GeV, 1.0*GeV, 0.0*GeV, 10.0*GeV,
false, false, Interface::limited);
static Reference<MEqq2gZ2ffPowhegQED,ShowerAlpha> interfaceAlphaQCD
("AlphaQCD",
"The object for the calculation of the strong coupling"
" for the hardest emission",
&MEqq2gZ2ffPowhegQED::alphaQCD_, false, false, true, false, false);
static Reference<MEqq2gZ2ffPowhegQED,ShowerAlpha> interfaceAlphaQED
("AlphaQED",
"The object for the calculation of the electromagnetic coupling"
" for the hardest emission",
&MEqq2gZ2ffPowhegQED::alphaQED_, false, false, true, false, false);
static Switch<MEqq2gZ2ffPowhegQED,int> interfaceProcess
("Process",
"Which process to included",
&MEqq2gZ2ffPowhegQED::process_, 2, false, false);
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 Parameter<MEqq2gZ2ffPowhegQED,int> interfaceMaxFlavour
("MaxFlavour",
"The maximum flavour of the incoming quarks",
&MEqq2gZ2ffPowhegQED::maxFlavour_, 5, 1, 5,
false, false, Interface::limited);
static Parameter<MEqq2gZ2ffPowhegQED,double> interfacezPower
("zPower",
"The sampling power for z",
&MEqq2gZ2ffPowhegQED::zPow_, 0.5, 0.0, 1.0,
false, false, Interface::limited);
static Parameter<MEqq2gZ2ffPowhegQED,double> interfaceyPower
("yPower",
"The sampling power for y",
&MEqq2gZ2ffPowhegQED::yPow_, 0.9, 0.0, 1.0,
false, false, Interface::limited);
static Switch<MEqq2gZ2ffPowhegQED,unsigned int> interfaceQEDContributions
("QEDContributions",
"Which QED corrections to include",
&MEqq2gZ2ffPowhegQED::QEDContributions_, 0, false, false);
static SwitchOption interfaceQEDContributionsAll
(interfaceQEDContributions,
"All",
"Include all the corrections",
0);
static SwitchOption interfaceQEDContributionsISR
(interfaceQEDContributions,
"ISR",
"Only include initial-state QED radiation",
1);
static SwitchOption interfaceQEDContributionsFSR
(interfaceQEDContributions,
"FSR",
"Only include final-state QED radiation",
2);
static SwitchOption interfaceQEDContributionsISRFSR
(interfaceQEDContributions,
"ISRPlusFSR",
"Only include inital- and final-state QED radiation, no intereference",
3);
static Reference<MEqq2gZ2ffPowhegQED,OneLoopFFAWZVertex> interfaceOneLoopVertex
("OneLoopVertex",
"The vertex include the one-loop corrections",
&MEqq2gZ2ffPowhegQED::oneLoopVertex_, false, false, true, false, false);
static Switch<MEqq2gZ2ffPowhegQED,int> interfaceQCDRadiationType
("QCDRadiationType",
"Whic types of QCD radiation ot include",
&MEqq2gZ2ffPowhegQED::QCDRadiationType_, -1, false, false);
static SwitchOption interfaceQCDRadiationTypeAll
(interfaceQCDRadiationType,
"All",
"All type",
-1);
static SwitchOption interfaceQCDRadiationTypeQuarkAntiQuark
(interfaceQCDRadiationType,
"QuarkAntiQuark",
"quark radiates gluon",
0);
static SwitchOption interfaceQCDRadiationTypeAntiQuarkQuark
(interfaceQCDRadiationType,
"AntiQuarkQuark",
"antiquark radaites gluon",
1);
static SwitchOption interfaceQCDRadiationTypeGluonAntiquark
(interfaceQCDRadiationType,
"GluonAntiquark",
"gluon splits radiation antiquark",
2);
static SwitchOption interfaceQCDRadiationTypeQuarkGluon
(interfaceQCDRadiationType,
"QuarkGluon",
"Gluon splits radiating quark",
3);
}
double MEqq2gZ2ffPowhegQED::subtractedVirtual() const {
double output(0.);
// ISR QCD correction
if(corrections_==1||corrections_==4||corrections_==5)
output += CFfact_*2.;
// ISR QED correction
if((corrections_==2||corrections_==4||corrections_==5) && QEDContributions_ != 2)
output += sqr(double(mePartonData()[0]->iCharge())/3.)*EMfact_*2.;
// FSR QED correction
- if((corrections_==2||corrections_==4||corrections_==5) && QEDContributions_ != 1) {
+ if((corrections_==2||corrections_==4||corrections_==5) && QEDContributions_ != 1 &&
+ mePartonData()[2]->charged()) {
double mu2 = sqr(mePartonData()[2]->mass())/sHat();
double mu = sqrt(mu2), mu4 = sqr(mu2), lmu = log(mu);
double v = sqrt(1.-4.*mu2),v2 = sqr(v),omv = 4.*mu2/(1.+v);
double f1,f2,fNS,VNS;
double r = omv/(1.+v),lr(log(r));
// normal form
if(mu>1e-4) {
f1 =
( +1. + 3.*log(0.5*(1.+v)) - 1.5*log(0.5*(1.+v2)) + sqr(Constants::pi)/6.
- 0.5*sqr(lr) - (1.+v2)/v*(lr*log(1.+v2) + sqr(Constants::pi)/12.
-0.5*log(4.*mu2)*lr + 0.25*sqr(lr)));
fNS = -0.5*(1.+2.*v2)*lr/v + 1.5*lr - 2./3.*sqr(Constants::pi) + 0.5*sqr(lr)
+ (1.+v2)/v*(Herwig::Math::ReLi2(r) + sqr(Constants::pi)/3. -
0.25*sqr(lr) + lr*log((2.*v/ (1.+v))));
VNS = 1.5*log(0.5*(1.+v2))
+ 0.5*(1.+v2)/v*( 2.*lr*log(2.*(1.+v2)/sqr(1.+v)) + 2.*Herwig::Math::ReLi2(sqr(r))
- 2.*Herwig::Math::ReLi2(2.*v/(1.+v)) - sqr(Constants::pi)/6.)
+ log(1.-mu) - 2.*log(1.-2.*mu) - 4.*mu2/(1.+v2)*log(mu/(1.-mu)) - mu/(1.-mu)
+ 4.*(2.*mu2-mu)/(1.+v2) + 0.5*sqr(Constants::pi);
f2 = mu2*lr/v;
}
// small mass limit
else {
f1 = -1./6.*
( - 6. - 24.*lmu*mu2 - 15.*mu4 - 12.*mu4*lmu - 24.*mu4*sqr(lmu)
+ 2.*mu4*sqr(Constants::pi) - 12.*mu2*mu4 - 96.*mu2*mu4*sqr(lmu)
+ 8.*mu2*mu4*sqr(Constants::pi) - 80.*mu2*mu4*lmu);
fNS = - mu2/18.*( + 36.*lmu - 36. - 45.*mu2 + 216.*lmu*mu2 - 24.*mu2*sqr(Constants::pi)
+ 72.*mu2*sqr(lmu) - 22.*mu4 + 1032.*mu4 * lmu
- 96.*mu4*sqr(Constants::pi) + 288.*mu4*sqr(lmu));
VNS = - mu2/1260.*(-6930. + 7560.*lmu + 2520.*mu - 16695.*mu2 + 1260.*mu2*sqr(Constants::pi)
+ 12600.*lmu*mu2 + 1344.*mu*mu2 - 52780.*mu4 + 36960.*mu4*lmu
+ 5040.*mu4*sqr(Constants::pi) - 12216.*mu*mu4);
f2 = mu2*( 2.*lmu + 4.*mu2*lmu + 2.*mu2 + 12.*mu4*lmu + 7.*mu4);
}
// subtracted virtual correction
output += sqr(double(mePartonData()[2]->iCharge())/3.)*
2.*EMfact_*(f1+fNS+VNS + f2*f2term_/loME_);
}
// ISR/FSR interference
- if((corrections_==2||corrections_==4||corrections_==5) && QEDContributions_==0 ) {
+ if((corrections_==2||corrections_==4||corrections_==5) && QEDContributions_==0 &&
+ mePartonData()[2]->charged()) {
output += alphaEM_*oneLoopVertex_->
neutralCurrentQEDME(mePartonData()[0],mePartonData()[1],
mePartonData()[2],mePartonData()[3],
sHat(),tHat(),uHat());
}
// genuine EW corrections
if(corrections_==3||corrections_==5) output += EWterm_;
// return the total
return output;
}
double MEqq2gZ2ffPowhegQED::NLOWeight() const {
// if leading-order return 1
if(contrib_==0) {
weights_.resize(1,loME_);
return loME_;
}
// strong coupling
Energy2 mu2(scale());
if(!fixedCouplings_) {
alphaS_ = SM().alphaS (mu2);
alphaEM_ = SM().alphaEM(mu2);
}
// prefactors
CFfact_ = 4./3.*alphaS_ /Constants::twopi;
TRfact_ = 1./2.*alphaS_ /Constants::twopi;
EMfact_ = alphaEM_/Constants::twopi;
// virtual pieces
double virt = subtractedVirtual();
// extract the partons and stuff for the real emission
// and collinear counter terms
// hadrons
pair<tcBeamPtr,tcBeamPtr> hadrons=
make_pair(dynamic_ptr_cast<tcBeamPtr>(lastParticles().first->dataPtr() ),
dynamic_ptr_cast<tcBeamPtr>(lastParticles().second->dataPtr()));
// momentum fractions
pair<double,double> x = make_pair(lastX1(),lastX2());
// partons
pair<tcPDPtr,tcPDPtr> partons = make_pair(mePartonData()[0],mePartonData()[1]);
// If necessary swap the particle data objects so that
// first beam gives the incoming quark
if(lastPartons().first ->dataPtr()!=partons.first) {
swap(x.first,x.second);
swap(hadrons.first,hadrons.second);
}
// convert the values of z tilde to z
pair<double,double> z;
pair<double,double> zJac;
double rhomax(pow(1.-x.first,1.-power_));
double rho = zTilde_*rhomax;
z.first = 1.-pow(rho,1./(1.-power_));
zJac.first = rhomax*pow(1.-z.first,power_)/(1.-power_);
rhomax = pow(1.-x.second,1.-power_);
rho = zTilde_*rhomax;
z.second = 1.-pow(rho,1./(1.-power_));
zJac.second = rhomax*pow(1.-z.second,power_)/(1.-power_);
// calculate the PDFs
pair<double,double> oldqPDF =
make_pair(hadrons.first ->pdf()->xfx(hadrons.first ,partons.first ,scale(),
x.first )/x.first ,
hadrons.second->pdf()->xfx(hadrons.second,partons.second,scale(),
x.second)/x.second);
// real/coll q/qbar
pair<double,double> newqPDF =
make_pair(hadrons.first ->pdf()->xfx(hadrons.first ,partons.first ,scale(),
x.first /z.first )*z.first /x.first ,
hadrons.second->pdf()->xfx(hadrons.second,partons.second,scale(),
x.second/z.second)*z.second/x.second);
// real/coll gluon
pair<double,double> newgPDF =
make_pair(hadrons.first ->pdf()->xfx(hadrons.first ,gluon_,scale(),
x.first /z.first )*z.first /x.first ,
hadrons.second->pdf()->xfx(hadrons.second,gluon_,scale(),
x.second/z.second)*z.second/x.second);
pair<double,double> newpPDF(make_pair(-1.,-1.));
// real/coll photon
if(incomingPhotons_) {
// if check the PDF has photons
cPDVector partons = hadrons.first ->pdf()->partons(hadrons.first);
if(find(partons.begin(),partons.end(),gamma_)!=partons.end())
newpPDF.first = hadrons.first ->pdf()->xfx(hadrons.first ,gamma_,scale(),
x.first /z.first )*z.first /x.first;
partons = hadrons.second->pdf()->partons(hadrons.second);
if(find(partons.begin(),partons.end(),gamma_)!=partons.end())
newpPDF.second = hadrons.second->pdf()->xfx(hadrons.second,gluon_,scale(),
x.second/z.second)*z.second/x.second;
}
// collinear remnants
double coll = 0.;
// common terms
// q -> q
double collQQ = collinearQuark(x.first ,mu2,zJac.first ,z.first ,
oldqPDF.first ,newqPDF.first );
// qbar -> qbar
double collQbarQbar = collinearQuark(x.second,mu2,zJac.second,z.second,
oldqPDF.second,newqPDF.second);
// QCD
if(corrections_==1||corrections_==4||corrections_==5) {
// g -> q
double collGQ = collinearBoson(mu2,zJac.first ,z.first ,
oldqPDF.first ,newgPDF.first );
// g -> qbar
double collGQbar = collinearBoson(mu2,zJac.second,z.second,
oldqPDF.second,newgPDF.second);
// add to sum
coll += CFfact_*(collQQ+collQbarQbar)+TRfact_*(collGQ+collGQbar);
}
// QED
if((corrections_==2||corrections_==4||corrections_==5) &&
QEDContributions_!=2 ) {
// gamma -> q
double collPQ = newpPDF.first < 0. ? 0. :
collinearBoson(mu2,zJac.first ,z.first ,oldqPDF.first ,newpPDF.first );
// gamma -> qbar
double collPQbar = newpPDF.second < 0. ? 0. :
collinearBoson(mu2,zJac.second,z.second,oldqPDF.second,newpPDF.second);
// add to sum
coll += sqr(double(mePartonData()[0]->iCharge())/3.)*EMfact_*
(collQQ+collQbarQbar+3.*(collPQ+collPQbar));
// q -> q (DIS factorization scheme)
double collQQDIS = collinearQuarkKDIS(x.first,zJac.first ,z.first ,
oldqPDF.first ,newqPDF.first );
// qbar -> qbar (DIS factorization scheme)
double collQbarQbarDIS = collinearQuarkKDIS(x.second,zJac.second,z.second,
oldqPDF.second,newqPDF.second );
// gamma -> q (DIS factorization scheme)
double collPQDIS = newpPDF.first < 0. ? 0. :
collinearBosonKDIS(zJac.first ,z.first ,oldqPDF.first ,newpPDF.first );
// gamma -> qbar (DIS factorization scheme)
double collPQbarDIS = newpPDF.second < 0. ? 0. :
collinearBosonKDIS(zJac.second,z.second,oldqPDF.second,newpPDF.second);
// add to sum
coll+= sqr(double(mePartonData()[0]->iCharge())/3.)*EMfact_*
(collQQDIS+collQbarQbarDIS+3.*(collPQDIS+collPQbarDIS));
// q -> q (QED IF piece)
double collQIF = collinearQuarkIF(x.first,zJac.first ,z.first ,
oldqPDF.first ,newqPDF.first ) ;
// qbar -> qbar (QED IF piece)
double collQbarIF = collinearQuarkIF(x.second,zJac.second,z.second,
oldqPDF.second,newqPDF.second) ;
// SumPop_IF corresponds to CS, eq. 10.25 (Ti*Tap terms of the P operator),
// for the QED case.
// Notice that for Z production the analogous terms in the K operator (CS, eq. 10.24)
// vanish when the sum is performed.
double SumPop_IF=0.;
for (unsigned int iin=0; iin<2; ++iin) {
double collIF = iin==0 ? collQIF : collQbarIF ;
for(unsigned int iout=2; iout<4; ++iout) {
// - sign because outgoing particles should be counted with a minus //ER
int QiQo= - mePartonData()[iin]->iCharge()*mePartonData()[iout]->iCharge();
if( QiQo != 0) {
Energy2 sioHat = 2.*meMomenta()[iin].dot(meMomenta()[iout]) ;
//cout<<iin<<iout<<" "<<collIF/collQIF<<" "<<collIF/collQbarIF<<endl;
//Energy2 sioHat2 = ((iin+iout) %2 ==0 ) ? -tHat() : -uHat();
//cout << sioHat/sioHat2 << endl;
SumPop_IF += double(QiQo)/9. * log(mu2/sioHat) * collIF;
}
}
}
// add to sum
coll += SumPop_IF*EMfact_ ;
}
// add up the virtual and remnant terms
double wgt = loME_*( 1. + virt + coll );
// real QCD emission
vector<double> realQCD1,realQCD2;
if(corrections_==1||corrections_==4||corrections_==5) {
realQCD1 = subtractedRealQCD(x,z. first,zJac. first,
oldqPDF. first,newqPDF. first,
newgPDF. first, II12);
realQCD2 = subtractedRealQCD(x,z.second,zJac.second,
oldqPDF.second,newqPDF.second,
newgPDF.second, II21);
wgt += realQCD1[0] + realQCD1[2] +realQCD2[0] +realQCD2[2];
}
// real QED emission
vector<double> realQED1(4,0.),realQED2(4,0.),
realQED3(2,0.),realQED4(2,0.),
realQED5(2,0.),realQED6(2,0.),
realQED7(2,0.),realQED8(2,0.);
if(corrections_==2||corrections_==4||corrections_==5) {
// ISR
if(QEDContributions_!=2) {
realQED1 = subtractedRealQED(x,z. first,zJac. first,
oldqPDF. first,newqPDF. first,
newpPDF. first, II12);
realQED2 = subtractedRealQED(x,z.second,zJac.second,
oldqPDF.second,newqPDF.second,
newpPDF.second, II21);
wgt += realQED1[0] + realQED1[2] +realQED2[0] +realQED2[2];
}
// FSR
if(QEDContributions_!=1) {
realQED3 = subtractedRealQED(x,zTilde_,1.,oldqPDF. first,
oldqPDF. first,0.,FF34);
realQED4 = subtractedRealQED(x,zTilde_,1.,oldqPDF. first,
oldqPDF. first,0.,FF43);
wgt += realQED3[0] + realQED4[0];
}
// ISR/FSR interference
if(QEDContributions_==0) {
if(mePartonData()[0]->iCharge()*mePartonData()[2]->iCharge()>0)
realQED5 = subtractedRealQED(x,z. first,zJac. first,
oldqPDF. first,newqPDF. first,
newpPDF. first, IF13);
if(mePartonData()[0]->iCharge()*mePartonData()[3]->iCharge()>0)
realQED6 = subtractedRealQED(x,z. first,zJac. first,
oldqPDF. first,newqPDF. first,
newpPDF. first, IF14);
if(mePartonData()[1]->iCharge()*mePartonData()[2]->iCharge()>0)
realQED7 = subtractedRealQED(x,z.second,zJac.second,
oldqPDF.second,newqPDF.second,
newpPDF.second, IF23);
if(mePartonData()[1]->iCharge()*mePartonData()[3]->iCharge()>0)
realQED8 = subtractedRealQED(x,z.second,zJac.second,
oldqPDF.second,newqPDF.second,
newpPDF.second, IF24);
wgt += (realQED5[0] + realQED6[0] + realQED7[0] + realQED8[0] );
}
}
if(isnan(wgt)||isinf(wgt)) {
generator()->log() << "testing bad weight "
<< virt << " " << coll << "\n";
generator()->log() << "QCD1 ";
for(unsigned int ix=0;ix<realQCD1.size();++ix)
generator()->log() << realQCD1[ix] << " ";
generator()->log() << "\n";
generator()->log() << "QCD2 ";
for(unsigned int ix=0;ix<realQCD2.size();++ix)
generator()->log() << realQCD2[ix] << " ";
generator()->log() << "\n";
generator()->log() << "QED1 ";
for(unsigned int ix=0;ix<realQED1.size();++ix)
generator()->log() << realQED1[ix] << " ";
generator()->log() << "\n";
generator()->log() << "QED2 ";
for(unsigned int ix=0;ix<realQED2.size();++ix)
generator()->log() << realQED2[ix] << " ";
generator()->log() << "\n";
generator()->log() << "QED3 ";
for(unsigned int ix=0;ix<realQED3.size();++ix)
generator()->log() << realQED3[ix] << " ";
generator()->log() << "\n";
generator()->log() << "QED4 ";
for(unsigned int ix=0;ix<realQED4.size();++ix)
generator()->log() << realQED4[ix] << " ";
generator()->log() << "\n";
generator()->log() << "QED5 ";
for(unsigned int ix=0;ix<realQED5.size();++ix)
generator()->log() << realQED5[ix] << " ";
generator()->log() << "\n";
generator()->log() << "QED6 ";
for(unsigned int ix=0;ix<realQED6.size();++ix)
generator()->log() << realQED6[ix] << " ";
generator()->log() << "\n";
generator()->log() << "QED7 ";
for(unsigned int ix=0;ix<realQED7.size();++ix)
generator()->log() << realQED7[ix] << " ";
generator()->log() << "\n";
generator()->log() << "QED8 ";
for(unsigned int ix=0;ix<realQED8.size();++ix)
generator()->log() << realQED8[ix] << " ";
generator()->log() << "\n";
generator()->log() << "testing z " << z.first << " " << z.second << "\n";
generator()->log() << "testing z " << 1.-z.first << " " << 1.-z.second << "\n";
generator()->log() << flush;
assert(false);
}
weights_.resize(15,0.);
if(corrections_==1||corrections_==4||corrections_==5) {
weights_[ 1] = realQCD1[1];
weights_[ 2] = realQCD1[3];
weights_[ 3] = realQCD2[1];
weights_[ 4] = realQCD2[3];
}
if(corrections_==2||corrections_==4||corrections_==5) {
weights_[ 5] = realQED1[1];
weights_[ 6] = realQED1[3];
weights_[ 7] = realQED2[1];
weights_[ 8] = realQED2[3];
weights_[ 9] = realQED3[1];
weights_[10] = realQED4[1];
weights_[11] = realQED5[1];
weights_[12] = realQED6[1];
weights_[13] = realQED7[1];
weights_[14] = realQED8[1];
}
if( contrib_ < 3 ) {
weights_[0] = wgt;
wgt = std::accumulate(weights_.begin(),weights_.end(),0.);
return contrib_ == 1 ? max(0.,wgt) : max(0.,-wgt);
}
else if(contrib_==3) {
weights_[0] = 0.;
return std::accumulate(weights_.begin(),weights_.end(),0.);
}
else
return wgt;
}
double
MEqq2gZ2ffPowhegQED::collinearQuark(double x, Energy2 mu2,
double jac, double z,
double oldPDF, double newPDF) const {
if(1.-z < 1.e-8) return 0.;
return
// this bit is multiplied by LO PDF
sqr(Constants::pi)/3.-5.+2.*sqr(log(1.-x ))
+(1.5+2.*log(1.-x ))*log(sHat()/mu2)
// NLO PDF bit
+jac /z * newPDF /oldPDF *
(1.-z -(1.+z )*log(sqr(1.-z )/z )
-(1.+z )*log(sHat()/mu2)-2.*log(z )/(1.-z ))
// + function bit
+jac /z *(newPDF /oldPDF -z )*
2./(1.-z )*log(sHat()*sqr(1.-z )/mu2);
}
double
MEqq2gZ2ffPowhegQED::collinearBoson(Energy2 mu2, double jac, double z,
double oldPDF, double newPDF) const {
if(1.-z < 1.e-8) return 0.;
return jac/z*newPDF/oldPDF*
((sqr(z)+sqr(1.-z))*log(sqr(1.-z)*sHat()/z/mu2)
+2.*z*(1.-z));
}
double
MEqq2gZ2ffPowhegQED::collinearQuarkIF(double x, double jac, double z,
double oldPDF, double newPDF) const {
if(1.-z < 1.e-8) return 0.;
return
// this bit is multiplied by LO PDF
1.5+2*log(1.-x)
// plus distribution bit
+jac /(1.-z) *
(newPDF /oldPDF *(1+z*z) /z - 2) ;
}
double
MEqq2gZ2ffPowhegQED::collinearQuarkKDIS(double x, double jac, double z,
double oldPDF, double newPDF) const {
// this is the function defined in eq. C.25 of CS
double fun=(1+z*z)/(1-z)*(log((1.-z)/z)-0.75) + (9+5*z)/4.;
// this is artanh(1-2x)
double atanhom2x=0.5*log((1.-x)/x);
// this is \int_0^x (fun(z) dz)
double intfun0x=0.5*(4*Math::ReLi2(x)
+ x *(2*x+7)
-2 *log(1.-x) *(log(1.-x) -2*log(x) -3)
-2 *x*(x+2)*atanhom2x) ;
if(1.-z < 1.e-8) return 0.;
return
// this bit is multiplied by LO PDF
intfun0x
// plus distribution bit
- jac * fun *
(newPDF /oldPDF /z -1);
}
double
MEqq2gZ2ffPowhegQED::collinearBosonKDIS(double jac, double z,
double oldPDF, double newPDF) const {
if(1.-z < 1.e-8) return 0.;
return jac/z*newPDF/oldPDF*
((sqr(z)+sqr(1.-z))*log((1.-z)/z) + 8*z*(1.-z) -1.);
}
vector<double>
MEqq2gZ2ffPowhegQED::subtractedRealQCD(pair<double,double> x, double z,
double zJac, double oldqPDF,
double newqPDF, double newgPDF,
DipoleType dipole) const {
double vt = vTilde_*(1.-z);
double vJac = 1.-z;
Energy pT = sqrt(sHat()*vt*(1.-vt-z)/z);
// rapidities
double rapidity;
if(dipole==II12) {
rapidity = -log(x.second*sqrt(lastS())/pT*vt);
}
else if(dipole==II21) {
rapidity = log(x.first *sqrt(lastS())/pT*vt);
}
else {
assert(false);
}
// CMS system
Energy rs=sqrt(lastS());
Lorentz5Momentum pcmf = Lorentz5Momentum(ZERO,ZERO,0.5*rs*(x.first-x.second),
0.5*rs*(x.first+x.second));
pcmf.rescaleMass();
Boost blab(pcmf.boostVector());
// emission from the quark radiation
vector<Lorentz5Momentum> pnew(5);
if(dipole==II12) {
pnew [0] = Lorentz5Momentum(ZERO,ZERO,0.5*rs*x.first/z,
0.5*rs*x.first/z,ZERO);
pnew [1] = Lorentz5Momentum(ZERO,ZERO,-0.5*rs*x.second,
0.5*rs*x.second,ZERO) ;
}
else if(dipole==II21) {
pnew[0] = Lorentz5Momentum(ZERO,ZERO,0.5*rs*x.first,
0.5*rs*x.first,ZERO);
pnew[1] = Lorentz5Momentum(ZERO,ZERO,-0.5*rs*x.second/z,
0.5*rs*x.second/z,ZERO) ;
}
else {
assert(false);
}
pnew [2] = meMomenta()[2];
pnew [3] = meMomenta()[3];
pnew [4] = Lorentz5Momentum(pT*cos(phi_),pT*sin(phi_),
pT*sinh(rapidity),
pT*cosh(rapidity), ZERO);
Lorentz5Momentum K = pnew [0]+pnew [1]-pnew [4];
Lorentz5Momentum Kt = pcmf;
Lorentz5Momentum Ksum = K+Kt;
Energy2 K2 = K.m2();
Energy2 Ksum2 = Ksum.m2();
for(unsigned int ix=2;ix<4;++ix) {
pnew [ix].boost(blab);
pnew [ix] = pnew [ix] - 2.*Ksum*(Ksum*pnew [ix])/Ksum2
+2*K*(Kt*pnew [ix])/K2;
}
// phase-space prefactors
// double phase = zJac*vJac/sqr(z);
double phase = zJac*vJac/z;
// real emission q qbar
vector<double> output(4,0.);
if(dipole==II12) {
realEmissionQCDGluon1_ = pnew;
realEmissionQCDQuark1_ = pnew;
}
else if(dipole==II21) {
realEmissionQCDGluon2_ = pnew;
realEmissionQCDQuark2_ = pnew;
}
else {
assert(false);
}
if(!(zTilde_<1e-7 || vt<1e-7 || 1.-z-vt < 1e-7 )) {
pair<double,double> realQQ = subtractedQCDMEqqbar(pnew,dipole,true);
double fact1 = CFfact_*phase*newqPDF/oldqPDF;
pair<double,double> realGQ = subtractedQCDMEgqbar(pnew,dipole,true);
double fact2 = TRfact_*phase*newgPDF/oldqPDF;
output[0] = realQQ.first *fact1;
output[1] = realQQ.second*fact1;
output[2] = realGQ.first *fact2;
output[3] = realGQ.second*fact2;
}
// return the answer
return output;
}
pair<double,double>
MEqq2gZ2ffPowhegQED::subtractedQCDMEqqbar(const vector<Lorentz5Momentum> & p,
DipoleType dipole,bool subtract) const {
// use the inheriting class to calculate the matrix element
cPDVector particles(mePartonData());
particles.push_back(gluon_);
double me = 0.75*realQCDME(particles,p);
// compute the two dipole terms
double x = (p[0]*p[1]-p[4]*p[1]-p[4]*p[0])/(p[0]*p[1]);
Lorentz5Momentum Kt = p[0]+p[1]-p[4];
vector<Lorentz5Momentum> pa(4),pb(4);
// momenta for q -> q g emission
pa[0] = x*p[0];
pa[1] = p[1];
Lorentz5Momentum K = pa[0]+pa[1];
Lorentz5Momentum Ksum = K+Kt;
Energy2 K2 = K.m2();
Energy2 Ksum2 = Ksum.m2();
for(unsigned int ix=2;ix<4;++ix)
pa[ix] = p[ix]-2.*Ksum*(Ksum*p[ix])/Ksum2+2*K*(Kt*p[ix])/K2;
// first LO matrix element
double lo1 = loME(mePartonData(),pa,false);
// momenta for qbar -> qbar g emission
pb[0] = p[0];
pb[1] = x*p[1];
K = pb[0]+pb[1];
Ksum = K+Kt;
K2 = K.m2();
Ksum2 = Ksum.m2();
for(unsigned int ix=2;ix<4;++ix)
pb[ix] = p[ix]-2.*Ksum*(Ksum*p[ix])/Ksum2+2*K*(Kt*p[ix])/K2;
// second LO matrix element
double lo2 = loME(mePartonData(),pb,false);
// first dipole
InvEnergy2 D1 = 0.5/(p[0]*p[4])/x*(2./(1.-x)-(1.+x));
// second dipole
InvEnergy2 D2 = 0.5/(p[1]*p[4])/x*(2./(1.-x)-(1.+x));
// results
pair<double,double> supressionFactor = supressionFunction(sqr(p[4].x())+sqr(p[4].y()));
pair<double,double> output = make_pair(0.,0.);
if(lo1>0.&&lo2>0.) {
if(dipole==II12) {
me *= abs(D1)*lo1/(abs(D1)*lo1+abs(D2)*lo2);
if(subtract) {
output.first = sHat()*(UnitRemoval::InvE2*me*supressionFactor.first -D1*lo1);
}
else {
output.first = sHat()*UnitRemoval::InvE2*me*supressionFactor.first;
}
output.second = sHat()*(UnitRemoval::InvE2*me*supressionFactor.second);
}
else if(dipole==II21) {
me *= abs(D2)*lo2/(abs(D1)*lo1+abs(D2)*lo2);
if(subtract) {
output.first = sHat()*(UnitRemoval::InvE2*me*supressionFactor.first -D2*lo2);
}
else {
output.first = sHat()*UnitRemoval::InvE2*me*supressionFactor.first;
}
output.second = sHat()*(UnitRemoval::InvE2*me*supressionFactor.second);
}
else {
assert(false);
}
}
return output;
}
pair<double,double>
MEqq2gZ2ffPowhegQED::subtractedQCDMEgqbar(const vector<Lorentz5Momentum> & p,
DipoleType dipole,bool subtract) const {
// use the inheriting class to calculate the matrix element
cPDVector particles(mePartonData());
if(dipole==II12) {
particles.push_back(particles[0]->CC());
particles[0] = gluon_;
}
else if(dipole==II21) {
particles.push_back(particles[1]->CC());
particles[1] = gluon_;
}
else {
assert(false);
}
double me = 2.*realQCDME(particles,p);
// compute the two dipole terms
double x = 1.-(p[4]*p[1]+p[4]*p[0])/(p[0]*p[1]);
Lorentz5Momentum Kt = p[0]+p[1]-p[4];
vector<Lorentz5Momentum> pa(4);
// momenta for ISR
if(dipole==II12) {
pa[0] = x*p[0];
pa[1] = p[1];
}
else if(dipole==II21) {
pa[0] = p[0];
pa[1] = x*p[1];
}
else {
assert(false);
}
Lorentz5Momentum K = pa[0]+pa[1];
Lorentz5Momentum Ksum = K+Kt;
Energy2 K2 = K.m2();
Energy2 Ksum2 = Ksum.m2();
for(unsigned int ix=2;ix<4;++ix)
pa[ix] = p[ix]-2.*Ksum*(Ksum*p[ix])/Ksum2+2*K*(Kt*p[ix])/K2;
// first LO matrix element
double lo1 = loME(mePartonData(),pa,false);
// dipole
InvEnergy2 D1;
if(dipole==II12) {
D1 = 0.5/(p[0]*p[4])/x*(1.-2.*x*(1.-x));
}
else if(dipole==II21) {
D1 = 0.5/(p[1]*p[4])/x*(1.-2.*x*(1.-x));
}
else {
assert(false);
}
pair<double,double> supressionFactor =
supressionFunction(sqr(p[4].x())+sqr(p[4].y()));
if(subtract) {
return make_pair(sHat()*(UnitRemoval::InvE2*me*supressionFactor.first -D1*lo1),
sHat()*(UnitRemoval::InvE2*me*supressionFactor.second));
}
else {
return make_pair(sHat()*(UnitRemoval::InvE2*me*supressionFactor.first ),
sHat()*(UnitRemoval::InvE2*me*supressionFactor.second));
}
}
double MEqq2gZ2ffPowhegQED::realQCDME(const cPDVector & particles,
const vector<Lorentz5Momentum> & momenta) const {
vector<SpinorWaveFunction> fin(2),aout(2);
vector<SpinorBarWaveFunction> ain(2),fout(2);
vector<VectorWaveFunction> gluon(2);
// wavefunctions for the q qbar -> l+ l- g process
if(particles[0]->id()==-particles[1]->id()) {
for( unsigned int i = 0; i < 2; ++i ) {
fin[i] = SpinorWaveFunction (momenta[0],particles[0], i,incoming);
ain[i] = SpinorBarWaveFunction(momenta[1],particles[1], i,incoming);
gluon[i] = VectorWaveFunction (momenta[4],particles[4],2*i,outgoing);
}
}
else if(particles[0]->id()==ParticleID::g && particles[1]->id()<0) {
for( unsigned int i = 0; i < 2; ++i ) {
fin[i] = SpinorWaveFunction (momenta[4],particles[4], i,outgoing);
ain[i] = SpinorBarWaveFunction(momenta[1],particles[1], i,incoming);
gluon[i] = VectorWaveFunction (momenta[0],particles[0],2*i,incoming);
}
}
else if(particles[0]->id()>0 && particles[1]->id()==ParticleID::g) {
for( unsigned int i = 0; i < 2; ++i ) {
fin[i] = SpinorWaveFunction (momenta[0],particles[0], i,incoming);
ain[i] = SpinorBarWaveFunction(momenta[4],particles[4], i,outgoing);
gluon[i] = VectorWaveFunction (momenta[1],particles[1],2*i,incoming);
}
}
else {
for(unsigned int ix=0;ix<particles.size();++ix) {
generator()->log() << particles[ix]->PDGName() << " " << momenta[ix]/GeV << "\n";
}
assert(false);
}
// wavefunctions for the leptons
for(unsigned int i=0; i<2; ++i) {
fout[i] = SpinorBarWaveFunction(momenta[2],particles[2],i,outgoing);
aout[i] = SpinorWaveFunction (momenta[3],particles[3],i,outgoing);
}
double output(0.);
vector<Complex> diag(4,0.);
Energy2 q2 = scale();
for(unsigned int lhel1=0;lhel1<2;++lhel1) {
for(unsigned int lhel2=0;lhel2<2;++lhel2) {
VectorWaveFunction Zwave = oneLoopVertex_->evaluate(q2, 1, Z0_,
aout[lhel2],fout[lhel1]);
VectorWaveFunction Pwave = oneLoopVertex_->evaluate(q2, 1, gamma_,
aout[lhel2],fout[lhel1]);
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
//////// Z diagrams //////////
// first Z diagram
SpinorWaveFunction inters = FFGVertex_->
evaluate(q2,5,fin[ihel1].particle(),fin[ihel1],gluon[ohel1]);
diag[0] = oneLoopVertex_->evaluate(q2, inters, ain[ihel2], Zwave);
// second Z diagram
SpinorBarWaveFunction interb = FFGVertex_->
evaluate(q2,5,ain[ihel1].particle(),ain[ihel2],gluon[ohel1]);
diag[1] = oneLoopVertex_->evaluate(q2, fin[ihel1], interb, Zwave);
//////// photon diagrams //////////
if(particles[2]->id()==-particles[3]->id()&&
particles[2]->charged()) {
// first photon diagram
diag[2] = oneLoopVertex_->evaluate(q2, inters, ain[ihel2], Pwave);
// second photon diagram
diag[3] = oneLoopVertex_->evaluate(q2, fin[ihel1], interb, Pwave);
}
// add them up
output += norm(std::accumulate(diag.begin(),diag.end(),Complex(0.)));
}
}
}
}
}
// colour and spin factors
if(particles[0]->id()==-particles[1]->id()) {
output *= 1./9.;
}
else {
output *= 1./24.;
}
// divided by 2 g_S^2
return 0.5*output/norm(FFGVertex_->norm());
}
vector<double>
MEqq2gZ2ffPowhegQED::subtractedRealQED(pair<double,double> x, double z,
double zJac, double oldqPDF,
double newqPDF, double newpPDF,
DipoleType dipole) const {
// ISR
if(dipole==II12||dipole==II21) {
double vt = vTilde_*(1.-z);
double vJac = 1.-z;
Energy pT = sqrt(sHat()*vt*(1.-vt-z)/z);
// rapidities
double rapidity;
if(dipole==II12) {
rapidity = -log(x.second*sqrt(lastS())/pT*vt);
}
else if(dipole==II21) {
rapidity = log(x.first *sqrt(lastS())/pT*vt);
}
else {
assert(false);
}
// CMS system
Energy rs=sqrt(lastS());
Lorentz5Momentum pcmf = Lorentz5Momentum(ZERO,ZERO,0.5*rs*(x.first-x.second),
0.5*rs*(x.first+x.second));
pcmf.rescaleMass();
Boost blab(pcmf.boostVector());
// emission from the quark radiation
vector<Lorentz5Momentum> pnew(5);
if(dipole==II12) {
pnew [0] = Lorentz5Momentum(ZERO,ZERO,0.5*rs*x.first/z,
0.5*rs*x.first/z,ZERO);
pnew [1] = Lorentz5Momentum(ZERO,ZERO,-0.5*rs*x.second,
0.5*rs*x.second,ZERO) ;
}
else if(dipole==II21) {
pnew[0] = Lorentz5Momentum(ZERO,ZERO,0.5*rs*x.first,
0.5*rs*x.first,ZERO);
pnew[1] = Lorentz5Momentum(ZERO,ZERO,-0.5*rs*x.second/z,
0.5*rs*x.second/z,ZERO) ;
}
else {
assert(false);
}
pnew [2] = meMomenta()[2];
pnew [3] = meMomenta()[3];
pnew [4] = Lorentz5Momentum(pT*cos(phi_),pT*sin(phi_),
pT*sinh(rapidity),
pT*cosh(rapidity), ZERO);
Lorentz5Momentum K = pnew [0]+pnew [1]-pnew [4];
Lorentz5Momentum Kt = pcmf;
Lorentz5Momentum Ksum = K+Kt;
Energy2 K2 = K.m2();
Energy2 Ksum2 = Ksum.m2();
for(unsigned int ix=2;ix<4;++ix) {
pnew [ix].boost(blab);
pnew [ix] = pnew [ix] - 2.*Ksum*(Ksum*pnew [ix])/Ksum2
+2*K*(Kt*pnew [ix])/K2;
}
// phase-space prefactors
double phase = zJac*vJac/z;
if(dipole==II12) {
realEmissionQEDPhoton1_ = pnew;
realEmissionQEDQuark1_ = pnew;
}
else if(dipole==II21) {
realEmissionQEDPhoton2_ = pnew;
realEmissionQEDQuark2_ = pnew;
}
else {
assert(false);
}
vector<double> output(4,0.);
if(!(zTilde_<1e-7 || vt<1e-7 || 1.-z-vt < 1e-7 )) {
// real emission q qbar
pair<double,double> realQQ = subtractedQEDMEqqbar(pnew,dipole,true);
double fact1 = EMfact_*phase*newqPDF/oldqPDF;
pair<double,double> realPQ(make_pair(0.,0.));
double fact2 = 0.;
if(newpPDF>0.) {
realPQ = subtractedQEDMEpqbar(pnew,dipole,true);
fact2 = EMfact_*phase*newpPDF/oldqPDF;
}
output[0] = realQQ.first *fact1;
output[1] = realQQ.second*fact1;
output[2] = realPQ.first *fact2;
output[3] = realPQ.second*fact2;
}
// return the answer
return output;
}
// FSR
else if(dipole==FF34||dipole==FF43) {
// reduced mass
double mu2 = sqr(mePartonData()[2]->mass())/sHat();
double mu = sqrt(mu2);
// jacobian
double jac = zJac;
// generate y
double yminus = 0.;
double yplus = 1.-2.*mu*(1.-mu)/(1.-2*mu2);
double rhoymax = pow(yplus-yminus,1.-yPow_);
double rhoy = zTilde_*rhoymax;
double y = yminus+pow(rhoy,1./(1.-yPow_));
jac *= pow(y-yminus,yPow_)*rhoymax/(1.-yPow_);
// generate z
double vt = sqrt(max(sqr(2.*mu2+(1.-2.*mu2)*(1.-y))-4.*mu2,0.))/(1.-2.*mu2)/(1.-y);
double zplus = (1.+vt)*(1.-2.*mu2)*y/2./(mu2 +(1.-2.*mu2)*y);
double zminus = (1.-vt)*(1.-2.*mu2)*y/2./(mu2 +(1.-2.*mu2)*y);
double rhozmax = pow(zplus-zminus,1.-zPow_);
double rhoz = vTilde_*rhozmax;
double z = zminus+pow(rhoz,1./(1.-zPow_));
jac *= pow(z-zminus,zPow_)*rhozmax/(1.-zPow_);
// calculate x1,x2,x3 and xT
double x2 = 1. - y*(1.-2.*mu2);
double x1 = 1. - z*(x2-2.*mu2);
double x3 = 2.-x1-x2;
double xT = sqrt(max(0.,sqr(x3) -0.25*sqr(sqr(x2)+sqr(x3)-sqr(x1))/(sqr(x2)-4.*mu2)));
// calculate the momenta
Energy M = sqrt(sHat());
Lorentz5Momentum pspect(ZERO,ZERO,-0.5*M*sqrt(max(sqr(x2)-4.*mu2,0.)),0.5*M*x2,M*mu);
Lorentz5Momentum pemit (-0.5*M*xT*cos(phi_),-0.5*M*xT*sin(phi_),
0.5*M*sqrt(max(sqr(x1)-sqr(xT)-4.*mu2,0.)),0.5*M*x1,M*mu);
Lorentz5Momentum pphoton( 0.5*M*xT*cos(phi_), 0.5*M*xT*sin(phi_),
0.5*M*sqrt(max(sqr(x3)-sqr(xT),0.)),0.5*M*x3,ZERO);
pphoton.rescaleEnergy();
if(abs(pspect.z()+pemit.z()-pphoton.z())/M<1e-6)
pphoton.setZ(-pphoton.z());
else if(abs(pspect.z()-pemit.z()+pphoton.z())/M<1e-6)
pemit .setZ(- pemit.z());
// boost and rotate momenta
LorentzRotation eventFrame( ( meMomenta()[2] + meMomenta()[3] ).findBoostToCM() );
Lorentz5Momentum spectator;
if(dipole==FF34) {
spectator = eventFrame*meMomenta()[2];
}
else {
spectator = eventFrame*meMomenta()[3];
}
eventFrame.rotateZ( -spectator.phi() );
eventFrame.rotateY( -spectator.theta() );
eventFrame.invert();
vector<Lorentz5Momentum> momenta(meMomenta());
if(dipole==FF34) {
momenta[3] = eventFrame*pspect;
momenta[2] = eventFrame*pemit ;
}
else {
momenta[2] = eventFrame*pspect;
momenta[3] = eventFrame*pemit ;
}
momenta.push_back(eventFrame*pphoton);
// phase-space factor
double realFact = EMfact_*(1.-y)*jac*sqr(1.-2.*mu2)/sqrt(1.-4.*mu2);
pair<double,double> realFF = make_pair(0.,0.);
if(1.-x1>1e-5 && 1.-x2>1e-5) {
realFF = subtractedQEDMEqqbar(momenta,dipole,true);
}
vector<double> output(2,0.);
output[0] = realFF.first *realFact;
output[1] = realFF.second*realFact;
return output;
}
// ISR/FSR interference
else if (dipole == IF13 || dipole == IF14 ||
dipole == IF23 || dipole == IF24) {
// particles making up the dipole
int iin = dipole == IF13 || dipole == IF14 ? 0 : 1;
int iout = dipole == IF13 || dipole == IF23 ? 2 : 3;
// momentum of system
Lorentz5Momentum q = meMomenta()[iout]-meMomenta()[iin];
q.rescaleMass();
Energy Q = -q.mass();
Energy2 Q2 = sqr(Q);
// reduced mass
Energy mj = meMomenta()[iout].mass();
double mu2 = sqr(mj)/Q2;
// second integration variable
double vJac = (1.-mu2*z/(1.+mu2-z));
double vt = vTilde_*vJac;
// work out LT to Breit-Frame
Lorentz5Momentum pb = meMomenta()[iin ];
Axis axis(q.vect().unit());
double sinth(sqrt(sqr(axis.x())+sqr(axis.y())));
LorentzRotation rot;
if(axis.perp2()>1e-20) {
rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.));
rot.rotateX(Constants::pi);
}
if(abs(1.-q.e()/q.vect().mag())>1e-6)
rot.boostZ( q.e()/q.vect().mag());
pb *= rot;
if(pb.perp2()/GeV2>1e-20) {
Boost trans = -1./pb.e()*pb.vect();
trans.setZ(0.);
rot.boost(trans);
}
// born incoming and outgoing momenta
Lorentz5Momentum pij = rot*meMomenta()[iout];
Lorentz5Momentum pat = rot*meMomenta()[iin ];
// generate the real emission momenta
double x1 = -(1.+mu2)/z;
double x2 = 1-mu2-vt*(1.+mu2)/z;
double x3 = 2.+x1-x2;
double corr = (1.-z-vt)*mu2/((1.-vt)*(1.-z));
double xT = sqrt(4.*(1.-z)/z*vt*(1.-vt)*(1.+corr));
// incoming momentum
Lorentz5Momentum pa(ZERO,ZERO,-0.5*x1*Q,-0.5*x1*Q,ZERO);
// outgoing momentum
Lorentz5Momentum pj( 0.5*Q*xT*cos(phi_), 0.5*Q*xT*sin(phi_),
-0.5*Q*x2,0.5*Q*sqrt(sqr(x2)+sqr(xT)+4.*mu2),mj);
Lorentz5Momentum pi(-0.5*Q*xT*cos(phi_),-0.5*Q*xT*sin(phi_),
-0.5*Q*x3,0.5*Q*sqrt(sqr(x3)+sqr(xT) ),ZERO);
// boost back to the lab
rot.invert();
pa *= rot;
pi *= rot;
pj *= rot;
// new momenta
vector<Lorentz5Momentum> pnew(5);
// incoming
if(iin==0) {
pnew[0] = pa;
pnew[1] = meMomenta()[1];
}
else {
pnew[0] = meMomenta()[0];
pnew[1] = pa;
}
// outgoing
if(iout==2) {
pnew[2] = pj;
pnew[3] = meMomenta()[3];
}
else {
pnew[2] = meMomenta()[2];
pnew[3] = pj;
}
// emitted
pnew[4] = pi;
// phase-space prefactors
double phase = zJac*vJac/z*(1.+mu2);
if ( dipole == IF13 ) {
realEmissionQEDIF13_ = pnew;
}
else if ( dipole == IF14 ) {
realEmissionQEDIF14_ = pnew;
}
else if ( dipole == IF23 ) {
realEmissionQEDIF23_ = pnew;
}
else if ( dipole == IF24 ) {
realEmissionQEDIF24_ = pnew;
}
else
assert(false);
vector<double> output(2,0.);
if(!(zTilde_<1e-7 || vt<1e-7 || 1.-z-vt < 1e-7 )) {
pair<double,double> realIF = subtractedQEDMEqqbar(pnew,dipole,true);
double fact = EMfact_*phase*newqPDF/oldqPDF;
output[0] = realIF.first *fact;
output[1] = realIF.second*fact;
}
// return the answer
return output;
}
else {
assert(false);
return vector<double>(4,0.);
}
}
pair<double,double>
MEqq2gZ2ffPowhegQED::subtractedQEDMEqqbar(const vector<Lorentz5Momentum> & p,
DipoleType dipole, bool subtract) const {
// calculate the matrix element
cPDVector particles(mePartonData());
particles.push_back(gamma_);
vector<double> me = realQEDME(particles,p);
// scale for the phase space
Energy2 scale(ZERO);
/////////// compute the two II dipole terms ////////////////////////////
InvEnergy2 DII[2] = {ZERO,ZERO};
if(QEDContributions_!=2) {
double x = (p[0]*p[1]-p[4]*p[1]-p[4]*p[0])/(p[0]*p[1]);
Lorentz5Momentum Kt = p[0]+p[1]-p[4];
vector<Lorentz5Momentum> pa(4),pb(4);
// momenta for q -> q gamma emission
pa[0] = x*p[0];
pa[1] = p[1];
Lorentz5Momentum K = pa[0]+pa[1];
Lorentz5Momentum Ksum = K+Kt;
Energy2 K2 = K.m2();
Energy2 Ksum2 = Ksum.m2();
for(unsigned int ix=2;ix<4;++ix)
pa[ix] = p[ix]-2.*Ksum*(Ksum*p[ix])/Ksum2+2*K*(Kt*p[ix])/K2;
// first LO matrix element
double lo1 = loME(mePartonData(),pa,false);
// momenta for qbar -> qbar gamma emission
pb[0] = p[0];
pb[1] = x*p[1];
K = pb[0]+pb[1];
Ksum = K+Kt;
K2 = K.m2();
Ksum2 = Ksum.m2();
for(unsigned int ix=2;ix<4;++ix)
pb[ix] = p[ix]-2.*Ksum*(Ksum*p[ix])/Ksum2+2.*K*(Kt*p[ix])/K2;
// second LO matrix element
double lo2 = loME(mePartonData(),pb,false);
// II dipoles
DII[0] = 0.5/(p[0]*p[4])/x*(2./(1.-x)-(1.+x))*lo1;
DII[1] = 0.5/(p[1]*p[4])/x*(2./(1.-x)-(1.+x))*lo2;
// charge factors
for(unsigned int ix=0;ix<2;++ix)
DII[ix] *= sqr(double(mePartonData()[0]->iCharge())/3.);
// phase-space factor
if(dipole==II12||dipole==II21) scale = sHat();
}
/////////// compute the two FF dipole terms ////////////////////////////
InvEnergy2 DFF[2]={ZERO,ZERO};
Energy2 pT2final[2]={ZERO,ZERO};
if(QEDContributions_!=1) {
Lorentz5Momentum q = p[0]+p[1];
Energy2 Q2=q.m2();
Energy2 lambda = sqrt((Q2-sqr(p[2].mass()+p[3].mass()))*
(Q2-sqr(p[2].mass()-p[3].mass())));
for(unsigned int iemit=0;iemit<2;++iemit) {
unsigned int ispect = iemit==0 ? 1 : 0;
Energy2 pipj = p[4 ] * p[2+iemit ];
Energy2 pipk = p[4 ] * p[2+ispect];
Energy2 pjpk = p[2+iemit] * p[2+ispect];
double y = pipj/(pipj+pipk+pjpk);
double z = pipk/( pipk+pjpk);
Energy mij = sqrt(2.*pipj+sqr(p[2+iemit].mass()));
Energy2 lamB = sqrt((Q2-sqr(mij+p[2+ispect].mass()))*
(Q2-sqr(mij-p[2+ispect].mass())));
Energy2 Qpk = q*p[2+ispect];
Lorentz5Momentum pkt =
lambda/lamB*(p[2+ispect]-Qpk/Q2*q)
+0.5/Q2*(Q2+sqr(p[2+ispect].mass())-sqr(p[2+ispect].mass()))*q;
Lorentz5Momentum pijt =
q-pkt;
double muj = p[2+iemit ].mass()/sqrt(Q2);
double muk = p[2+ispect].mass()/sqrt(Q2);
double vt = sqrt((1.-sqr(muj+muk))*(1.-sqr(muj-muk)))/(1.-sqr(muj)-sqr(muk));
double v = sqrt(sqr(2.*sqr(muk)+(1.-sqr(muj)-sqr(muk))*(1.-y))-4.*sqr(muk))
/(1.-y)/(1.-sqr(muj)-sqr(muk));
// transverse momentum
double x1 = 2.*p[2+iemit ]*q/Q2;
double x2 = 2.*p[2+ispect]*q/Q2;
pT2final[iemit] = 0.25*Q2/(sqr(x2)-4.*sqr(muk))*
((sqr(x1)-4.*sqr(muj))*(sqr(x2)-4.*sqr(muk)) -
sqr(2.*x1+2.*x2-2.-x1*x2-2.*sqr(muj)-2.*sqr(muk)));
// dipole term
DFF[iemit] = 0.5/pipj*(2./(1.-(1.-z)*(1.-y))
-vt/v*(2.-z+sqr(p[2+iemit].mass())/pipj));
// matrix element
vector<Lorentz5Momentum> lomom(4);
lomom[0] = p[0];
lomom[1] = p[1];
if(iemit==0) {
lomom[2] = pijt;
lomom[3] = pkt ;
}
else {
lomom[3] = pijt;
lomom[2] = pkt ;
}
// leading-order matrix element
double lo = loME(mePartonData(),lomom,false);
DFF[iemit] *= lo*sqr(double(mePartonData()[2]->iCharge())/3.);
}
// phase-space factpr
if(dipole==FF34||dipole==FF43) scale = sHat();
}
/////////// ISR/FSR interference ////////////////////////////
InvEnergy2 DIF[4]={ZERO,ZERO,ZERO,ZERO};
Energy2 pT2IF[4] ={ZERO,ZERO,ZERO,ZERO};
InvEnergy2 negativeDipoles(ZERO);
if(QEDContributions_==0) {
for(unsigned int ix=0;ix<4;++ix) {
// incoming and outgoing particles in the dipole
unsigned int iin = ix<2 ? 0 :1;
unsigned int iout = ix%2 == 0 ? 2 : 3;
// emission variables
double x = 1.-p[iout]*p[4]/(p[iin]*p[iout]+p[iin]*p[4]);
double z = p[iin ]*p[4]/(p[iin]*p[iout]+p[iin]*p[4]);
// momenta for the born process
Lorentz5Momentum pat = x*p[iin];
Lorentz5Momentum pjt = p[4]+p[iout]-(1.-x)*p[iin];
vector<Lorentz5Momentum> pa(4);
for(unsigned iy=0;iy<4;++iy) {
if(iy==iin) pa[iy] = pat;
else if(iy==iout) pa[iy] = pjt;
else pa[iy] = p[iy];
}
// pT
Energy mj = p[iout].mass();
Lorentz5Momentum q = pjt-pat;
q.rescaleMass();
Energy Q = -q.mass();
Energy2 Q2 = sqr(Q);
double mu2 = sqr(mj)/Q2;
double corr = (1.-x-z)*mu2/((1.-z)*(1.-x));
pT2IF[ix] = Q2*(1.-x)/x*z*(1.-z)*(1.+corr);
// LO matrix element
double lo = loME(mePartonData(),pa,false);
Energy2 dot1 = max(p[iin ]*p[4],1e-30*MeV2);
Energy2 dot2 = max(p[iout]*p[4],1e-30*MeV2);
InvEnergy2 split =
0.5/dot1/x*(2./(1.-x+z)-1.-x) +
0.5/dot2/x*(2./(1.-x+z)-2.+z-sqr(mj)/dot2);
// lo piece and charge factors
double charge = double(mePartonData()[iin]->iCharge()*
mePartonData()[iout]->iCharge())/9.;
//new //ER
// with the + sign because one of the 2 partons is outgoing,
// so revert the sign of the
// 'color' operator of the outgoing parton
InvEnergy2 Dipole= + lo*charge*split;
if(charge>0)
DIF[ix] = Dipole;
else if(dot1>1e-30*MeV2&&dot2>1e-30*MeV2)
negativeDipoles += Dipole;
if(int(ix)==int(dipole)-int(IF13)) scale = Q2;
}
}
// supression function
Energy2 pT2sup=ZERO;
if(dipole==II12||dipole==II21) {
pT2sup = sqr(p[4].x())+sqr(p[4].y());
}
else if(dipole==FF34||dipole==FF43) {
pT2sup = dipole==FF34 ? pT2final[0] : pT2final[1];
}
else if(dipole==IF13)
pT2sup = pT2IF[0];
else if(dipole==IF14)
pT2sup = pT2IF[1];
else if(dipole==IF23)
pT2sup = pT2IF[2];
else if(dipole==IF24)
pT2sup = pT2IF[3];
else
assert(false);
pair<double,double> supressionFactor = supressionFunction(pT2sup);
// numerator for dipole ratio
InvEnergy2 num;
switch (dipole) {
case II12 :
num = DII[0];
break;
case II21 :
num = DII[1];
break;
case FF34 :
num = DFF[0];
break;
case FF43 :
num = DFF[1];
break;
case IF13 :
num = DIF[0];
break;
case IF14 :
num = DIF[1];
break;
case IF23 :
num = DIF[2];
break;
case IF24 :
num = DIF[3];
break;
default:
assert(false);
};
double meout(0.);
InvEnergy2 den(ZERO);
// ISR
if(QEDContributions_==1 ||
(QEDContributions_==3 && (dipole==II12 || dipole ==II21))) {
assert(dipole==II12 || dipole ==II21);
meout = me[0];
den = abs(DII[0])+abs(DII[1]);
}
// FSR
else if(QEDContributions_==2 ||
(QEDContributions_==3 && (dipole==FF34 || dipole ==FF43))) {
assert(dipole==FF34 || dipole ==FF43);
meout = me[1];
den = abs(DFF[0])+abs(DFF[1]);
}
// full result
else if(QEDContributions_==0) {
meout = me[2];
den = abs(DII[0])+abs(DII[1])+abs(DFF[0])+abs(DFF[1]);
for(unsigned int ix=0;ix<4;++ix) den += abs(DIF[ix]);
}
else
assert(false);
// return the answer
pair<double,double> output = make_pair(0.,0.);
if(den>ZERO) {
if(subtract) {
output.first = scale*((UnitRemoval::InvE2*meout-negativeDipoles)*
abs(num)/den*supressionFactor.first -num);
}
else {
output.first = scale* UnitRemoval::InvE2*meout*
abs(num)/den*supressionFactor.first;
}
output.second = scale* UnitRemoval::InvE2*meout*
abs(num)/den*supressionFactor.second;
}
return output;
}
pair<double,double>
MEqq2gZ2ffPowhegQED::subtractedQEDMEpqbar(const vector<Lorentz5Momentum> & p,
DipoleType dipole, bool subtract) const {
// use the inheriting class to calculate the matrix element
cPDVector particles(mePartonData());
if(dipole==II12) {
particles.push_back(particles[0]->CC());
particles[0] = gluon_;
}
else if(dipole==II21) {
particles.push_back(particles[1]->CC());
particles[1] = gluon_;
}
else {
assert(false);
}
vector<double> me = realQEDME(particles,p);
// compute the two dipole terms
double x = 1.-(p[4]*p[1]+p[4]*p[0])/(p[0]*p[1]);
Lorentz5Momentum Kt = p[0]+p[1]-p[4];
vector<Lorentz5Momentum> pa(4);
// momenta for ISR
if(dipole==II12) {
pa[0] = x*p[0];
pa[1] = p[1];
}
else if(dipole==II21) {
pa[0] = p[0];
pa[1] = x*p[1];
}
else {
assert(false);
}
Lorentz5Momentum K = pa[0]+pa[1];
Lorentz5Momentum Ksum = K+Kt;
Energy2 K2 = K.m2();
Energy2 Ksum2 = Ksum.m2();
for(unsigned int ix=2;ix<4;++ix)
pa[ix] = p[ix]-2.*Ksum*(Ksum*p[ix])/Ksum2+2*K*(Kt*p[ix])/K2;
// first LO matrix element
double lo1 = loME(mePartonData(),pa,false);
// dipole
InvEnergy2 D1;
if(dipole==II12) {
D1 = 0.5/(p[0]*p[4])/x*(1.-2.*x*(1.-x));
}
else if(dipole==II21) {
D1 = 0.5/(p[1]*p[4])/x*(1.-2.*x*(1.-x));
}
else {
assert(false);
}
// charges
D1 *= sqr(double(mePartonData()[2]->iCharge())/3.)*lo1;
// supression function
pair<double,double> supressionFactor =
supressionFunction(sqr(p[4].x())+sqr(p[4].y()));
if(subtract) {
return make_pair(sHat()*(UnitRemoval::InvE2*me[0]*supressionFactor.first -D1),
sHat()*(UnitRemoval::InvE2*me[0]*supressionFactor.second));
}
else {
return make_pair(sHat()*(UnitRemoval::InvE2*me[0]*supressionFactor.first ),
sHat()*(UnitRemoval::InvE2*me[0]*supressionFactor.second));
}
}
vector<double>
MEqq2gZ2ffPowhegQED::realQEDME(const cPDVector & particles,
const vector<Lorentz5Momentum> & momenta) const {
vector<SpinorWaveFunction> fin(2),aout(2);
vector<SpinorBarWaveFunction> ain(2),fout(2);
vector<VectorWaveFunction> photon(2);
// wavefunctions for the q qbar -> l+ l- gamma process
if(particles[0]->id()==-particles[1]->id()) {
for( unsigned int i = 0; i < 2; ++i ) {
fin[i] = SpinorWaveFunction (momenta[0],particles[0], i,incoming);
ain[i] = SpinorBarWaveFunction(momenta[1],particles[1], i,incoming);
photon[i] = VectorWaveFunction (momenta[4],particles[4],2*i,outgoing);
}
}
else if(particles[0]->id()==ParticleID::g && particles[1]->id()<0) {
for( unsigned int i = 0; i < 2; ++i ) {
fin[i] = SpinorWaveFunction (momenta[4],particles[4], i,outgoing);
ain[i] = SpinorBarWaveFunction(momenta[1],particles[1], i,incoming);
photon[i] = VectorWaveFunction (momenta[0],particles[0],2*i,incoming);
}
}
else if(particles[0]->id()>0 && particles[1]->id()==ParticleID::g) {
for( unsigned int i = 0; i < 2; ++i ) {
fin[i] = SpinorWaveFunction (momenta[0],particles[0], i,incoming);
ain[i] = SpinorBarWaveFunction(momenta[4],particles[4], i,outgoing);
photon[i] = VectorWaveFunction (momenta[1],particles[1],2*i,incoming);
}
}
else {
for(unsigned int ix=0;ix<particles.size();++ix) {
generator()->log() << particles[ix]->PDGName() << " " << momenta[ix]/GeV << "\n";
}
assert(false);
}
// wavefunctions for the leptons
for(unsigned int i=0; i<2; ++i) {
fout[i] = SpinorBarWaveFunction(momenta[2],particles[2],i,outgoing);
aout[i] = SpinorWaveFunction (momenta[3],particles[3],i,outgoing);
}
// off-shell vector bosons for speed
Energy2 q2 = scale();
VectorWaveFunction ZwaveIn[2][2],ZwaveOut[2][2];
VectorWaveFunction PwaveIn[2][2],PwaveOut[2][2];
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
// intermediate Z
ZwaveIn [ihel1][ihel2] =
oneLoopVertex_->evaluate(q2,1,Z0_ ,fin [ihel1],ain [ihel2]);
ZwaveOut[ihel1][ihel2] =
oneLoopVertex_->evaluate(q2,1,Z0_ ,aout[ihel2],fout[ihel1]);
// intermediate photon
PwaveIn [ihel1][ihel2] =
oneLoopVertex_->evaluate(q2,1,gamma_,fin [ihel1],ain [ihel2]);
PwaveOut[ihel1][ihel2] =
oneLoopVertex_->evaluate(q2,1,gamma_,aout[ihel2],fout[ihel1]);
}
}
vector<double> output(3,0.);
vector<Complex> diagI(4,0.),diagF(4,0.);
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
for(unsigned int lhel1=0;lhel1<2;++lhel1) {
for(unsigned int lhel2=0;lhel2<2;++lhel2) {
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
// ISR diagrams
// first Z diagram
SpinorWaveFunction inters = oneLoopVertex_->
evaluate(q2,5,fin[ihel1].particle(),fin[ihel1],photon[ohel1]);
diagI[0] = oneLoopVertex_->
evaluate(q2, inters, ain[ihel2], ZwaveOut[lhel1][lhel2]);
// second Z diagram
SpinorBarWaveFunction interb = oneLoopVertex_->
evaluate(q2,5,ain[ihel2].particle(),ain[ihel2],photon[ohel1]);
diagI[1] = oneLoopVertex_->
evaluate(q2, fin[ihel1], interb, ZwaveOut[lhel1][lhel2]);
if(particles[2]->charged()) {
// first photon diagram
diagI[2] = oneLoopVertex_->
evaluate(q2, inters, ain[ihel2], PwaveOut[lhel1][lhel2]);
// second photon diagram
diagI[3] = oneLoopVertex_->
evaluate(q2, fin[ihel1], interb, PwaveOut[lhel1][lhel2]);
}
// FSR diagrams
if(particles[2]->charged()) {
SpinorBarWaveFunction off1 = oneLoopVertex_->
evaluate(q2,3,fout[lhel1].particle(),fout[lhel1],photon[ohel1]);
diagF[0] = oneLoopVertex_->
evaluate(q2,aout[lhel2],off1,ZwaveIn[ihel1][ihel2]);
diagF[1] = oneLoopVertex_->
evaluate(q2,aout[lhel2],off1,PwaveIn[ihel1][ihel2]);
SpinorWaveFunction off2 = oneLoopVertex_->
evaluate(q2,3,aout[lhel2].particle(),aout[lhel2],photon[ohel1]);
diagF[2] = oneLoopVertex_->
evaluate(q2,off2,fout[lhel1],ZwaveIn[ihel1][ihel2]);
diagF[3] = oneLoopVertex_->
evaluate(q2,off2,fout[lhel1],PwaveIn[ihel1][ihel2]);
}
// totals
Complex ISR = std::accumulate(diagI.begin(),diagI.end(),Complex(0.));
Complex FSR = std::accumulate(diagF.begin(),diagF.end(),Complex(0.));
output[0] += norm(ISR);
output[1] += norm(FSR);
output[2] += norm(ISR+FSR);
}
}
}
}
}
// colour and spin factors
if(particles[0]->id()==-particles[1]->id()) {
for(unsigned int ix=0;ix<output.size();++ix)
output[ix] *= 1./12.;
}
else {
for(unsigned int ix=0;ix<output.size();++ix)
output[ix] *= 0.25;
}
// divided by 2 e^2
for(unsigned int ix=0;ix<output.size();++ix)
output[ix] *= 0.5/norm(oneLoopVertex_->norm());
return output;
}
void MEqq2gZ2ffPowhegQED::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
if( hard[0]->id() != mePartonData()[0]->id() ) swap(hard[0], hard[1]);
if( hard[2]->id() != mePartonData()[2]->id() ) swap(hard[2], hard[3]);
// wavefunctions
vector<SpinorWaveFunction> fin,aout;
vector<SpinorBarWaveFunction> ain,fout;
SpinorWaveFunction( fin ,hard[0],incoming,false,true);
SpinorBarWaveFunction(ain ,hard[1],incoming,false,true);
SpinorBarWaveFunction(fout,hard[2],outgoing,true ,true);
SpinorWaveFunction( aout,hard[3],outgoing,true ,true);
qqbarME(fin,ain,fout,aout,true);
// get the spin info objects
SpinPtr spin[4];
for(unsigned int ix=0;ix<4;++ix) spin[ix]=hard[ix]->spinInfo();
// 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)
spin[ix]->productionVertex(hardvertex);
}
void MEqq2gZ2ffPowhegQED::hardQCDEmission(vector<ShowerProgenitorPtr> &
particlesToShower, int & emission_type,
Energy & pTmax) {
emission_type = -1;
pTmax = -GeV;
Energy rootS = sqrt(lastS());
// limits on the rapidity of the jet
double minyj = -10.0,maxyj = 10.0;
pair<double,double> x = make_pair(particlesToShower[0]->progenitor()->x(),
particlesToShower[1]->progenitor()->x());
// loop over the possible emissions
unsigned int imin(0),imax(4);
if(QCDRadiationType_>=0) {
imin = QCDRadiationType_;
imax = imin+1;
}
for(unsigned int ix=imin;ix<imax;++ix) {
Energy pT = 0.5*generator()->maximumCMEnergy();
// particles for the hard process
cPDVector particles;
for(unsigned int iy=0;iy<particlesToShower.size();++iy) {
particles.push_back(particlesToShower[iy]->progenitor()->dataPtr());
}
if(ix<2) particles.push_back(gluon_);
else if(ix==2) {
particles.push_back(particles[0]->CC());
particles[0] = gluon_;
}
else {
particles.push_back(particles[1]->CC());
particles[1] = gluon_;
}
vector<Lorentz5Momentum> momenta(5);
double a = alphaQCD_->overestimateValue()/Constants::twopi*
prefactorQCD_[ix]*(maxyj-minyj);
do {
pT *= pow(UseRandom::rnd(),1./a);
if(pT<=minpTQCD_) break;
double y = UseRandom::rnd()*(maxyj-minyj)+ minyj;
double vt,z;
if(ix%2==0) {
vt = pT*exp(-y)/rootS/x.second;
z = (1.-pT*exp(-y)/rootS/x.second)/(1.+pT*exp( y)/rootS/x.first );
if(z>1.||z<x.first) continue;
}
else {
vt = pT*exp( y)/rootS/x.first ;
z = (1.-pT*exp( y)/rootS/x.first )/(1.+pT*exp(-y)/rootS/x.second );
if(z>1.||z<x.second) continue;
}
if(vt>1.-z || vt<0.) continue;
if(ix%2==0) {
momenta[0] = particlesToShower[0]->progenitor()->momentum()/z;
momenta[1] = particlesToShower[1]->progenitor()->momentum();
}
else {
momenta[0] = particlesToShower[0]->progenitor()->momentum();
momenta[1] = particlesToShower[1]->progenitor()->momentum()/z;
}
double phi = Constants::twopi*UseRandom::rnd();
momenta[2] = particlesToShower[2]->progenitor()->momentum();
momenta[3] = particlesToShower[3]->progenitor()->momentum();
if(!_quarkplus) y *= -1.;
momenta[4] = Lorentz5Momentum(pT*cos(phi),pT*sin(phi),
pT*sinh(y),pT*cosh(y), ZERO);
Lorentz5Momentum K = momenta[0] + momenta[1] - momenta[4];
Lorentz5Momentum Kt = momenta[2]+momenta[3];
Lorentz5Momentum Ksum = K+Kt;
Energy2 K2 = Kt.m2(), Ksum2 = Ksum.m2();
for(unsigned int iy=2;iy<4;++iy) {
momenta [iy] = momenta [iy] - 2.*Ksum*(Ksum*momenta [iy])/Ksum2
+2.*K*(Kt*momenta [iy])/K2;
}
// matrix element piece
double wgt = alphaQCD_->ratio(sqr(pT))*z/(1.-vt)/prefactorQCD_[ix]/loME_;
// compute me piece here
if(ix==0)
wgt *= 8./3.*sqr(pT)/sHat()*subtractedQCDMEqqbar(momenta,II12,false).first;
else if(ix==1)
wgt *= 8./3.*sqr(pT)/sHat()*subtractedQCDMEqqbar(momenta,II21,false).first;
else if(ix==2)
wgt *= sqr(pT)/sHat()*subtractedQCDMEgqbar(momenta,II12,false).first;
else if(ix==3)
wgt *= sqr(pT)/sHat()*subtractedQCDMEgqbar(momenta,II21,false).first;
// pdf piece
double pdf[4];
if(ix%2==0) {
pdf[0] = _beams[0]->pdf()->xfx(_beams[0],_partons [0],
scale() ,x.first ) /x.first;
pdf[1] = _beams[0]->pdf()->xfx(_beams[0],particles[0],
scale()+sqr(pT),x.first /z)*z/x.first;
pdf[2] = _beams[1]->pdf()->xfx(_beams[1],_partons [1],
scale() ,x.second ) /x.second;
pdf[3] = _beams[1]->pdf()->xfx(_beams[1],particles[1],
scale()+sqr(pT),x.second ) /x.second;
}
else {
pdf[0] = _beams[1]->pdf()->xfx(_beams[1],_partons [1],
scale() ,x.second ) /x.second;
pdf[1] = _beams[1]->pdf()->xfx(_beams[1],particles[1],
scale()+sqr(pT),x.second/z)*z/x.second;
pdf[2] = _beams[0]->pdf()->xfx(_beams[0],_partons [0],
scale() ,x.first ) /x.first;
pdf[3] = _beams[0]->pdf()->xfx(_beams[0],particles[0],
scale()+sqr(pT),x.first ) /x.first;
}
if(pdf[0]<=0.||pdf[1]<=0.) continue;
if(pdf[2]<=0.||pdf[3]<=0.) continue;
wgt *= pdf[1]/pdf[0];
wgt *= pdf[3]/pdf[2];
// check weight less than one
if(wgt>1.) {
generator()->log() << "Weight greater than one for emission type " << ix
<< "in MEqq2gZ2ffPowhegQED::generateHardest()"
<< " weight = " << wgt << "\n";
}
// break if select emission
if(UseRandom::rnd()<wgt) break;
}
while(pT>minpTQCD_);
if(pT>minpTQCD_ && pT>pTmax) {
pTmax = pT;
if(ix==0) {
realEmissionQCDGluon1_=momenta;
emission_type=1;
}
else if(ix==1) {
realEmissionQCDGluon2_=momenta;
emission_type=3;
}
else if(ix==2) {
realEmissionQCDQuark1_=momenta;
emission_type=2;
}
else if(ix==3) {
realEmissionQCDQuark2_=momenta;
emission_type=4;
}
}
}
}
/**
* Generate a hard QED emission
*/
void MEqq2gZ2ffPowhegQED::hardQEDEmission(vector<ShowerProgenitorPtr> & particlesToShower,
int & emission_type, Energy & pTmax) {
emission_type = -1;
pTmax = -GeV;
Energy pT_II(-GeV),pT_IF(-GeV),pT_FF(-GeV);
int type_II(-1),type_IF(-1),type_FF(-1);
// initial-initial radiation
hardQEDIIEmission(particlesToShower,type_II,pT_II);
// final-final radiation
hardQEDFFEmission(particlesToShower,type_FF,pT_FF);
// initial-final radiation
hardQEDIFEmission(particlesToShower,type_IF,pT_IF);
if(type_II<0&&type_FF<0&&type_IF<0) return;
// select the maximum pT emission
if( pT_II>pT_FF && pT_II>pT_IF) {
pTmax = pT_II;
emission_type = type_II;
}
else if (pT_FF>pT_II && pT_FF>pT_IF) {
pTmax = pT_FF;
emission_type = type_FF;
}
else if (pT_IF>pT_FF && pT_IF>pT_II) {
pTmax = pT_IF;
emission_type = type_IF;
}
}
void MEqq2gZ2ffPowhegQED::hardQEDIIEmission(vector<ShowerProgenitorPtr> & particlesToShower,
int & emission_type, Energy & pTmax) {
emission_type = -1;
pTmax = -GeV;
if(QEDContributions_==2) return;
Energy rootS = sqrt(lastS());
// limits on the rapidity of the jet
double minyj = -10.0,maxyj = 10.0;
pair<double,double> x = make_pair(particlesToShower[0]->progenitor()->x(),
particlesToShower[1]->progenitor()->x());
// loop over the possible emissions
vector<Energy> pT;
double charge = sqr(double(particlesToShower[0]->progenitor()->dataPtr()->iCharge())/3.);
for(unsigned int ix=0;ix<4;++ix) {
// skip incoming photons if not required
if(!incomingPhotons_&&(ix==2||ix==3)) continue;
pT.push_back(0.5*generator()->maximumCMEnergy());
// particles for the hard process
cPDVector particles;
for(unsigned int iy=0;iy<particlesToShower.size();++iy) {
particles.push_back(particlesToShower[iy]->progenitor()->dataPtr());
}
if(ix<2) particles.push_back(gamma_);
else if(ix==2) {
particles.push_back(particles[0]->CC());
particles[0] = gamma_;
}
else {
particles.push_back(particles[1]->CC());
particles[1] = gamma_;
}
vector<Lorentz5Momentum> momenta(5);
double a = alphaQED_->overestimateValue()/Constants::twopi*
prefactorQED_[ix]*(maxyj-minyj)*charge;
do {
pT[ix] *= pow(UseRandom::rnd(),1./a);
if(pT[ix]<=minpTQEDII_) break;
double y = UseRandom::rnd()*(maxyj-minyj)+ minyj;
double vt,z;
if(ix%2==0) {
vt = pT[ix]*exp(-y)/rootS/x.second;
z = (1.-pT[ix]*exp(-y)/rootS/x.second)/(1.+pT[ix]*exp( y)/rootS/x.first );
if(z>1.||z<x.first) continue;
}
else {
vt = pT[ix]*exp( y)/rootS/x.first ;
z = (1.-pT[ix]*exp( y)/rootS/x.first )/(1.+pT[ix]*exp(-y)/rootS/x.second );
if(z>1.||z<x.second) continue;
}
if(vt>1.-z || vt<0.) continue;
if(ix%2==0) {
momenta[0] = particlesToShower[0]->progenitor()->momentum()/z;
momenta[1] = particlesToShower[1]->progenitor()->momentum();
}
else {
momenta[0] = particlesToShower[0]->progenitor()->momentum();
momenta[1] = particlesToShower[1]->progenitor()->momentum()/z;
}
double phi = Constants::twopi*UseRandom::rnd();
momenta[2] = particlesToShower[2]->progenitor()->momentum();
momenta[3] = particlesToShower[3]->progenitor()->momentum();
if(!_quarkplus) y *= -1.;
momenta[4] = Lorentz5Momentum(pT[ix]*cos(phi),pT[ix]*sin(phi),
pT[ix]*sinh(y),pT[ix]*cosh(y), ZERO);
Lorentz5Momentum K = momenta[0] + momenta[1] - momenta[4];
Lorentz5Momentum Kt = momenta[2]+momenta[3];
Lorentz5Momentum Ksum = K+Kt;
Energy2 K2 = K.m2(), Ksum2 = Ksum.m2();
for(unsigned int iy=2;iy<4;++iy) {
momenta [iy] = momenta [iy] - 2.*Ksum*(Ksum*momenta [iy])/Ksum2
+2*K*(Kt*momenta [iy])/K2;
}
// matrix element piece
double wgt = alphaQED_->ratio(sqr(pT[ix]))*z/(1.-vt)/prefactorQED_[ix]/loME_/charge;
// compute me piece here
if(ix==0)
wgt *= 2.*sqr(pT[ix])/sHat()*subtractedQEDMEqqbar(momenta,II12,false).first;
else if(ix==1)
wgt *= 2.*sqr(pT[ix])/sHat()*subtractedQEDMEqqbar(momenta,II21,false).first;
else if(ix==2)
wgt *= 2.*sqr(pT[ix])/sHat()*subtractedQEDMEpqbar(momenta,II12,false).first;
else if(ix==3)
wgt *= 2.*sqr(pT[ix])/sHat()*subtractedQEDMEpqbar(momenta,II21,false).first;
// pdf piece
double pdf[2];
if(ix%2==0) {
pdf[0] = _beams[0]->pdf()->xfx(_beams[0],_partons [0],
scale(), x.first ) /x.first;
pdf[1] = _beams[0]->pdf()->xfx(_beams[0],particles[0],
scale()+sqr(pT[ix]),x.first /z)*z/x.first;
}
else {
pdf[0] = _beams[1]->pdf()->xfx(_beams[1],_partons [1],
scale() ,x.second ) /x.second;
pdf[1] = _beams[1]->pdf()->xfx(_beams[1],particles[1],
scale()+sqr(pT[ix]),x.second/z)*z/x.second;
}
if(pdf[0]<=0.||pdf[1]<=0.) continue;
wgt *= pdf[1]/pdf[0];
// check weight less than one
if(wgt>1.) {
generator()->log() << "Weight greater than one for emission type " << ix
<< "in MEqq2gZ2ffPowhegQED::hardQEDIIEmission()"
<< " weight = " << wgt << "\n";
}
// break if select emission
if(UseRandom::rnd()<wgt) break;
}
while(pT[ix]>minpTQEDII_);
if(pT[ix]>minpTQEDII_ && pT[ix]>pTmax) {
pTmax = pT[ix];
if(ix==0) {
realEmissionQEDPhoton1_ = momenta;
emission_type=5;
}
else if(ix==1) {
realEmissionQEDPhoton2_ = momenta;
emission_type=7;
}
else if(ix==2) {
realEmissionQEDQuark1_ = momenta;
emission_type=6;
}
else if(ix==3) {
realEmissionQEDQuark2_ = momenta;
emission_type=8;
}
}
}
}
void MEqq2gZ2ffPowhegQED::hardQEDIFEmission(vector<ShowerProgenitorPtr> & particlesToShower,
int & emission_type, Energy & pTmax) {
if(QEDContributions_!=0) return;
emission_type = -1;
pTmax = -GeV;
// extract the particles
cPDVector particles;
for(unsigned int iy=0;iy<particlesToShower.size();++iy) {
particles.push_back(particlesToShower[iy]->progenitor()->dataPtr());
}
particles.push_back(gamma_);
// momentum fractions of the incoming particles
pair<double,double> x = make_pair(particlesToShower[0]->progenitor()->x(),
particlesToShower[1]->progenitor()->x());
// loop over the possible dipoles
for(unsigned int idipole=0;idipole<4;++idipole) {
// incoming and outgoing particles in the dipole
unsigned int iin = idipole<2 ? 0 :1;
unsigned int iout = idipole%2 == 0 ? 2 : 3;
// charge of the dipole
double charge = +
particlesToShower[iin ]->progenitor()->dataPtr()->iCharge()*
particlesToShower[iout]->progenitor()->dataPtr()->iCharge()/9.;
if(charge<0.) continue;
// which dipole are we doing
DipoleType dipole;
if (idipole==0) dipole = IF13;
else if(idipole==1) dipole = IF14;
else if(idipole==2) dipole = IF23;
else if(idipole==3) dipole = IF24;
// storage of the real emission momenta
vector<Lorentz5Momentum> realMomenta(5);
Lorentz5Momentum q =
particlesToShower[iout]->progenitor()->momentum() -
particlesToShower[iin ]->progenitor()->momentum();
q.rescaleMass();
Energy Q = -q.mass();
Energy2 Q2 = sqr(Q);
double xB = iin==0 ? x.first : x.second;
// reduced mass
Energy mj = particlesToShower[iout]->progenitor()->momentum().mass();
double mu2 = sqr(mj)/Q2;
// work out LT to the Breit-Frame
Lorentz5Momentum pb = particlesToShower[iin ]->progenitor()->momentum();
Axis axis(q.vect().unit());
double sinth(sqrt(sqr(axis.x())+sqr(axis.y())));
LorentzRotation rot;
if(axis.perp2()>1e-20) {
rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.));
rot.rotateX(Constants::pi);
}
if(abs(1.-q.e()/q.vect().mag())>1e-6)
rot.boostZ( q.e()/q.vect().mag());
pb *= rot;
if(pb.perp2()/GeV2>1e-20) {
Boost trans = -1./pb.e()*pb.vect();
trans.setZ(0.);
rot.boost(trans);
}
rot.invert();
// momenta not effected by the emission
for(unsigned int iy=0;iy<4;++iy) {
if(iy==iin||iy==iout) continue;
realMomenta[iy] = particlesToShower[iy]->progenitor()->momentum();
}
// maximum value of the xT
double xT = sqrt((1.-xB)/xB);
double xTMin = 2.*minpTQEDIF_/sqrt(Q2);
double wgt(0.);
// prefactor
double a = charge*alphaQED_->overestimateValue()*preIFQED_/Constants::twopi;
// loop to generate kinematics
double xp,zp;
double n=0.;
do {
wgt = 0.;
// intergration variables dxT/xT^3
xT *= pow(1.-(n+2.)*log(UseRandom::rnd())/a*pow(xT,n+2.),-1./(n+2));
// xT *= 1./sqrt(1.-2.*log(UseRandom::rnd())/a*sqr(xT));
// zp
zp = UseRandom::rnd();
// xp
xp = (1-zp*mu2/(1.-zp+mu2))/(1.+0.25*sqr(xT)/zp/(1.-zp+mu2));
// check allowed
if(xp<xB||xp>1.) continue;
// azimuth
double phi = Constants::twopi*UseRandom::rnd();
double x1 = -(1.+mu2)/xp;
double x2 = 1.-mu2-zp*(1.+mu2)/xp;
double x3 = 2.+x1-x2;
// now compute the momenta
realMomenta[iin] =
Lorentz5Momentum(ZERO,ZERO,-0.5*x1*Q,-0.5*x1*Q,ZERO);
realMomenta[iout] =
Lorentz5Momentum( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi),
-0.5*Q*x2,0.5*Q*sqrt(sqr(x2)+sqr(xT)+4.*mu2),mj);
realMomenta[4] =
Lorentz5Momentum(-0.5*Q*xT*cos(phi),-0.5*Q*xT*sin(phi),
-0.5*Q*x3,0.5*Q*sqrt(sqr(x3)+sqr(xT)),ZERO);
realMomenta[iin] *= rot;
realMomenta[iout] *= rot;
realMomenta[4] *= rot;
// phase-space piece of the weight
double corr =(1.-xp-zp)*mu2/(1.-xp)/(1.-zp);
wgt = pow(xT,n)*8.*zp*(1.-zp)*sqr(1.-xp)/xp/preIFQED_*(1.+mu2)/xp*
sqr(1.+corr)/(1.+mu2);
wgt *= alphaQED_->ratio(0.25*Q2*sqr(xT));
// PDF piece
double pdf[2]={_beams[iin]->pdf()->xfx(_beams[iin],_partons [iin],
scale(),xB) /xB,
_beams[iin]->pdf()->xfx(_beams[iin],particles[iin],
0.5*xT*Q2,xB/xp)*xp/xB};
if(pdf[0]<=0.||pdf[1]<=0.) {
wgt =0.;
continue;
}
wgt *= pdf[1]/pdf[0];
// matrix element piece
wgt *= subtractedQEDMEqqbar(realMomenta,dipole,false).first/charge/loME_;
if(wgt>1.) {
generator()->log() << "problem with IF weight " << wgt << " " << idipole << " "
<< xT << " " << zp << " " << xp << "\n";
for(unsigned int ix=0;ix<realMomenta.size();++ix)
generator()->log() << ix << " " << realMomenta[ix]/GeV << "\n";
generator()->log() << "testing masses "
<< (realMomenta[0]+realMomenta[1]).m()/GeV << " "
<< (realMomenta[2]+realMomenta[3]).m()/GeV << "\n";
generator()->log() << "sum "
<< (realMomenta[0]+realMomenta[1]-realMomenta[2]-realMomenta[3]-realMomenta[4])/GeV << "\n";
}
}
while(xT>xTMin&&UseRandom::rnd()>wgt);
if(xT<=xTMin) continue;
Energy pT = xT*0.5*Q;
if(pT<pTmax) continue;
pTmax = pT;
double isif = zp>xp ? 4 : 0;
emission_type = 11+idipole+isif;
if(idipole==0)
realEmissionQEDIF13_ = realMomenta;
else if(idipole==1)
realEmissionQEDIF14_ = realMomenta;
else if(idipole==2)
realEmissionQEDIF23_ = realMomenta;
else if(idipole==3)
realEmissionQEDIF24_ = realMomenta;
}
}
void MEqq2gZ2ffPowhegQED::
hardQEDFFEmission(vector<ShowerProgenitorPtr> & particlesToShower,
int & emission_type, Energy & pTmax) {
if(QEDContributions_==1) return;
emission_type = -1;
pTmax = -GeV;
// extract the particles
cPDVector particles;
for(unsigned int iy=0;iy<particlesToShower.size();++iy) {
particles.push_back(particlesToShower[iy]->progenitor()->dataPtr());
}
particles.push_back(gamma_);
// boost from lab to CMS frame with outgoing particles
// along the z axis
Lorentz5Momentum pcms = particlesToShower[2]->progenitor()->momentum() +
particlesToShower[3]->progenitor()->momentum();
LorentzRotation eventFrame( pcms.findBoostToCM() );
Lorentz5Momentum spectator = eventFrame*particlesToShower[2]->progenitor()->momentum();
eventFrame.rotateZ( -spectator.phi() );
eventFrame.rotateY( -spectator.theta() );
eventFrame.invert();
// mass of the final-state system
Energy2 M2 = pcms.m2();
Energy M = sqrt(M2);
double mu1 = particlesToShower[2]->progenitor()->momentum().mass()/M;
double mu2 = particlesToShower[2]->progenitor()->momentum().mass()/M;
double mu12 = sqr(mu1), mu22 = sqr(mu2);
double lambda = sqrt(1.+sqr(mu12)+sqr(mu22)-2.*mu12-2.*mu22-2.*mu12*mu22);
// max pT
pTmax = 0.5*sqrt(M2)*(1.-sqr(mu1+mu2));
// max y
double ymax = acosh(pTmax/minpTQEDFF_);
if(!particlesToShower[2]->progenitor()->dataPtr()->charged())
return;
double charge = sqr(double(particlesToShower[2]->
progenitor()->dataPtr()->iCharge())/3.);
double a = alphaQED_->overestimateValue()/Constants::twopi*2.*ymax*preFFQED_*charge;
// variables for the emission
Energy pT[2];
double y[2],phi[2],x3[2],x1[2][2],x2[2][2];
double contrib[2][2];
// storage of the real emission momenta
vector<Lorentz5Momentum> realMomenta[2][2]=
{{vector<Lorentz5Momentum>(5),vector<Lorentz5Momentum>(5)},
{vector<Lorentz5Momentum>(5),vector<Lorentz5Momentum>(5)}};
for(unsigned int ix=0;ix<2;++ix)
for(unsigned int iy=0;iy<2;++iy)
for(unsigned int iz=0;iz<2;++iz)
realMomenta[ix][iy][iz] = particlesToShower[iz]->progenitor()->momentum();
// generate the emission
for(unsigned int ix=0;ix<2;++ix) {
if(ix==1) {
swap(mu1 ,mu2 );
swap(mu12,mu22);
}
pT[ix] = pTmax;
y [ix] = 0.;
bool reject = true;
do {
// generate pT
pT[ix] *= pow(UseRandom::rnd(),1./a);
if(pT[ix]<minpTQEDFF_) {
pT[ix] = -GeV;
break;
}
// generate y
y[ix] = -ymax+2.*UseRandom::rnd()*ymax;
// generate phi
phi[ix] = UseRandom::rnd()*Constants::twopi;
// calculate x3 and check in allowed region
x3[ix] = 2.*pT[ix]*cosh(y[ix])/M;
if(x3[ix] < 0. || x3[ix] > 1. -sqr( mu1 + mu2 ) ) continue;
// find the possible solutions for x1
double xT2 = sqr(2./M*pT[ix]);
double root = (-sqr(x3[ix])+xT2)*
(xT2*mu22+2.*x3[ix]-sqr(mu12)+2.*mu22+2.*mu12-sqr(x3[ix])-1.
+2.*mu12*mu22-sqr(mu22)-2.*mu22*x3[ix]-2.*mu12*x3[ix]);
double c1=2.*sqr(x3[ix])-4.*mu22-6.*x3[ix]+4.*mu12-xT2*x3[ix]
+2.*xT2-2.*mu12*x3[ix]+2.*mu22*x3[ix]+4.;
if(root<0.) continue;
x1[ix][0] = 1./(4.-4.*x3[ix]+xT2)*(c1-2.*sqrt(root));
x1[ix][1] = 1./(4.-4.*x3[ix]+xT2)*(c1+2.*sqrt(root));
// change sign of y if 2nd particle emits
if(ix==1) y[ix] *=-1.;
// loop over the solutions
for(unsigned int iy=0;iy<2;++iy) {
contrib[ix][iy]=0.;
// check x1 value allowed
if(x1[ix][iy]<2.*mu1||x1[ix][iy]>1.+mu12-mu22) continue;
// calculate x2 value and check allowed
x2[ix][iy] = 2.-x3[ix]-x1[ix][iy];
double root = max(0.,sqr(x1[ix][iy])-4.*mu12);
root = sqrt(root);
double x2min = 1.+mu22-mu12
-0.5*(1.-x1[ix][iy]+mu12-mu22)/(1.-x1[ix][iy]+mu12)*(x1[ix][iy]-2.*mu12+root);
double x2max = 1.+mu22-mu12
-0.5*(1.-x1[ix][iy]+mu12-mu22)/(1.-x1[ix][iy]+mu12)*(x1[ix][iy]-2.*mu12-root);
if(x2[ix][iy]<x2min||x2[ix][iy]>x2max) continue;
// check the z components
double z1 = sqrt(sqr(x1[ix][iy])-4.*mu12-xT2);
double z2 = -sqrt(sqr(x2[ix][iy])-4.*mu22);
double z3 = pT[ix]*sinh(y[ix])*2./M;
if(ix==1) z3 *=-1.;
if(abs(-z1+z2+z3)<1e-9) z1 *= -1.;
if(abs(z1+z2+z3)>1e-5) continue;
// construct the momenta
realMomenta[ix][iy][4] =
Lorentz5Momentum(pT[ix]*cos(phi[ix]),pT[ix]*sin(phi[ix]),
pT[ix]*sinh(y[ix]) ,pT[ix]*cosh(y[ix]),ZERO);
if(ix==0) {
realMomenta[ix][iy][2] =
Lorentz5Momentum(-pT[ix]*cos(phi[ix]),-pT[ix]*sin(phi[ix]),
z1*0.5*M,x1[ix][iy]*0.5*M,M*mu1);
realMomenta[ix][iy][3] =
Lorentz5Momentum(ZERO,ZERO, z2*0.5*M,x2[ix][iy]*0.5*M,M*mu2);
}
else {
realMomenta[ix][iy][2] =
Lorentz5Momentum(ZERO,ZERO,-z2*0.5*M,x2[ix][iy]*0.5*M,M*mu2);
realMomenta[ix][iy][3] =
Lorentz5Momentum(-pT[ix]*cos(phi[ix]),-pT[ix]*sin(phi[ix]),
-z1*0.5*M,x1[ix][iy]*0.5*M,M*mu1);
}
// boost the momenta back to the lab
for(unsigned int iz=2;iz<5;++iz)
realMomenta[ix][iy][iz] *= eventFrame;
// jacobian and prefactors for the weight
Energy J = M/sqrt(xT2)*abs(-x1[ix][iy]*x2[ix][iy]+2.*mu22*x1[ix][iy]
+x2[ix][iy]+x2[ix][iy]*mu12+mu22*x2[ix][iy]
-sqr(x2[ix][iy]))
/pow(sqr(x2[ix][iy])-4.*mu22,1.5);
// prefactors etc
contrib[ix][iy] = 0.5*pT[ix]/J/preFFQED_/lambda;
// matrix element piece
double me;
if(ix==0) me = subtractedQEDMEqqbar(realMomenta[ix][iy],
FF34,false).first/charge/loME_;
else me = subtractedQEDMEqqbar(realMomenta[ix][iy],
FF43,false).first/charge/loME_;
contrib[ix][iy] *= 2.*me;
// coupling piece
contrib[ix][iy] *= alphaQED_->ratio(sqr(pT[ix]));
}
if(contrib[ix][0]+contrib[ix][1]>1.) {
ostringstream s;
s << "MEee2gZ2qq::generateHardest weight for channel " << ix
<< "is " << contrib[ix][0]+contrib[ix][1]
<< " which is greater than 1";
generator()->logWarning( Exception(s.str(), Exception::warning) );
}
reject = UseRandom::rnd() > contrib[ix][0] + contrib[ix][1];
}
while (reject);
if(pT[ix]<minpTQEDFF_)
pT[ix] = -GeV;
}
emission_type = -1;
pTmax = -GeV;
if(pT[0]<ZERO&&pT[1]<ZERO) return;
// now pick the emmision with highest pT
if(pT[0]>pT[1]) {
emission_type=9;
pTmax = pT[0];
if(UseRandom::rnd()<contrib[0][0]/(contrib[0][0]+contrib[0][1]))
realEmissionQEDFFLepton3_ = realMomenta[0][0];
else
realEmissionQEDFFLepton3_ = realMomenta[0][1];
}
else {
emission_type=10;
pTmax = pT[1];
if(UseRandom::rnd()<contrib[1][0]/(contrib[1][0]+contrib[1][1]))
realEmissionQEDFFLepton4_ = realMomenta[1][0];
else
realEmissionQEDFFLepton4_ = realMomenta[1][1];
}
}
HardTreePtr MEqq2gZ2ffPowhegQED::generateHardest(ShowerTreePtr tree,
vector<ShowerInteraction::Type> inter) {
// get the particles to be showered
_beams.clear();
_partons.clear();
// find the incoming particles
ShowerParticleVector incoming;
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cit;
_quarkplus = true;
vector<ShowerProgenitorPtr> particlesToShower;
//progenitor particles are produced in z direction.
for( cit = tree->incomingLines().begin(); cit != tree->incomingLines().end(); ++cit ) {
incoming.push_back( cit->first->progenitor() );
_beams.push_back( cit->first->beam() );
_partons.push_back( cit->first->progenitor()->dataPtr() );
// check that quark is along +ve z direction
if(cit->first->progenitor()->id() > 0 &&
cit->first->progenitor()->momentum().z() < ZERO )
_quarkplus = false;
particlesToShower.push_back( cit->first );
}
// we are assuming quark first, swap order to ensure this
// if antiquark first
if(_partons[0]->id()<_partons[1]->id()) {
swap(_partons[0],_partons[1]);
swap(_beams[0],_beams[1]);
swap(incoming[0],incoming[1]);
swap(particlesToShower[0],particlesToShower[1]);
}
// outgoing particles
for( map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt= tree->outgoingLines().begin();
cjt != tree->outgoingLines().end();++cjt ) {
particlesToShower.push_back( cjt->first );
}
if(particlesToShower[2]->id()<0)
swap(particlesToShower[2],particlesToShower[3]);
// genuine hard emission in matrix element
double wgtb = std::accumulate(++weights_.begin(),weights_.end(),0.);
int emission_type(-1);
bool hardEmission=false;
if(wgtb>UseRandom::rnd()*(weights_[0]+wgtb)) {
wgtb *= UseRandom::rnd();
unsigned int itype=1;
for(;itype<weights_.size();++itype) {
if(weights_[itype]>=wgtb) break;
wgtb-=weights_[itype];
}
emission_type = itype;
hardEmission = true;
}
// generate a hard emission from the sudakov
else {
int qcd_type(-1),qed_type(-1);
Energy qcd_pT(-GeV),qed_pT(-GeV);
for(unsigned int ix=0;ix<inter.size();++ix) {
if(inter[ix]==ShowerInteraction::QCD)
hardQCDEmission(particlesToShower,qcd_type,qcd_pT);
else if(inter[ix]==ShowerInteraction::QED)
hardQEDEmission(particlesToShower,qed_type,qed_pT);
}
if(qcd_type<0&&qed_type<0) {
Energy ptminQED= min(min(minpTQEDII_,minpTQEDIF_),minpTQEDFF_);
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
particlesToShower[ix]->maximumpT(minpTQCD_,ShowerInteraction::QCD);
particlesToShower[ix]->maximumpT(ptminQED ,ShowerInteraction::QED);
}
return HardTreePtr();
}
else if(qcd_type>0&&qed_type>0) {
if(qcd_pT>=qed_pT) {
emission_type = qcd_type;
}
else {
emission_type = qed_type;
}
}
else if(qcd_type>0) {
emission_type = qcd_type;
}
else {
emission_type = qed_type;
}
}
// construct the HardTree object needed to perform the showers
ShowerParticleVector newparticles;
// make the particles for the HardTree
// create the partons
// q qbar -> g X
vector<Lorentz5Momentum> pnew;
if(emission_type==1||emission_type==3) {
newparticles.push_back(new_ptr(ShowerParticle(_partons[0] ,false)));
newparticles.push_back(new_ptr(ShowerParticle(_partons[1] ,false)));
newparticles.push_back(new_ptr(ShowerParticle(gluon_ , true)));
if(emission_type ==1) pnew = realEmissionQCDGluon1_;
else pnew = realEmissionQCDGluon2_;
}
// q g -> q X
else if(emission_type==4) {
newparticles.push_back(new_ptr(ShowerParticle(_partons[0] ,false)));
newparticles.push_back(new_ptr(ShowerParticle(gluon_ ,false)));
newparticles.push_back(new_ptr(ShowerParticle(_partons[1]->CC(), true)));
pnew = realEmissionQCDQuark2_;
}
// g qbar -> qbar X
else if(emission_type==2) {
newparticles.push_back(new_ptr(ShowerParticle(gluon_ ,false)));
newparticles.push_back(new_ptr(ShowerParticle(_partons[1] ,false)));
newparticles.push_back(new_ptr(ShowerParticle(_partons[0]->CC(), true)));
pnew = realEmissionQCDQuark1_;
}
else if(emission_type==5||emission_type==7) {
newparticles.push_back(new_ptr(ShowerParticle(_partons[0] ,false)));
newparticles.push_back(new_ptr(ShowerParticle(_partons[1] ,false)));
newparticles.push_back(new_ptr(ShowerParticle(gamma_ , true)));
if(emission_type ==5) pnew = realEmissionQEDPhoton1_;
else pnew = realEmissionQEDPhoton2_;
}
else if(emission_type==8) {
newparticles.push_back(new_ptr(ShowerParticle(_partons[0] ,false)));
newparticles.push_back(new_ptr(ShowerParticle(gamma_ ,false)));
newparticles.push_back(new_ptr(ShowerParticle(_partons[1]->CC(), true)));
pnew = realEmissionQEDQuark2_;
}
else if(emission_type==6) {
newparticles.push_back(new_ptr(ShowerParticle(gamma_ ,false)));
newparticles.push_back(new_ptr(ShowerParticle(_partons[1] ,false)));
newparticles.push_back(new_ptr(ShowerParticle(_partons[0]->CC(), true)));
pnew = realEmissionQEDQuark1_;
}
else if(emission_type==9 || emission_type==10) {
newparticles.push_back(new_ptr(ShowerParticle(_partons[0] ,false)));
newparticles.push_back(new_ptr(ShowerParticle(_partons[1] ,false)));
newparticles.push_back(new_ptr(ShowerParticle(gamma_ , true)));
if(emission_type ==9) pnew = realEmissionQEDFFLepton3_;
else pnew = realEmissionQEDFFLepton4_;
}
else if(emission_type>10&&emission_type<=18) {
newparticles.push_back(new_ptr(ShowerParticle(_partons[0] ,false)));
newparticles.push_back(new_ptr(ShowerParticle(_partons[1] ,false)));
newparticles.push_back(new_ptr(ShowerParticle(gamma_ , true)));
if (emission_type==11||emission_type==15) pnew =realEmissionQEDIF13_;
else if(emission_type==12||emission_type==16) pnew =realEmissionQEDIF14_;
else if(emission_type==13||emission_type==17) pnew =realEmissionQEDIF23_;
else if(emission_type==14||emission_type==18) pnew =realEmissionQEDIF24_;
}
else {
assert(false);
}
// transform to get directions right if hard emission
LorentzRotation R;
if(!_quarkplus&&hardEmission) {
PPair partons = make_pair(particlesToShower[0]->progenitor(),
particlesToShower[1]->progenitor());
if(partons.first->id()<0) swap(partons.first,partons.second);
Boost bv = (partons.first->momentum()+
partons.second->momentum()).boostVector();
R = LorentzRotation(-bv);
R.rotateY(-partons.first->momentum().theta());
R.boost(bv);
for(unsigned int ix=0;ix<pnew.size();++ix)
pnew[ix].transform(R);
}
// work out which particle emits
int iemit(-1),ispect(-1);
if(emission_type==1 || emission_type==2 ||
emission_type==5 || emission_type==6) {
iemit = 0;
ispect = 1;
}
else if(emission_type==3 || emission_type==4 ||
emission_type==7 || emission_type==8) {
iemit = 1;
ispect = 0;
}
else if(emission_type==9) {
iemit = 3;
ispect = 4;
}
else if(emission_type==10) {
iemit = 4;
ispect = 3;
}
else if(emission_type>10&&emission_type<=18) {
iemit = (emission_type==11||emission_type==15||
emission_type==12||emission_type==16) ? 0 : 1;
ispect = (emission_type==11||emission_type==15||
emission_type==13||emission_type==17) ? 3 : 4;
if(emission_type>14) swap(iemit,ispect);
}
assert(iemit>=0&&ispect>=0);
// work out which interaction
ShowerInteraction::Type interaction =
emission_type<=4 ? ShowerInteraction::QCD : ShowerInteraction::QED;
// set the momenta
for(unsigned int ix=0;ix<2;++ix) newparticles[ix]->set5Momentum(pnew[ix]);
newparticles[2]->set5Momentum(pnew[4]);
// ISR
if(iemit<2) {
// create the off-shell particle
Lorentz5Momentum poff=pnew[iemit]-pnew[4];
poff.rescaleMass();
newparticles.push_back(new_ptr(ShowerParticle(_partons[iemit],false)));
newparticles.back()->set5Momentum(poff);
}
// FSR
else {
// create the off-shell particle
Lorentz5Momentum poff=pnew[iemit-1]+pnew[4];
poff.rescaleMass();
newparticles.push_back(new_ptr(ShowerParticle(mePartonData()[iemit-1],true)));
newparticles.back()->set5Momentum(poff);
}
// outgoing particles
for(unsigned int ix=2;ix<4;++ix) {
newparticles.push_back(new_ptr(ShowerParticle(particlesToShower[ix]
->progenitor()->dataPtr(),
true)));
}
newparticles[4]->set5Momentum(pnew[2]);
newparticles[5]->set5Momentum(pnew[3]);
vector<HardBranchingPtr> inBranch,hardBranch;
// create the branchings for the incoming particles
inBranch.push_back(new_ptr(HardBranching(newparticles[0],SudakovPtr(),
HardBranchingPtr(),HardBranching::Incoming)));
inBranch.push_back(new_ptr(HardBranching(newparticles[1],SudakovPtr(),
HardBranchingPtr(),HardBranching::Incoming)));
// ISR
if(iemit<2) {
// intermediate IS particle
hardBranch.push_back(new_ptr(HardBranching(newparticles[3],SudakovPtr(),
inBranch[iemit],HardBranching::Incoming)));
inBranch[iemit]->addChild(hardBranch.back());
// create the branching for the emitted jet
inBranch[iemit]->addChild(new_ptr(HardBranching(newparticles[2],SudakovPtr(),
inBranch[iemit],
HardBranching::Outgoing)));
// add other particle
hardBranch.push_back(inBranch[iemit==0 ? 1 : 0]);
// outgoing particles
for(unsigned int ix=4;ix<newparticles.size();++ix) {
hardBranch.push_back(new_ptr(HardBranching(newparticles[ix],SudakovPtr(),
HardBranchingPtr(),
HardBranching::Outgoing)));
}
}
// FSR
else {
hardBranch.push_back(inBranch[0]);
hardBranch.push_back(inBranch[1]);
if(iemit==3) {
hardBranch.push_back(new_ptr(HardBranching(newparticles[3],SudakovPtr(),
HardBranchingPtr(),
HardBranching::Outgoing)));
hardBranch.back()->addChild(new_ptr(HardBranching(newparticles[4],SudakovPtr(),
hardBranch.back(),
HardBranching::Outgoing)));
hardBranch.back()->addChild(new_ptr(HardBranching(newparticles[2],SudakovPtr(),
hardBranch.back(),
HardBranching::Outgoing)));
hardBranch.push_back(new_ptr(HardBranching(newparticles[5],SudakovPtr(),
HardBranchingPtr(),
HardBranching::Outgoing)));
}
else {
hardBranch.push_back(new_ptr(HardBranching(newparticles[4],SudakovPtr(),
HardBranchingPtr(),
HardBranching::Outgoing)));
hardBranch.push_back(new_ptr(HardBranching(newparticles[3],SudakovPtr(),
HardBranchingPtr(),
HardBranching::Outgoing)));
hardBranch.back()->addChild(new_ptr(HardBranching(newparticles[5],SudakovPtr(),
hardBranch.back(),
HardBranching::Outgoing)));
hardBranch.back()->addChild(new_ptr(HardBranching(newparticles[2],SudakovPtr(),
hardBranch.back(),
HardBranching::Outgoing)));
}
}
// set the evolution partners
if(emission_type<=4) {
hardBranch[0]->colourPartner(hardBranch[1]);
hardBranch[1]->colourPartner(hardBranch[0]);
}
else if(emission_type<=10) {
hardBranch[2]->colourPartner(hardBranch[3]);
hardBranch[3]->colourPartner(hardBranch[2]);
hardBranch[2]->colourPartner(hardBranch[3]);
hardBranch[3]->colourPartner(hardBranch[2]);
}
else if(emission_type<=18) {
if(iemit>2) {
hardBranch[iemit -1]->colourPartner(hardBranch[ispect ]);
hardBranch[ispect ]->colourPartner(hardBranch[iemit -1]);
}
else {
hardBranch[iemit ]->colourPartner(hardBranch[ispect-1]);
hardBranch[ispect-1]->colourPartner(hardBranch[iemit ]);
}
}
else {
assert(false);
}
// make the tree
HardTreePtr hardtree=new_ptr(HardTree(hardBranch,inBranch,interaction));
// connect the ShowerParticles with the branchings
// and set the maximum pt for the radiation
Energy pt = pnew[4].perp();
set<HardBranchingPtr> hard=hardtree->branchings();
Energy ptminQED= min(min(minpTQEDII_,minpTQEDIF_),minpTQEDFF_);
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
particlesToShower[ix]->maximumpT(max(pt,minpTQCD_),ShowerInteraction::QCD);
particlesToShower[ix]->maximumpT(max(pt,ptminQED),ShowerInteraction::QED);
for(set<HardBranchingPtr>::const_iterator mit=hard.begin();
mit!=hard.end();++mit) {
if(particlesToShower[ix]->progenitor()->id()==(*mit)->branchingParticle()->id()&&
(( particlesToShower[ix]->progenitor()->isFinalState()&&
(**mit).status()==HardBranching::Outgoing)||
(!particlesToShower[ix]->progenitor()->isFinalState()&&
(**mit).status()==HardBranching::Incoming))) {
hardtree->connect(particlesToShower[ix]->progenitor(),*mit);
if((**mit).status()==HardBranching::Incoming) {
(*mit)->beam(particlesToShower[ix]->original()->parents()[0]);
HardBranchingPtr parent=(*mit)->parent();
while(parent) {
parent->beam(particlesToShower[ix]->original()->parents()[0]);
parent=parent->parent();
};
}
}
}
}
ColinePtr newline=new_ptr(ColourLine());
for(set<HardBranchingPtr>::const_iterator cit=hardtree->branchings().begin();
cit!=hardtree->branchings().end();++cit) {
if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3)
newline->addColoured((**cit).branchingParticle());
else if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3bar)
newline->addAntiColoured((**cit).branchingParticle());
}
// return the tree
// generator()->log() << "Had hard radiation " << iemit << "\n";
// generator()->log() << *hardtree << "\n";
// cerr << "Had hard radiation " << iemit << "\n";
// cerr << *hardtree << "\n";
return hardtree;
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Nov 19, 9:17 PM (1 d, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3806228
Default Alt Text
(120 KB)

Event Timeline