Page MenuHomeHEPForge

No OneTemporary

diff --git a/MatrixElement/Powheg/MEqq2gZ2ffPowhegQED.cc b/MatrixElement/Powheg/MEqq2gZ2ffPowhegQED.cc
old mode 120000
new mode 100644
--- a/MatrixElement/Powheg/MEqq2gZ2ffPowhegQED.cc
+++ b/MatrixElement/Powheg/MEqq2gZ2ffPowhegQED.cc
@@ -1,1 +1,3972 @@
-MEqq2gZ2ffPowhegQED.cc.new
\ No newline at end of file
+// -*- 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),
+ DipoleSum_(0),
+ 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_ << DipoleSum_;
+}
+
+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_ >> DipoleSum_;
+}
+
+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 Switch<MEqq2gZ2ffPowhegQED,unsigned int> interfaceDipoleSum
+ ("DipoleSum",
+ "Organization of QED dipoles subtraction",
+ &MEqq2gZ2ffPowhegQED::DipoleSum_, 0, false, false);
+
+ static SwitchOption interfaceDipoleSum0
+ (interfaceDipoleSum,
+ "0",
+ "(R-Sum(D_IF-))*|D_II_FF_IF+|/Sum|D_II_FF_IF+|",
+ 0);
+ static SwitchOption interfaceDipoleSum1
+ (interfaceDipoleSum,
+ "1",
+ "R*|D|/Sum|D|",
+ 1);
+ static SwitchOption interfaceDipoleSum2
+ (interfaceDipoleSum,
+ "2",
+ "R*|D_II_FF_IFsameemitter|/Sum|D_II_FF_IFsameemitter|",
+ 2);
+ static SwitchOption interfaceDipoleSum3
+ (interfaceDipoleSum,
+ "3",
+ "R-alldipoles",
+ 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 &&
+ 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 &&
+ 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) {
+// cout<<"====II======="<<endl;
+// cout<<mePartonData()[0]->PDGName()<<" "<<
+// mePartonData()[1]->PDGName()<<" "<<
+// mePartonData()[2]->PDGName()<<" "<<
+// mePartonData()[3]->PDGName()<<" "<<endl;
+
+ realQED1 = subtractedRealQED(x,
+ z.first,zJac.first,
+ oldqPDF.first,newqPDF.first,newpPDF.first,
+ z.second,zJac.second,
+ oldqPDF.second,newqPDF.second,newpPDF.second,
+ II12);
+
+ realQED2 = subtractedRealQED(x,
+ z.first,zJac.first,
+ oldqPDF.first,newqPDF.first,newpPDF.first,
+ z.second,zJac.second,
+ oldqPDF.second,newqPDF.second,newpPDF.second,
+ II21);
+
+ wgt += realQED1[0] + realQED1[2] +realQED2[0] +realQED2[2];
+ }
+ // FSR
+ if(QEDContributions_!=1) {
+// cout<<"====FF======="<<endl;
+// cout<<mePartonData()[0]->PDGName()<<" "<<
+// mePartonData()[1]->PDGName()<<" "<<
+// mePartonData()[2]->PDGName()<<" "<<
+// mePartonData()[3]->PDGName()<<" "<<endl;
+
+
+ realQED3 = subtractedRealQED(x,
+ zTilde_,1.,
+ oldqPDF.first,oldqPDF.first,0.,
+ zTilde_,1.,
+ oldqPDF.second,oldqPDF.second,0.,
+ FF34);
+
+ realQED4 = subtractedRealQED(x,
+ zTilde_,1.,
+ oldqPDF.first,oldqPDF.first,0.,
+ zTilde_,1.,
+ oldqPDF.second,oldqPDF.second,0.,
+ FF43);
+
+ wgt += realQED3[0] + realQED4[0];
+ }
+ // ISR/FSR interference
+ if(QEDContributions_==0) {
+// cout<<"====IF======="<<endl;
+// cout<<mePartonData()[0]->PDGName()<<" "<<
+// mePartonData()[1]->PDGName()<<" "<<
+// mePartonData()[2]->PDGName()<<" "<<
+// mePartonData()[3]->PDGName()<<" "<<endl;
+
+ if(DipoleSum_<=1) {
+ if(DipoleSum_==0 ||
+ mePartonData()[0]->iCharge()*mePartonData()[2]->iCharge()>0)
+ realQED5 = subtractedRealQED(x,
+ z.first,zJac.first,
+ oldqPDF.first,newqPDF.first,newpPDF.first,
+ z.second,zJac.second,
+ oldqPDF.second,newqPDF.second,newpPDF.second,
+ IF13);
+ if(DipoleSum_==0 ||
+ mePartonData()[0]->iCharge()*mePartonData()[3]->iCharge()>0)
+ realQED6 = subtractedRealQED(x,
+ z.first,zJac.first,
+ oldqPDF.first,newqPDF.first,newpPDF.first,
+ z.second,zJac.second,
+ oldqPDF.second,newqPDF.second,newpPDF.second,
+ IF14);
+ if(DipoleSum_==0 ||
+ mePartonData()[1]->iCharge()*mePartonData()[2]->iCharge()>0)
+ realQED7 = subtractedRealQED(x,
+ z.first,zJac.first,
+ oldqPDF.first,newqPDF.first,newpPDF.first,
+ z.second,zJac.second,
+ oldqPDF.second,newqPDF.second,newpPDF.second,
+ IF23);
+ if(DipoleSum_==0 ||
+ mePartonData()[1]->iCharge()*mePartonData()[3]->iCharge()>0)
+ realQED8 = subtractedRealQED(x,
+ z.first,zJac.first,
+ oldqPDF.first,newqPDF.first,newpPDF.first,
+ z.second,zJac.second,
+ oldqPDF.second,newqPDF.second,newpPDF.second,
+ IF24);
+ }
+
+ else if(DipoleSum_ ==2) {
+// cout<<"IF1, zfirst "<<z.first<<endl;
+ realQED5 = subtractedRealQED(x,
+ z.first,zJac.first,
+ oldqPDF.first,newqPDF.first,newpPDF.first,
+ z.second,zJac.second,
+ oldqPDF.second,newqPDF.second,newpPDF.second,
+ IF1);
+
+// cout<<"IF2, zsecond "<<z.second<<endl;
+ realQED6 = subtractedRealQED(x,
+ z.first,zJac.first,
+ oldqPDF.first,newqPDF.first,newpPDF.first,
+ z.second,zJac.second,
+ oldqPDF.second,newqPDF.second,newpPDF.second,
+ IF2);
+
+// cout<<"IF3, zfirst,zsecond "<<z.first<<" "<<z.second<<endl;
+ realQED7 = subtractedRealQED(x,
+ z.first,zJac.first,
+ oldqPDF.first,newqPDF.first,newpPDF.first,
+ z.second,zJac.second,
+ oldqPDF.second,newqPDF.second,newpPDF.second,
+ IF3);
+
+// cout<<"IF4, zfirst,zsecond "<<z.first<<" "<<z.second<<endl;
+ realQED8 = subtractedRealQED(x,
+ z.first,zJac.first,
+ oldqPDF.first,newqPDF.first,newpPDF.first,
+ z.second,zJac.second,
+ oldqPDF.second,newqPDF.second,newpPDF.second,
+ IF4);
+ }
+ else {
+ realQED5 = subtractedRealQED(x,
+ z.first,zJac.first,
+ oldqPDF.first,newqPDF.first,newpPDF.first,
+ z.second,zJac.second,
+ oldqPDF.second,newqPDF.second,newpPDF.second,
+ IF13);
+ }
+ 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 z1,
+ double z1Jac,
+ double oldqPDF1, double newqPDF1, double newpPDF1,
+ double z2,
+ double z2Jac,
+ double oldqPDF2, double newqPDF2, double newpPDF2,
+ DipoleType dipole) const {
+ // ISR
+ if(dipole==II12||dipole==II21) {
+ double z,zJac,newqPDF,oldqPDF,newpPDF;
+ if(dipole==II12) {
+ z = z1;
+ zJac = z1Jac;
+ newqPDF = newqPDF1;
+ oldqPDF = oldqPDF1;
+ newpPDF = newpPDF1;
+ }
+ else {
+ z = z2;
+ zJac = z2Jac;
+ newqPDF = newqPDF2;
+ oldqPDF = oldqPDF2;
+ newpPDF = newpPDF2;
+ }
+ 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) {
+ double zJac;
+ if(dipole==FF34) {
+ zJac = z1Jac;
+ }
+ else {
+ zJac = z2Jac;
+ }
+// cout<<"FF check: must be 1 "<<zJac<<endl;
+
+ // 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) {
+
+ if(DipoleSum_ == 2) {
+ cout<<"error"<<endl;
+ }
+
+ double z,zJac,newqPDF,oldqPDF;
+ if(dipole==IF13 || dipole==IF14) {
+ z = z1;
+ zJac = z1Jac;
+ newqPDF = newqPDF1;
+ oldqPDF = oldqPDF1;
+ }
+ else {
+ z = z2;
+ zJac = z2Jac;
+ newqPDF = newqPDF2;
+ oldqPDF = oldqPDF2;
+ }
+ // 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);
+ //Here we can use an overall phase*newqPDF/oldqPDF, since
+ //all the dipoles included in the current term have
+ //the same kinematics and the same underlying Born ME.
+ //ER: check that PDF change is ok also for real ME, since
+ // we are using an overall pdf rescaling
+ double fact = EMfact_*phase*newqPDF/oldqPDF;
+ output[0] = realIF.first *fact;
+ output[1] = realIF.second*fact;
+ }
+ // return the answer
+ return output;
+ }
+ ///////////////////////////////////////////////////
+ else if (dipole == IF1 || dipole == IF2 ||
+ dipole == IF3 || dipole == IF4) {
+ if(DipoleSum_!=2) {
+ cout<<"Error2 in subtractedRealQED"<<endl;
+ assert(false);
+ }
+
+ // particles making up the dipole
+ int iin=-1,iout=-1;
+ // new momenta
+ vector<Lorentz5Momentum> pnew(5);
+
+ double z=ZERO,zJac=ZERO;
+ double charge02 = double(mePartonData()[0]->iCharge()*
+ mePartonData()[2]->iCharge())/9.;
+ double charge12 = double(mePartonData()[1]->iCharge()*
+ mePartonData()[2]->iCharge())/9.;
+ if(dipole == IF1 || dipole == IF2) {
+ // initial_em-final_spect
+ iin = dipole==IF1 ? 0 : 1;
+ // build 'real' kinematics assuming spectator is such that
+ // Q_em*Q_sp>0
+ iout= (dipole==IF1 && charge02 > 0) || (dipole==IF2 && charge12 > 0)
+ ? 2 : 3;
+ if(dipole==IF1) {
+ z = z1;
+ zJac = z1Jac;
+ if(iin!=0) cout<<"Error 0"<<endl;
+ }
+ else {
+ z = z2;
+ zJac = z2Jac;
+ if(iin!=1) cout<<"Error 1"<<endl;
+ }
+ }
+ else if(dipole == IF3 || dipole == IF4) {
+ // initial_sp-final_emitter
+ iout= dipole==IF3 ? 2 : 3;
+ // build 'real' kinematics assuming spectator is such that
+ // Q_em*Q_sp>0
+ iin = (dipole==IF3 && charge02 > 0) || (dipole==IF4 && charge12 > 0)
+ ? 0 : 1;
+
+ z = iin==0 ? z1 : z2; //ER:
+ zJac = iin==0 ? z1Jac : z2Jac; //ER:
+ }
+ //now (iin,iout) are well defined
+// cout<<"In subtractedrealqed I'll use "<<iin<<iout<<" "<<z<<endl;
+
+ // 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;
+ // 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 = vJac*(1.+mu2);
+ //Here compute dipoles
+ vector<double> output(2,0.);
+// cout<<"call QEDMEqqbar2 with "<<zTilde_<<" "<<vt<<" "<<1.-z-vt<<endl;
+ if(!(zTilde_<1e-7 || vt<1e-7 || 1.-z-vt < 1e-7 )) {
+ pair<double,double> realIF =
+ subtractedQEDMEqqbar2(pnew,
+ z1,z1Jac,oldqPDF1,newqPDF1,
+ z2,z2Jac,oldqPDF2,newqPDF2,
+ dipole,iin,iout,true);
+ double fact = EMfact_*phase;//ER: *newqPDF/oldqPDF;
+ output[0] = realIF.first *fact;
+ output[1] = realIF.second*fact;
+ }
+ // return the answer
+ return output;
+ }
+
+/////////////////////////// Assume for now that this is not needed
+// 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);
+//////////////////////////////////////////////
+ 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);
+ Energy2 scaleIF[4] = {ZERO,ZERO,ZERO,ZERO};
+ /////////// compute the two II dipole terms ////////////////////////////
+ InvEnergy2 DII[2] = {ZERO,ZERO};
+ if(QEDContributions_!=2) {
+ // cout<<"doing II dipoles"<<endl;
+ 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) {
+ //cout<<"doing FF dipoles"<<endl;
+ 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};
+ InvEnergy2 DFI[4]={ZERO,ZERO,ZERO,ZERO};
+ Energy2 pT2IF[4] ={ZERO,ZERO,ZERO,ZERO};
+ InvEnergy2 negativeDipoles(ZERO);
+ if(QEDContributions_==0) {
+ if(DipoleSum_ != 2) {
+ // cout<<"doing IF dipoles"<<endl;
+ 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.;
+ // 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(DipoleSum_!=0 || 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;
+ }
+ }
+ else {
+// if(dipole==IF1 || dipole==IF2 || dipole==IF3 || dipole==IF4) cout<<"IF IF"<<endl;
+ 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);
+ // lo piece and charge factors
+ double charge = double(mePartonData()[iin]->iCharge()*
+ mePartonData()[iout]->iCharge())/9.;
+ InvEnergy2 splitIF = 0.5/dot1/x*(2./(1.-x+z)-1.-x);
+ InvEnergy2 splitFI = 0.5/dot2/x*(2./(1.-x+z)-2.+z-sqr(mj)/dot2);
+
+ DIF[ix]=charge*splitIF*lo;
+ DFI[ix]=charge*splitFI*lo;
+ scaleIF[ix]=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,numscale;
+ switch (dipole) {
+ case II12 :
+ num = DII[0];
+ numscale=num;
+ break;
+ case II21 :
+ num = DII[1];
+ numscale=num;
+ break;
+ case FF34 :
+ num = DFF[0];
+ numscale=num;
+ break;
+ case FF43 :
+ num = DFF[1];
+ numscale=num;
+ break;
+ case IF13 :
+ num = DIF[0];
+ numscale=num;
+ break;
+ case IF14 :
+ num = DIF[1];
+ numscale=num;
+ break;
+ case IF23 :
+ num = DIF[2];
+ numscale=num;
+ break;
+ case IF24 :
+ num = DIF[3];
+ numscale=num;
+ break;
+ default:
+ assert(false);
+ };
+ double meout(0.);
+ InvEnergy2 den(ZERO);
+ InvEnergy2 allDipoles(ZERO); //needed to check limits
+ // 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]);
+ allDipoles=DII[0]+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]);
+ allDipoles=DFF[0]+DFF[1];
+ }
+ // full result
+ else if(QEDContributions_==0) {
+ meout = me[2];
+ den = abs(DII[0])+abs(DII[1])+abs(DFF[0])+abs(DFF[1]);
+ if(DipoleSum_!=2) {
+ for(unsigned int ix=0;ix<4;++ix) den += abs(DIF[ix]);
+ allDipoles = (DII[0])+(DII[1])+(DFF[0])+(DFF[1]);
+ for(unsigned int ix=0;ix<4;++ix) allDipoles += DIF[ix];
+ }
+ else if(DipoleSum_==2) {
+ den=den + // DENFIXED
+ abs(DIF[0]+DIF[1]) +
+ abs(DIF[2]+DIF[3]) +
+ abs(DFI[0]+DFI[2]) +
+ abs(DFI[1]+DFI[3]) ;
+// for(unsigned int ix=0;ix<4;++ix) {
+// den += abs(DIF[ix]+DFI[ix]);
+// }
+ }
+ else
+ assert(false);
+ if (DipoleSum_ ==3) {
+ negativeDipoles = ZERO;
+ numscale = allDipoles;
+ den = 1./GeV2;
+ num = den ;
+ }
+ }
+ 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 -numscale);
+ }
+ 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::subtractedQEDMEqqbar2(const vector<Lorentz5Momentum> & p,
+ double z1,double z1Jac,double oldqPDF1,double newqPDF1,
+ double z2,double z2Jac,double oldqPDF2,double newqPDF2,
+ DipoleType dipole, int iin, int iout, bool subtract) const {
+ //////////////////////
+ //ER:
+ //////////////////////
+
+ //Sanity check
+ if(DipoleSum_!=2) {
+ cout<<"Error in subtractedQEDMEqqbar2"<<endl;
+ assert(false);
+ }
+
+// cout<<"In qqbar2: iin, iout "<<" "<<iin<<" "<<iout<<endl;
+
+
+ // 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);
+ Energy2 scaleIF[4] = {ZERO,ZERO,ZERO,ZERO};
+ /////////// compute the two II dipole terms ////////////////////////////
+ InvEnergy2 DII[2] = {ZERO,ZERO};
+ if(QEDContributions_!=2) {
+ // cout<<"doing II dipoles"<<endl;
+ 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();
+ cout<<"ERROR IN QQBAR2, called with II dipole"<<endl;
+ }
+ }
+ /////////// compute the two FF dipole terms ////////////////////////////
+ InvEnergy2 DFF[2]={ZERO,ZERO};
+ Energy2 pT2final[2]={ZERO,ZERO};
+ if(QEDContributions_!=1) {
+ //cout<<"doing FF dipoles"<<endl;
+ 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();
+ cout<<"ERROR IN QQBAR2, called with FF dipole"<<endl;
+ }
+ }
+ /////////// ISR/FSR interference ////////////////////////////
+ InvEnergy2 DIF[4]={ZERO,ZERO,ZERO,ZERO};
+ InvEnergy2 DFI[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]);
+// cout<<"iin, iout, x "<<" "<<iin<<" "<<iout<<" "<<x<<endl;
+ // 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);
+ // lo piece and charge factors
+ double charge = double(mePartonData()[iin]->iCharge()*
+ mePartonData()[iout]->iCharge())/9.;
+ InvEnergy2 splitIF = 0.5/dot1/x*(2./(1.-x+z)-1.-x);
+ InvEnergy2 splitFI = 0.5/dot2/x*(2./(1.-x+z)-2.+z-sqr(mj)/dot2);
+
+ DIF[ix]=charge*splitIF*lo;
+ DFI[ix]=charge*splitFI*lo;
+ scaleIF[ix]=Q2;
+ }
+ }
+
+ // supression function
+ Energy2 pT2sup=ZERO;
+ InvEnergy2 dipolesubtract=ZERO;
+ if(dipole==IF1 || dipole==IF2 || dipole==IF3 || dipole==IF4)
+ pT2sup = ZERO; //!ER: Needs to be fixed
+ else
+ assert(false);
+ pair<double,double> supressionFactor = supressionFunction(pT2sup);
+ // numerator for dipole ratio
+ InvEnergy2 num;
+ double pdfratio,phase;
+ switch (dipole) {
+ case IF1 :
+ num = DIF[0]+DIF[1];
+ scale= iout==2 ? scaleIF[0] : scaleIF[1];
+ if(iin!=0) cout<<"Error iin 0"<<endl;
+ pdfratio=newqPDF1/oldqPDF1;
+ phase=z1Jac/z1;
+ dipolesubtract=num*pdfratio*phase;
+ break;
+ case IF2 :
+ num = DIF[2]+DIF[3];
+ scale= iout==2 ? scaleIF[2] : scaleIF[3];
+ if(iin!=1) cout<<"Error iin 1"<<endl;
+ pdfratio=newqPDF2/oldqPDF2;
+ phase=z2Jac/z2;
+ dipolesubtract=num*pdfratio*phase;
+ break;
+ case IF3 :
+ num = DFI[0]+DFI[2];
+ scale= iin==0 ? scaleIF[0] : scaleIF[2];
+ pdfratio = iin==0 ? newqPDF1/oldqPDF1 : newqPDF2/oldqPDF2;//ER:
+ phase= iin==0 ? z1Jac/z1 : z2Jac/z2;//ER:
+ dipolesubtract=num*pdfratio*phase;
+ break;
+ case IF4 :
+ num = DFI[1]+DFI[3];
+ scale= iin==0 ? scaleIF[1] : scaleIF[3];
+ pdfratio = iin==0 ? newqPDF1/oldqPDF1 : newqPDF2/oldqPDF2;//ER:
+ phase= iin==0 ? z1Jac/z1 : z2Jac/z2;//ER:
+ dipolesubtract=num*pdfratio*phase;
+ break;
+ default:
+ assert(false);
+ };
+ double meout(0.);
+ InvEnergy2 den(ZERO);
+ InvEnergy2 allDipoles(ZERO);
+ // ISR
+ if(QEDContributions_==1 ||
+ (QEDContributions_==3 && (dipole==II12 || dipole ==II21))) {
+ cout<<"error"<<endl;
+ }
+ // FSR
+ else if(QEDContributions_==2 ||
+ (QEDContributions_==3 && (dipole==FF34 || dipole ==FF43))) {
+ cout<<"error"<<endl;
+ }
+ // full result
+ else if(QEDContributions_==0) {
+ meout = me[2]*pdfratio*phase;
+ den = abs(DII[0])+abs(DII[1])+abs(DFF[0])+abs(DFF[1]);
+ den=den +
+ abs(DIF[0]+DIF[1]) + // DENFIXED
+ abs(DIF[2]+DIF[3]) +
+ abs(DFI[0]+DFI[2]) +
+ abs(DFI[1]+DFI[3]) ;
+ // for(unsigned int ix=0;ix<4;++ix) den += abs(DIF[ix]+DFI[ix]);
+ }
+ else
+ assert(false);
+ // return the answer
+ pair<double,double> output = make_pair(0.,0.);
+
+ //ER: fix here
+
+ if(den>ZERO) {
+ if(subtract) {
+ // cout<<"Forse non va perche metto assieme dipoli con kin diversa"<<endl;
+ output.first = scale*(UnitRemoval::InvE2*meout
+ *abs(num)/den*supressionFactor.first -dipolesubtract);
+ }
+ 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;
+ int 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
Wed, May 14, 10:03 AM (1 d, 11 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5111029
Default Alt Text
(140 KB)

Event Timeline