diff --git a/Analysis/BasicConsistency.cc b/Analysis/BasicConsistency.cc --- a/Analysis/BasicConsistency.cc +++ b/Analysis/BasicConsistency.cc @@ -1,328 +1,328 @@ // -*- C++ -*- // // BasicConsistency.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the BasicConsistency class. // #include "BasicConsistency.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/EventRecord/Event.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Utilities/EnumParticles.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Utilities/ColourOutput.h" using namespace Herwig; using namespace ThePEG; -BasicConsistency::BasicConsistency() +BasicConsistency::BasicConsistency() : _epsmom(ZERO),_checkquark(true), _checkcharge(true), _checkcluster(true), _checkBR(true), _absolutemomentumtolerance(1*MeV), _relativemomentumtolerance(1e-5) {} IBPtr BasicConsistency::clone() const { return new_ptr(*this); } IBPtr BasicConsistency::fullclone() const { return new_ptr(*this); } void BasicConsistency::analyze(tEventPtr event, long, int, int) { bool writeEvent=false; set particles; event->selectFinalState(inserter(particles)); - + int charge(-event->incoming().first->dataPtr()->iCharge() -event->incoming().second->dataPtr()->iCharge()); - Lorentz5Momentum + Lorentz5Momentum ptotal(-event->incoming().first->momentum() -event->incoming().second->momentum()); const Energy beamenergy = ptotal.m(); - for(set::const_iterator it = particles.begin(); + for(set::const_iterator it = particles.begin(); it != particles.end(); ++it) { if (_checkquark && (*it)->coloured()) { - cerr << "Had quarks in final state in event " - << event->number() + cerr << "Had quarks in final state in event " + << event->number() << '\n'; - generator()->log() << "Had quarks in final state in event " + generator()->log() << "Had quarks in final state in event " << event->number() << '\n'; writeEvent = true; } else if( _checkcluster && (**it).id()==ParticleID::Cluster) { - cerr << "Had clusters in final state in event " - << event->number() + cerr << "Had clusters in final state in event " + << event->number() << '\n'; - generator()->log() << "Had clusters in final state in event " + generator()->log() << "Had clusters in final state in event " << event->number() << '\n'; writeEvent = true; } charge += (*it)->dataPtr()->iCharge(); ptotal += (*it)->momentum(); bool problem=false; LorentzDistance test; for(unsigned int ix=0;ix<5;++ix) { switch (ix) { case 0: test = (*it)->vertex(); break; case 1: test = (*it)->labVertex(); break; case 2: test = (*it)->decayVertex(); break; case 3: test = (*it)->labDecayVertex(); break; case 4: test = (*it)->lifeLength(); break; } - problem |= ! ( isfinite(double(test.x()/mm)) && - isfinite(double(test.y()/mm)) && - isfinite(double(test.z()/mm)) && + problem |= ! ( isfinite(double(test.x()/mm)) && + isfinite(double(test.y()/mm)) && + isfinite(double(test.z()/mm)) && isfinite(double(test.t()/mm)) ); } if(problem) { generator()->log() << "Problem with position of " << **it << "\n" << (*it)->vertex()/mm << "\n" << (*it)->labVertex()/mm << "\n" << (*it)->decayVertex()/mm << "\n" << (*it)->labDecayVertex()/mm << "\n" - << (*it)->lifeLength()/mm << "\n"; + << (*it)->lifeLength()/mm << "\n"; } } - + if ( _checkcharge && charge != 0 ) { - cerr << "\nCharge imbalance by " - << charge - << "in event " - << event->number() + cerr << "\nCharge imbalance by " + << charge + << " in event " + << event->number() << '\n'; - generator()->log() << "Charge imbalance by " - << charge - << "in event " + generator()->log() << "Charge imbalance by " + << charge + << " in event " << event->number() << '\n'; writeEvent = true; } Energy mag = ptotal.m(); Energy ee = ptotal.e(); if (std::isnan(double(mag/MeV))) { - cerr << "\nMomentum is 'nan'; " << ptotal/MeV + cerr << "\nMomentum is 'nan'; " << ptotal/MeV << " MeV in event " << event->number() << '\n'; - generator()->log() <<"\nMomentum is 'nan'; " << ptotal/MeV + generator()->log() <<"\nMomentum is 'nan'; " << ptotal/MeV << " MeV in event " << event->number() << '\n'; writeEvent = true; } const Energy epsilonmax = max( _absolutemomentumtolerance, _relativemomentumtolerance * beamenergy ); if (abs(mag) > epsilonmax || abs(ee) > epsilonmax) { - cerr << "\nMomentum imbalance by " << ptotal/MeV + cerr << "\nMomentum imbalance by " << ptotal/MeV << " MeV in event " << event->number() << '\n'; - generator()->log() <<"\nMomentum imbalance by " << ptotal/MeV + generator()->log() <<"\nMomentum imbalance by " << ptotal/MeV << " MeV in event " << event->number() << '\n'; writeEvent = true; } if (abs(mag) > _epsmom) _epsmom = abs(mag); if (abs(ee) > _epsmom) _epsmom = abs(ee); if (abs(ptotal.x()) > _epsmom) _epsmom = abs(ptotal.x()); if (abs(ptotal.y()) > _epsmom) _epsmom = abs(ptotal.y()); if (abs(ptotal.z()) > _epsmom) _epsmom = abs(ptotal.z()); particles.clear(); event->select(inserter(particles), ThePEG::AllSelector()); - for(set::const_iterator it = particles.begin(); + for(set::const_iterator it = particles.begin(); it != particles.end(); ++it) { bool problem=false; LorentzDistance test; for(unsigned int ix=0;ix<5;++ix) { switch (ix) { case 0: test = (*it)->vertex(); break; case 1: test = (*it)->labVertex(); break; case 2: test = (*it)->decayVertex(); break; case 3: test = (*it)->labDecayVertex(); break; case 4: test = (*it)->lifeLength(); break; } problem |= ( ! isfinite(double(test.m2()/mm/mm)) ); } if(problem) { generator()->log() << "Problem with position of " << **it << "\n" << (*it)->vertex()/mm << "\n" << (*it)->labVertex()/mm << "\n" << (*it)->decayVertex()/mm << "\n" << (*it)->labDecayVertex()/mm << "\n" - << (*it)->lifeLength()/mm << "\n"; + << (*it)->lifeLength()/mm << "\n"; writeEvent=true; } } if(writeEvent) generator()->log() << *event; } void BasicConsistency::persistentOutput(PersistentOStream & os) const { os << _checkquark << _checkcharge << _checkcluster << _checkBR << ounit(_absolutemomentumtolerance,MeV) << _relativemomentumtolerance; } void BasicConsistency::persistentInput(PersistentIStream & is, int) { is >> _checkquark >> _checkcharge >> _checkcluster >> _checkBR >> iunit(_absolutemomentumtolerance,MeV) >> _relativemomentumtolerance; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigBasicConsistency("Herwig::BasicConsistency", "HwAnalysis.so"); void BasicConsistency::Init() { static ClassDocumentation documentation ("The BasicConsistency analysis handler checks for" " momentum and charge conservation."); static Switch interfaceCheckQuark ("CheckQuark", "Check whether there are quarks in the final state", &BasicConsistency::_checkquark, true, false, false); static SwitchOption interfaceCheckQuarkCheck (interfaceCheckQuark, "Yes", "Check for quarks", true); static SwitchOption interfaceCheckQuarkNoCheck (interfaceCheckQuark, "No", "Don't check for quarks", false); static Switch interfaceCheckCharge ("CheckCharge", "Check whether charge is conserved", &BasicConsistency::_checkcharge, true, false, false); static SwitchOption interfaceCheckChargeCheck (interfaceCheckCharge, "Yes", "Check charge conservation", true); static SwitchOption interfaceCheckChargeNoCheck (interfaceCheckCharge, "No", "Don't check charge conservation", false); static Switch interfaceCheckCluster ("CheckCluster", "Check whether there are clusters in the final state", &BasicConsistency::_checkcluster, true, false, false); static SwitchOption interfaceCheckClusterCheck (interfaceCheckCluster, "Yes", "Check for clusters", true); static SwitchOption interfaceCheckClusterNoCheck (interfaceCheckCluster, "No", "Don't check for clusters", false); static Switch interfaceCheckBranchingRatios ("CheckBranchingRatios", "Check whether the branching ratios of the particles add up to one.", &BasicConsistency::_checkBR, true, false, false); static SwitchOption interfaceCheckBranchingRatiosYes (interfaceCheckBranchingRatios, "Yes", "Perform the check", true); static SwitchOption interfaceCheckBranchingRatiosNo (interfaceCheckBranchingRatios, "No", "Don't perform the check", false); static Parameter interfaceAbsoluteMomentumTolerance ("AbsoluteMomentumTolerance", "The value of the momentum imbalance above which warnings are issued/MeV.\n" "Final tolerance is the larger of AbsoluteMomentumTolerance and\n" "RelativeMomentumTolerance*beam energy.", &BasicConsistency::_absolutemomentumtolerance, MeV, 1*MeV, ZERO, 1e10*GeV, false, false, true); static Parameter interfaceRelativeMomentumTolerance ("RelativeMomentumTolerance", "The value of the momentum imbalance as a fraction of the beam energy\n" "above which warnings are issued.\n" "Final tolerance is the larger of AbsoluteMomentumTolerance and\n" "RelativeMomentumTolerance*beam energy.", &BasicConsistency::_relativemomentumtolerance, 1e-5, 0.0, 1.0, false, false, true); } void BasicConsistency::dofinish() { AnalysisHandler::dofinish(); - cout << "\nBasicConsistency: maximum 4-momentum violation: " + cout << "\nBasicConsistency: maximum 4-momentum violation: " << ANSI::blue << _epsmom/MeV << " MeV\n" << ANSI::reset; } void BasicConsistency::doinitrun() { AnalysisHandler::doinitrun(); static double eps=1e-12; for(ParticleMap::const_iterator it=generator()->particles().begin(); it!=generator()->particles().end();++it) { if(it->second->stable()) continue; double total(0.); for(DecaySet::const_iterator dit=it->second->decayModes().begin(); dit!=it->second->decayModes().end();++dit) { if((**dit).on()) total +=(**dit).brat(); } if(abs(total-1.)>eps) { - cerr << "Warning: Total BR for " - << it->second->PDGName() + cerr << "Warning: Total BR for " + << it->second->PDGName() << " does not add up to 1. sum = " << total << "\n"; } } } diff --git a/Decay/PerturbativeDecayer.cc b/Decay/PerturbativeDecayer.cc --- a/Decay/PerturbativeDecayer.cc +++ b/Decay/PerturbativeDecayer.cc @@ -1,1174 +1,1174 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the PerturbativeDecayer class. // #include "PerturbativeDecayer.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/EventRecord/Particle.h" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Utilities/EnumIO.h" using namespace Herwig; void PerturbativeDecayer::persistentOutput(PersistentOStream & os) const { os << ounit(pTmin_,GeV) << oenum(inter_) << alphaS_ << alphaEM_ << useMEforT2_ << C_ << ymax_ << phaseOpt_; } void PerturbativeDecayer::persistentInput(PersistentIStream & is, int) { is >> iunit(pTmin_,GeV) >> ienum(inter_) >> alphaS_ >> alphaEM_ >> useMEforT2_ >> C_ >> ymax_ >> phaseOpt_; } // The following static variable is needed for the type // description system in ThePEG. DescribeAbstractClass describeHerwigPerturbativeDecayer("Herwig::PerturbativeDecayer", "Herwig.so HwPerturbativeDecay.so"); void PerturbativeDecayer::Init() { static ClassDocumentation documentation ("The PerturbativeDecayer class is the mase class for " "perturbative decays in Herwig"); static Parameter interfacepTmin ("pTmin", "Minimum transverse momentum from gluon radiation", &PerturbativeDecayer::pTmin_, GeV, 1.0*GeV, 0.0*GeV, 10.0*GeV, false, false, Interface::limited); static Switch interfaceInteractions ("Interactions", "which interactions to include for the hard corrections", &PerturbativeDecayer::inter_, ShowerInteraction::QCD, false, false); static SwitchOption interfaceInteractionsQCD (interfaceInteractions, "QCD", "QCD Only", ShowerInteraction::QCD); static SwitchOption interfaceInteractionsQED (interfaceInteractions, "QED", "QED only", ShowerInteraction::QED); static SwitchOption interfaceInteractionsQCDandQED (interfaceInteractions, "QCDandQED", "Both QCD and QED", - ShowerInteraction::Both); + ShowerInteraction::QEDQCD); static Reference interfaceAlphaS ("AlphaS", "Object for the coupling in the generation of hard QCD radiation", &PerturbativeDecayer::alphaS_, false, false, true, true, false); static Reference interfaceAlphaEM ("AlphaEM", "Object for the coupling in the generation of hard QED radiation", &PerturbativeDecayer::alphaEM_, false, false, true, true, false); static Switch interfaceUseMEForT2 ("UseMEForT2", "Use the matrix element correction, if available to fill the T2" " region for the decay shower and don't fill using the shower", &PerturbativeDecayer::useMEforT2_, true, false, false); static SwitchOption interfaceUseMEForT2Shower (interfaceUseMEForT2, "Shower", "Use the shower to fill the T2 region", false); static SwitchOption interfaceUseMEForT2ME (interfaceUseMEForT2, "ME", "Use the Matrix element to fill the T2 region", true); static Parameter interfacePrefactor ("Prefactor", "The prefactor for the sampling of the powheg Sudakov", &PerturbativeDecayer::C_, 6.3, 0.0, 1e10, false, false, Interface::limited); static Parameter interfaceYMax ("YMax", "The maximum value for the rapidity", &PerturbativeDecayer::ymax_, 10., 0.0, 100., false, false, Interface::limited); static Switch interfacePhaseSpaceOption ("PhaseSpaceOption", "Option for the phase-space sampling", &PerturbativeDecayer::phaseOpt_, 0, false, false); static SwitchOption interfacePhaseSpaceOptionFixedYLimits (interfacePhaseSpaceOption, "FixedYLimits", "Use a fixed limit for the rapidity", 0); static SwitchOption interfacePhaseSpaceOptionVariableYLimits (interfacePhaseSpaceOption, "VariableYLimits", "Change limit for the rapidity with pT", 1); } double PerturbativeDecayer::matrixElementRatio(const Particle & , const ParticleVector & , const ParticleVector & , MEOption , ShowerInteraction ) { throw Exception() << "Base class PerturbativeDecayer::matrixElementRatio() " << "called, should have an implementation in the inheriting class" << Exception::runerror; return 0.; } RealEmissionProcessPtr PerturbativeDecayer::generateHardest(RealEmissionProcessPtr born) { return getHardEvent(born,false,inter_); } RealEmissionProcessPtr PerturbativeDecayer::applyHardMatrixElementCorrection(RealEmissionProcessPtr born) { return getHardEvent(born,true,ShowerInteraction::QCD); } RealEmissionProcessPtr PerturbativeDecayer::getHardEvent(RealEmissionProcessPtr born, bool inDeadZone, ShowerInteraction inter) { // check one incoming assert(born->bornIncoming().size()==1); // search for coloured/charged particles bool colouredParticles=born->bornIncoming()[0]->dataPtr()->coloured(); bool chargedParticles=born->bornIncoming()[0]->dataPtr()->charged(); for(unsigned int ix=0;ixbornOutgoing().size();++ix) { if(born->bornOutgoing()[ix]->dataPtr()->coloured()) colouredParticles=true; if(born->bornOutgoing()[ix]->dataPtr()->charged()) chargedParticles=true; } // if no coloured/charged particles return if ( !colouredParticles && !chargedParticles ) return RealEmissionProcessPtr(); if ( !colouredParticles && inter==ShowerInteraction::QCD ) return RealEmissionProcessPtr(); if ( ! chargedParticles && inter==ShowerInteraction::QED ) return RealEmissionProcessPtr(); // check exactly two outgoing particles if(born->bornOutgoing().size()==2) return RealEmissionProcessPtr(); // for decay b -> a c // set progenitors PPtr cProgenitor = born->bornOutgoing()[0]; PPtr aProgenitor = born->bornOutgoing()[1]; // get the decaying particle PPtr bProgenitor = born->bornIncoming()[0]; // identify which dipoles are required vector dipoles; if(!identifyDipoles(dipoles,aProgenitor,bProgenitor,cProgenitor,inter)) { return RealEmissionProcessPtr(); } Energy trialpT = pTmin_; LorentzRotation eventFrame; vector momenta; vector trialMomenta(4); PPtr finalEmitter, finalSpectator; PPtr trialEmitter, trialSpectator; DipoleType finalType(FFa,ShowerInteraction::QCD); for (int i=0; imomentum().findBoostToCM()); Lorentz5Momentum pspectator = (trialEventFrame*trialSpectator->momentum()); trialEventFrame.rotateZ( -pspectator.phi() ); trialEventFrame.rotateY( -pspectator.theta() - Constants::pi ); // invert it trialEventFrame.invert(); // try to generate an emission pT_ = pTmin_; vector trialMomenta = hardMomenta(bProgenitor, trialEmitter, trialSpectator, dipoles, i, inDeadZone); // select dipole which gives highest pT emission if(pT_>trialpT) { trialpT = pT_; momenta = trialMomenta; eventFrame = trialEventFrame; finalEmitter = trialEmitter; finalSpectator = trialSpectator; finalType = dipoles[i]; if (dipoles[i].type==FFc || dipoles[i].type==FFa ) { if((momenta[3]+momenta[1]).m2()-momenta[1].m2()> (momenta[3]+momenta[2]).m2()-momenta[2].m2()) { swap(finalEmitter,finalSpectator); swap(momenta[1],momenta[2]); } } } } pT_ = trialpT; // if no emission return if(momenta.empty()) { - if(inter==ShowerInteraction::Both || inter==ShowerInteraction::QCD) + if(inter==ShowerInteraction::ALL || inter==ShowerInteraction::QEDQCD || inter==ShowerInteraction::QCD) born->pT()[ShowerInteraction::QCD] = pTmin_; - if(inter==ShowerInteraction::Both || inter==ShowerInteraction::QED) + if(inter==ShowerInteraction::ALL || inter==ShowerInteraction::QEDQCD || inter==ShowerInteraction::QED) born->pT()[ShowerInteraction::QED] = pTmin_; return born; } // rotate momenta back to the lab for(unsigned int ix=0;ixpT()[ShowerInteraction::QCD] = pT_; - if(inter==ShowerInteraction::Both || inter==ShowerInteraction::QED) + if(inter==ShowerInteraction::ALL || inter==ShowerInteraction::QEDQCD || inter==ShowerInteraction::QED) born->pT()[ShowerInteraction::QED] = pT_; // get ParticleData objects tcPDPtr b = bProgenitor ->dataPtr(); tcPDPtr e = finalEmitter ->dataPtr(); tcPDPtr s = finalSpectator->dataPtr(); tcPDPtr boson = getParticleData(finalType.interaction==ShowerInteraction::QCD ? ParticleID::g : ParticleID::gamma); // create new ShowerParticles PPtr emitter = e ->produceParticle(momenta[1]); PPtr spectator = s ->produceParticle(momenta[2]); PPtr gauge = boson->produceParticle(momenta[3]); PPtr incoming = b ->produceParticle(bProgenitor->momentum()); // insert the particles born->incoming().push_back(incoming); unsigned int iemit(0),ispect(0); for(unsigned int ix=0;ixbornOutgoing().size();++ix) { if(born->bornOutgoing()[ix]==finalEmitter) { born->outgoing().push_back(emitter); iemit = born->outgoing().size(); } else if(born->bornOutgoing()[ix]==finalSpectator) { born->outgoing().push_back(spectator); ispect = born->outgoing().size(); } } born->outgoing().push_back(gauge); if(!spectator->dataPtr()->coloured() || (finalType.type != FFa && finalType.type!=FFc) ) ispect = 0; born->emitter(iemit); born->spectator(ispect); born->emitted(3); // boost if being use as ME correction if(inDeadZone) { if(finalType.type==IFa || finalType.type==IFba) { LorentzRotation trans(cProgenitor->momentum().findBoostToCM()); trans.boost(spectator->momentum().boostVector()); born->transformation(trans); } else if(finalType.type==IFc || finalType.type==IFbc) { LorentzRotation trans(bProgenitor->momentum().findBoostToCM()); trans.boost(spectator->momentum().boostVector()); born->transformation(trans); } } // set the interaction born->interaction(finalType.interaction); // set up colour lines getColourLines(born); // return the tree return born; } bool PerturbativeDecayer::identifyDipoles(vector & dipoles, PPtr & aProgenitor, PPtr & bProgenitor, PPtr & cProgenitor, ShowerInteraction inter) const { enhance_ = 1.; // identify any QCD dipoles if(inter==ShowerInteraction::QCD || - inter==ShowerInteraction::Both) { + inter==ShowerInteraction::ALL || inter==ShowerInteraction::QEDQCD ) { PDT::Colour bColour = bProgenitor->dataPtr()->iColour(); PDT::Colour cColour = cProgenitor->dataPtr()->iColour(); PDT::Colour aColour = aProgenitor->dataPtr()->iColour(); // decaying colour singlet if (bColour==PDT::Colour0 ) { if ((cColour==PDT::Colour3 && aColour==PDT::Colour3bar) || (cColour==PDT::Colour3bar && aColour==PDT::Colour3) || (cColour==PDT::Colour8 && aColour==PDT::Colour8)){ dipoles.push_back(DipoleType(FFa,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(FFc,ShowerInteraction::QCD)); if(aProgenitor->id()==ParticleID::g && cProgenitor->id()==ParticleID::g ) { enhance_ = 1.5; dipoles.push_back(DipoleType(FFg,ShowerInteraction::QCD)); } } } // decaying colour triplet else if (bColour==PDT::Colour3 ) { if (cColour==PDT::Colour3 && aColour==PDT::Colour0){ dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFc ,ShowerInteraction::QCD)); } else if (cColour==PDT::Colour0 && aColour==PDT::Colour3){ dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFa ,ShowerInteraction::QCD)); } else if (cColour==PDT::Colour8 && aColour==PDT::Colour3){ dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFc ,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(FFc ,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(FFa ,ShowerInteraction::QCD)); } else if (cColour==PDT::Colour3 && aColour==PDT::Colour8){ dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFa ,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(FFc ,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(FFa ,ShowerInteraction::QCD)); } else if(cColour==PDT::Colour3bar && aColour==PDT::Colour3bar) { dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFa,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFc,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(FFc ,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(FFa ,ShowerInteraction::QCD)); } } // decaying colour anti-triplet else if (bColour==PDT::Colour3bar) { if ((cColour==PDT::Colour3bar && aColour==PDT::Colour0)){ dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFc ,ShowerInteraction::QCD)); } else if ((cColour==PDT::Colour0 && aColour==PDT::Colour3bar)){ dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFa ,ShowerInteraction::QCD)); } else if (cColour==PDT::Colour8 && aColour==PDT::Colour3bar){ dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFc ,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(FFc ,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(FFa ,ShowerInteraction::QCD)); } else if (cColour==PDT::Colour3bar && aColour==PDT::Colour8){ dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFa ,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(FFc ,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(FFa ,ShowerInteraction::QCD)); } else if(cColour==PDT::Colour3 && aColour==PDT::Colour3) { dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFa,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFc,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(FFc ,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(FFa ,ShowerInteraction::QCD)); } } // decaying colour octet else if (bColour==PDT::Colour8){ if ((cColour==PDT::Colour3 && aColour==PDT::Colour3bar) || (cColour==PDT::Colour3bar && aColour==PDT::Colour3)){ dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFa,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFc,ShowerInteraction::QCD)); } else if (cColour==PDT::Colour8 && aColour==PDT::Colour0){ dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFc,ShowerInteraction::QCD)); } else if (cColour==PDT::Colour0 && aColour==PDT::Colour8){ dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFa,ShowerInteraction::QCD)); } } // decaying colour sextet else if(bColour==PDT::Colour6) { if (cColour==PDT::Colour3 && aColour==PDT::Colour3) { dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFa,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFc,ShowerInteraction::QCD)); } } // decaying colour antisextet else if(bColour==PDT::Colour6bar) { if (cColour==PDT::Colour3bar && aColour==PDT::Colour3bar) { dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFa,ShowerInteraction::QCD)); dipoles.push_back(DipoleType(IFc,ShowerInteraction::QCD)); } } } // QED dipoles - if(inter==ShowerInteraction::Both || + if(inter==ShowerInteraction::ALL || inter==ShowerInteraction::QEDQCD || inter==ShowerInteraction::QED) { const bool & bCharged = bProgenitor->dataPtr()->charged(); const bool & cCharged = cProgenitor->dataPtr()->charged(); const bool & aCharged = aProgenitor->dataPtr()->charged(); // initial-final if(bCharged && aCharged) { dipoles.push_back(DipoleType(IFba,ShowerInteraction::QED)); dipoles.push_back(DipoleType(IFa ,ShowerInteraction::QED)); } if(bCharged && cCharged) { dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QED)); dipoles.push_back(DipoleType(IFc ,ShowerInteraction::QED)); } // final-state if(aCharged && cCharged) { dipoles.push_back(DipoleType(FFa,ShowerInteraction::QED)); dipoles.push_back(DipoleType(FFc,ShowerInteraction::QED)); } } // check colour structure is allowed return !dipoles.empty(); } vector PerturbativeDecayer::hardMomenta(PPtr in, PPtr emitter, PPtr spectator, const vector &dipoles, int i, bool inDeadZone) { // get masses of the particles mb_ = in ->momentum().mass(); e_ = emitter ->momentum().mass()/mb_; s_ = spectator->momentum().mass()/mb_; e2_ = sqr(e_); s2_ = sqr(s_); vector particleMomenta; Energy2 lambda = sqr(mb_)*sqrt(1.+sqr(s2_)+sqr(e2_)-2.*s2_-2.*e2_-2.*s2_*e2_); // calculate A double pre = C_; // multiply by the colour factor of the dipole // ISR if (dipoles[i].type==IFba || dipoles[i].type==IFbc) { pre *= colourCoeff(in->dataPtr(),emitter->dataPtr(),spectator->dataPtr(),dipoles[i]); } // radiation from a/c with initial-final connection else if (dipoles[i].type==IFa || dipoles[i].type==IFc) { pre *= colourCoeff(emitter->dataPtr(),in->dataPtr(),spectator->dataPtr(),dipoles[i]); } // radiation from a/c with final-final connection else if (dipoles[i].type==FFa || dipoles[i].type==FFc) { pre *= colourCoeff(emitter->dataPtr(),spectator->dataPtr(),in->dataPtr(),dipoles[i]); } double A = 2.*abs(pre)/Constants::twopi; // factor due sampling choice if(phaseOpt_==0) A *= ymax_; // coupling factor if(dipoles[i].interaction==ShowerInteraction::QCD) A *= alphaS() ->overestimateValue(); else A *= alphaEM()->overestimateValue(); Energy pTmax = 0.5*mb_*(1.-sqr(s_+e_)); // if no possible branching return if ( pTmax < pTmin_ ) return particleMomenta; // loop over the two regions for(unsigned int j=0;j<2;++j) { Energy pT=pTmax; vector momenta(4); while (pT >= pTmin_) { double ymax; // overestimate with flat y limit if(phaseOpt_==0) { pT *= pow(UseRandom::rnd(),(1./A)); ymax=ymax_; } // pT sampling including tighter pT dependent y limit else { pT = 2.*pTmax*exp(-sqrt(-2.*log(UseRandom::rnd())/A+sqr(log(2.*pTmax/pT)))); // choice of limit overestimate ln(2*pTmax/pT) (true limit acosh(pTmax/pT)) ymax = log(2.*pTmax/pT); } if (pT < pTmin_) break; double phi = UseRandom::rnd()*Constants::twopi; double y = ymax*(2.*UseRandom::rnd()-1.); double xs, xe, xe_z, xg; // check if the momenta are physical if (!calcMomenta(j, pT, y, phi, xg, xs, xe, xe_z, momenta)) continue; // check if point lies within phase space if (!psCheck(xg, xs)) continue; // check if point lies within the dead-zone (if required) if(inDeadZone && !inTotalDeadZone(xg,xs,dipoles,i)) continue; // decay products for 3 body decay PPtr inpart = in ->dataPtr()->produceParticle(momenta[0]); ParticleVector decay3; decay3.push_back(emitter ->dataPtr()->produceParticle(momenta[1])); decay3.push_back(spectator->dataPtr()->produceParticle(momenta[2])); if(dipoles[i].interaction==ShowerInteraction::QCD) decay3.push_back(getParticleData(ParticleID::g )->produceParticle(momenta[3])); else decay3.push_back(getParticleData(ParticleID::gamma)->produceParticle(momenta[3])); // decay products for 2 body decay Lorentz5Momentum p1(ZERO,ZERO, lambda/2./mb_,(mb_/2.)*(1.+e2_-s2_),mb_*e_); Lorentz5Momentum p2(ZERO,ZERO,-lambda/2./mb_,(mb_/2.)*(1.+s2_-e2_),mb_*s_); ParticleVector decay2; decay2.push_back(emitter ->dataPtr()->produceParticle(p1)); decay2.push_back(spectator->dataPtr()->produceParticle(p2)); if (dipoles[i].type==FFa || dipoles[i].type==IFa || dipoles[i].type==IFba) { swap(decay2[0],decay2[1]); swap(decay3[0],decay3[1]); } // calculate matrix element ratio R/B double meRatio = matrixElementRatio(*inpart,decay2,decay3,Initialize,dipoles[i].interaction); // calculate dipole factor double dipoleSum(0.),numerator(0.); for (int k=0; k dipole = calculateDipole(dipoles[k],*inpart,decay3); dipoleSum += abs(dipole.first); if (k==i) numerator = abs(dipole.second); } meRatio *= numerator/dipoleSum; // calculate jacobian Energy2 denom = (mb_-momenta[3].e())*momenta[2].vect().mag() - momenta[2].e()*momenta[3].z(); InvEnergy2 J = (momenta[2].vect().mag2())/(lambda*denom); // calculate weight double weight = enhance_*meRatio*fabs(sqr(pT)*J)/pre/Constants::twopi; if(dipoles[i].interaction==ShowerInteraction::QCD) weight *= alphaS() ->ratio(pT*pT); else weight *= alphaEM()->ratio(pT*pT); // accept point if weight > R if (pT > pT_ && weight > UseRandom::rnd()) { particleMomenta=momenta; if (weight > 1.) { generator()->log() << "WEIGHT PROBLEM " << fullName() << " " << weight << "\n"; generator()->log() << xe << " " << xs << " " << xg << "\n"; for(unsigned int ix=0;ixlog() << particleMomenta[ix]/GeV << "\n"; } pT_ = pT; break; } } } return particleMomenta; } bool PerturbativeDecayer::calcMomenta(int j, Energy pT, double y, double phi, double& xg, double& xs, double& xe, double& xe_z, vector& particleMomenta) { // calculate xg xg = 2.*pT*cosh(y) / mb_; if (xg>(1. - sqr(e_ + s_)) || xg<0.) return false; // calculate the two values of zs double xT = 2.*pT / mb_; double zg = 2.*pT*sinh(y) / mb_; double A = (sqr(xT) - 4. * xg + 4.); double B = 2. * zg * (s2_ - e2_ - xg + 1.); double det = -4. * (-sqr(s2_) + (2. * e2_ + sqr(xT) - 2. * xg + 2.) * s2_ - sqr(e2_ + xg - 1.)) * sqr(xg - 2.); if (det<0.) return false; double zs= j==0 ? (-B+sqrt(det))/A : (-B-sqrt(det))/A; // zs must be negative if(zs>0.) return false; xs = sqrt(sqr(zs)+4.*s2_); // check value of xs is physical if (xs>(1.+s2_-e2_) || xs<2.*s_) return false; // calculate xe xe = 2.-xs-xg; // check value of xe is physical if (xe>(1.+e2_-s2_) || xe<2.*e_) return false; // calculate xe_z xe_z = -zg-zs; // calculate 4 momenta particleMomenta[0].setE ( mb_); particleMomenta[0].setX ( ZERO); particleMomenta[0].setY ( ZERO); particleMomenta[0].setZ ( ZERO); particleMomenta[0].setMass( mb_); particleMomenta[1].setE ( mb_*xe/2.); particleMomenta[1].setX (-pT*cos(phi)); particleMomenta[1].setY (-pT*sin(phi)); particleMomenta[1].setZ ( mb_*xe_z/2.); particleMomenta[1].setMass( mb_*e_); particleMomenta[2].setE ( mb_*xs/2.); particleMomenta[2].setX ( ZERO); particleMomenta[2].setY ( ZERO); particleMomenta[2].setZ ( mb_*zs/2.); particleMomenta[2].setMass( mb_*s_); particleMomenta[3].setE ( pT*cosh(y)); particleMomenta[3].setX ( pT*cos(phi)); particleMomenta[3].setY ( pT*sin(phi)); particleMomenta[3].setZ ( pT*sinh(y)); particleMomenta[3].setMass( ZERO); return true; } bool PerturbativeDecayer::psCheck(const double xg, const double xs) { // check is point is in allowed region of phase space double xe_star = (1.-s2_+e2_-xg)/sqrt(1.-xg); double xg_star = xg/sqrt(1.-xg); if ((sqr(xe_star)-4.*e2_) < 1e-10) return false; double xs_max = (4.+4.*s2_-sqr(xe_star+xg_star)+ sqr(sqrt(sqr(xe_star)-4.*e2_)+xg_star))/ 4.; double xs_min = (4.+4.*s2_-sqr(xe_star+xg_star)+ sqr(sqrt(sqr(xe_star)-4.*e2_)-xg_star))/ 4.; if (xs < xs_min || xs > xs_max) return false; return true; } pair PerturbativeDecayer::calculateDipole(const DipoleType & dipoleId, const Particle & inpart, const ParticleVector & decay3) { // calculate dipole for decay b->ac pair dipole = make_pair(0.,0.); double x1 = 2.*decay3[0]->momentum().e()/mb_; double x2 = 2.*decay3[1]->momentum().e()/mb_; double xg = 2.*decay3[2]->momentum().e()/mb_; double mu12 = sqr(decay3[0]->mass()/mb_); double mu22 = sqr(decay3[1]->mass()/mb_); tcPDPtr part[3] = {inpart.dataPtr(),decay3[0]->dataPtr(),decay3[1]->dataPtr()}; if(dipoleId.type==FFa || dipoleId.type == IFa || dipoleId.type == IFba) { swap(part[1],part[2]); swap(x1,x2); swap(mu12,mu22); } // radiation from b with initial-final connection if (dipoleId.type==IFba || dipoleId.type==IFbc) { dipole.first = -2./sqr(xg); dipole.first *= colourCoeff(part[0],part[1],part[2],dipoleId); } // radiation from a/c with initial-final connection else if (dipoleId.type==IFa || dipoleId.type==IFc) { double z = 1. - xg/(1.-mu22+mu12); dipole.first = (-2.*mu12/sqr(1.-x2+mu22-mu12) + (1./(1.-x2+mu22-mu12))* (2./(1.-z)-dipoleSpinFactor(part[1],z))); dipole.first *= colourCoeff(part[1],part[0],part[2],dipoleId); } // radiation from a/c with final-final connection else if (dipoleId.type==FFa || dipoleId.type==FFc) { double z = 1. + ((x1-1.+mu22-mu12)/(x2-2.*mu22)); double y = (1.-x2-mu12+mu22)/(1.-mu12-mu22); double vt = sqrt((1.-sqr(e_+s_))*(1.-sqr(e_-s_)))/(1.-mu12-mu22); double v = sqrt(sqr(2.*mu22+(1.-mu12-mu22)*(1.-y))-4.*mu22) /(1.-y)/(1.-mu12-mu22); if(part[1]->iSpin()!=PDT::Spin1) { dipole.first = (1./(1.-x2+mu22-mu12))* ((2./(1.-z*(1.-y)))-vt/v*(dipoleSpinFactor(part[1],z)+(2.*mu12/(1.+mu22-mu12-x2)))); } else { dipole.first = (1./(1.-x2+mu22-mu12))* (1./(1.-z*(1.-y))+1./(1.-(1.-z)*(1.-y))+(z*(1.-z)-2.)/v-vt/v*(2.*mu12/(1.+mu22-mu12-x2))); dipole.second = (1./(1.-x2+mu22-mu12))* (2./(1.-z*(1.-y))+(z*(1.-z)-2.)/v-vt/v*(2.*mu12/(1.+mu22-mu12-x2))); dipole.second *= colourCoeff(part[1],part[2],part[0],dipoleId); } dipole.first *= colourCoeff(part[1],part[2],part[0],dipoleId); } // special for the case that all particles are gluons else if(dipoleId.type==FFg) { double z = (1.-x2)/xg; double y = 1.-xg; dipole.first = 1./(1.-xg)*(1./(1.-z*(1.-y))+1./(1.-(1.-z)*(1.-y))+(z*(1.-z)-2.)); dipole.first *= colourCoeff(part[1],part[2],part[0],dipoleId); } else assert(false); // coupling prefactors if(dipole.second==0.) dipole.second=dipole.first; dipole.first *= 8.*Constants::pi; dipole.second *= 8.*Constants::pi; // return the answer return dipole; } double PerturbativeDecayer::dipoleSpinFactor(tcPDPtr part, double z){ // calculate the spin dependent component of the dipole if (part->iSpin()==PDT::Spin0) return 2.; else if (part->iSpin()==PDT::Spin1Half) return (1. + z); else if (part->iSpin()==PDT::Spin1) return -(z*(1.-z) - 1./(1.-z) + 1./z -2.); return 0.; } namespace { double colourCharge(PDT::Colour icol) { switch(icol) { case PDT::Colour0 : return 0.; case PDT::Colour3 : case PDT::Colour3bar : return 4./3.; case PDT::Colour8: return 3.; case PDT::Colour6 : case PDT::Colour6bar : return 10./3.; default : assert(false); return 0.; } } } double PerturbativeDecayer::colourCoeff(tcPDPtr emitter, tcPDPtr spectator, tcPDPtr other, DipoleType dipole) { if(dipole.interaction==ShowerInteraction::QCD) { double emitterColour = colourCharge(emitter ->iColour()); double spectatorColour = colourCharge(spectator->iColour()); double otherColour = colourCharge(other ->iColour()); double val = 0.5*(sqr(emitterColour)+sqr(spectatorColour)-sqr(otherColour))/emitterColour; return val; } else { double val = double(emitter->iCharge()*spectator->iCharge())/9.; // FF dipoles if(dipole.type==FFa || dipole.type == FFc) return -val; // IF dipoles else return val; } } void PerturbativeDecayer::getColourLines(RealEmissionProcessPtr real) { // extract the particles vector branchingPart; branchingPart.push_back(real->incoming()[0]); for(unsigned int ix=0;ixoutgoing().size();++ix) { branchingPart.push_back(real->outgoing()[ix]); } vector sing,trip,atrip,oct,sex,asex; for (size_t ib=0;ibdataPtr()->iColour()==PDT::Colour0 ) sing. push_back(ib); else if(branchingPart[ib]->dataPtr()->iColour()==PDT::Colour3 ) trip. push_back(ib); else if(branchingPart[ib]->dataPtr()->iColour()==PDT::Colour3bar) atrip.push_back(ib); else if(branchingPart[ib]->dataPtr()->iColour()==PDT::Colour8 ) oct. push_back(ib); else if(branchingPart[ib]->dataPtr()->iColour()==PDT::Colour6 ) sex. push_back(ib); else if(branchingPart[ib]->dataPtr()->iColour()==PDT::Colour6bar) asex. push_back(ib); } // decaying colour singlet if (branchingPart[0]->dataPtr()->iColour()==PDT::Colour0) { // 0 -> 3 3bar if (trip.size()==1 && atrip.size()==1) { if(real->interaction()==ShowerInteraction::QCD) { branchingPart[atrip[0]]->colourConnect(branchingPart[ 3 ]); branchingPart[ 3 ]->colourConnect(branchingPart[trip[0]]); } else { branchingPart[atrip[0]]->colourConnect(branchingPart[trip[0]]); } } // 0 -> 8 8 else if (oct.size()==2 ) { if(real->interaction()==ShowerInteraction::QCD) { bool col = UseRandom::rndbool(); branchingPart[oct[0]]->colourConnect(branchingPart[ 3 ],col); branchingPart[ 3 ]->colourConnect(branchingPart[oct[1]],col); branchingPart[oct[1]]->colourConnect(branchingPart[oct[0]],col); } else { branchingPart[oct[0]]->colourConnect(branchingPart[oct[1]]); branchingPart[oct[1]]->colourConnect(branchingPart[oct[0]]); } } else assert(real->interaction()==ShowerInteraction::QED); } // decaying colour triplet else if (branchingPart[0]->dataPtr()->iColour()==PDT::Colour3 ) { // 3 -> 3 0 if (trip.size()==2 && sing.size()==1) { if(real->interaction()==ShowerInteraction::QCD) { branchingPart[3]->incomingColour(branchingPart[trip[0]]); branchingPart[3]-> colourConnect(branchingPart[trip[1]]); } else { branchingPart[trip[1]]->incomingColour(branchingPart[trip[0]]); } } // 3 -> 3 8 else if (trip.size()==2 && oct.size()==1) { if(real->interaction()==ShowerInteraction::QCD) { // 8 emit incoming partner if(real->emitter()==oct[0]&&real->spectator()==0) { branchingPart[ 3 ]->incomingColour(branchingPart[trip[0]]); branchingPart[ 3 ]-> colourConnect(branchingPart[oct[0] ]); branchingPart[oct[0]]-> colourConnect(branchingPart[trip[1]]); } // 8 emit final spectator or vice veras else { branchingPart[oct[0]]->incomingColour(branchingPart[trip[0]]); branchingPart[oct[0]]-> colourConnect(branchingPart[ 3 ]); branchingPart[ 3 ]-> colourConnect(branchingPart[trip[1]]); } } else { branchingPart[oct[0]]->incomingColour(branchingPart[trip[0]]); branchingPart[oct[0]]-> colourConnect(branchingPart[trip[1]]); } } // 3 -> 3bar 3bar else if(trip.size() ==1 && atrip.size()==2) { if(real->interaction()==ShowerInteraction::QCD) { if(real->emitter()==atrip[0]) { branchingPart[3]->colourConnect(branchingPart[atrip[0]],true); tColinePtr col[3] = {ColourLine::create(branchingPart[ trip[0]],false), ColourLine::create(branchingPart[ 3],true ), ColourLine::create(branchingPart[atrip[1]],true)}; col[0]->setSinkNeighbours(col[1],col[2]); } else { branchingPart[3]->colourConnect(branchingPart[atrip[1]],true); tColinePtr col[3] = {ColourLine::create(branchingPart[ trip[0]],false), ColourLine::create(branchingPart[atrip[0]],true ), ColourLine::create(branchingPart[ 3],true)}; col[0]->setSinkNeighbours(col[1],col[2]); } } else { tColinePtr col[3] = {ColourLine::create(branchingPart[ trip[0]],false), ColourLine::create(branchingPart[atrip[0]],true ), ColourLine::create(branchingPart[atrip[1]],true)}; col[0]->setSinkNeighbours(col[1],col[2]); } } else assert(false); } // decaying colour anti-triplet else if (branchingPart[0]->dataPtr()->iColour()==PDT::Colour3bar) { // 3bar -> 3bar 0 if (atrip.size()==2 && sing.size()==1) { if(real->interaction()==ShowerInteraction::QCD) { branchingPart[3]->incomingColour(branchingPart[atrip[0]],true); branchingPart[3]-> colourConnect(branchingPart[atrip[1]],true); } else { branchingPart[atrip[1]]->incomingColour(branchingPart[atrip[0]],true); } } // 3 -> 3 8 else if (atrip.size()==2 && oct.size()==1){ if(real->interaction()==ShowerInteraction::QCD) { // 8 emit incoming partner if(real->emitter()==oct[0]&&real->spectator()==0) { branchingPart[ 3 ]->incomingColour(branchingPart[atrip[0]],true); branchingPart[ 3 ]-> colourConnect(branchingPart[oct[0] ],true); branchingPart[oct[0]]-> colourConnect(branchingPart[atrip[1]],true); } // 8 emit final spectator or vice veras else { if(real->interaction()==ShowerInteraction::QCD) { branchingPart[oct[0]]->incomingColour(branchingPart[atrip[0]],true); branchingPart[oct[0]]-> colourConnect(branchingPart[ 3 ],true); branchingPart[3]-> colourConnect(branchingPart[atrip[1]] ,true); } } } else { branchingPart[oct[0]]->incomingColour(branchingPart[atrip[0]],true); branchingPart[oct[0]]-> colourConnect(branchingPart[atrip[1]],true); } } // 3bar -> 3 3 else if(atrip.size() ==1 && trip.size()==2) { if(real->interaction()==ShowerInteraction::QCD) { if(real->emitter()==trip[0]) { branchingPart[3]->colourConnect(branchingPart[trip[0]],false); tColinePtr col[3] = {ColourLine::create(branchingPart[atrip[0]],true ), ColourLine::create(branchingPart[ 3],false), ColourLine::create(branchingPart[ trip[1]],false)}; col[0]->setSourceNeighbours(col[1],col[2]); } else { branchingPart[3]->colourConnect(branchingPart[trip[1]],false); tColinePtr col[3] = {ColourLine::create(branchingPart[atrip[0]],true ), ColourLine::create(branchingPart[ trip[0]],false), ColourLine::create(branchingPart[ 3],false)}; col[0]->setSourceNeighbours(col[1],col[2]); } } else { tColinePtr col[3] = {ColourLine::create(branchingPart[atrip[0]],true ), ColourLine::create(branchingPart[ trip[0]],false), ColourLine::create(branchingPart[ trip[1]],false)}; col[0]->setSourceNeighbours(col[1],col[2]); } } else assert(false); } // decaying colour octet else if(branchingPart[0]->dataPtr()->iColour()==PDT::Colour8 ) { // 8 -> 3 3bar if (trip.size()==1 && atrip.size()==1) { if(real->interaction()==ShowerInteraction::QCD) { // 3 emits if(trip[0]==real->emitter()) { branchingPart[3] ->incomingColour(branchingPart[oct[0]] ); branchingPart[3] -> colourConnect(branchingPart[trip[0]]); branchingPart[atrip[0]]->incomingColour(branchingPart[oct[0]],true); } // 3bar emits else { branchingPart[3] ->incomingColour(branchingPart[oct[0]] ,true); branchingPart[3] -> colourConnect(branchingPart[atrip[0]],true); branchingPart[trip[0]]->incomingColour(branchingPart[oct[0]] ); } } else { branchingPart[trip[0]]->incomingColour(branchingPart[oct[0]] ); branchingPart[atrip[0]]->incomingColour(branchingPart[oct[0]],true); } } // 8 -> 8 0 else if (sing.size()==1 && oct.size()==2) { if(real->interaction()==ShowerInteraction::QCD) { bool col = UseRandom::rndbool(); branchingPart[ 3 ]->colourConnect (branchingPart[oct[1]], col); branchingPart[ 3 ]->incomingColour(branchingPart[oct[0]], col); branchingPart[oct[1]]->incomingColour(branchingPart[oct[0]],!col); } else { branchingPart[oct[1]]->incomingColour(branchingPart[oct[0]]); branchingPart[oct[1]]->incomingColour(branchingPart[oct[0]],true); } } else assert(false); } // sextet else if(branchingPart[0]->dataPtr()->iColour() == PDT::Colour6) { if(trip.size()==2) { if(real->interaction()==ShowerInteraction::QCD) { Ptr::pointer parentColour = dynamic_ptr_cast::pointer> (branchingPart[0]->colourInfo()); if(trip[0]==real->emitter()) { ColinePtr cline = new_ptr(ColourLine()); parentColour->colourLine(cline); cline->addColoured(branchingPart[3]); branchingPart[3] -> colourConnect(branchingPart[trip[0]]); cline = new_ptr(ColourLine()); parentColour->colourLine(cline); cline->addColoured(branchingPart[trip[1]]); } else { ColinePtr cline = new_ptr(ColourLine()); parentColour->colourLine(cline); cline->addColoured(branchingPart[3]); branchingPart[3] -> colourConnect(branchingPart[trip[1]]); cline = new_ptr(ColourLine()); parentColour->colourLine(cline); cline->addColoured(branchingPart[trip[0]]); } } else { Ptr::pointer parentColour = dynamic_ptr_cast::pointer> (branchingPart[0]->colourInfo()); for(unsigned int ix=0;ix<2;++ix) { ColinePtr cline = new_ptr(ColourLine()); parentColour->colourLine(cline); cline->addColoured(branchingPart[trip[ix]]); } } } else assert(false); } // antisextet else if(branchingPart[0]->dataPtr()->iColour() == PDT::Colour6bar) { if(atrip.size()==2) { if(real->interaction()==ShowerInteraction::QCD) { Ptr::pointer parentColour = dynamic_ptr_cast::pointer> (branchingPart[0]->colourInfo()); if(atrip[0]==real->emitter()) { ColinePtr cline = new_ptr(ColourLine()); parentColour->antiColourLine(cline); cline->addAntiColoured(branchingPart[3]); branchingPart[3]->antiColourConnect(branchingPart[atrip[0]]); cline = new_ptr(ColourLine()); parentColour->antiColourLine(cline); cline->addAntiColoured(branchingPart[atrip[1]]); } else { ColinePtr cline = new_ptr(ColourLine()); parentColour->antiColourLine(cline); cline->addAntiColoured(branchingPart[3]); branchingPart[3]->antiColourConnect(branchingPart[atrip[1]]); cline = new_ptr(ColourLine()); parentColour->antiColourLine(cline); cline->addAntiColoured(branchingPart[trip[0]]); } } else { Ptr::pointer parentColour = dynamic_ptr_cast::pointer> (branchingPart[0]->colourInfo()); for(unsigned int ix=0;ix<2;++ix) { ColinePtr cline = new_ptr(ColourLine()); parentColour->antiColourLine(cline); cline->addColoured(branchingPart[atrip[ix]],true); } } } else assert(false); } else assert(false); } PerturbativeDecayer::phaseSpaceRegion PerturbativeDecayer::inInitialFinalDeadZone(double xg, double xa, double a, double c) const { double lam = sqrt(1.+a*a+c*c-2.*a-2.*c-2.*a*c); double kappab = 1.+0.5*(1.-a+c+lam); double kappac = kappab-1.+c; double kappa(0.); // check whether or not in the region for emission from c double r = 0.5; if(c!=0.) r += 0.5*c/(1.+a-xa); double pa = sqrt(sqr(xa)-4.*a); double z = ((2.-xa)*(1.-r)+r*pa-xg)/pa; if(z<1. && z>0.) { kappa = (1.+a-c-xa)/(z*(1.-z)); if(kappa-1e-10) v= 0.; v = sqrt(v); if(xa<0.5*((u+v)/w+(u-v)/z)) { if(xg0.) { if((1.-b+c-xc)/(z*(1.-z))<0.5*(1.+b-c+lam)) return emissionFromB; } // check whether or not in the region for emission from c r = 0.5; if(c!=0.) r+=0.5*c/(1.+b-xb); double pb = sqrt(sqr(xb)-4.*b); z = -((2.-xb)*r-r*pb-xc)/pb; if(z<1. and z>0.) { if((1.-c+b-xb)/(z*(1.-z))<0.5*(1.-b+c+lam)) return emissionFromC; } return deadZone; } bool PerturbativeDecayer::inTotalDeadZone(double xg, double xs, const vector & dipoles, int i) { double xb,xc,b,c; if(dipoles[i].type==FFa || dipoles[i].type == IFa || dipoles[i].type == IFba) { xc = xs; xb = 2.-xg-xs; b = e2_; c = s2_; } else { xb = xs; xc = 2.-xg-xs; b = s2_; c = e2_; } for(unsigned int ix=0;ix #include "Herwig/Shower/RealEmissionProcess.h" using namespace Herwig; using namespace ThePEG::Helicity; // namespace { // using namespace Herwig; // using namespace ThePEG::Helicity; // // void debuggingMatrixElement(bool BGF,const Lorentz5Momentum & pin, // const Lorentz5Momentum & p1, // const Lorentz5Momentum & p2, // tcPDPtr gluon, // const Lorentz5Momentum & pl1, // const Lorentz5Momentum & pl2, // const Lorentz5Momentum & pq1, // const Lorentz5Momentum & pq2, // tcPDPtr lepton1,tcPDPtr lepton2, // tcPDPtr quark1 ,tcPDPtr quark2, // Energy2 Q2,double phi, double x2, double x3, // double xperp, double zp, double xp, // const vector & azicoeff, // bool normalize) { // tcHwSMPtr hwsm=ThePEG::dynamic_ptr_cast // (CurrentGenerator::current().standardModel()); // assert(hwsm); // vector weakVertex; // vector bosons; // AbstractFFVVertexPtr strongVertex = hwsm->vertexFFG(); // if(lepton1->id()==lepton2->id()) { // weakVertex.push_back(hwsm->vertexFFZ()); // bosons.push_back(hwsm->getParticleData(ParticleID::Z0)); // weakVertex.push_back(hwsm->vertexFFP()); // bosons.push_back(hwsm->getParticleData(ParticleID::gamma)); // } // else { // weakVertex.push_back(hwsm->vertexFFW()); // bosons.push_back(hwsm->getParticleData(ParticleID::Wplus)); // } // if(!BGF) { // SpinorWaveFunction l1,q1,qp1; // SpinorBarWaveFunction l2,q2,qp2; // VectorWaveFunction gl(p2,gluon,outgoing); // if(lepton1->id()>0) { // l1 = SpinorWaveFunction (pl1,lepton1,incoming); // l2 = SpinorBarWaveFunction(pl2,lepton2,outgoing); // } // else { // l1 = SpinorWaveFunction (pl2,lepton2,outgoing); // l2 = SpinorBarWaveFunction(pl1,lepton1,incoming); // } // if(quark1->id()>0) { // q1 = SpinorWaveFunction (pq1,quark1,incoming); // q2 = SpinorBarWaveFunction(pq2,quark2,outgoing); // qp1 = SpinorWaveFunction (pin,quark1,incoming); // qp2 = SpinorBarWaveFunction(p1 ,quark2,outgoing); // } // else { // q1 = SpinorWaveFunction (pq2,quark2,outgoing); // q2 = SpinorBarWaveFunction(pq1,quark1,incoming); // qp1 = SpinorWaveFunction (p1 ,quark2,outgoing); // qp2 = SpinorBarWaveFunction(pin,quark1,incoming); // } // double lome(0.),realme(0.); // for(unsigned int lhel1=0;lhel1<2;++lhel1) { // l1.reset(lhel1); // for(unsigned int lhel2=0;lhel2<2;++lhel2) { // l2.reset(lhel2); // for(unsigned int qhel1=0;qhel1<2;++qhel1) { // q1.reset(qhel1); // qp1.reset(qhel1); // for(unsigned int qhel2=0;qhel2<2;++qhel2) { // q2.reset(qhel2); // qp2.reset(qhel2); // // leading order matrix element // Complex diagLO(0.); // for(unsigned int ix=0;ixevaluate(Q2,3,bosons[ix],l1,l2); // diagLO += weakVertex[ix]->evaluate(Q2,q1,q2,inter); // } // lome += norm(diagLO); // // real emission matrix element // for(unsigned int ghel=0;ghel<2;++ghel) { // gl.reset(2*ghel); // Complex diagReal(0.); // for(unsigned int ix=0;ixevaluate(Q2,3,bosons[ix],l1,l2); // SpinorWaveFunction off1 = // strongVertex->evaluate(Q2,5,qp1.particle(),qp1,gl); // Complex diag1 = weakVertex[ix]->evaluate(Q2,off1,qp2,inter); // SpinorBarWaveFunction off2 = // strongVertex->evaluate(Q2,5,qp2.particle(),qp2,gl); // Complex diag2 = weakVertex[ix]->evaluate(Q2,qp1,off2,inter); // diagReal += diag1+diag2; // } // realme += norm(diagReal); // } // } // } // } // } // double test1 = realme/lome/hwsm->alphaS(Q2)*Q2*UnitRemoval::InvE2; // double cphi(cos(phi)); // double test2; // if(normalize) { // test2 = 8.*Constants::pi/(1.-xp)/(1.-zp)* // (azicoeff[0]+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi))* // (1.+sqr(xp)*(sqr(x2)+1.5*sqr(xperp))); // } // else { // test2 = 8.*Constants::pi/(1.-xp)/(1.-zp)* // (azicoeff[0]+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi)); // } // cerr << "testing RATIO A " << test1/test2 << "\n"; // } // else { // SpinorWaveFunction l1,q1,qp1; // SpinorBarWaveFunction l2,q2,qp2; // VectorWaveFunction gl(pin,gluon,incoming); // if(lepton1->id()>0) { // l1 = SpinorWaveFunction (pl1,lepton1,incoming); // l2 = SpinorBarWaveFunction(pl2,lepton2,outgoing); // } // else { // l1 = SpinorWaveFunction (pl2,lepton2,outgoing); // l2 = SpinorBarWaveFunction(pl1,lepton1,incoming); // } // if(quark1->id()>0) { // q1 = SpinorWaveFunction (pq1,quark1 ,incoming); // q2 = SpinorBarWaveFunction(pq2,quark2 ,outgoing); // qp2 = SpinorBarWaveFunction(p1 ,quark2 ,outgoing); // qp1 = SpinorWaveFunction (p2 ,quark1->CC(),outgoing); // } // else { // q1 = SpinorWaveFunction (pq2,quark2 ,outgoing); // q2 = SpinorBarWaveFunction(pq1,quark1 ,incoming); // qp2 = SpinorBarWaveFunction(p2 ,quark1->CC(),outgoing); // qp1 = SpinorWaveFunction (p1 ,quark2 ,outgoing); // } // double lome(0.),realme(0.); // for(unsigned int lhel1=0;lhel1<2;++lhel1) { // l1.reset(lhel1); // for(unsigned int lhel2=0;lhel2<2;++lhel2) { // l2.reset(lhel2); // for(unsigned int qhel1=0;qhel1<2;++qhel1) { // q1.reset(qhel1); // qp1.reset(qhel1); // for(unsigned int qhel2=0;qhel2<2;++qhel2) { // q2.reset(qhel2); // qp2.reset(qhel2); // // leading order matrix element // Complex diagLO(0.); // for(unsigned int ix=0;ixevaluate(Q2,3,bosons[ix],l1,l2); // diagLO += weakVertex[ix]->evaluate(Q2,q1,q2,inter); // } // lome += norm(diagLO); // // real emission matrix element // for(unsigned int ghel=0;ghel<2;++ghel) { // gl.reset(2*ghel); // Complex diagReal(0.); // for(unsigned int ix=0;ixevaluate(Q2,3,bosons[ix],l1,l2); // SpinorWaveFunction off1 = // strongVertex->evaluate(Q2,5,qp1.particle(),qp1,gl); // Complex diag1 = weakVertex[ix]->evaluate(Q2,off1,qp2,inter); // SpinorBarWaveFunction off2 = // strongVertex->evaluate(Q2,5,qp2.particle(),qp2,gl); // Complex diag2 = weakVertex[ix]->evaluate(Q2,qp1,off2,inter); // diagReal += diag1+diag2; // } // realme += norm(diagReal); // } // } // } // } // } // double test1 = realme/lome/hwsm->alphaS(Q2)*Q2*UnitRemoval::InvE2; // double cphi(cos(phi)); // double test2; // if(normalize) { // test2 = 8.*Constants::pi/zp/(1.-zp)* // (azicoeff[0]+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi))* // sqr(xp)*(sqr(x3)+sqr(x2)+3.*sqr(xperp)); // } // else { // test2 = 8.*Constants::pi/zp/(1.-zp)* // (azicoeff[0]+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi)); // } // cerr << "testing RATIO B " << test1/test2 << "\n"; // } // } // // } DISBase::DISBase() : initial_(6.), final_(3.), procProb_(0.35), comptonInt_(0.), bgfInt_(0.), comptonWeight_(50.), BGFWeight_(150.), pTmin_(0.1*GeV), scaleOpt_(1), muF_(100.*GeV), scaleFact_(1.), contrib_(0), power_(0.1) {} DISBase::~DISBase() {} void DISBase::persistentOutput(PersistentOStream & os) const { os << comptonInt_ << bgfInt_ << procProb_ << initial_ << final_ << alpha_ << ounit(pTmin_,GeV) << comptonWeight_ << BGFWeight_ << gluon_ << ounit(muF_,GeV) << scaleFact_ << scaleOpt_ << contrib_<< power_; } void DISBase::persistentInput(PersistentIStream & is, int) { is >> comptonInt_ >> bgfInt_ >> procProb_ >> initial_ >> final_ >> alpha_ >> iunit(pTmin_,GeV) >> comptonWeight_ >> BGFWeight_ >> gluon_ >> iunit(muF_,GeV) >> scaleFact_ >> scaleOpt_ >> contrib_ >> power_; } // The following static variable is needed for the type // description system in ThePEG. DescribeAbstractClass describeHerwigDISBase("Herwig::DISBase", "HwMEDIS.so"); void DISBase::Init() { static ClassDocumentation documentation ("The DISBase class provides the base class for the " "implementation of DIS type processes including the " "hard corrections in either the old-fashioned matrix " "element correction of POWHEG approaches"); static Parameter interfaceProcessProbability ("ProcessProbability", "The probabilty of the QCD compton process for the process selection", &DISBase::procProb_, 0.3, 0.0, 1., false, false, Interface::limited); static Reference interfaceCoupling ("Coupling", "Pointer to the object to calculate the coupling for the correction", &DISBase::alpha_, false, false, true, false, false); static Parameter interfacepTMin ("pTMin", "The minimum pT", &DISBase::pTmin_, GeV, 1.*GeV, 0.0*GeV, 10.0*GeV, false, false, Interface::limited); static Parameter interfaceComptonWeight ("ComptonWeight", "Weight for the overestimate ofthe compton channel", &DISBase::comptonWeight_, 50.0, 0.0, 100.0, false, false, Interface::limited); static Parameter interfaceBGFWeight ("BGFWeight", "Weight for the overestimate of the BGF channel", &DISBase::BGFWeight_, 100.0, 0.0, 1000.0, false, false, Interface::limited); static Switch interfaceContribution ("Contribution", "Which contributions to the cross section to include", &DISBase::contrib_, 0, false, false); static SwitchOption interfaceContributionLeadingOrder (interfaceContribution, "LeadingOrder", "Just generate the leading order cross section", 0); static SwitchOption interfaceContributionPositiveNLO (interfaceContribution, "PositiveNLO", "Generate the positive contribution to the full NLO cross section", 1); static SwitchOption interfaceContributionNegativeNLO (interfaceContribution, "NegativeNLO", "Generate the negative contribution to the full NLO cross section", 2); static Switch interfaceScaleOption ("ScaleOption", "Option for the choice of factorization (and renormalization) scale", &DISBase::scaleOpt_, 1, false, false); static SwitchOption interfaceDynamic (interfaceScaleOption, "Dynamic", "Dynamic factorization scale equal to the current sqrt(sHat())", 1); static SwitchOption interfaceFixed (interfaceScaleOption, "Fixed", "Use a fixed factorization scale set with FactorizationScaleValue", 2); static Parameter interfaceFactorizationScale ("FactorizationScale", "Value to use in the event of a fixed factorization scale", &DISBase::muF_, GeV, 100.0*GeV, 1.0*GeV, 500.0*GeV, true, false, Interface::limited); static Parameter interfaceScaleFactor ("ScaleFactor", "The factor used before Q2 if using a running scale", &DISBase::scaleFact_, 1.0, 0.0, 10.0, false, false, Interface::limited); static Parameter interfaceSamplingPower ("SamplingPower", "Power for the sampling of xp", &DISBase::power_, 0.6, 0.0, 1., false, false, Interface::limited); } void DISBase::doinit() { HwMEBase::doinit(); // integrals of me over phase space double r5=sqrt(5.),darg((r5-1.)/(r5+1.)),ath(0.5*log((1.+1./r5)/(1.-1./r5))); comptonInt_ = 2.*(-21./20.-6./(5.*r5)*ath+sqr(Constants::pi)/3. -2.*Math::ReLi2(1.-darg)-2.*Math::ReLi2(1.-1./darg)); bgfInt_ = 121./9.-56./r5*ath; // extract the gluon ParticleData objects gluon_ = getParticleData(ParticleID::g); } void DISBase::initializeMECorrection(RealEmissionProcessPtr born, double & initial, double & final) { initial = initial_; final = final_; // incoming particles for(unsigned int ix=0;ixbornIncoming().size();++ix) { if(QuarkMatcher::Check(born->bornIncoming()[ix]->data())) { partons_[0] = born->bornIncoming()[ix]->dataPtr(); pq_[0] = born->bornIncoming()[ix]->momentum(); } else if(LeptonMatcher::Check(born->bornIncoming()[ix]->data())) { leptons_[0] = born->bornIncoming()[ix]->dataPtr(); pl_[0] = born->bornIncoming()[ix]->momentum(); } } // outgoing particles for(unsigned int ix=0;ixbornOutgoing().size();++ix) { if(QuarkMatcher::Check(born->bornOutgoing()[ix]->data())) { partons_[1] = born->bornOutgoing()[ix]->dataPtr(); pq_[1] = born->bornOutgoing()[ix]->momentum(); } else if(LeptonMatcher::Check(born->bornOutgoing()[ix]->data())) { leptons_[1] = born->bornOutgoing()[ix]->dataPtr(); pl_[1] = born->bornOutgoing()[ix]->momentum(); } } // extract the born variables q_ =pl_[0]-pl_[1]; q2_ = -q_.m2(); double yB = (q_*pq_[0])/(pl_[0]*pq_[0]); l_ = 2./yB-1.; // calculate the A coefficient for the correlations acoeff_ = A(leptons_[0],leptons_[1], partons_[0],partons_[1],q2_); } RealEmissionProcessPtr DISBase::applyHardMatrixElementCorrection(RealEmissionProcessPtr born) { static const double eps=1e-6; // find the incoming and outgoing quarks and leptons PPtr quark[2],lepton[2]; PPtr hadron; unsigned int iqIn(0),iqOut(0); // incoming particles for(unsigned int ix=0;ixbornIncoming().size();++ix) { if(QuarkMatcher::Check(born->bornIncoming()[ix]->data())) { iqIn=ix; quark[0] = born->bornIncoming()[ix]; hadron = born->hadrons()[ix]; beam_ = dynamic_ptr_cast(hadron->dataPtr()); xB_ = quark[0]->momentum().rho()/hadron->momentum().rho(); } else if(LeptonMatcher::Check(born->bornIncoming()[ix]->data())) { lepton[0] = born->bornIncoming()[ix]; } } pdf_ = beam_->pdf(); assert(beam_&&pdf_&&quark[0]&&lepton[0]); // outgoing particles for(unsigned int ix=0;ixbornOutgoing().size();++ix) { if(QuarkMatcher::Check(born->bornOutgoing()[ix]->data())) { iqOut=ix; quark [1] = born->bornOutgoing()[ix]; } else if(LeptonMatcher::Check(born->bornOutgoing()[ix]->data())) { lepton[1] = born->bornOutgoing()[ix]; } } // momentum fraction assert(quark[1]&&lepton[1]); // calculate the matrix element vector azicoeff; // select the type of process bool BGF = UseRandom::rnd()>procProb_; double xp,zp,wgt,x1,x2,x3,xperp; // generate a QCD compton process if(!BGF) { wgt = generateComptonPoint(xp,zp); if(xpvalue(scale)/procProb_; // PDF piece wgt *= pdf_->xfx(beam_,quark[0]->dataPtr(),scale,xB_/xp)/ pdf_->xfx(beam_,quark[0]->dataPtr(),q2_ ,xB_); // other bits xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp); x1 = -1./xp; x2 = 1.-(1.-zp)/xp; x3 = 2.+x1-x2; // matrix element pieces azicoeff = ComptonME(xp,x2,xperp,true); } // generate a BGF process else { wgt = generateBGFPoint(xp,zp); if(xpvalue(scale)/(1.-procProb_); // PDF piece wgt *= pdf_->xfx(beam_,gluon_ ,scale,xB_/xp)/ pdf_->xfx(beam_,quark[0]->dataPtr(),q2_ ,xB_); // other bits xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp); x1 = -1./xp; x2 = 1.-(1.-zp)/xp; x3 = 2.+x1-x2; // matrix element pieces azicoeff = BGFME(xp,x2,x3,xperp,true); } // compute the azimuthal average of the weight wgt *= (azicoeff[0]+0.5*azicoeff[2]); // decide whether or not to accept the weight if(UseRandom::rnd()>wgt) return RealEmissionProcessPtr(); // if generate generate phi unsigned int itry(0); double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.); double phiwgt,phi; do { phi = UseRandom::rnd()*Constants::twopi; double cphi(cos(phi)); phiwgt = azicoeff[0]+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi); ++itry; } while (phimax*UseRandom::rnd() > phiwgt && itry<200); if(itry==200) throw Exception() << "Too many tries in DISMECorrection" << "::applyHardMatrixElementCorrection() to" << " generate phi" << Exception::eventerror; // construct lorentz transform from lab to breit frame Lorentz5Momentum phadron = hadron->momentum(); phadron.setMass(0.*GeV); phadron.rescaleEnergy(); Lorentz5Momentum pcmf = phadron+0.5/xB_*q_; pcmf.rescaleMass(); LorentzRotation rot(-pcmf.boostVector()); Lorentz5Momentum pbeam = rot*phadron; Axis axis(pbeam.vect().unit()); double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); rot.rotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); Lorentz5Momentum pl = rot*pl_[0]; rot.rotateZ(-atan2(pl.y(),pl.x())); pl_[0] *= rot; pl_[1] *= rot; pq_[0] *= rot; pq_[1] *= rot; // compute the new incoming and outgoing momenta Energy Q(sqrt(q2_)); Lorentz5Momentum p1 = Lorentz5Momentum( 0.5*Q*xperp*cos(phi), 0.5*Q*xperp*sin(phi), -0.5*Q*x2,0.*GeV,0.*GeV); p1.rescaleEnergy(); Lorentz5Momentum p2 = Lorentz5Momentum(-0.5*Q*xperp*cos(phi),-0.5*Q*xperp*sin(phi), -0.5*Q*x3,0.*GeV,0.*GeV); p2.rescaleEnergy(); Lorentz5Momentum pin(0.*GeV,0.*GeV,-0.5*x1*Q,-0.5*x1*Q,0.*GeV); // debuggingMatrixElement(BGF,pin,p1,p2,gluon_,pl_[0],pl_[1],pq_[0],pq_[1], // lepton[0]->dataPtr(),lepton[1]->dataPtr(), // quark [0]->dataPtr(),quark [1]->dataPtr(), // q2_,phi,x2,x3,xperp,zp,xp,azicoeff,true); // we need the Lorentz transform back to the lab rot.invert(); // transform the momenta to lab frame pin *= rot; p1 *= rot; p2 *= rot; // test to ensure outgoing particles can be put on-shell if(!BGF) { if(p1.e()dataPtr()->constituentMass()) return RealEmissionProcessPtr(); if(p2.e()constituentMass()) return RealEmissionProcessPtr(); } else { if(p1.e()dataPtr() ->constituentMass()) return RealEmissionProcessPtr(); if(p2.e()dataPtr()->CC()->constituentMass()) return RealEmissionProcessPtr(); } // create the new particles and real emission process bool isQuark = quark[0]->colourLine(); bool FSR = false; // incoming lepton if first if(iqIn==1) born->incoming().push_back(born->bornIncoming()[0]->dataPtr()-> produceParticle(born->bornIncoming()[0]->momentum())); // outgoing lepton if first if(iqOut==1) born->outgoing().push_back(born->bornOutgoing()[0]->dataPtr()-> produceParticle(born->bornOutgoing()[0]->momentum())); PPtr newin,newout,emitted; // radiating system if(!BGF) { newin = quark[0]->dataPtr()->produceParticle(pin); emitted = gluon_ ->produceParticle(p2 ); newout = quark[1]->dataPtr()->produceParticle(p1 ); emitted->incomingColour(newin,!isQuark); emitted->colourConnect(newout,!isQuark); FSR = xp>zp; } else { newin = gluon_ ->produceParticle(pin); emitted = quark[0]->dataPtr()->CC()->produceParticle(p2 ); newout = quark[1]->dataPtr() ->produceParticle(p1 ); emitted->incomingColour(newin, isQuark); newout ->incomingColour(newin,!isQuark); FSR = false; } // set x double x(xB_/xp); if(born->incoming().size()==0) born->x(make_pair(x,1.)); else born->x(make_pair(1.,x)); if(FSR) { born->emitter(born->outgoing().size()+2); born->spectator(born->incoming().size()); } else { born->emitter(born->incoming().size()); born->spectator(born->outgoing().size()+2); } born->emitted(4); // radiating particles born->incoming().push_back(newin ); born->outgoing().push_back(newout); // incoming lepton if second if(iqIn==0) born->incoming().push_back(born->bornIncoming()[1]->dataPtr()-> produceParticle(born->bornIncoming()[1]->momentum())); // outgoing lepton if second if(iqOut==0) born->outgoing().push_back(born->bornOutgoing()[1]->dataPtr()-> produceParticle(born->bornOutgoing()[1]->momentum())); // radiated particle born->outgoing().push_back(emitted); born->interaction(ShowerInteraction::QCD); return born; } bool DISBase::softMatrixElementVeto(PPtr parent, PPtr progenitor, const bool & fs, const Energy & highestpT, const vector & ids, const double & z, const Energy & scale, const Energy & pT) { bool veto = !UseRandom::rndbool(fs ? 1./final_ : 1./initial_); // check if me correction should be applied long id[2]={progenitor->id(),parent->id()}; if(id[0]!=id[1]||id[1]==ParticleID::g) return veto; // check if hardest so far if(pT azicoeff = ComptonME(xp,x2,xperp,false); wgt = (azicoeff[0]+0.5*azicoeff[2])*xp/(1.+sqr(z))/final_; if(wgt<.0||wgt>1.) { ostringstream wstring; wstring << "Soft ME correction weight too large or " << "negative for FSR in DISBase::" << "softMatrixElementVeto() soft weight " << " xp = " << xp << " zp = " << zp << " weight = " << wgt << "\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } else { double xp = 2.*z/(1.+zk+sqrt(sqr(1.+zk)-4.*z*zk)); double zp = 0.5* (1.-zk+sqrt(sqr(1.+zk)-4.*z*zk)); double xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp); double x1 = -1./xp, x2 = 1.-(1.-zp)/xp, x3 = 2.+x1-x2; // compton if(ids[0]->id()!=ParticleID::g) { vector azicoeff = ComptonME(xp,x2,xperp,false); wgt = (azicoeff[0]+0.5*azicoeff[2])*xp*(1.-z)/(1.-xp)/(1.+sqr(z))/ (1.-zp+xp-2.*xp*(1.-zp)); } // BGF else { vector azicoeff = BGFME(xp,x2,x3,xperp,true); wgt = (azicoeff[0]+0.5*azicoeff[2])*xp/(1.-zp+xp-2.*xp*(1.-zp))/(sqr(z)+sqr(1.-z)); } wgt /=initial_; if(wgt<.0||wgt>1.) { ostringstream wstring; wstring << "Soft ME correction weight too large or " << "negative for ISR in DISBase::" << "softMatrixElementVeto() soft weight " << " xp = " << xp << " zp = " << zp << " weight = " << wgt << "\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } // return whether or not vetoed return !UseRandom::rndbool(wgt); } double DISBase::generateComptonPoint(double &xp, double & zp) { static const double maxwgt = 1.; double wgt; do { xp = UseRandom::rnd(); double zpmin = xp, zpmax = 1./(1.+xp*(1.-xp)); zp = 1.-pow((1.-zpmin)/(1.-zpmax),UseRandom::rnd())*(1.-zpmax); wgt = log((1.-zpmin)/(1.-zpmax))*(1.-zp); if(UseRandom::rndbool()) swap(xp,zp); double xperp2 = 4.*(1.-xp)*(1.-zp)*zp/xp,x2=1.-(1.-zp)/xp; wgt *= 2.*(1.+sqr(xp)*(sqr(x2)+1.5*xperp2))/(1.-xp)/(1.-zp); if(wgt>maxwgt) { ostringstream wstring; wstring << "DISBase::generateComptonPoint " << "Weight greater than maximum " << "wgt = " << wgt << " maxwgt = 1\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } while(wgtmaxwgt) { ostringstream wstring; wstring << "DISBase::generateBGFPoint " << "Weight greater than maximum " << "wgt = " << wgt << " maxwgt = 1\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } while(wgt1.+ac) cerr << "testing violates BGF maxA " << wgt << "\n"; // } // while(wgtmaxwgt*zpwgt) cerr << "testing violates BGF maxB " << wgt/xpwgt << "\n"; // } // while(wgt DISBase::ComptonME(double xp, double x2, double xperp, bool norm) { vector output(3,0.); double cos2 = x2 /sqrt(sqr(x2)+sqr(xperp)); double sin2 = xperp/sqrt(sqr(x2)+sqr(xperp)); double root = sqrt(sqr(l_)-1.); output[0] = sqr(cos2)+acoeff_*cos2*l_+sqr(l_); output[1] = -acoeff_*cos2*root*sin2-2.*l_*root*sin2; output[2] = sqr(root)*sqr(sin2); double lo(1+acoeff_*l_+sqr(l_)); double denom = norm ? 1.+sqr(xp)*(sqr(x2)+1.5*sqr(xperp)) : 1.; double fact = sqr(xp)*(sqr(x2)+sqr(xperp))/lo; for(unsigned int ix=0;ix DISBase::BGFME(double xp, double x2, double x3, double xperp, bool norm) { vector output(3,0.); double cos2 = x2 /sqrt(sqr(x2)+sqr(xperp)); double sin2 = xperp/sqrt(sqr(x2)+sqr(xperp)); double fact2 = sqr(xp)*(sqr(x2)+sqr(xperp)); double cos3 = x3 /sqrt(sqr(x3)+sqr(xperp)); double sin3 = xperp/sqrt(sqr(x3)+sqr(xperp)); double fact3 = sqr(xp)*(sqr(x3)+sqr(xperp)); double root = sqrt(sqr(l_)-1.); output[0] = fact2*(sqr(cos2)+acoeff_*cos2*l_+sqr(l_)) + fact3*(sqr(cos3)-acoeff_*cos3*l_+sqr(l_)); output[1] = - fact2*(acoeff_*cos2*root*sin2+2.*l_*root*sin2) - fact3*(acoeff_*cos3*root*sin3-2.*l_*root*sin3); output[2] = fact2*(sqr(root)*sqr(sin2)) + fact3*(sqr(root)*sqr(sin3)); double lo(1+acoeff_*l_+sqr(l_)); double denom = norm ? sqr(xp)*(sqr(x3)+sqr(x2)+3.*sqr(xperp))*lo : lo; for(unsigned int ix=0;ixbornIncoming().size();++ix) { if(QuarkMatcher::Check(born->bornIncoming()[ix]->data())) { iqIn=ix; hadron = born->hadrons()[ix]; quark [0] = born->bornIncoming()[ix]; beam_ = dynamic_ptr_cast(hadron->dataPtr()); xB_ = quark[0]->momentum().rho()/hadron->momentum().rho(); } else if(LeptonMatcher::Check(born->bornIncoming()[ix]->data())) { lepton[0] = born->bornIncoming()[ix]; leptons_[0] = lepton[0]->dataPtr(); } } pdf_=beam_->pdf(); assert(beam_&&pdf_&&quark[0]&&lepton[0]); // outgoing particles for(unsigned int ix=0;ixbornOutgoing().size();++ix) { if(QuarkMatcher::Check(born->bornOutgoing()[ix]->data())) { iqOut=ix; quark [1] = born->bornOutgoing()[ix]; } else if(LeptonMatcher::Check(born->bornOutgoing()[ix]->data())) { lepton[1] = born->bornOutgoing()[ix]; leptons_[1] = lepton[1]->dataPtr(); } } assert(quark[1]&&lepton[1]); // Particle data objects for(unsigned int ix=0;ix<2;++ix) partons_[ix] = quark[ix]->dataPtr(); // extract the born variables q_ =lepton[0]->momentum()-lepton[1]->momentum(); q2_ = -q_.m2(); double yB = ( q_*quark[0]->momentum())/ (lepton[0]->momentum()*quark[0]->momentum()); l_ = 2./yB-1.; // construct lorentz transform from lab to breit frame Lorentz5Momentum phadron = hadron->momentum(); phadron.setMass(0.*GeV); phadron.rescaleRho(); Lorentz5Momentum pb = quark[0]->momentum(); Axis axis(q_.vect().unit()); double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); LorentzRotation rot_ = LorentzRotation(); if(axis.perp2()>1e-20) { rot_.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); rot_.rotateX(Constants::pi); } if(abs(1.-q_.e()/q_.vect().mag())>1e-6) rot_.boostZ( q_.e()/q_.vect().mag()); pb *= rot_; if(pb.perp2()/GeV2>1e-20) { Boost trans = -1./pb.e()*pb.vect(); trans.setZ(0.); rot_.boost(trans); } Lorentz5Momentum pl = rot_*lepton[0]->momentum(); rot_.rotateZ(-atan2(pl.y(),pl.x())); // momenta of the particles pl_[0]=rot_*lepton[0]->momentum(); pl_[1]=rot_*lepton[1]->momentum(); pq_[0]=rot_* quark[0]->momentum(); pq_[1]=rot_* quark[1]->momentum(); q_ *= rot_; // coefficient for the matrix elements acoeff_ = A(lepton[0]->dataPtr(),lepton[1]->dataPtr(), quark [0]->dataPtr(),quark [1]->dataPtr(),q2_); // generate a compton point generateCompton(); generateBGF(); // no valid emission, return if(pTCompton_pT()[ShowerInteraction::QCD] = pTmin_; return born; } // type of emission, pick highest pT bool isCompton=pTCompton_>pTBGF_; // create the process with real emission bool isQuark = quark[0]->colourLine(); bool FSR = false; // incoming lepton if first if(iqIn==1) born->incoming().push_back(born->bornIncoming()[0]->dataPtr()-> produceParticle(born->bornIncoming()[0]->momentum())); // outgoing lepton if first if(iqOut==1) born->outgoing().push_back(born->bornOutgoing()[0]->dataPtr()-> produceParticle(born->bornOutgoing()[0]->momentum())); PPtr newout,newin,emitted; // compton hardest if(isCompton) { rot_.invert(); for(unsigned int ix=0;ixproduceParticle(ComptonMomenta_[1]); emitted = gluon_ ->produceParticle(ComptonMomenta_[2]); newin = partons_[0]->produceParticle(ComptonMomenta_[0]); emitted->incomingColour(newin,!isQuark); emitted->colourConnect(newout,!isQuark); FSR = !ComptonISFS_; born->pT()[ShowerInteraction::QCD] = pTCompton_; } // BGF hardest else { rot_.invert(); for(unsigned int ix=0;ixproduceParticle(BGFMomenta_[0]); emitted = quark[0]->dataPtr()->CC()->produceParticle(BGFMomenta_[2]); newout = quark[1]->dataPtr() ->produceParticle(BGFMomenta_[1]); emitted->incomingColour(newin, isQuark); newout ->incomingColour(newin,!isQuark); FSR = false; born->pT()[ShowerInteraction::QCD] = pTBGF_; } double x = newin->momentum().rho()/hadron->momentum().rho(); if(born->incoming().size()==0) born->x(make_pair(x,1.)); else born->x(make_pair(1.,x)); if(FSR) { born->emitter(born->outgoing().size()+2); born->spectator(born->incoming().size()); } else { born->emitter(born->incoming().size()); born->spectator(born->outgoing().size()+2); } born->emitted(4); // radiating particles born->incoming().push_back(newin ); born->outgoing().push_back(newout); // incoming lepton if second if(iqIn==0) born->incoming().push_back(born->bornIncoming()[1]->dataPtr()-> produceParticle(born->bornIncoming()[1]->momentum())); // outgoing lepton if second if(iqOut==0) born->outgoing().push_back(born->bornOutgoing()[1]->dataPtr()-> produceParticle(born->bornOutgoing()[1]->momentum())); // radiated particle born->outgoing().push_back(emitted); born->interaction(ShowerInteraction::QCD); return born; } void DISBase::generateCompton() { // maximum value of the xT double xT = sqrt((1.-xB_)/xB_); double xTMin = 2.*pTmin_/sqrt(q2_); double zp; // prefactor double a = alpha_->overestimateValue()*comptonWeight_/Constants::twopi; // loop to generate kinematics double wgt(0.),xp(0.); vector azicoeff; do { wgt = 0.; // intergration variables dxT/xT^3 xT *= 1./sqrt(1.-2.*log(UseRandom::rnd())/a*sqr(xT)); // zp zp = UseRandom::rnd(); xp = 1./(1.+0.25*sqr(xT)/zp/(1.-zp)); // check allowed if(xp1.) continue; // phase-space piece of the weight wgt = 8.*(1.-xp)*zp/comptonWeight_; // PDF piece of the weight Energy2 scale = q2_*((1.-xp)*(1-zp)*zp/xp+1.); wgt *= pdf_->xfx(beam_,partons_[0],scale,xB_/xp)/ pdf_->xfx(beam_,partons_[0],q2_ ,xB_); // me piece of the weight double x2 = 1.-(1.-zp)/xp; azicoeff = ComptonME(xp,x2,xT,false); wgt *= 4./3.*alpha_->ratio(0.25*q2_*sqr(xT))*(azicoeff[0]+0.5*azicoeff[2]); if(wgt>1.||wgt<0.) { ostringstream wstring; wstring << "DISBase::generateCompton() " << "Weight greater than one or less than zero" << "wgt = " << wgt << "\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } while(xT>xTMin&&UseRandom::rnd()>wgt); if(xT<=xTMin) { pTCompton_=-GeV; return; } // generate phi unsigned int itry(0); double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.); double phiwgt,phi; do { phi = UseRandom::rnd()*Constants::twopi; double cphi(cos(phi)); phiwgt = azicoeff[0]+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi); ++itry; } while (phimax*UseRandom::rnd() > phiwgt && itry<200); if(itry==200) throw Exception() << "Too many tries in DISMECorrection" << "::generateCompton() to" << " generate phi" << Exception::eventerror; // momenta for the configuration Energy Q(sqrt(q2_)); double x1 = -1./xp; double x2 = 1.-(1.-zp)/xp; double x3 = 2.+x1-x2; Lorentz5Momentum p1( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi), -0.5*Q*x2, 0.5*Q*sqrt(sqr(xT)+sqr(x2))); Lorentz5Momentum p2(-0.5*Q*xT*cos(phi), -0.5*Q*xT*sin(phi), -0.5*Q*x3, 0.5*Q*sqrt(sqr(xT)+sqr(x3))); Lorentz5Momentum p0(ZERO,ZERO,-0.5*Q*x1,-0.5*Q*x1); pTCompton_ = 0.5*Q*xT; ComptonMomenta_.resize(3); ComptonMomenta_[0] = p0; ComptonMomenta_[1] = p1; ComptonMomenta_[2] = p2; ComptonISFS_ = zp>xp; // debuggingMatrixElement(false,p0,p1,p2,gluon_,pl_[0],pl_[1],pq_[0],pq_[1], // leptons_[0],leptons_[1], // partons_[0],partons_[1], // q2_,phi,x2,x3,xT,zp,xp,azicoeff,false); } void DISBase::generateBGF() { // maximum value of the xT double xT = (1.-xB_)/xB_; double xTMin = 2.*max(pTmin_,pTCompton_)/sqrt(q2_); double zp; // prefactor double a = alpha_->overestimateValue()*BGFWeight_/Constants::twopi; // loop to generate kinematics double wgt(0.),xp(0.); vector azicoeff; do { wgt = 0.; // intergration variables dxT/xT^3 xT *= 1./sqrt(1.-2.*log(UseRandom::rnd())/a*sqr(xT)); // zp zp = UseRandom::rnd(); xp = 1./(1.+0.25*sqr(xT)/zp/(1.-zp)); // check allowed if(xp1.) continue; // phase-space piece of the weight wgt = 8.*sqr(1.-xp)*zp/BGFWeight_; // PDF piece of the weight Energy2 scale = q2_*((1.-xp)*(1-zp)*zp/xp+1.); wgt *= pdf_->xfx(beam_,gluon_ ,scale,xB_/xp)/ pdf_->xfx(beam_,partons_[0],q2_ ,xB_); // me piece of the weight double x1 = -1./xp; double x2 = 1.-(1.-zp)/xp; double x3 = 2.+x1-x2; azicoeff = BGFME(xp,x2,x3,xT,false); wgt *= 0.5*alpha_->ratio(0.25*q2_*sqr(xT))* (azicoeff[0]+0.5*azicoeff[2]); if(wgt>1.||wgt<0.) { ostringstream wstring; wstring << "DISBase::generateBGF() " << "Weight greater than one or less than zero" << "wgt = " << wgt << "\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } while(xT>xTMin&&UseRandom::rnd()>wgt); if(xT<=xTMin) { pTBGF_=-GeV; return; } // generate phi unsigned int itry(0); double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.); double phiwgt,phi; do { phi = UseRandom::rnd()*Constants::twopi; double cphi(cos(phi)); phiwgt = azicoeff[0]+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi); ++itry; } while (phimax*UseRandom::rnd() > phiwgt && itry<200); if(itry==200) throw Exception() << "Too many tries in DISMECorrection" << "::generateBGF() to" << " generate phi" << Exception::eventerror; // momenta for the configuration Energy Q(sqrt(q2_)); double x1 = -1./xp; double x2 = 1.-(1.-zp)/xp; double x3 = 2.+x1-x2; Lorentz5Momentum p1( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi), -0.5*Q*x2, 0.5*Q*sqrt(sqr(xT)+sqr(x2))); Lorentz5Momentum p2(-0.5*Q*xT*cos(phi), -0.5*Q*xT*sin(phi), -0.5*Q*x3, 0.5*Q*sqrt(sqr(xT)+sqr(x3))); Lorentz5Momentum p0(ZERO,ZERO,-0.5*Q*x1,-0.5*Q*x1); pTBGF_=0.5*Q*xT; BGFMomenta_.resize(3); BGFMomenta_[0]=p0; BGFMomenta_[1]=p1; BGFMomenta_[2]=p2; // debuggingMatrixElement(true,p0,p1,p2,gluon_,pl_[0],pl_[1],pq_[0],pq_[1], // leptons_[0],leptons_[1], // partons_[0],partons_[1], // q2_,phi,x2,x3,xT,zp,xp,azicoeff,false); } int DISBase::nDim() const { return HwMEBase::nDim() + (contrib_>0 ? 1 : 0 ); } bool DISBase::generateKinematics(const double * r) { // Born kinematics if(!HwMEBase::generateKinematics(r)) return false; if(contrib_!=0) { // hadron and momentum fraction if(HadronMatcher::Check(*lastParticles().first->dataPtr())) { hadron_ = dynamic_ptr_cast(lastParticles().first->dataPtr()); xB_ = lastX1(); } else { hadron_ = dynamic_ptr_cast(lastParticles().second->dataPtr()); xB_ = lastX2(); } // Q2 q2_ = -(meMomenta()[0]-meMomenta()[2]).m2(); // xp int ndim=nDim(); double rhomin = pow(1.-xB_,1.-power_); double rho = r[ndim-1]*rhomin; xp_ = 1.-pow(rho,1./(1.-power_)); jac_ = rhomin/(1.-power_)*pow(1.-xp_,power_); jacobian(jacobian()*jac_); } return true; } Energy2 DISBase::scale() const { return scaleOpt_ == 1 ? -sqr(scaleFact_)*tHat() : sqr(scaleFact_*muF_); } CrossSection DISBase::dSigHatDR() const { return NLOWeight()*HwMEBase::dSigHatDR(); } double DISBase::NLOWeight() const { // If only leading order is required return 1: if(contrib_==0) return 1.; // scale and prefactors Energy2 mu2(scale()); double aS = SM().alphaS(mu2); double CFfact = 4./3.*aS/Constants::twopi; double TRfact = 1./2.*aS/Constants::twopi; // LO + dipole subtracted virtual + collinear quark bit with LO pdf double virt = 1.+CFfact*(-4.5-1./3.*sqr(Constants::pi)+1.5*log(q2_/mu2/(1.-xB_)) +2.*log(1.-xB_)*log(q2_/mu2)+sqr(log(1.-xB_))); virt /= jac_; // PDF from leading-order double loPDF = hadron_->pdf()->xfx(hadron_,mePartonData()[1],mu2,xB_)/xB_; if(loPDF==0.) return 0.; // NLO gluon PDF tcPDPtr gluon = getParticleData(ParticleID::g); double gPDF = hadron_->pdf()->xfx(hadron_,gluon,mu2,xB_/xp_)*xp_/xB_; // NLO quark PDF double qPDF = hadron_->pdf()->xfx(hadron_,mePartonData()[1],mu2,xB_/xp_)*xp_/xB_; // collinear counterterms // gluon double collg = TRfact/xp_*gPDF*(2.*xp_*(1.-xp_)+(sqr(xp_)+sqr(1.-xp_))*log((1.-xp_)*q2_/xp_/mu2)); // quark double collq = CFfact/xp_*qPDF*(1-xp_-2./(1.-xp_)*log(xp_)-(1.+xp_)*log((1.-xp_)/xp_*q2_/mu2))+ CFfact/xp_*(qPDF-xp_*loPDF)*(2./(1.-xp_)*log(q2_*(1.-xp_)/mu2)-1.5/(1.-xp_)); // calculate the A coefficient for the real pieces double a(A(mePartonData()[0],mePartonData()[2], mePartonData()[1],mePartonData()[3],q2_)); // cacluate lepton kinematic variables Lorentz5Momentum q = meMomenta()[0]-meMomenta()[2]; double yB = (q*meMomenta()[1])/(meMomenta()[0]*meMomenta()[1]); double l = 2./yB-1.; // q -> qg term double realq = CFfact/xp_/(1.+a*l+sqr(l))*qPDF/loPDF* (2.+2.*sqr(l)-xp_+3.*xp_*sqr(l)+a*l*(2.*xp_+1.)); // g -> q qbar term double realg =-TRfact/xp_/(1.+a*l+sqr(l))*gPDF/loPDF* ((1.+sqr(l)+2.*(1.-3.*sqr(l))*xp_*(1.-xp_)) +2.*a*l*(1.-2.*xp_*(1.-xp_))); // return the full result double wgt = virt+((collq+collg)/loPDF+realq+realg); // double f2g = gPDF/xp_*TRfact*((sqr(1-xp_)+sqr(xp_))*log((1-xp_)/xp_)+ // 8*xp_*(1.-xp_)-1.); // double f2q = // loPDF/jac_*(1.+CFfact*(-1.5*log(1.-xB_)+sqr(log(1.-xB_)) // -sqr(Constants::pi)/3.-4.5)) // +qPDF *CFfact/xp_*(3.+2.*xp_-(1.+xp_)*log(1.-xp_) // -(1.+sqr(xp_))/(1.-xp_)*log(xp_)) // +(qPDF-xp_*loPDF)*CFfact/xp_*(2.*log(1.-xp_)/(1.-xp_)-1.5/(1.-xp_)); // double wgt = (f2g+f2q)/loPDF; return contrib_ == 1 ? max(0.,wgt) : max(0.,-wgt); } diff --git a/MatrixElement/DrellYanBase.cc b/MatrixElement/DrellYanBase.cc --- a/MatrixElement/DrellYanBase.cc +++ b/MatrixElement/DrellYanBase.cc @@ -1,909 +1,912 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the DrellYanBase class. // #include "DrellYanBase.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/EnumParticles.h" #include "Herwig/Shower/RealEmissionProcess.h" using namespace Herwig; DrellYanBase::DrellYanBase() : _channelwgtA(0.12), _channelwgtB(2.00), _nover(0), _maxwgt(0.), _power(2.0),_preqqbar(6.5),_preqg(4.0),_pregqbar(4.0), _min_pt(2.*GeV) {} void DrellYanBase::persistentOutput(PersistentOStream & os) const { os << _channelwgtA << _channelwgtB << _channelweights << _alpha << _power << _preqqbar << _preqg << _pregqbar << ounit( _min_pt, GeV ) << _prefactor; } void DrellYanBase::persistentInput(PersistentIStream & is, int) { is >> _channelwgtA >> _channelwgtB >> _channelweights >> _alpha >> _power >> _preqqbar >> _preqg >> _pregqbar >> iunit( _min_pt, GeV ) >> _prefactor; } // The following static variable is needed for the type // description system in ThePEG. DescribeAbstractClass describeHerwigDrellYanBase("Herwig::DrellYanBase", "Herwig.so"); void DrellYanBase::Init() { static ClassDocumentation documentation ("The DrellYanBase class provides a base class for the" " corrections to Drell-Yan type processes"); static Parameter interfaceQQbarChannelWeight ("QQbarChannelWeight", "The relative weights of the q qbar abd q g channels for selection." " This is a technical parameter for the phase-space generation and " "should not affect the results only the efficiency and fraction" " of events with weight > 1.", &DrellYanBase::_channelwgtA, 0.12, 0.01, 100., false, false, Interface::limited); static Parameter interfaceQGChannelWeight ("QGChannelWeight", "The relative weights of the qg abd qbar g channels for selection." " This is a technical parameter for the phase-space generation and " "should not affect the results only the efficiency and fraction", &DrellYanBase::_channelwgtB, 2., 0.01, 100., false, false, Interface::limited); static Reference interfaceCoupling ("Coupling", "Pointer to the object to calculate the coupling for the correction", &DrellYanBase::_alpha, false, false, true, false, false); static Parameter interfacePower ("Power", "The power for the sampling of the matrix elements", &DrellYanBase::_power, 2.0, 1.0, 10.0, false, false, Interface::limited); static Parameter interfacePrefactorqqbar ("Prefactorqqbar", "The prefactor for the sampling of the q qbar channel", &DrellYanBase::_preqqbar, 5.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacePrefactorqg ("Prefactorqg", "The prefactor for the sampling of the q g channel", &DrellYanBase::_preqg, 3.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacePrefactorgqbar ("Prefactorgqbar", "The prefactor for the sampling of the g qbar channel", &DrellYanBase::_pregqbar, 3.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacePtMin ("minPt", "The pt cut on hardest emision generation" "2*(1-Beta)*exp(-sqr(intrinsicpT/RMS))/sqr(RMS)", &DrellYanBase::_min_pt, GeV, 2.*GeV, ZERO, 100000.0*GeV, false, false, Interface::limited); } void DrellYanBase::doinit() { HwMEBase::doinit(); _channelweights.push_back(_channelwgtA/(1.+_channelwgtA)); _channelweights.push_back(_channelweights[0]+1./(1.+_channelwgtA)/(1+_channelwgtB)); _channelweights.push_back(1.0); _prefactor.push_back(_preqqbar); _prefactor.push_back(_preqg); _prefactor.push_back(_pregqbar); } void DrellYanBase::dofinish() { HwMEBase::dofinish(); if(_nover==0) return; generator()->log() << "DrellYanBase when applying the hard correction " << _nover << " weights larger than one were generated of which" << " the largest was " << _maxwgt << "\n"; } RealEmissionProcessPtr DrellYanBase::applyHardMatrixElementCorrection(RealEmissionProcessPtr born) { // get the quark,antiquark ParticleVector incoming; vector beams; Lorentz5Momentum phadron; for(unsigned int ix=0;ixbornIncoming().size();++ix) { incoming.push_back(born->bornIncoming()[ix]); tPPtr beam = born->hadrons()[ix]; phadron+=beam->momentum(); beams.push_back(dynamic_ptr_cast(beam->dataPtr())); } Energy2 shad = phadron.m2(); pair xnew = born->x(); // ensure that the quark is first if(incoming[0]->id()id()) { swap(incoming[0],incoming[1]); swap(beams[0],beams[1]); swap(xnew.first,xnew.second); } // and the gauge boson Lorentz5Momentum pboson; for(unsigned int ix=0;ixbornOutgoing().size();++ix) { pboson += born->bornOutgoing()[ix]->momentum(); } pboson.rescaleMass(); // calculate the momenta unsigned int iemit,itype; vector pnew; LorentzRotation trans; // if not accepted return if(!applyHard(incoming,beams,pboson,iemit,itype,pnew,trans,xnew,shad)) return RealEmissionProcessPtr(); // if applying ME correction create the new particles // first the final-state particles Boost boostv=pboson.findBoostToCM(); trans *=LorentzRotation(boostv); born->transformation(trans); for(unsigned int ix=0;ixbornOutgoing().size();++ix) { Lorentz5Momentum pnew = trans*(born->bornOutgoing()[ix]->momentum()); born->outgoing().push_back(born->bornOutgoing()[ix]->dataPtr()->produceParticle(pnew)); } // then emitter, spectator and emitted // emission of a final-state gluon if(itype==0) { // get the momenta of the new particles Lorentz5Momentum pquark(pnew[0]),panti(pnew[1]),pgluon(pnew[2]); if(iemit==2) swap(pquark,panti); // ensure gluon can be put on shell Lorentz5Momentum ptest(pgluon); if(ptest.boost(-(pquark+panti).boostVector()).e() < getParticleData(ParticleID::g)->constituentMass()) return RealEmissionProcessPtr(); // outgoing gluon born->outgoing().push_back(getParticleData(ParticleID::g)->produceParticle(pgluon)); // incoming particles if(born->bornIncoming()[0]->id()>0) { if(iemit==1) { born->emitter(0); born->spectator(1); } else { born->emitter(1); born->spectator(0); } born->incoming().push_back(born->bornIncoming()[0]->dataPtr()->produceParticle(pquark)); born->incoming().push_back(born->bornIncoming()[1]->dataPtr()->produceParticle(panti)); born->outgoing().back()->incomingColour(born->incoming()[0]); born->outgoing().back()->incomingAntiColour(born->incoming()[1]); } else { if(iemit==1) { born->emitter(1); born->spectator(0); } else { born->emitter(0); born->spectator(1); } born->incoming().push_back(born->bornIncoming()[0]->dataPtr()->produceParticle(panti)); born->incoming().push_back(born->bornIncoming()[1]->dataPtr()->produceParticle(pquark)); born->outgoing().back()->incomingColour(born->incoming()[1]); born->outgoing().back()->incomingAntiColour(born->incoming()[0]); } } else if(itype==1) { Lorentz5Momentum pin(pnew[0]),pout(pnew[1]),pgluon(pnew[2]); if(iemit==2) swap(pin,pout); // ensure outgoing quark can be put on-shell Lorentz5Momentum ptest(pout); if(ptest.boost(-(pin+pgluon).boostVector()).e() < incoming[1]->dataPtr()->constituentMass()) return RealEmissionProcessPtr(); // create the new gluon PPtr newg = getParticleData(ParticleID::g)->produceParticle(pgluon); // create the new outgoing quark PPtr newout= incoming[1]->dataPtr()->CC()->produceParticle(pout); // create the new incoming quark PPtr newin = incoming[0]->dataPtr()->produceParticle(pin); // colours newout->incomingColour(newg); newin->antiColourNeighbour(newg); if(born->bornIncoming()[0]->id()>0) { born->emitter (1); born->spectator(0); born->incoming().push_back(newin); born->incoming().push_back(newg ); } else { born->emitter (0); born->spectator(1); born->incoming().push_back(newg ); born->incoming().push_back(newin); } born->outgoing().push_back(newout); } else if(itype==2) { Lorentz5Momentum pin(pnew[0]),pout(pnew[1]),pgluon(pnew[2]); if(iemit==2) swap(pin,pout); // ensure outgoing antiquark can be put on-shell Lorentz5Momentum ptest(pout); if(ptest.boost(-(pin+pgluon).boostVector()).e() < incoming[0]->dataPtr()->constituentMass()) return RealEmissionProcessPtr(); // create the new gluon PPtr newg = getParticleData(ParticleID::g)->produceParticle(pgluon); // create the new outgoing antiquark PPtr newout= incoming[0]->dataPtr()->CC()->produceParticle(pout); // create the new incoming antiquark PPtr newin = incoming[1]->dataPtr()->produceParticle(pin); // colours newout->incomingAntiColour(newg); newin->colourNeighbour(newg); if(born->bornIncoming()[0]->id()>0) { born->emitter (0); born->spectator(1); born->incoming().push_back(newg ); born->incoming().push_back(newin); } else { born->emitter (1); born->spectator(0); born->incoming().push_back(newin); born->incoming().push_back(newg ); } born->outgoing().push_back(newout); } else assert(false); born->emitted(born->outgoing().size()+1); if(born->bornIncoming()[0]->id()<0) { swap(xnew.first,xnew.second); } born->x(xnew); born->interaction(ShowerInteraction::QCD); return born; } bool DrellYanBase::applyHard(ParticleVector & quarks, vector beams, Lorentz5Momentum boson, unsigned int & iemit,unsigned int & itype, vector & pnew, LorentzRotation & trans, pair & xout, Energy2 shad) { // check that quark along +z and qbar along -z bool quarkplus=quarks[0]->momentum().z()>quarks[1]->momentum().z(); // calculate the limits on s Energy mb = sqrt(mb2_); Energy2 smin=mb2_; Energy2 smax(shad); // calculate the rapidity of the boson double yB=0.5*log((boson.e()+boson.z())/ (boson.e()-boson.z())); if(!quarkplus) yB=-yB; // if no phase-space return if(smaxpdf(); assert(pdf[ix]); fx[ix]=pdf[ix]->xfx(beams[ix],quarks[ix]->dataPtr(),mb2_,x[ix]); } // select the type of process and generate the kinematics double rn(UseRandom::rnd()); Energy2 shat(ZERO),uhat(ZERO),that(ZERO); double weight(0.),xnew[2]={1.,1.}; // generate the value of s according to 1/s^2 shat = smax*smin/(smin+UseRandom::rnd()*(smax-smin)); Energy2 jacobian = sqr(shat)*(1./smin-1./smax); double sbar=shat/mb2_; // calculate limits on that Energy2 tmax=mb2_*kappa[0]*(1.-sbar)/(kappa[0]+sbar); Energy2 tmin=shat*(1.-sbar)/(kappa[1]+sbar); // calculate the limits on uhat Energy2 umax(mb2_-shat-tmin),umin(mb2_-shat-tmax); // check inside phase space if(tmax g V if(rn<_channelweights[0]) { // generate t and u according to 1/t+1/u // generate in 1/t if(UseRandom::rndbool(0.5)) { that=tmax*pow(tmin/tmax,UseRandom::rnd()); uhat=mb2_-shat-that; jacobian *=log(tmin/tmax); } // generate in 1/u else { uhat=umax*pow(umin/umax,UseRandom::rnd()); that=mb2_-shat-uhat; jacobian *=log(umin/umax); } Energy4 jacobian2 = jacobian * 2.*uhat*that/(shat-mb2_); // new scale (this is mt^2=pt^2+mb^2) Energy2 scale(uhat*that/shat+mb2_); // the PDF's with the emitted gluon double fxnew[2]; xnew[0]=exp(yB)/sqrt(shad)*sqrt(shat*(mb2_-uhat)/(mb2_-that)); xnew[1]=shat/(shad*xnew[0]); for(unsigned int ix=0;ix<2;++ix) { fxnew[ix] = xnew[ix]<=1. ? pdf[ix]->xfx(beams[ix],quarks[ix]->dataPtr(),scale,xnew[ix]) : 0.; } // jacobian and me parts of the weight weight=jacobian2*(sqr(mb2_-that)+sqr(mb2_-uhat))/(sqr(shat)*that*uhat); // pdf part of the weight weight *=fxnew[0]*fxnew[1]*x[0]*x[1]/(fx[0]*fx[1]*xnew[0]*xnew[1]); // finally coupling, colour factor and different channel pieces weight *= 2./3./Constants::pi/_channelweights[0]*_alpha->value(scale); // select the emiting particle iemit=1; if(UseRandom::rnd()_channelweights[1]) { swap(tmax,tmin); tmax=mb2_-shat-tmax; tmin=mb2_-shat-tmin; } that=tmax*pow(tmin/tmax,UseRandom::rnd()); uhat=mb2_-shat-that; Energy4 jacobian2 = jacobian * that*log(tmax/tmin); // new scale (this is mt^2=pt^2+mb^2) Energy2 scale(uhat*that/shat+mb2_); // g qbar -> qbar V double fxnew[2]; if(rn<_channelweights[1]) { itype=2; xnew[0]=exp(yB)/sqrt(shad)*sqrt(shat*(mb2_-uhat)/(mb2_-that)); xnew[1]=shat/(shad*xnew[0]); fxnew[0] = xnew[0] <=1. ? pdf[0]->xfx(beams[0],getParticleData(ParticleID::g),scale,xnew[0]) : 0.; fxnew[1] = xnew[1] <=1. ? pdf[1]->xfx(beams[1],quarks[1]->dataPtr() ,scale,xnew[1]) : 0.; jacobian2/=(_channelweights[1]-_channelweights[0]); } // q g -> q V else { itype=1; xnew[0]=exp(yB)/sqrt(shad)*sqrt(shat*(mb2_-that)/(mb2_-uhat)); xnew[1]=shat/(shad*xnew[0]); fxnew[0] = xnew[0] <=1. ? pdf[0]->xfx(beams[0],quarks[0]->dataPtr(),scale,xnew[0]) : 0.; fxnew[1] = xnew[1] <=1. ? pdf[1]->xfx(beams[1],getParticleData(ParticleID::g),scale,xnew[1]) : 0.; jacobian2/=(_channelweights[2]-_channelweights[1]); } // jacobian and me parts of the weight weight=-jacobian2*(sqr(mb2_-that)+sqr(mb2_-shat))/(sqr(shat)*shat*that); // pdf part of the weight weight *=fxnew[0]*fxnew[1]*x[0]*x[1]/(fx[0]*fx[1]*xnew[0]*xnew[1]); // finally coupling, colour factor and different channel pieces weight *= 0.25/Constants::pi*_alpha->value(scale); // select the emiting particle iemit=1; if(UseRandom::rnd()1.) { ++_nover; _maxwgt=max(_maxwgt,weight); weight=1.; } if(UseRandom::rnd()>weight) return false; // construct the momenta in the rest frame of the boson Lorentz5Momentum pb(ZERO,ZERO,ZERO,mb,mb),pspect,pg,pemit; double cos3 = 0.0; if(itype==0) { pg = Lorentz5Momentum(ZERO,ZERO,ZERO,0.5*(shat-mb2_)/mb,ZERO); Energy2 tp(that),up(uhat); double zsign(quarkplus ? -1. : 1.); if(iemit==2) { tp=uhat; up=that; zsign *= -1.; } pspect = Lorentz5Momentum(ZERO,ZERO,zsign*0.5*(mb2_-tp)/mb, 0.5*(mb2_-tp)/mb,ZERO); Energy eemit=0.5*(mb2_-up)/mb; cos3 = 0.5/pspect.z()/pg.e()*(sqr(pspect.e())+sqr(pg.e())-sqr(eemit)); } else { pg=Lorentz5Momentum(ZERO,ZERO,ZERO,0.5*(mb2_-uhat)/mb,ZERO); double zsign(quarkplus ? 1. : -1.); if(iemit==1) { if(itype==1) zsign *= -1.; pspect=Lorentz5Momentum(ZERO,ZERO,0.5*zsign*(shat-mb2_)/mb, 0.5*(shat-mb2_)/mb); Energy eemit=0.5*(mb2_-that)/mb; cos3 = 0.5/pspect.z()/pg.e()*(sqr(pspect.e())+sqr(pg.e())-sqr(eemit)); } else { if(itype==2) zsign *= -1.; pspect=Lorentz5Momentum(ZERO,ZERO,0.5*zsign*(mb2_-that)/mb, 0.5*(mb2_-that)/mb); Energy eemit=0.5*(shat-mb2_)/mb; cos3 = 0.5/pspect.z()/pg.e()*(-sqr(pspect.e())-sqr(pg.e())+sqr(eemit)); } } // rotate the gluon double sin3(sqrt(1.-sqr(cos3))); double phi(Constants::twopi*UseRandom::rnd()); pg.setX(pg.e()*sin3*cos(phi)); pg.setY(pg.e()*sin3*sin(phi)); pg.setZ(pg.e()*cos3); if(itype==0) { pemit=pb+pg-pspect; } else { if(iemit==1) pemit=pb+pspect-pg; else pemit=pspect+pg-pb; } pemit.rescaleMass(); // find the new CMF Lorentz5Momentum pp[2]; if(itype==0) { if(iemit==1) { pp[0]=pemit; pp[1]=pspect; } else { pp[0]=pspect; pp[1]=pemit; } } else if(itype==1) { pp[1]=pg; if(iemit==1) pp[0]=pemit; else pp[0]=pspect; } else { pp[0]=pg; if(iemit==1) pp[1]=pemit; else pp[1]=pspect; } Lorentz5Momentum pz= quarkplus ? pp[0] : pp[1]; pp[0]/=xnew[0]; pp[1]/=xnew[1]; Lorentz5Momentum plab(pp[0]+pp[1]); plab.rescaleMass(); // construct the boost to rest frame of plab trans=LorentzRotation(plab.findBoostToCM()); pz.transform(trans); // rotate so emitting particle along z axis // rotate so in x-z plane trans.rotateZ(-atan2(pz.y(),pz.x())); // rotate so along trans.rotateY(-acos(pz.z()/pz.vect().mag())); // undo azimuthal rotation trans.rotateZ(atan2(pz.y(),pz.x())); // perform the transforms pb .transform(trans); pspect.transform(trans); pg .transform(trans); pemit .transform(trans); // momenta to be returned pnew.push_back(pemit); pnew.push_back(pspect); pnew.push_back(pg); pnew.push_back(pb); xout.first=xnew[0]; xout.second=xnew[1]; return true; } bool DrellYanBase::softMatrixElementVeto(PPtr parent, PPtr progenitor, const bool & fs, const Energy & highestpT, const vector & ids, const double & z, const Energy & scale, const Energy & pT) { if(fs) return false; // check if me correction should be applied long id[2]={progenitor->id(),parent->id()}; if(id[0]!=id[1]||id[1]==ParticleID::g) return false; // check if hardest so far if(pT0&&ids[0]->id()==ParticleID::g) wgt=mb2_/(shat+uhat)*(sqr(mb2_-that)+sqr(mb2_-shat))/(sqr(shat+uhat)+sqr(uhat)); else if(id[0]>0&&ids[0]->id()==id[0]) wgt=mb2_/(shat+uhat)*(sqr(mb2_-uhat)+sqr(mb2_-that))/(sqr(shat)+sqr(shat+uhat)); else if(id[0]<0&&ids[0]->id()==ParticleID::g) wgt=mb2_/(shat+uhat)*(sqr(mb2_-that)+sqr(mb2_-shat))/(sqr(shat+uhat)+sqr(uhat)); else if(id[0]<0&&ids[0]->id()==id[0]) wgt=mb2_/(shat+uhat)*(sqr(mb2_-uhat)+sqr(mb2_-that))/(sqr(shat)+sqr(shat+uhat)); else return false; if(wgt<.0||wgt>1.) generator()->log() << "Soft ME correction weight too large or " << "negative in DrellYanBase::" << "softMatrixElementVeto()soft weight " << " sbar = " << shat/mb2_ << " tbar = " << that/mb2_ << "weight = " << wgt << "\n"; // return whether or not vetoed return !UseRandom::rndbool(wgt); } RealEmissionProcessPtr DrellYanBase::generateHardest(RealEmissionProcessPtr born, ShowerInteraction inter) { - if(inter==ShowerInteraction::QED) return RealEmissionProcessPtr(); + // check if generating QCD radiation + if(inter!=ShowerInteraction::QCD && inter!=ShowerInteraction::QEDQCD && + inter!=ShowerInteraction::ALL) + return RealEmissionProcessPtr(); useMe(); // get the particles to be showered _beams.clear(); _partons.clear(); // find the incoming particles ParticleVector incoming; _quarkplus = true; ParticleVector particlesToShower; // progenitor particles are produced in z direction. for(unsigned int ix=0;ixbornIncoming().size();++ix) { incoming.push_back(born->bornIncoming()[ix]); tPPtr beam = born->hadrons()[ix]; _beams.push_back(dynamic_ptr_cast(beam->dataPtr())); _partons.push_back( born->bornIncoming()[ix]->dataPtr() ); // check that quark is along +ve z direction if(born->bornIncoming()[ix]->id() > 0 && born->bornIncoming()[ix]->momentum().z() < ZERO ) _quarkplus = false; particlesToShower.push_back( born->bornIncoming()[ix] ); } Lorentz5Momentum pboson; for(unsigned int ix=0;ixbornOutgoing().size();++ix) { pboson += born->bornOutgoing()[ix]->momentum(); } pboson.rescaleMass(); // calculate the rapidity of the boson _yb = 0.5 * log((pboson.e()+pboson.z())/(pboson.e()-pboson.z())); _yb *= _quarkplus ? 1. : -1.; _mass = pboson.mass(); // we are assuming quark first, swap order to ensure this // if antiquark first bool order = _partons[0]->id()<_partons[1]->id(); if(order) { swap(_partons[0],_partons[1]); swap(_beams[0],_beams[1]); } vector pnew; int emission_type(-1); // generate the hard emission and return if no emission if(!getEvent(pnew,emission_type)) { born->pT()[ShowerInteraction::QCD] = _min_pt; return born; } // construct the HardTree object needed to perform the showers ParticleVector newparticles; // make the particles for the HardTree tcPDPtr gluon=getParticleData(ParticleID::g); // create the partons int iemit; // q qbar -> g V ColinePtr newline[2]={new_ptr(ColourLine()),new_ptr(ColourLine())}; if(emission_type==0) { newparticles.push_back(_partons[0]->produceParticle(pnew[0])); newparticles.push_back(_partons[1]->produceParticle(pnew[1])); newparticles.push_back(gluon ->produceParticle(pnew[2])); newline[1]->addColoured(newparticles[0]); newline[1]->addColoured(newparticles[2]); newline[0]->addAntiColoured(newparticles[1]); newline[0]->addAntiColoured(newparticles[2]); iemit = (pnew[0]-pnew[2]).m2()>(pnew[1]-pnew[2]).m2() ? 0 : 1; } // q g -> q V else if(emission_type==1) { iemit =1; newparticles.push_back(_partons[0]->produceParticle(pnew[0])); newparticles.push_back(gluon ->produceParticle(pnew[1])); newparticles.push_back(_partons[1]->CC()->produceParticle(pnew[2])); newline[1]->addColoured(newparticles[0]); newline[1]->addAntiColoured(newparticles[1]); newline[0]->addColoured(newparticles[1]); newline[0]->addColoured(newparticles[2]); } // g qbar -> qbar V else { iemit =0; newparticles.push_back(gluon ->produceParticle(pnew[0])); newparticles.push_back(_partons[1]->produceParticle(pnew[1])); newparticles.push_back(_partons[0]->CC()->produceParticle(pnew[2])); newline[0]->addAntiColoured(newparticles[1]); newline[0]->addColoured(newparticles[0]); newline[1]->addAntiColoured(newparticles[0]); newline[1]->addAntiColoured(newparticles[2]); } int ispect = iemit == 0 ? 1 : 0; if(iemit==0) newline[0]->addColoured(newparticles.back()); else newline[1]->addAntiColoured(newparticles.back()); // compute the boost for the bosons LorentzRotation boost(pboson.findBoostToCM()); boost.boost(pnew[3].boostVector()); born->transformation(boost); for(unsigned int ix=0;ixbornOutgoing().size();++ix) { born->outgoing().push_back(born->bornOutgoing()[ix]->dataPtr()-> produceParticle(born->bornOutgoing()[ix]->momentum())); born->outgoing().back()->transform(boost); } if(!order) { born->incoming().push_back(newparticles[0]); born->incoming().push_back(newparticles[1]); } else { born->incoming().push_back(newparticles[1]); born->incoming().push_back(newparticles[0]); swap(iemit,ispect); } born->outgoing().push_back(newparticles[2]); born->emitter (iemit ); born->spectator(ispect); born->emitted(born->bornOutgoing().size()+2); pair xnew; for(unsigned int ix=0;ix<2;++ix) { double x = born->incoming()[ix]->momentum().rho()/born->hadrons()[ix]->momentum().rho(); if(ix==0) xnew.first = x; else xnew.second = x; } born->x(xnew); born->pT()[ShowerInteraction::QCD] = _pt; born->interaction(ShowerInteraction::QCD); return born; } double DrellYanBase::getResult(int emis_type, Energy pt, double yj) { Energy2 s=sqr(generator()->maximumCMEnergy()); Energy2 m2(sqr(_mass)); Energy2 scale = m2+sqr(pt); Energy et=sqrt(scale); // longitudinal real correction fractions double x = pt*exp( yj)/sqrt(s)+et*exp( _yb)/sqrt(s); double y = pt*exp(-yj)/sqrt(s)+et*exp(-_yb)/sqrt(s); // reject if outside region if(x<0.||x>1.||y<0.||y>1.||x*ypdf()->xfx(_beams[0],_partons[0],m2,x1); pdf[1]=_beams[1]->pdf()->xfx(_beams[1],_partons[1],m2,y1); //qqbar2Zg using Constants::pi; if(emis_type==0) { pdf[2]=_beams[0]->pdf()->xfx(_beams[0],_partons[0],scale,x); pdf[3]=_beams[1]->pdf()->xfx(_beams[1],_partons[1],scale,y); res = 4./3./pi*(sqr(th-m2)+sqr(uh-m2))*pt/(sh*uh*th)*GeV; } //qg2Zq else if(emis_type==1) { pdf[2]=_beams[0]->pdf()->xfx(_beams[0],_partons[0],scale,x); pdf[3]=_beams[1]->pdf()->xfx(_beams[1],getParticleData(ParticleID::g),scale,y); res = -1./2./pi*(sqr(uh-m2)+sqr(sh-m2))*pt/(sh*sh*uh)*GeV; } //qbarg2Zqbar else { pdf[2]=_beams[0]->pdf()->xfx(_beams[0],getParticleData(ParticleID::g),scale,x); pdf[3]=_beams[1]->pdf()->xfx(_beams[1],_partons[1],scale,y); res =- 1./2./pi*(sqr(th-m2)+sqr(sh-m2))*pt/(sh*sh*th)*GeV; } //deals with pdf zero issue at large x if(pdf[0]<=0.||pdf[1]<=0.||pdf[2]<=0.||pdf[3]<=0.) { res=0.; } else { res*=pdf[2]*pdf[3]/pdf[0]/pdf[1]*m2/sh; } res*=_alpha->ratio(sqr(pt)); return res; } bool DrellYanBase::getEvent(vector & pnew, int & emis_type){ // pt cut-off // Energy minp = 0.1*GeV; // maximum pt (half of centre-of-mass energy) Energy maxp = 0.5*generator()->maximumCMEnergy(); // set pt of emission to zero _pt=ZERO; //Working Variables Energy pt; double yj; // limits on the rapidity of the jet double minyj = -8.0,maxyj = 8.0; bool reject; double wgt; emis_type=-1; for(int j=0;j<3;j++) { pt=maxp; double a = _alpha->overestimateValue()*_prefactor[j]*(maxyj-minyj)/(_power-1.); do { // generate next pt pt=GeV/pow(pow(GeV/pt,_power-1)-log(UseRandom::rnd())/a,1./(_power-1.)); // generate rapidity of the jet yj=UseRandom::rnd()*(maxyj-minyj)+ minyj; // calculate rejection weight wgt=getResult(j,pt,yj); wgt/= _prefactor[j]*pow(GeV/pt,_power); reject = UseRandom::rnd()>wgt; //no emission event if p goes past p min - basically set to outside //of the histogram bounds (hopefully hist object just ignores it) if(pt<_min_pt){ pt=ZERO; reject = false; } if(wgt>1.0) { ostringstream s; s << "DrellYanBase::getEvent weight for channel " << j << "is " << wgt << " which is greater than 1"; generator()->logWarning( Exception(s.str(), Exception::warning) ); } } while(reject); // set pt of emission etc if(pt>_pt){ emis_type = j; _pt=pt; _yj=yj; } } //was this an (overall) no emission event? if(_pt<_min_pt){ _pt=ZERO; emis_type = 3; } if(emis_type==3) return false; // generate the momenta of the particles // hadron-hadron cmf Energy2 s=sqr(generator()->maximumCMEnergy()); // transverse energy Energy2 m2(sqr(_mass)); Energy et=sqrt(m2+sqr(_pt)); // first calculate all the kinematic variables // longitudinal real correction fractions double x = _pt*exp( _yj)/sqrt(s)+et*exp( _yb)/sqrt(s); double y = _pt*exp(-_yj)/sqrt(s)+et*exp(-_yb)/sqrt(s); // that and uhat Energy2 th = -sqrt(s)*x*_pt*exp(-_yj); Energy2 uh = -sqrt(s)*y*_pt*exp( _yj); Energy2 sh = x*y*s; if(emis_type==1) swap(th,uh); // decide which was the emitting particle unsigned int iemit=1; // from q qbar if(emis_type==0) { if(UseRandom::rnd() &orig) { + for (unsigned int i=0; i> K_ORDER_ >> B_ORDER_; +} + + +// The following static variable is needed for the type +// description system in ThePEG. +DescribeClass +describeHerwigCollinearSudakov("Herwig::CollinearSudakov", "HwMEEW.so"); + +void CollinearSudakov::Init() { + + static ClassDocumentation documentation + ("The CollinearSudakov class implements the collinear evolution"); + + +} + + +Complex CollinearSudakov::highScaleIntegral(bool SU3, bool SU2, double Y, + Energy2 s, Energy mu_h, Energy mu_l, + bool fermion, bool longitudinal, + double yukFactor) { + SU3_ = SU3; + SU2_ = SU2; + Y_ = Y; + s_ = s; + fermion_ = fermion; + longitudinal_ = longitudinal; + yukFactor_ = yukFactor; + // perform the integral + Complex result; + high_ = true; + // real piece + real_ = true; + result.real(integrator_.value(*this,mu_h,mu_l)); + // imaginary piece + real_ = false; + result.imag(integrator_.value(*this,mu_h,mu_l)); + // return the answer + return exp(result); +} + +Complex CollinearSudakov::lowScaleIntegral(bool SU3, double Q, Energy2 s, + Energy mu_h, Energy mu_l, bool fermion, + double boostFactor) { + SU3_ = SU3; + Q_ = Q; + s_ = s; + fermion_ = fermion; + boostFactor_ = boostFactor; + // perform the integral + Complex result; + high_ = false; + // real piece + real_ = true; + result.real(integrator_.value(*this,mu_h,mu_l)); + // imaginary piece + real_ = false; + result.imag(integrator_.value(*this,mu_h,mu_l)); + // return the answer + return exp(result); +} + +InvEnergy CollinearSudakov::highScaleIntegrand(Energy mu) const { + using namespace GroupInvariants; + using Constants::pi; + Complex gamma = 0.0; + // Include K-factor Contributions (Cusps): + GaugeContributions cusp = cuspContributions(mu,K_ORDER_,high_); + // Include B-factors (B1 for U1, B2 for SU2, B3 for SU3): + GaugeContributions nonCusp = BContributions(mu,B_ORDER_,fermion_,longitudinal_); + // common log + Complex plog = PlusLog(s_/sqr(mu)); + // SU(3) + if(SU3_) { + if(fermion_) + gamma += C_F(3)*cusp.SU3*0.5*plog + 0.5*nonCusp.SU3; + else + gamma += (C_A(3))*cusp.SU3*0.5*plog + 0.5*nonCusp.SU3; + } + // SU(2) + if(SU2_) { + if (fermion_ || longitudinal_ ) + gamma += (C_F(2))*cusp.SU2*0.5*plog + 0.5*nonCusp.SU2; + else + gamma += (C_A(2))*cusp.SU2*0.5*plog + 0.5*nonCusp.SU2; + } + + if (fermion_ || longitudinal_ ) { + gamma += sqr(Y_)*(cusp.U1*0.5*plog + 0.5*nonCusp.U1); + } + else { + // U(1) Gauge boson + if (!SU3_ && !SU2_ && abs(Y_)<0.001) { + gamma += 0.5*nonCusp.U1; + } + } + // top Yukawa piece + double y_t = ElectroWeakReweighter::coupling()->y_t(mu); + gamma += yukFactor_*sqr(y_t)/(16.0*sqr(pi)); + // return the answer + return real_ ? gamma.real()/mu : gamma.imag()/mu; +} + +InvEnergy CollinearSudakov::lowScaleIntegrand(Energy mu) const { + using namespace GroupInvariants; + using Constants::pi; + Complex gamma = 0.0; + // Include K-factor Contributions (Cusps): + GaugeContributions cusp = cuspContributions(mu,K_ORDER_,false); + // Include B-factors (B1 for U1, B2 for SU2, B3 for SU3): + GaugeContributions nonCusp = BContributionsLow(mu,B_ORDER_,fermion_,boostFactor_); + // common log + Complex plog = PlusLog(s_/sqr(mu)); + Complex blog(0.); + if(boostFactor_ >0.001) blog = PlusLog(4.0*boostFactor_); + // SU(3) + if (SU3_) { + if (fermion_) { + // not a bHQET top quark field + if (abs(boostFactor_)<0.001) + gamma += C_F(3)*cusp.SU3*0.5*plog + 0.5*nonCusp.SU3; + else + gamma += C_F(3)*cusp.SU3*0.5*blog + 0.5*nonCusp.SU3; + } + else { + gamma += C_A(3)*cusp.SU3*0.5*plog + 0.5*nonCusp.SU3; + } + } + // fermions + if (fermion_) { + // not a bHQET top quark field + if (abs(boostFactor_)<0.001) + gamma += sqr(Q_)*(cusp.U1*0.5*plog + 0.5*nonCusp.U1); + else + gamma += sqr(Q_)*(cusp.U1*0.5*blog + 0.5*nonCusp.U1); + } + else { + // i.e., not a fermion, not a bHQ, not a gluon => photon + if (abs(boostFactor_)<0.001 && !SU3_) + gamma += 0.5*nonCusp.U1; + // i.e., W treated as a bHQET field + else if (abs(boostFactor_)>0.001) + gamma += sqr(Q_)*(cusp.U1*0.5*blog + 0.5*nonCusp.U1); + } + // return the answer + return real_ ? gamma.real()/mu : gamma.imag()/mu; +} + +void CollinearSudakov::evaluateHighScale(Energy highScale, Energy EWScale, Energy2 S) { + double yCoeffQt(0.), yCoefftR(0.), yCoeffPhi(0.); + if (K_ORDER_ >= 1) { + yCoeffQt = 0.5; + yCoefftR = 1.0; + yCoeffPhi = 3.0; + } + highColW_ = highScaleIntegral(false,true ,0.0 ,S,highScale,EWScale,false,false,0.0); + highColB_ = highScaleIntegral(false,false,0.0 ,S,highScale,EWScale,false,false,0.0); + highColG_ = highScaleIntegral(true ,false,0.0 ,S,highScale,EWScale,false,false,0.0); + highColQ_ = highScaleIntegral(true ,true ,1./6. ,S,highScale,EWScale,true,false,0.0); + highColQt_ = highScaleIntegral(true ,true ,1./6. ,S,highScale,EWScale,true,false,yCoeffQt); + highColU_ = highScaleIntegral(true ,false,2./3. ,S,highScale,EWScale,true,false,0.0); + highColtR_ = highScaleIntegral(true ,false,2./3. ,S,highScale,EWScale,true,false,yCoefftR); + highColD_ = highScaleIntegral(true ,false,-1./3.,S,highScale,EWScale,true,false,0.0); + highColL_ = highScaleIntegral(false,true ,-1./2.,S,highScale,EWScale,true,false,0.0); + highColE_ = highScaleIntegral(false,false,-1. ,S,highScale,EWScale,true,false,0.0); + highColPhi_ = highScaleIntegral(false,true ,1./2. ,S,highScale,EWScale,false,true,yCoeffPhi); +} + +void CollinearSudakov::evaluateLowScale(Energy EWScale, Energy lowScale, Energy2 S) { + lowColW_ = lowScaleIntegral(false,1. ,S,EWScale,lowScale,false, + S/sqr(2.*ElectroWeakReweighter::coupling()->mW())); + lowColA_ = lowScaleIntegral(false,0. ,S,EWScale,lowScale,false,0.0); + lowColG_ = lowScaleIntegral(true ,0. ,S,EWScale,lowScale,false,0.0); + lowColU_ = lowScaleIntegral(true ,2./3. ,S,EWScale,lowScale,true,0.0); + lowColt_ = lowScaleIntegral(true ,2./3. ,S,EWScale,lowScale,true, + S/sqr(2.*ElectroWeakReweighter::coupling()->mT())); + lowColD_ = lowScaleIntegral(true ,-1./3.,S,EWScale,lowScale,true,0.0); + lowColE_ = lowScaleIntegral(false,-1. ,S,EWScale,lowScale,true,0.0); +} + +void CollinearSudakov::evaluateMatching(Energy EWScale,Energy2 s) { + using Constants::pi; + using GroupInvariants::PlusLog; + static const Complex I(0,1.0); + // wave function corrections + WaveFunctionCorrections WFC = waveFunctionCorrections(EWScale); + + double aS = ElectroWeakReweighter::coupling()->a3(EWScale); + double aEM = ElectroWeakReweighter::coupling()->aEM(EWScale); + double aW = ElectroWeakReweighter::coupling()->aW(EWScale); + double aZ = ElectroWeakReweighter::coupling()->aZ(EWScale); + double cW2 = ElectroWeakReweighter::coupling()->Cos2thW(EWScale); + double sW2 = ElectroWeakReweighter::coupling()->Sin2thW(EWScale); + Energy mW = ElectroWeakReweighter::coupling()->mW(); + Energy mZ = ElectroWeakReweighter::coupling()->mZ(); + Energy mH = ElectroWeakReweighter::coupling()->mH(); + Energy mT = ElectroWeakReweighter::coupling()->mT(); + double gPHI = ElectroWeakReweighter::coupling()->g_phiPlus(EWScale); + double y_t = ElectroWeakReweighter::coupling()->y_t(EWScale); + + double lz = log(mZ/EWScale); + double lw = log(mW/EWScale); + + complex F_W = 4.0*lw*0.5*PlusLog(s/EWScale/EWScale)-2.0*lw*lw-2.0*lw-5.0*pi*pi/12.0+1.0; + complex F_Z = 4.0*lz*0.5*PlusLog(s/EWScale/EWScale)-2.0*lz*lz-2.0*lz-5.0*pi*pi/12.0+1.0; + + // Taken from Manohar... along with his formulae for F_tL, F_tR, and F_bL (for 3rd/1st Gen. Wavefunction Differences) + complex W1 = WFC.fFW0-0.5*WFC.aW0-0.5*WFC.cW0; + complex W2 = WFC.fF0W-0.5*WFC.a0W; + complex U1 = ElectroWeakReweighter::coupling()->g_Lu(EWScale)*ElectroWeakReweighter::coupling()->g_Lu(EWScale)*(WFC.fFZZ-0.5*WFC.aZZ) - + 0.5*WFC.cZZ*(ElectroWeakReweighter::coupling()->g_Lu(EWScale)*ElectroWeakReweighter::coupling()->g_Lu(EWScale) + + ElectroWeakReweighter::coupling()->g_Ru(EWScale)*ElectroWeakReweighter::coupling()->g_Ru(EWScale)) + + ElectroWeakReweighter::coupling()->g_Lu(EWScale)*ElectroWeakReweighter::coupling()->g_Ru(EWScale)*WFC.bZZ; + complex U2 = ElectroWeakReweighter::coupling()->g_Ru(EWScale)*ElectroWeakReweighter::coupling()->g_Ru(EWScale)*(WFC.fFZZ-0.5*WFC.aZZ) - + 0.5*WFC.cZZ*(ElectroWeakReweighter::coupling()->g_Lu(EWScale)*ElectroWeakReweighter::coupling()->g_Lu(EWScale) + + ElectroWeakReweighter::coupling()->g_Ru(EWScale)*ElectroWeakReweighter::coupling()->g_Ru(EWScale)) + + ElectroWeakReweighter::coupling()->g_Lu(EWScale)*ElectroWeakReweighter::coupling()->g_Ru(EWScale)*WFC.bZZ; + complex HtL = -0.5*y_t*y_t/(16.0*pi*pi)*(0.25-0.5*log(mH/EWScale)-0.5*lz+ + 0.5*WFC.atHH+0.5*WFC.atZZ+WFC.ctHH+WFC.ctZZ+ + WFC.ctW0-WFC.btHH+WFC.btZZ); + complex HtR = HtL-0.5*y_t*y_t/(16.0*pi*pi)*(0.25-lw+WFC.atW0); + complex HbL = -0.5*y_t*y_t/(16.0*pi*pi)*(0.25-lw+WFC.at0W); + + complex F_tL = (4.0/3.0*aS+4.0/9.0*aEM)/(4.0*pi)*(2.0*log(mT/EWScale)*log(mT/EWScale)-log(mT/EWScale)+ + pi*pi/12.0+2.0) + HtL + + aW/(4.0*pi)*0.5*W1 + aZ/(4.0*pi)*U1; + + complex F_tR = (4.0/3.0*aS+4.0/9.0*aEM)/(4.0*pi)*(2.0*log(mT/EWScale)*log(mT/EWScale)-log(mT/EWScale)+ + pi*pi/12.0+2.0) + HtR - + aW/(4.0*pi)*0.25*WFC.cW0 + aZ/(4.0*pi)*U2; + + complex F_bL = HbL + aW/(4.0*pi)*0.5*W2; + + Complex Dw = CollinearDw(s,EWScale); + Complex Dz = CollinearDz(s,EWScale); + + complex D_C_UL = ElectroWeakReweighter::coupling()->g_Lu(EWScale)*ElectroWeakReweighter::coupling()->g_Lu(EWScale)*Dz + 0.5*Dw; + complex D_C_DL = ElectroWeakReweighter::coupling()->g_Ld(EWScale)*ElectroWeakReweighter::coupling()->g_Ld(EWScale)*Dz + 0.5*Dw; + + complex D_C_UR = ElectroWeakReweighter::coupling()->g_Ru(EWScale)*ElectroWeakReweighter::coupling()->g_Ru(EWScale)*Dz; + complex D_C_DR = ElectroWeakReweighter::coupling()->g_Rd(EWScale)*ElectroWeakReweighter::coupling()->g_Rd(EWScale)*Dz; + + complex D_C_nuL = ElectroWeakReweighter::coupling()->g_Lnu(EWScale)*ElectroWeakReweighter::coupling()->g_Lnu(EWScale)*Dz + 0.5*Dw; + complex D_C_EL = ElectroWeakReweighter::coupling()->g_Le(EWScale)*ElectroWeakReweighter::coupling()->g_Le(EWScale)*Dz + 0.5*Dw; + complex D_C_ER = ElectroWeakReweighter::coupling()->g_Re(EWScale)*ElectroWeakReweighter::coupling()->g_Re(EWScale)*Dz; + + complex D_C_WW = aW/(4.0*pi)*cW2*(F_Z+WFC.fsWZWZ) + + aW/(4.0*pi)*cW2*(F_W+WFC.fs1ZW) + aW/(4.0*pi)*sW2*(F_W+WFC.fs10) + + aW/(4.0*pi)*sW2*(2.0*lw*lw- + 2.0*lw+pi*pi/12.0+2.0) + 0.5*WFC.RW; + complex D_C_WZ = aW/(4.0*pi)*2.0*(F_W+WFC.fsZW1) + 0.5*WFC.RZ + sqrt(sW2/cW2)*WFC.RAtoZ; + complex D_C_WA = aW/(4.0*pi)*2.0*(F_W+WFC.fs01) + 0.5*WFC.RA + sqrt(cW2/sW2)*WFC.RZtoA; + complex D_C_BZ = 0.5*WFC.RZ - sqrt(cW2/sW2)*WFC.RAtoZ; + complex D_C_BA = 0.5*WFC.RA - sqrt(sW2/cW2)*WFC.RZtoA; + + // The WFC.RW and WFC.RZ are used on purpose (instead of WFC.RPhi and WFC.RPhi3, respectively): + complex D_C_PhiW = aW/(4.0*pi)*0.25*(F_W+WFC.fs1HW) + + aW/(4.0*pi)*0.25*(F_W+WFC.fs1ZW) + aZ/(4.0*pi)*gPHI*gPHI*(F_Z+WFC.fsWZWZ) + + aW/(4.0*pi)*sW2*(2.0*lw*lw-2.0*lw+pi*pi/12.0+2.0) + + 0.5*WFC.RW + WFC.EW; + complex D_C_PhiZ = aW/(4.0*pi)*0.5*(F_W+WFC.fsZW1) + aZ/(4.0*pi)*0.25*(F_Z+WFC.fs1HZ) + 0.5*WFC.RZ + WFC.EZ; + complex D_C_PhiH = aW/(4.0*pi)*0.5*(F_W+WFC.fsHW1) + aZ/(4.0*pi)*0.25*(F_Z+WFC.fsHZ1) + 0.5*WFC.RH; + + complex D_C_GG = aS/(4.0*pi)*2.0/3.0*log(mT/EWScale); + + ULcollinearCorr_ = exp(D_C_UL); + DLcollinearCorr_ = exp(D_C_DL); + URcollinearCorr_ = exp(D_C_UR); + DRcollinearCorr_ = exp(D_C_DR); + + tLcollinearCorr_ = exp(D_C_UL+F_tL); + tRcollinearCorr_ = exp(D_C_UR+F_tR); + bLcollinearCorr_ = exp(D_C_DL+F_bL); + + nuLcollinearCorr_ = exp(D_C_nuL); + ELcollinearCorr_ = exp(D_C_EL); + ERcollinearCorr_ = exp(D_C_ER); + + WtoWcollinearCorr_ = exp(D_C_WW); + WtoZcollinearCorr_ = exp(D_C_WZ); + WtoAcollinearCorr_ = exp(D_C_WA); + BtoZcollinearCorr_ = exp(D_C_BZ); + BtoAcollinearCorr_ = exp(D_C_BA); + + PhitoWcollinearCorr_ = exp(D_C_PhiW); + PhitoZcollinearCorr_ = exp(D_C_PhiZ); + PhitoHcollinearCorr_ = exp(D_C_PhiH); + + GcollinearCorr_ = exp(D_C_GG); +} + +WaveFunctionCorrections CollinearSudakov::waveFunctionCorrections(Energy EWScale) { + static const Complex I(0.,1.); + using Constants::pi; + double lZ = 2.0*log(ElectroWeakReweighter::coupling()->mZ()/EWScale); + WaveFunctionCorrections WFC; + // From Manohar, 2/12/12: (these assume mH=125, mZ=91.1876, mW=80.399) + WFC.RW = (0.8410283377963967 - 9.424777961271568*I) + 1.2785863646210789*lZ; + WFC.RA = (1.4835982362022198 + 1.855775680704845*pow(10.,-9)*I) - 0.27209907467584415*lZ; + WFC.RZ = (1.5114724841549798 - 9.926944419863688*I) + 1.0834802397165764*lZ; + WFC.RAtoZ = (0.3667485032811715 - 2.2770907130064835*I) - 1.2994544609942593*lZ; + WFC.RZtoA = -0.2095310079712942 + 0.8320191107808546*lZ; + WFC.RH = (12.229832449946716 - 1.7643103462419842*10.0*pow(10.,-12)*I) + 5.309998583664737*lZ; + WFC.RPhi = (5.569012418081201 + 1.5439133581417356*0.10*pow(10.,-9)*I) + 5.309998583664737*lZ; + WFC.RPhi3 = (8.945333042265943 + 5.499309445612249*pow(10.,-12)*I) + 5.309998583664737*lZ; + WFC.EW = (3.967645734304811 + 4.712388980384717*I) + 2.238332625165702*lZ; + WFC.EZ = (5.916079892937651 + 4.96347220970469*I) + 2.1132591719740788*lZ; + + WFC.RW *= ElectroWeakReweighter::coupling()->a2(EWScale)/(4.0*pi); + WFC.RA *= ElectroWeakReweighter::coupling()->a2(EWScale)/(4.0*pi); + WFC.RZ *= ElectroWeakReweighter::coupling()->a2(EWScale)/(4.0*pi); + WFC.RAtoZ *= ElectroWeakReweighter::coupling()->a2(EWScale)/(4.0*pi); + WFC.RZtoA *= ElectroWeakReweighter::coupling()->a2(EWScale)/(4.0*pi); + WFC.RPhi *= ElectroWeakReweighter::coupling()->a2(EWScale)/(4.0*pi); + WFC.EW *= ElectroWeakReweighter::coupling()->a2(EWScale)/(4.0*pi); + WFC.EZ *= ElectroWeakReweighter::coupling()->a2(EWScale)/(4.0*pi); + WFC.RPhi3 *= ElectroWeakReweighter::coupling()->a2(EWScale)/(4.0*pi); + WFC.RH *= ElectroWeakReweighter::coupling()->a2(EWScale)/(4.0*pi); + + + WFC.RW = WFC.RW.real(); + WFC.RA = WFC.RA.real(); + WFC.RZ = WFC.RZ.real(); + WFC.RAtoZ = WFC.RAtoZ.real(); + WFC.RZtoA = WFC.RZtoA.real(); + WFC.RPhi = WFC.RPhi.real(); + WFC.RPhi3 = WFC.RPhi3.real(); + WFC.RH = WFC.RH.real(); + + // Also from Manohar, 2/10/12 + WFC.fFW0 = -3.7946842553189453 - 4.709019671388589*I; + WFC.fF0W = 3.8181790485161176; + WFC.fFZZ = 1.364503250377989 + 0.*I; + WFC.aHH = -0.474396977740686 + 0.*I; + WFC.aZZ = -0.6806563210877914 + 0.*I; + WFC.aW0 = 0.49036102506811907 + 1.9323351450971642*I; + WFC.a0W = -1.2184776671065072; + WFC.bHH = 1.234775745474991 + 0.*I; + WFC.bZZ = 1.7303526426747613 + 0.*I; + WFC.cHH = 0.33140608274387473 + 0.*I; + WFC.cZZ = 0.4961363208382017 + 0.*I; + WFC.cW0 = -1.005299829777395 + 1.063048500002757*I; + WFC.atHH = -0.237198488870343 + 0.*I; + WFC.atZZ = -0.3403281605438957 + 0.*I; + WFC.atW0 = 0.24518051253405954 + 0.9661675725485821*I; + WFC.at0W = -0.6092388335532536; + WFC.ctHH = 0.16570304137193737 + 0.*I; + WFC.ctZZ = 0.24806816041910085 + 0.*I; + WFC.ctW0 = -0.5026499148886975 + 0.5315242500013785*I; + WFC.btHH = -0.30869393636874776 + 0.*I; + WFC.btZZ = -0.4325881606686903 + 0.*I; + + WFC.fs10 = -2.289868133696459; + WFC.fs1ZW = 1.8627978596240622; + WFC.fsWZWZ = 1.1866922529667008; + WFC.fsZW1 = 1.0840307611156266; + WFC.fs01 = 2.2898681336964595; + WFC.fsHW1 = -0.32306745562682404; + WFC.fsHZ1 = 0.4042992116255279; + WFC.fs1HW = 3.330954543719127; + WFC.fs1HZ = 2.69768201932412; + return WFC; +} + +Complex CollinearSudakov::CollinearDw(Energy2 s, Energy EWScale) { + using Constants::pi; + using GroupInvariants::PlusLog; + double lw = log(ElectroWeakReweighter::coupling()->mW()/EWScale); + //s = s/2.; // This should not be here... I think this is a discrepency with Sascha + return ElectroWeakReweighter::coupling()->aW(EWScale)/(4.0*pi)* + (4.0*lw*0.5*PlusLog(s/EWScale/EWScale) - 2.0*lw*lw - + 3.0*lw - 5.0/12.0*pi*pi + 9.0/4.0); +} + +Complex CollinearSudakov::CollinearDz(Energy2 s, Energy EWScale) { + using Constants::pi; + using GroupInvariants::PlusLog; + double lz = log(ElectroWeakReweighter::coupling()->mZ()/EWScale); + return ElectroWeakReweighter::coupling()->aZ(EWScale)/(4.0*pi)* + (4.0*lz*0.5*PlusLog(s/EWScale/EWScale) - 2.0*lz*lz - + 3.0*lz - 5.0/12.0*pi*pi + 9.0/4.0); +} + +namespace { + +void writeLine(ofstream & file, vector x, vector y, + string name,string title, + string colour, string style) { + file << "# BEGIN HISTO1D "+name +"\n"; + file << "SmoothLine=1\n"; + file << "ErrorBars=0\n"; + file << "Path="+name+"\n"; + file << "Title="+title+"\n"; + file << "LineColor="+colour+"\n"; + file << "LineStyle="+style +"\n"; + file << "# xlow xhigh val errminus errplus\n"; + for(unsigned int ix=0;ix np; + vector uL,uR,tL,tR,dL,dR,bL,bR,nuL,eL,eR,Wgamma,Bgamma,g,WT,WL,WZT,BZT,ZL,H; + Energy mZ = ElectroWeakReweighter::coupling()->mZ(); + for(Energy x=200.*GeV;x<5000.*GeV;x*=1.02) { + Energy2 s(sqr(x)); + np.push_back(x); + evaluateHighScale(x,mZ,s); + evaluateMatching(mZ,s); + uL .push_back(real(highColQ_ * ULcollinearCorr_ )); + uR .push_back(real(highColU_ * URcollinearCorr_ )); + tL .push_back(real(highColQt_ * tLcollinearCorr_ )); + tR .push_back(real(highColtR_ * tRcollinearCorr_ )); + dL .push_back(real(highColQ_ * DLcollinearCorr_ )); + dR .push_back(real(highColD_ * DRcollinearCorr_ )); + bL .push_back(real(highColQt_ * bLcollinearCorr_ )); + bR .push_back(real(highColD_ * DRcollinearCorr_ )); + nuL .push_back(real(highColL_ * nuLcollinearCorr_ )); + eL .push_back(real(highColL_ * ELcollinearCorr_ )); + eR .push_back(real(highColE_ * ERcollinearCorr_ )); + Wgamma.push_back(real(highColW_ * WtoAcollinearCorr_ )); + Bgamma.push_back(real(highColB_ * BtoAcollinearCorr_ )); + g .push_back(real(highColG_ * GcollinearCorr_ )); + WT .push_back(real(highColW_ * WtoWcollinearCorr_ )); + WL .push_back(real(highColPhi_ * PhitoWcollinearCorr_)); + WZT .push_back(real(highColW_ * WtoZcollinearCorr_ )); + BZT .push_back(real(highColB_ * BtoZcollinearCorr_ )); + ZL .push_back(real(highColPhi_ * PhitoZcollinearCorr_)); + H .push_back(real(highColPhi_ * PhitoHcollinearCorr_)); + } + ofstream fig1a("fig1a.dat"); + fig1a << "#BEGIN PLOT\n"; + fig1a << "LegendOnly=/uL /uR /tL /tR\n"; + fig1a << "DrawOnly=/uL /uR /tL /tR\n"; + fig1a << "Title=Figure 1a\n"; + fig1a << "RatioPlot=0\n"; + fig1a << "LogX=1\n"; + fig1a << "XLabel=$\\bar{n}\\cdot p$ [GeV]\n"; + fig1a << "YLabel=u, t\n"; + fig1a << "Legend=1\n"; + fig1a << "XMin=250.\n"; + fig1a << "YMin=0.7\n"; + fig1a << "YMax=1.05\n"; + fig1a << "# END PLOT\n"; + writeLine(fig1a,np,uL,"/uL","$u_L$","green","dotted" ); + writeLine(fig1a,np,uR,"/uR","$u_R$","cyan" ,"solid" ); + writeLine(fig1a,np,tL,"/tL","$t_L$","red" ,"dashed" ); + writeLine(fig1a,np,tR,"/tR","$t_R$","blue" ,"dotdashed"); + fig1a.close(); + ofstream fig1b("fig1b.dat"); + fig1b << "#BEGIN PLOT\n"; + fig1b << "LegendOnly=/dL /dR /bL /bR\n"; + fig1b << "DrawOnly=/dL /dR /bL /bR\n"; + fig1b << "Title=Figure 1b\n"; + fig1b << "RatioPlot=0\n"; + fig1b << "LogX=1\n"; + fig1b << "XLabel=$\\bar{n}\\cdot p$ [GeV]\n"; + fig1b << "YLabel=d, b\n"; + fig1b << "Legend=1\n"; + fig1b << "XMin=250.\n"; + fig1b << "YMin=0.7\n"; + fig1b << "YMax=1.05\n"; + fig1b << "# END PLOT\n"; + writeLine(fig1b,np,dL,"/dL","$d_L$","green","dotted" ); + writeLine(fig1b,np,dR,"/dR","$d_R$","cyan" ,"solid" ); + writeLine(fig1b,np,bL,"/bL","$b_L$","red" ,"dashed" ); + writeLine(fig1b,np,bR,"/bR","$b_R$","blue" ,"dotdashed"); + fig1b.close(); + ofstream fig2("fig2.dat"); + fig2 << "#BEGIN PLOT\n"; + fig2 << "LegendOnly=/uL /uR /dL /dR\n"; + fig2 << "DrawOnly=/uL /uR /dL /dR\n"; + fig2 << "Title=Figure 2\n"; + fig2 << "RatioPlot=0\n"; + fig2 << "LogX=1\n"; + fig2 << "XLabel=$\\bar{n}\\cdot p$ [GeV]\n"; + fig2 << "YLabel=u, d\n"; + fig2 << "Legend=1\n"; + fig2 << "XMin=250.\n"; + fig2 << "YMin=0.7\n"; + fig2 << "YMax=1.05\n"; + fig2 << "# END PLOT\n"; + writeLine(fig2,np,uL,"/uL","$u_L$","green","dotted" ); + writeLine(fig2,np,uR,"/uR","$u_R$","cyan" ,"solid" ); + writeLine(fig2,np,dL,"/dL","$d_L$","red" ,"dashed" ); + writeLine(fig2,np,dR,"/dR","$d_R$","blue" ,"dotdashed"); + fig2.close(); + ofstream fig3("fig3.dat"); + fig3 << "#BEGIN PLOT\n"; + fig3 << "LegendOnly=/nuL /eL /eR\n"; + fig3 << "DrawOnly=/nuL /eL /eR\n"; + fig3 << "Title=Figure 3\n"; + fig3 << "RatioPlot=0\n"; + fig3 << "LogX=1\n"; + fig3 << "XLabel=$\\bar{n}\\cdot p$ [GeV]\n"; + fig3 << "YLabel=$\\nu$, $e$\n"; + fig3 << "Legend=1\n"; + fig3 << "XMin=250.\n"; + fig3 << "YMin=0.9\n"; + fig3 << "YMax=1.05\n"; + fig3 << "# END PLOT\n"; + writeLine(fig3,np,nuL,"/nuL","$\\nu_L$","blue","dashed"); + writeLine(fig3,np, eL,"/eL" ,"$e_L$" ,"red" ,"dotted"); + writeLine(fig3,np, eR,"/eR" ,"$e_R$" ,"red" ,"solid" ); + fig3.close(); + ofstream fig5("fig5.dat"); + fig5 << "#BEGIN PLOT\n"; + fig5 << "LegendOnly=/g /Wgamma /Bgamma\n"; + fig5 << "DrawOnly=/g /Wgamma /Bgamma\n"; + fig5 << "Title=Figure 5\n"; + fig5 << "RatioPlot=0\n"; + fig5 << "LogX=1\n"; + fig5 << "XLabel=$\\bar{n}\\cdot p$ [GeV]\n"; + fig5 << "YLabel=$\\gamma$, g\n"; + fig5 << "Legend=1\n"; + fig5 << "XMin=250.\n"; + fig5 << "YMin=0.7\n"; + fig5 << "YMax=1.05\n"; + fig5 << "# END PLOT\n"; + writeLine(fig5,np,g ,"/g" ,"$g$" ,"blue","dashed"); + writeLine(fig5,np,Wgamma,"/Wgamma","$W\\to\\gamma$","red" ,"solid" ); + writeLine(fig5,np,Bgamma,"/Bgamma","$B\\to\\gamma$","red" ,"dotted"); + fig5.close(); + ofstream fig6a("fig6a.dat"); + fig6a << "#BEGIN PLOT\n"; + fig6a << "LegendOnly=/WT /WL\n"; + fig6a << "DrawOnly=/WT /WL\n"; + fig6a << "Title=Figure 6a\n"; + fig6a << "RatioPlot=0\n"; + fig6a << "LogX=1\n"; + fig6a << "XLabel=$\\bar{n}\\cdot p$ [GeV]\n"; + fig6a << "YLabel=$Z_L$, $Z_T$, $H$\n"; + fig6a << "Legend=1\n"; + fig6a << "XMin=250.\n"; + fig6a << "YMin=0.7\n"; + fig6a << "YMax=1.05\n"; + fig6a << "# END PLOT\n"; + writeLine(fig6a,np,WT,"/WT","$W_T$","red" ,"solid"); + writeLine(fig6a,np,WL,"/WL","$W_L$","blue" ,"dashed" ); + fig6a.close(); + ofstream fig6b("fig6b.dat"); + fig6b << "#BEGIN PLOT\n"; + fig6b << "LegendOnly=/WZT /BZT /ZL /H\n"; + fig6b << "DrawOnly=/WZT /BZT /ZL /H\n"; + fig6b << "Title=Figure 6b\n"; + fig6b << "RatioPlot=0\n"; + fig6b << "LogX=1\n"; + fig6b << "XLabel=$\\bar{n}\\cdot p$ [GeV]\n"; + fig6b << "YLabel=d, b\n"; + fig6b << "Legend=1\n"; + fig6b << "XMin=250.\n"; + fig6b << "YMin=0.7\n"; + fig6b << "YMax=1.05\n"; + fig6b << "# END PLOT\n"; + writeLine(fig6b,np,WZT,"/WZT","$W\\to Z_T$","red" ,"solid" ); + writeLine(fig6b,np,BZT,"/BZT","$B\\to Z_T$","red" ,"dotted" ); + writeLine(fig6b,np,ZL ,"/ZL ","$Z_L$" ,"blue" ,"dashed" ); + writeLine(fig6b,np,H ,"/H ","$H$" ,"green","dotdashed"); + fig6b.close(); + + + np.clear(); + vector e30,e50,q30,q50,g30,g50; + for(Energy x=200.*GeV;x<5000.*GeV;x*=1.02) { + Energy2 s(sqr(x)); + np.push_back(x); + evaluateLowScale(mZ,30.*GeV,s); + e30.push_back(real(lowColE_)); + q30.push_back(real(lowColU_)); + g30.push_back(real(lowColG_)); + evaluateLowScale(mZ,50.*GeV,s); + e50.push_back(real(lowColE_)); + q50.push_back(real(lowColU_)); + g50.push_back(real(lowColG_)); + } + ofstream fig4a("fig4a.dat"); + fig4a << "#BEGIN PLOT\n"; + fig4a << "LegendOnly=/e30 /e50\n"; + fig4a << "DrawOnly=/e30 /e50\n"; + fig4a << "Title=Figure 4a\n"; + fig4a << "RatioPlot=0\n"; + fig4a << "LogX=1\n"; + fig4a << "XLabel=$\\bar{n}\\cdot p$ [GeV]\n"; + fig4a << "YLabel=e\n"; + fig4a << "Legend=1\n"; + fig4a << "XMin=250.\n"; + fig4a << "YMin=0.7\n"; + fig4a << "YMax=1.05\n"; + fig4a << "# END PLOT\n"; + writeLine(fig4a,np,e30,"/e30","e $(\\mu_f=30\\,\\mathrm{GeV})$","red" ,"solid" ); + writeLine(fig4a,np,e50,"/e50","e $(\\mu_f=50\\,\\mathrm{GeV})$","blue","dashed"); + fig4a.close(); + ofstream fig4b("fig4b.dat"); + fig4b << "#BEGIN PLOT\n"; + fig4b << "LegendOnly=/q30 /q50 /g30 /g50\n"; + fig4b << "DrawOnly=/q30 /q50 /g30 /g50\n"; + fig4b << "Title=Figure 4a\n"; + fig4b << "RatioPlot=0\n"; + fig4b << "LogX=1\n"; + fig4b << "XLabel=$\\bar{n}\\cdot p$ [GeV]\n"; + fig4b << "YLabel=e\n"; + fig4b << "Legend=1\n"; + fig4b << "XMin=250.\n"; + fig4b << "YMin=0.5\n"; + fig4b << "YMax=1.05\n"; + fig4b << "# END PLOT\n"; + writeLine(fig4b,np,q30,"/q30","q $(\\mu_f=30\\,\\mathrm{GeV})$","red" ,"solid" ); + writeLine(fig4b,np,q50,"/q50","q $(\\mu_f=50\\,\\mathrm{GeV})$","blue","dashed"); + writeLine(fig4b,np,g30,"/g30","g $(\\mu_f=30\\,\\mathrm{GeV})$","green" ,"dotted" ); + writeLine(fig4b,np,g50,"/g50","g $(\\mu_f=50\\,\\mathrm{GeV})$","blue","dotdashed"); + fig4b.close(); +} + +boost::numeric::ublas::matrix +CollinearSudakov::electroWeakMatching(Energy EWScale, Energy2 s, + Herwig::EWProcess::Process process, + bool oneLoop) { + using namespace EWProcess; + // calculate the matching coefficients + evaluateMatching(EWScale,s); + // fill the matrix + boost::numeric::ublas::matrix result(1,1); + switch (process) { + case QQQQ: + case QQQQiden: + { + unsigned int numGauge = 4, numBrokenGauge = 12; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + result(0,0) = result(6,0) = ULcollinearCorr_*ULcollinearCorr_*ULcollinearCorr_*ULcollinearCorr_; + result(3,0) = result(9,0) = DLcollinearCorr_*DLcollinearCorr_*DLcollinearCorr_*DLcollinearCorr_; + for (int i=0; i<12; i++) { + if (i!=0 && i!=3 && i!=6 && i!=9) { + result(i,0) = ULcollinearCorr_*ULcollinearCorr_*DLcollinearCorr_*DLcollinearCorr_; + } + } + DuplicateColumn0(result); + } + break; + case QtQtQQ: + { + unsigned int numGauge = 4, numBrokenGauge = 12; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + result(0,0) = result(6,0) = ULcollinearCorr_*ULcollinearCorr_*tLcollinearCorr_*tLcollinearCorr_; + result(3,0) = result(9,0) = DLcollinearCorr_*DLcollinearCorr_*bLcollinearCorr_*bLcollinearCorr_; + for (int i=0; i<12; i++) { + if (i==4 || i==5 || i==10 || i==11) { + result(i,0) = ULcollinearCorr_*tLcollinearCorr_*DLcollinearCorr_*bLcollinearCorr_; + } + else if (i==1 || i==7) { + result(i,0) = DLcollinearCorr_*DLcollinearCorr_*tLcollinearCorr_*tLcollinearCorr_; + } + else if (i==2 || i==8) { + result(i,0) = ULcollinearCorr_*ULcollinearCorr_*bLcollinearCorr_*bLcollinearCorr_; + } + } + DuplicateColumn0(result); + } + break; + case QQUU: + { + unsigned int numGauge = 2; + unsigned int numBrokenGauge = 4; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = result(2,0) = ULcollinearCorr_*ULcollinearCorr_*URcollinearCorr_*URcollinearCorr_; + result(1,0) = result(3,0) = DLcollinearCorr_*DLcollinearCorr_*URcollinearCorr_*URcollinearCorr_; + DuplicateColumn0(result); + } + break; + case QtQtUU: + { + unsigned int numGauge = 2; + unsigned int numBrokenGauge = 4; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = result(2,0) = tLcollinearCorr_*tLcollinearCorr_*URcollinearCorr_*URcollinearCorr_; + result(1,0) = result(3,0) = bLcollinearCorr_*bLcollinearCorr_*URcollinearCorr_*URcollinearCorr_; + DuplicateColumn0(result); + } + break; + case QQtRtR: + { + unsigned int numGauge = 2; + unsigned int numBrokenGauge = 4; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = result(2,0) = ULcollinearCorr_*ULcollinearCorr_*tRcollinearCorr_*tRcollinearCorr_; + result(1,0) = result(3,0) = DLcollinearCorr_*DLcollinearCorr_*tRcollinearCorr_*tRcollinearCorr_; + DuplicateColumn0(result); + } + break; + case QQDD: + { + unsigned int numGauge = 2; + unsigned int numBrokenGauge = 4; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = result(2,0) = ULcollinearCorr_*ULcollinearCorr_*DRcollinearCorr_*DRcollinearCorr_; + result(1,0) = result(3,0) = DLcollinearCorr_*DLcollinearCorr_*DRcollinearCorr_*DRcollinearCorr_; + DuplicateColumn0(result); + } + break; + case QtQtDD: + { + unsigned int numGauge = 2; + unsigned int numBrokenGauge = 4; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = result(2,0) = tLcollinearCorr_*tLcollinearCorr_*DRcollinearCorr_*DRcollinearCorr_; + result(1,0) = result(3,0) = bLcollinearCorr_*bLcollinearCorr_*DRcollinearCorr_*DRcollinearCorr_; + DuplicateColumn0(result); + } + break; + case QQLL: + { + unsigned int numGauge = 2; + unsigned int numBrokenGauge = 6; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = nuLcollinearCorr_*nuLcollinearCorr_*ULcollinearCorr_*ULcollinearCorr_; + result(1,0) = nuLcollinearCorr_*nuLcollinearCorr_*DLcollinearCorr_*DLcollinearCorr_; + result(2,0) = ELcollinearCorr_*ELcollinearCorr_*ULcollinearCorr_*ULcollinearCorr_; + result(3,0) = ELcollinearCorr_*ELcollinearCorr_*DLcollinearCorr_*DLcollinearCorr_; + result(4,0) = result(5,0) = nuLcollinearCorr_*ELcollinearCorr_*ULcollinearCorr_*DLcollinearCorr_; + DuplicateColumn0(result); + } + break; + case QQEE: + { + unsigned int numGauge = 1; + unsigned int numBrokenGauge = 2; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = ULcollinearCorr_*ULcollinearCorr_*ERcollinearCorr_*ERcollinearCorr_; + result(1,0) = DLcollinearCorr_*DLcollinearCorr_*ERcollinearCorr_*ERcollinearCorr_; + DuplicateColumn0(result); + } + break; + case UUUU: + case UUUUiden: + { + unsigned int numGauge = 2; + unsigned int numBrokenGauge = 2; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = result(1,0) = URcollinearCorr_*URcollinearCorr_*URcollinearCorr_*URcollinearCorr_; + DuplicateColumn0(result); + } + break; + case tRtRUU: + { + unsigned int numGauge = 2; + unsigned int numBrokenGauge = 2; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = result(1,0) = tRcollinearCorr_*tRcollinearCorr_*URcollinearCorr_*URcollinearCorr_; + DuplicateColumn0(result); + } + break; + case UUDD: + { + unsigned int numGauge = 2; + unsigned int numBrokenGauge = 2; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = result(1,0) = URcollinearCorr_*URcollinearCorr_*DRcollinearCorr_*DRcollinearCorr_; + DuplicateColumn0(result); + } + break; + case tRtRDD: + { + unsigned int numGauge = 2; + unsigned int numBrokenGauge = 2; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = result(1,0) = tRcollinearCorr_*tRcollinearCorr_*DRcollinearCorr_*DRcollinearCorr_; + DuplicateColumn0(result); + } + break; + case UULL: + { + unsigned int numGauge = 1; + unsigned int numBrokenGauge = 2; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = nuLcollinearCorr_*nuLcollinearCorr_*URcollinearCorr_*URcollinearCorr_; + result(1,0) = ELcollinearCorr_*ELcollinearCorr_*URcollinearCorr_*URcollinearCorr_; + DuplicateColumn0(result); + } + break; + case UUEE: + { + unsigned int numGauge = 1; + unsigned int numBrokenGauge = 1; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = URcollinearCorr_*URcollinearCorr_*ERcollinearCorr_*ERcollinearCorr_; + DuplicateColumn0(result); + } + break; + case DDDD: + case DDDDiden: + { + unsigned int numGauge = 2; + unsigned int numBrokenGauge = 2; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = result(1,0) = DRcollinearCorr_*DRcollinearCorr_*DRcollinearCorr_*DRcollinearCorr_; + DuplicateColumn0(result); + } + break; + case DDLL: + { + unsigned int numGauge = 1; + unsigned int numBrokenGauge = 2; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = nuLcollinearCorr_*nuLcollinearCorr_*DRcollinearCorr_*DRcollinearCorr_; + result(1,0) = ELcollinearCorr_*ELcollinearCorr_*DRcollinearCorr_*DRcollinearCorr_; + DuplicateColumn0(result); + } + break; + case DDEE: + { + unsigned int numGauge = 1; + unsigned int numBrokenGauge = 1; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = DRcollinearCorr_*DRcollinearCorr_*ERcollinearCorr_*ERcollinearCorr_; + DuplicateColumn0(result); + } + break; + case LLLL: + case LLLLiden: + { + unsigned int numGauge = 2; + unsigned int numBrokenGauge = 6; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = nuLcollinearCorr_*nuLcollinearCorr_*nuLcollinearCorr_*nuLcollinearCorr_; + result(1,0) = nuLcollinearCorr_*nuLcollinearCorr_*ELcollinearCorr_*ELcollinearCorr_; + result(2,0) = ELcollinearCorr_*ELcollinearCorr_*nuLcollinearCorr_*nuLcollinearCorr_; + result(3,0) = ELcollinearCorr_*ELcollinearCorr_*ELcollinearCorr_*ELcollinearCorr_; + result(4,0) = result(5,0) = nuLcollinearCorr_*ELcollinearCorr_*nuLcollinearCorr_*ELcollinearCorr_; + DuplicateColumn0(result); + } + break; + case LLEE: + { + unsigned int numGauge = 1; + unsigned int numBrokenGauge = 2; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = nuLcollinearCorr_*nuLcollinearCorr_*ERcollinearCorr_*ERcollinearCorr_; + result(1,0) = ELcollinearCorr_*ELcollinearCorr_*ERcollinearCorr_*ERcollinearCorr_; + DuplicateColumn0(result); + } + break; + case EEEE: + case EEEEiden: + { + unsigned int numGauge = 1; + unsigned int numBrokenGauge = 1; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = ERcollinearCorr_*ERcollinearCorr_*ERcollinearCorr_*ERcollinearCorr_; + DuplicateColumn0(result); + } + break; + case QQWW: + case LLWW: + { + unsigned int numGauge = 5; + unsigned int numBrokenGauge = 20; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + for (unsigned int row = 0; row < result.size1(); row++) { + for (unsigned int col = 0; col < result.size2(); col++) { + + // Boson Collinear Corr_ections: + if (col==0 || col==1) { + if (row==0 || row==1 || row==6 || row==7) result(row,col) = (WtoWcollinearCorr_*WtoWcollinearCorr_); + if (row==2 || row==8) result(row,col) = (WtoZcollinearCorr_*WtoZcollinearCorr_); + if (row==3 || row==4 || row==9 || row==10) result(row,col) = (WtoZcollinearCorr_*WtoAcollinearCorr_); + if (row==5 || row==11) result(row,col) = (WtoAcollinearCorr_*WtoAcollinearCorr_); + if (row==12 || row==14) result(row,col) = (WtoWcollinearCorr_*WtoZcollinearCorr_); + if (row==13 || row==15) result(row,col) = (WtoWcollinearCorr_*WtoAcollinearCorr_); + if (row==16 || row==18) result(row,col) = (WtoWcollinearCorr_*WtoZcollinearCorr_); + if (row==17 || row==19) result(row,col) = (WtoWcollinearCorr_*WtoAcollinearCorr_); + } + if (col==2) { + if (row==2 || row==8) result(row,col) = (WtoZcollinearCorr_*BtoZcollinearCorr_); + if (row==3 || row==9) result(row,col) = (WtoZcollinearCorr_*BtoAcollinearCorr_); + if (row==4 || row==10) result(row,col) = (WtoAcollinearCorr_*BtoZcollinearCorr_); + if (row==5 || row==11) result(row,col) = (WtoAcollinearCorr_*BtoAcollinearCorr_); + if (row==14) result(row,col) = (WtoWcollinearCorr_*BtoZcollinearCorr_); + if (row==15) result(row,col) = (WtoWcollinearCorr_*BtoAcollinearCorr_); + if (row==16) result(row,col) = (WtoWcollinearCorr_*BtoZcollinearCorr_); + if (row==17) result(row,col) = (WtoWcollinearCorr_*BtoAcollinearCorr_); + } + if (col==3) { + if (row==2 || row==8) result(row,col) = (WtoZcollinearCorr_*BtoZcollinearCorr_); + if (row==3 || row==9) result(row,col) = (WtoAcollinearCorr_*BtoZcollinearCorr_); + if (row==4 || row==10) result(row,col) = (WtoZcollinearCorr_*BtoAcollinearCorr_); + if (row==5 || row==11) result(row,col) = (WtoAcollinearCorr_*BtoAcollinearCorr_); + if (row==12) result(row,col) = (WtoWcollinearCorr_*BtoZcollinearCorr_); + if (row==13) result(row,col) = (WtoWcollinearCorr_*BtoAcollinearCorr_); + if (row==18) result(row,col) = (WtoWcollinearCorr_*BtoZcollinearCorr_); + if (row==19) result(row,col) = (WtoWcollinearCorr_*BtoAcollinearCorr_); + } + if (col==4) { + if (row==2 || row==8) result(row,col) = (BtoZcollinearCorr_*BtoZcollinearCorr_); + if (row==3 || row==4 || row==9 || row==10) result(row,col) = (BtoZcollinearCorr_*BtoAcollinearCorr_); + if (row==5 || row==11) result(row,col) = (BtoAcollinearCorr_*BtoAcollinearCorr_); + } + + // Particle Collinear Corr_ections: + if (process==QQWW) { + if (row<6) result(row,col) *= (ULcollinearCorr_*ULcollinearCorr_); + if ((row>=6)&&(row<12)) result(row,col) *= (DLcollinearCorr_*DLcollinearCorr_); + if (row>=12) result(row,col) *= (ULcollinearCorr_*DLcollinearCorr_); + } + else if (process==LLWW) { + if (row<6) result(row,col) *= (nuLcollinearCorr_*nuLcollinearCorr_); + if ((row>=6)&&(row<12)) result(row,col) *= (ELcollinearCorr_*ELcollinearCorr_); + if (row>=12) result(row,col) *= (nuLcollinearCorr_*ELcollinearCorr_); + } + } + } + } + break; + case QQPhiPhi: + case LLPhiPhi: + { + unsigned int numGauge = 2; + unsigned int numBrokenGauge = 14; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + for (unsigned int row = 0; row < result.size1(); row++) { + + // Boson Colinear Corr_ections: + if (row==0 || row==5) result(row,0) = (PhitoWcollinearCorr_*PhitoWcollinearCorr_); + if (row==1 || row==6) result(row,0) = (PhitoZcollinearCorr_*PhitoZcollinearCorr_); + if (row==2 || row==3 || row==7 || row==8) result(row,0) = (PhitoZcollinearCorr_*PhitoHcollinearCorr_); + if (row==4 || row==9) result(row,0) = (PhitoHcollinearCorr_*PhitoHcollinearCorr_); + if (row==10) result(row,0) = (PhitoWcollinearCorr_*PhitoZcollinearCorr_); + if (row==11) result(row,0) = (PhitoWcollinearCorr_*PhitoHcollinearCorr_); + if (row==12) result(row,0) = (PhitoWcollinearCorr_*PhitoZcollinearCorr_); + if (row==13) result(row,0) = (PhitoWcollinearCorr_*PhitoHcollinearCorr_); + + // Particle Colinear Corr_ections: + if (process==QQPhiPhi) { + if (row<5) result(row,0) *= (ULcollinearCorr_*ULcollinearCorr_); + if ((row>=5)&&(row<10)) result(row,0) *= (DLcollinearCorr_*DLcollinearCorr_); + if (row>=10) result(row,0) *= (ULcollinearCorr_*DLcollinearCorr_); + } + else if (process==LLPhiPhi) { + if (row<5) result(row,0) *= (nuLcollinearCorr_*nuLcollinearCorr_); + if ((row>=5)&&(row<10)) result(row,0) *= (ELcollinearCorr_*ELcollinearCorr_); + if (row>=10) result(row,0) *= (nuLcollinearCorr_*ELcollinearCorr_); + } + } + DuplicateColumn0(result); + } + break; + case QQWG: + { + unsigned int numGauge = 1; + unsigned int numBrokenGauge = 6; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = result(1,0) = ULcollinearCorr_*DLcollinearCorr_*GcollinearCorr_*WtoWcollinearCorr_; + result(2,0) = ULcollinearCorr_*ULcollinearCorr_*GcollinearCorr_*WtoZcollinearCorr_; + result(3,0) = ULcollinearCorr_*ULcollinearCorr_*GcollinearCorr_*WtoAcollinearCorr_; + result(4,0) = DLcollinearCorr_*DLcollinearCorr_*GcollinearCorr_*WtoZcollinearCorr_; + result(5,0) = DLcollinearCorr_*DLcollinearCorr_*GcollinearCorr_*WtoAcollinearCorr_; + DuplicateColumn0(result); + } + break; + case QQBG: + { + unsigned int numGauge = 1; + unsigned int numBrokenGauge = 4; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = ULcollinearCorr_*ULcollinearCorr_*GcollinearCorr_*BtoZcollinearCorr_; + result(1,0) = ULcollinearCorr_*ULcollinearCorr_*GcollinearCorr_*BtoAcollinearCorr_; + result(2,0) = DLcollinearCorr_*DLcollinearCorr_*GcollinearCorr_*BtoZcollinearCorr_; + result(3,0) = DLcollinearCorr_*DLcollinearCorr_*GcollinearCorr_*BtoAcollinearCorr_; + DuplicateColumn0(result); + } + break; + case QQGG: + { + unsigned int numGauge = 3; + unsigned int numBrokenGauge = 6; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = result(1,0) = result(2,0) = ULcollinearCorr_*ULcollinearCorr_*GcollinearCorr_*GcollinearCorr_; + result(3,0) = result(4,0) = result(5,0) = DLcollinearCorr_*DLcollinearCorr_*GcollinearCorr_*GcollinearCorr_; + DuplicateColumn0(result); + } + break; + case QtQtGG: + { + unsigned int numGauge = 3; + unsigned int numBrokenGauge = 6; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = result(1,0) = result(2,0) = tLcollinearCorr_*tLcollinearCorr_*GcollinearCorr_*GcollinearCorr_; + result(3,0) = result(4,0) = result(5,0) = bLcollinearCorr_*bLcollinearCorr_*GcollinearCorr_*GcollinearCorr_; + DuplicateColumn0(result); + } + break; + case UUBB: + { + unsigned int numGauge = 1; + unsigned int numBrokenGauge = 4; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = URcollinearCorr_*URcollinearCorr_*BtoZcollinearCorr_*BtoZcollinearCorr_; + result(1,0) = URcollinearCorr_*URcollinearCorr_*BtoZcollinearCorr_*BtoAcollinearCorr_; + result(2,0) = URcollinearCorr_*URcollinearCorr_*BtoAcollinearCorr_*BtoZcollinearCorr_; + result(3,0) = URcollinearCorr_*URcollinearCorr_*BtoAcollinearCorr_*BtoAcollinearCorr_; + DuplicateColumn0(result); + } + break; + case UUPhiPhi: + { + unsigned int numGauge = 1; + unsigned int numBrokenGauge = 5; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = URcollinearCorr_*URcollinearCorr_*PhitoWcollinearCorr_*PhitoWcollinearCorr_; + result(1,0) = URcollinearCorr_*URcollinearCorr_*PhitoZcollinearCorr_*PhitoZcollinearCorr_; + result(2,0) = URcollinearCorr_*URcollinearCorr_*PhitoHcollinearCorr_*PhitoZcollinearCorr_; + result(3,0) = URcollinearCorr_*URcollinearCorr_*PhitoZcollinearCorr_*PhitoHcollinearCorr_; + result(4,0) = URcollinearCorr_*URcollinearCorr_*PhitoHcollinearCorr_*PhitoHcollinearCorr_; + DuplicateColumn0(result); + } + break; + case UUBG: + { + unsigned int numGauge = 1; + unsigned int numBrokenGauge = 2; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = URcollinearCorr_*URcollinearCorr_*GcollinearCorr_*BtoZcollinearCorr_; + result(1,0) = URcollinearCorr_*URcollinearCorr_*GcollinearCorr_*BtoAcollinearCorr_; + DuplicateColumn0(result); + } + break; + case UUGG: + { + unsigned int numGauge = 3; + unsigned int numBrokenGauge = 3; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = result(1,0) = result(2,0) = URcollinearCorr_*URcollinearCorr_*GcollinearCorr_*GcollinearCorr_; + DuplicateColumn0(result); + } + break; + case tRtRGG: + { + unsigned int numGauge = 3; + unsigned int numBrokenGauge = 3; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = result(1,0) = result(2,0) = tRcollinearCorr_*tRcollinearCorr_*GcollinearCorr_*GcollinearCorr_; + DuplicateColumn0(result); + } + break; + case DDBB: + { + unsigned int numGauge = 1; + unsigned int numBrokenGauge = 4; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = DRcollinearCorr_*DRcollinearCorr_*BtoZcollinearCorr_*BtoZcollinearCorr_; + result(1,0) = DRcollinearCorr_*DRcollinearCorr_*BtoZcollinearCorr_*BtoAcollinearCorr_; + result(2,0) = DRcollinearCorr_*DRcollinearCorr_*BtoAcollinearCorr_*BtoZcollinearCorr_; + result(3,0) = DRcollinearCorr_*DRcollinearCorr_*BtoAcollinearCorr_*BtoAcollinearCorr_; + DuplicateColumn0(result); + } + break; + case DDPhiPhi: + { + unsigned int numGauge = 1; + unsigned int numBrokenGauge = 5; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = DRcollinearCorr_*DRcollinearCorr_*PhitoWcollinearCorr_*PhitoWcollinearCorr_; + result(1,0) = DRcollinearCorr_*DRcollinearCorr_*PhitoZcollinearCorr_*PhitoZcollinearCorr_; + result(2,0) = DRcollinearCorr_*DRcollinearCorr_*PhitoHcollinearCorr_*PhitoZcollinearCorr_; + result(3,0) = DRcollinearCorr_*DRcollinearCorr_*PhitoZcollinearCorr_*PhitoHcollinearCorr_; + result(4,0) = DRcollinearCorr_*DRcollinearCorr_*PhitoHcollinearCorr_*PhitoHcollinearCorr_; + DuplicateColumn0(result); + } + break; + case DDBG: + { + unsigned int numGauge = 1; + unsigned int numBrokenGauge = 2; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = DRcollinearCorr_*DRcollinearCorr_*GcollinearCorr_*BtoZcollinearCorr_; + result(1,0) = DRcollinearCorr_*DRcollinearCorr_*GcollinearCorr_*BtoAcollinearCorr_; + DuplicateColumn0(result); + } + break; + case DDGG: + { + unsigned int numGauge = 3; + unsigned int numBrokenGauge = 3; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = result(1,0) = result(2,0) = DRcollinearCorr_*DRcollinearCorr_*GcollinearCorr_*GcollinearCorr_; + DuplicateColumn0(result); + } + break; + case EEBB: + { + unsigned int numGauge = 1; + unsigned int numBrokenGauge = 4; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = ERcollinearCorr_*ERcollinearCorr_*BtoZcollinearCorr_*BtoZcollinearCorr_; + result(1,0) = ERcollinearCorr_*ERcollinearCorr_*BtoZcollinearCorr_*BtoAcollinearCorr_; + result(2,0) = ERcollinearCorr_*ERcollinearCorr_*BtoAcollinearCorr_*BtoZcollinearCorr_; + result(3,0) = ERcollinearCorr_*ERcollinearCorr_*BtoAcollinearCorr_*BtoAcollinearCorr_; + DuplicateColumn0(result); + } + break; + case EEPhiPhi: + { + unsigned int numGauge = 1; + unsigned int numBrokenGauge = 5; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); result *= 0.0; + result(0,0) = ERcollinearCorr_*ERcollinearCorr_*PhitoWcollinearCorr_*PhitoWcollinearCorr_; + result(1,0) = ERcollinearCorr_*ERcollinearCorr_*PhitoZcollinearCorr_*PhitoZcollinearCorr_; + result(2,0) = ERcollinearCorr_*ERcollinearCorr_*PhitoHcollinearCorr_*PhitoZcollinearCorr_; + result(3,0) = ERcollinearCorr_*ERcollinearCorr_*PhitoZcollinearCorr_*PhitoHcollinearCorr_; + result(4,0) = ERcollinearCorr_*ERcollinearCorr_*PhitoHcollinearCorr_*PhitoHcollinearCorr_; + DuplicateColumn0(result); + } + break; + default: + assert(false); + } + + // This is done at the end instead of the beginning for result.size1() and cols() + if (!oneLoop) { + boost::numeric::ublas::matrix OnesMatrix(result.size1(),result.size2()); + for (unsigned int i=0; i +CollinearSudakov::highEnergyRunning(Energy highScale, Energy EWScale, Energy2 s, + Herwig::EWProcess::Process process, + bool fixedOrder) { + using namespace EWProcess; + // perform the calculation + evaluateHighScale(highScale,EWScale,s); + Complex colW(highColW_); + Complex colB(highColB_); + Complex colG(highColG_); + Complex colQ(highColQ_); + Complex colQt(highColQt_); + Complex colU(highColU_); + Complex coltR(highColtR_); + Complex colD(highColD_); + Complex colL(highColL_); + Complex colE(highColE_); + Complex colPhi(highColPhi_); + if (fixedOrder) { + /* colX not necessarily positive for s = (1000TeV)^2 for the following: + colW = log(colW.real()); + colB = log(colB.real()); + colPhi = log(colPhi.real()); + */ + colG = log(colG.real()); + colQ = log(colQ.real()); + colQt = log(colQt.real()); + colU = log(colU.real()); + coltR = log(coltR.real()); + colD = log(colD.real()); + colL = log(colL.real()); + colE = log(colE.real()); + } + // set up the matrix + boost::numeric::ublas::matrix result; + unsigned int numGauge(0); + switch (process) { + + case QQQQ: + case QQQQiden: + case QtQtQQ: + numGauge = 4; + result = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + if (process!=QtQtQQ) { + for (unsigned int i=0; i(numGauge,numGauge); + if (process==QQUU) { + for (unsigned int i=0; i(numGauge,numGauge); + if (process==QQDD) { + for (unsigned int i=0; i(numGauge,numGauge); + for (unsigned int i=0; i(numGauge,numGauge); + for (unsigned int i=0; i(numGauge,numGauge); + if (process!=tRtRUU) { + for (unsigned int i=0; i(numGauge,numGauge); + if (process==UUDD) { + for (unsigned int i=0; i(numGauge,numGauge); + for (unsigned int i=0; i(numGauge,numGauge); + for (unsigned int i=0; i(numGauge,numGauge); + for (unsigned int i=0; i(numGauge,numGauge); + for (unsigned int i=0; i(numGauge,numGauge); + for (unsigned int i=0; i(numGauge,numGauge); + for (unsigned int i=0; i(numGauge,numGauge); + for (unsigned int i=0; i(numGauge,numGauge); + for (unsigned int i=0; i(numGauge,numGauge); + if (fixedOrder) { + result(0,0) = result(1,1) = 1.0+colQ+colQ+colW+colW; + result(2,2) = result(3,3) = 1.0+colQ+colQ+colW+colB; + result(4,4) = 1.0+colQ+colQ+colB+colB; + } + else { + result(0,0) = result(1,1) = colQ*colQ*colW*colW; + result(2,2) = result(3,3) = colQ*colQ*colW*colB; + result(4,4) = colQ*colQ*colB*colB; + } + break; + + case QQPhiPhi: + numGauge = 2; + result = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + if (fixedOrder) { + result(0,0) = result(1,1) = 1.0+colQ+colQ+colPhi+colPhi; + } + else { + result(0,0) = result(1,1) = colQ*colQ*colPhi*colPhi; + } + break; + + case QQWG: + numGauge = 1; + result = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + if (fixedOrder) { + result(0,0) = 1.0+colQ+colQ+colW+colG; + } + else { + result(0,0) = colQ*colQ*colW*colG; + } + break; + + case QQBG: + numGauge = 1; + result = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + if (fixedOrder) { + result(0,0) = 1.0+colQ+colQ+colB+colG; + } + else { + result(0,0) = colQ*colQ*colB*colG; + } + break; + + case QQGG: + case QtQtGG: + numGauge = 3; + result = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + if (process==QQGG) { + if (fixedOrder) { + result(0,0) = result(1,1) = result(2,2) = 1.0+colQ+colQ+colG+colG; + } + else { + result(0,0) = result(1,1) = result(2,2) = colQ*colQ*colG*colG; + } + } + else { + if (fixedOrder) { + result(0,0) = result(1,1) = result(2,2) = 1.0+colQt+colQt+colG+colG; + } + else { + result(0,0) = result(1,1) = result(2,2) = colQt*colQt*colG*colG; + } + } + break; + + case LLWW: + numGauge = 5; + result = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + if (fixedOrder) { + result(0,0) = result(1,1) = 1.0+colL+colL+colW+colW; + result(2,2) = result(3,3) = 1.0+colL+colL+colW+colB; + result(4,4) = 1.0+colL+colL+colB+colB; + } + else { + result(0,0) = result(1,1) = colL*colL*colW*colW; + result(2,2) = result(3,3) = colL*colL*colW*colB; + result(4,4) = colL*colL*colB*colB; + } + break; + + case LLPhiPhi: + numGauge = 2; + result = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + if (fixedOrder) { + result(0,0) = result(1,1) = 1.0+colL+colL+colPhi+colPhi; + } + else { + result(0,0) = result(1,1) = colL*colL*colPhi*colPhi; + } + break; + + case UUBB: + numGauge = 1; + result = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + if (fixedOrder) { + result(0,0) = 1.0+colU+colU+colB+colB; + } + else { + result(0,0) = colU*colU*colB*colB; + } + break; + + case UUPhiPhi: + numGauge = 1; + result = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + if (fixedOrder) { + result(0,0) = 1.0+colU+colU+colPhi+colPhi; + } + else { + result(0,0) = colU*colU*colPhi*colPhi; + } + break; + + case UUBG: + numGauge = 1; + result = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + if (fixedOrder) { + result(0,0) = 1.0+colU+colU+colB+colG; + } + else { + result(0,0) = colU*colU*colB*colG; + } + break; + + case UUGG: + case tRtRGG: + numGauge = 3; + result = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + if (process==UUGG) { + if (fixedOrder) { + result(0,0) = result(1,1) = result(2,2) = 1.0+colU+colU+colG+colG; + } + else { + result(0,0) = result(1,1) = result(2,2) = colU*colU*colG*colG; + } + } + else { + if (fixedOrder) { + result(0,0) = result(1,1) = result(2,2) = 1.0+coltR+coltR+colG+colG; + } + else { + result(0,0) = result(1,1) = result(2,2) = coltR*coltR*colG*colG; + } + } + break; + + case DDBB: + numGauge = 1; + result = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + if (fixedOrder) { + result(0,0) = 1.0+colD+colD+colB+colB; + } + else { + result(0,0) = colD*colD*colB*colB; + } + break; + + case DDPhiPhi: + numGauge = 1; + result = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + if (fixedOrder) { + result(0,0) = 1.0+colD+colD+colPhi+colPhi; + } + else { + result(0,0) = colD*colD*colPhi*colPhi; + } + break; + + case DDBG: + numGauge = 1; + result = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + if (fixedOrder) { + result(0,0) = 1.0+colD+colD+colB+colG; + } + else { + result(0,0) = colD*colD*colB*colG; + } + break; + + case DDGG: + numGauge = 3; + result = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + if (fixedOrder) { + result(0,0) = result(1,1) = result(2,2) = 1.0+colD+colD+colG+colG; + } + else { + result(0,0) = result(1,1) = result(2,2) = colD*colD*colG*colG; + } + break; + + case EEBB: + numGauge = 1; + result = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + if (fixedOrder) { + result(0,0) = 1.0+colE+colE+colB+colB; + } + else { + result(0,0) = colE*colE*colB*colB; + } + break; + + case EEPhiPhi: + numGauge = 1; + result = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + if (fixedOrder) { + result(0,0) = 1.0+colE+colE+colPhi+colPhi; + } + else { + result(0,0) = colE*colE*colPhi*colPhi; + } + break; + + default: + assert(false); + } + + return result; +} + +boost::numeric::ublas::matrix +CollinearSudakov::lowEnergyRunning(Energy EWScale, Energy lowScale, Energy2 s, + Herwig::EWProcess::Process process) { + using namespace EWProcess; + // evaluate the running + evaluateLowScale(EWScale,lowScale,s); + + Complex colUL = lowColU_; + Complex colDL = lowColD_; + Complex colUR = lowColU_; + Complex colDR = lowColD_; + + Complex coltL = lowColt_; + Complex coltR = lowColt_; + Complex colbL = lowColD_; + + Complex colnuL = 1.0; + Complex colEL = lowColE_; + Complex colER = lowColE_; + + Complex colW = lowColW_; + Complex colZ = 1.0; + Complex colA = lowColA_; + + Complex colPhi = lowColW_; + Complex colPhi3 = 1.0; + Complex colH = 1.0; + + Complex colG = lowColG_; + + // calculate the matrix + boost::numeric::ublas::matrix result; + unsigned int numBrokenGauge; + switch (process) { + case QQQQ: + case QQQQiden: + numBrokenGauge = 12; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = result(6,6) = colUL*colUL*colUL*colUL; + result(3,3) = result(9,9) = colDL*colDL*colDL*colDL; + for (unsigned int i=0; i<12; i++) { + if (i!=0 && i!=3 && i!=6 && i!=9) { + result(i,i) = colUL*colUL*colDL*colDL; + } + } + break; + case QtQtQQ: + numBrokenGauge = 12; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = result(6,6) = colUL*colUL*coltL*coltL; + result(3,3) = result(9,9) = colDL*colDL*colbL*colbL; + for (unsigned int i=0; i<12; i++) { + if (i==4 || i==5 || i==10 || i==11) { + result(i,i) = colUL*coltL*colDL*colbL; + } + else if (i==1 || i==7) { + result(i,i) = colDL*colDL*coltL*coltL; + } + else if (i==2 || i==8) { + result(i,i) = colUL*colUL*colbL*colbL; + } + } + break; + case QQUU: + numBrokenGauge = 4; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = result(2,2) = colUL*colUL*colUR*colUR; + result(1,1) = result(3,3) = colDL*colDL*colUR*colUR; + break; + case QtQtUU: + numBrokenGauge = 4; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = result(2,2) = coltL*coltL*colUR*colUR; + result(1,1) = result(3,3) = colbL*colbL*colUR*colUR; + break; + case QQtRtR: + numBrokenGauge = 4; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = result(2,2) = colUL*colUL*coltR*coltR; + result(1,1) = result(3,3) = colDL*colDL*coltR*coltR; + break; + case QQDD: + numBrokenGauge = 4; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = result(2,2) = colUL*colUL*colDR*colDR; + result(1,1) = result(3,3) = colDL*colDL*colDR*colDR; + break; + case QtQtDD: + numBrokenGauge = 4; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = result(2,2) = coltL*coltL*colDR*colDR; + result(1,1) = result(3,3) = colbL*colbL*colDR*colDR; + break; + case QQLL: + numBrokenGauge = 6; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = colnuL*colnuL*colUL*colUL; + result(1,1) = colnuL*colnuL*colDL*colDL; + result(2,2) = colEL*colEL*colUL*colUL; + result(3,3) = colEL*colEL*colDL*colDL; + result(4,4) = result(5,5) = colnuL*colEL*colUL*colDL; + break; + case QQEE: + numBrokenGauge = 2; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = colUL*colUL*colER*colER; + result(1,1) = colDL*colDL*colER*colER; + break; + case UUUU: + case UUUUiden: + numBrokenGauge = 2; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = result(1,1) = colUR*colUR*colUR*colUR; + break; + case tRtRUU: + numBrokenGauge = 2; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = result(1,1) = coltR*coltR*colUR*colUR; + break; + case UUDD: + numBrokenGauge = 2; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = result(1,1) = colUR*colUR*colDR*colDR; + break; + case tRtRDD: + numBrokenGauge = 2; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = result(1,1) = coltR*coltR*colDR*colDR; + break; + case UULL: + numBrokenGauge = 2; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = colnuL*colnuL*colUR*colUR; + result(1,1) = colEL*colEL*colUR*colUR; + break; + case UUEE: + numBrokenGauge = 1; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = colUR*colUR*colER*colER; + break; + case DDDD: + case DDDDiden: + numBrokenGauge = 2; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = result(1,1) = colDR*colDR*colDR*colDR; + break; + case DDLL: + numBrokenGauge = 2; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = colnuL*colnuL*colDR*colDR; + result(1,1) = colEL*colEL*colDR*colDR; + break; + case DDEE: + numBrokenGauge = 1; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = colDR*colDR*colER*colER; + break; + case LLLL: + case LLLLiden: + numBrokenGauge = 6; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = colnuL*colnuL*colnuL*colnuL; + result(1,1) = colnuL*colnuL*colEL*colEL; + result(2,2) = colEL*colEL*colnuL*colnuL; + result(3,3) = colEL*colEL*colEL*colEL; + result(4,4) = result(5,5) = colnuL*colEL*colnuL*colEL; + break; + case LLEE: + numBrokenGauge = 2; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = colnuL*colnuL*colER*colER; + result(1,1) = colEL*colEL*colER*colER; + break; + case EEEE: + case EEEEiden: + numBrokenGauge = 1; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = colER*colER*colER*colER; + break; + case QQWW: + case LLWW: + numBrokenGauge = 20; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + for (unsigned int row = 0; row < result.size1(); row++) { + // Boson Collinear Corrections: + if (row==0 || row==1 || row==6 || row==7) result(row,row) = (colW*colW); + else if (row==2 || row==8) result(row,row) = (colZ*colZ); + else if (row==3 || row==4 || row==9 || row==10) result(row,row) = (colZ*colA); + else if (row==5 || row==11) result(row,row) = (colA*colA); + else if (row==12 || row==14) result(row,row) = (colW*colZ); + else if (row==13 || row==15) result(row,row) = (colW*colA); + else if (row==16 || row==18) result(row,row) = (colW*colZ); + else if (row==17 || row==19) result(row,row) = (colW*colA); + + // Particle Collinear Corrections: + if (process==QQWW) { + if (row<6) result(row,row) *= (colUL*colUL); + if ((row>=6)&&(row<12)) result(row,row) *= (colDL*colDL); + if (row>=12) result(row,row) *= (colUL*colDL); + } + else if (process==LLWW) { + if (row<6) result(row,row) *= (colnuL*colnuL); + if ((row>=6)&&(row<12)) result(row,row) *= (colEL*colEL); + if (row>=12) result(row,row) *= (colnuL*colEL); + } + } + break; + case QQPhiPhi: + case LLPhiPhi: + numBrokenGauge = 14; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + for (unsigned int row = 0; row < result.size1(); row++) { + + // Boson Colinear Corrections: + if (row==0 || row==5) result(row,row) = (colPhi*colPhi); + else if (row==1 || row==6) result(row,row) = (colPhi3*colPhi3); + else if (row==2 || row==3 || row==7 || row==8) result(row,row) = (colPhi3*colH); + else if (row==4 || row==9) result(row,row) = (colH*colH); + else if (row==10) result(row,row) = (colPhi*colPhi3); + else if (row==11) result(row,row) = (colPhi*colH); + else if (row==12) result(row,row) = (colPhi*colPhi3); + else if (row==13) result(row,row) = (colPhi*colH); + + // Particle Colinear Corrections: + if (process==QQPhiPhi) { + if (row<5) result(row,row) *= (colUL*colUL); + if ((row>=5)&&(row<10)) result(row,row) *= (colDL*colDL); + if (row>=10) result(row,row) *= (colUL*colDL); + } + else if (process==LLPhiPhi) { + if (row<5) result(row,row) *= (colnuL*colnuL); + if ((row>=5)&&(row<10)) result(row,row) *= (colEL*colEL); + if (row>=10) result(row,row) *= (colnuL*colEL); + } + } + break; + case QQWG: + numBrokenGauge = 6; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = result(1,1) = colUL*colDL*colG*colW; + result(2,2) = colUL*colUL*colG*colZ; + result(3,3) = colUL*colUL*colG*colA; + result(4,4) = colDL*colDL*colG*colZ; + result(5,5) = colDL*colDL*colG*colA; + break; + case QQBG: + numBrokenGauge = 4; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = colUL*colUL*colG*colZ; + result(1,1) = colUL*colUL*colG*colA; + result(2,2) = colDL*colDL*colG*colZ; + result(3,3) = colDL*colDL*colG*colA; + break; + case QQGG: + numBrokenGauge = 6; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = result(1,1) = result(2,2) = colUL*colUL*colG*colG; + result(3,3) = result(4,4) = result(5,5) = colDL*colDL*colG*colG; + break; + case QtQtGG: + numBrokenGauge = 6; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = result(1,1) = result(2,2) = coltL*coltL*colG*colG; + result(3,3) = result(4,4) = result(5,5) = colbL*colbL*colG*colG; + break; + case UUBB: + numBrokenGauge = 4; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = colUR*colUR*colZ*colZ; + result(1,1) = colUR*colUR*colZ*colA; + result(2,2) = colUR*colUR*colA*colZ; + result(3,3) = colUR*colUR*colA*colA; + break; + case UUPhiPhi: + numBrokenGauge = 5; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = colUR*colUR*colPhi*colPhi; + result(1,1) = colUR*colUR*colPhi3*colPhi3; + result(2,2) = colUR*colUR*colH*colPhi3; + result(3,3) = colUR*colUR*colPhi3*colH; + result(4,4) = colUR*colUR*colH*colH; + break; + case UUBG: + numBrokenGauge = 2; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = colUR*colUR*colG*colZ; + result(1,1) = colUR*colUR*colG*colA; + break; + case UUGG: + numBrokenGauge = 3; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = result(1,1) = result(2,2) = colUR*colUR*colG*colG; + break; + case tRtRGG: + numBrokenGauge = 3; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = result(1,1) = result(2,2) = coltR*coltR*colG*colG; + break; + case DDBB: + numBrokenGauge = 4; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = colDR*colDR*colZ*colZ; + result(1,1) = colDR*colDR*colZ*colA; + result(2,2) = colDR*colDR*colA*colZ; + result(3,3) = colDR*colDR*colA*colA; + break; + case DDPhiPhi: + numBrokenGauge = 5; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = colDR*colDR*colPhi*colPhi; + result(1,1) = colDR*colDR*colPhi3*colPhi3; + result(2,2) = colDR*colDR*colH*colPhi3; + result(3,3) = colDR*colDR*colPhi3*colH; + result(4,4) = colDR*colDR*colH*colH; + break; + case DDBG: + numBrokenGauge = 2; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = colDR*colDR*colG*colZ; + result(1,1) = colDR*colDR*colG*colA; + break; + + case DDGG: + numBrokenGauge = 3; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = result(1,1) = result(2,2) = colDR*colDR*colG*colG; + break; + case EEBB: + numBrokenGauge = 4; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = colER*colER*colZ*colZ; + result(1,1) = colER*colER*colZ*colA; + result(2,2) = colER*colER*colA*colZ; + result(3,3) = colER*colER*colA*colA; + break; + case EEPhiPhi: + numBrokenGauge = 5; + result = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + result(0,0) = colER*colER*colPhi*colPhi; + result(1,1) = colER*colER*colPhi3*colPhi3; + result(2,2) = colER*colER*colH*colPhi3; + result(3,3) = colER*colER*colPhi3*colH; + result(4,4) = colER*colER*colH*colH; + break; + default: + assert(false); + } + return result; +} + + + + diff --git a/MatrixElement/EW/CollinearSudakov.fh b/MatrixElement/EW/CollinearSudakov.fh new file mode 100644 --- /dev/null +++ b/MatrixElement/EW/CollinearSudakov.fh @@ -0,0 +1,18 @@ +// -*- C++ -*- +// +// This is the forward declaration of the CollinearSudakov class. +// +#ifndef Herwig_CollinearSudakov_FH +#define Herwig_CollinearSudakov_FH + +#include "ThePEG/Config/ThePEG.h" + +namespace Herwig { + +class CollinearSudakov; + +ThePEG_DECLARE_POINTERS(Herwig::CollinearSudakov,CollinearSudakovPtr); + +} + +#endif diff --git a/MatrixElement/EW/CollinearSudakov.h b/MatrixElement/EW/CollinearSudakov.h new file mode 100644 --- /dev/null +++ b/MatrixElement/EW/CollinearSudakov.h @@ -0,0 +1,546 @@ +// -*- C++ -*- +#ifndef Herwig_CollinearSudakov_H +#define Herwig_CollinearSudakov_H +// +// This is the declaration of the CollinearSudakov class. +// + +#include "ThePEG/Interface/Interfaced.h" +#include "Herwig/Utilities/GSLIntegrator.h" +// work around a Boost 1.64 bug where ublas headers would fail otherwise +#include +#if (BOOST_VERSION / 100 >= 1064) +#include +#endif +#include +#include "EWProcess.h" +#include "CollinearSudakov.fh" + +namespace Herwig { + +using namespace ThePEG; + +/** + * Struct for the wavefunction corrections + */ +struct WaveFunctionCorrections { + Complex RW; + Complex RA; + Complex RZ; + Complex RAtoZ; + Complex RZtoA; + Complex RPhi; + Complex EW; + Complex EZ; + Complex RPhi3; + Complex RH; + Complex tLuLDiff; + Complex bLdLDiff; + Complex tRuRDiff; + + // The following are constants from parameter integrals: + + Complex fFW0; + Complex fF0W; + Complex fFZZ; + Complex aHH; + Complex aZZ; + Complex aW0; + Complex a0W; + Complex bHH; + Complex bZZ; + Complex cHH; + Complex cZZ; + Complex cW0; + Complex atHH; + Complex atZZ; + Complex atW0; + Complex at0W; + Complex ctHH; + Complex ctZZ; + Complex ctW0; + Complex btHH; + Complex btZZ; + + Complex fs10; + Complex fs1ZW; + Complex fsWZWZ; + Complex fsZW1; + Complex fs01; + Complex fsHW1; + Complex fsHZ1; + Complex fs1HW; + Complex fs1HZ; +}; + +/** + * Here is the documentation of the CollinearSudakov class. + * + * @see \ref CollinearSudakovInterfaces "The interfaces" + * defined for CollinearSudakov. + */ +class CollinearSudakov: public Interfaced { + +public: + + /** @name Standard constructors and destructors. */ + //@{ + /** + * The default constructor. + */ + CollinearSudakov(); + + /** + * The destructor. + */ + virtual ~CollinearSudakov(); + //@} + +public: + + /** + * Evalaute the electroweak matching as a matrix + */ + boost::numeric::ublas::matrix + electroWeakMatching(Energy EWScale, Energy2 s, + Herwig::EWProcess::Process process, + bool oneLoop); + + /** + * Evalaute the high energy running as a matrix + */ + boost::numeric::ublas::matrix + highEnergyRunning(Energy highScale, Energy EWScale, Energy2 s, + Herwig::EWProcess::Process process, + bool fixedOrder); + + /** + * Evaluate the low energy running as a matrix + */ + boost::numeric::ublas::matrix + lowEnergyRunning(Energy EWScale, Energy lowScale, Energy2 s, + Herwig::EWProcess::Process process); +public: + + /** + * Make plots for tests + */ + void makePlots(); + +protected: + + /** + * Evaluate the high scale contributions + */ + void evaluateHighScale(Energy highScale, Energy EWScale, Energy2 S); + + /** + * Evaluate the low scale contributions + */ + void evaluateLowScale(Energy EWScale, Energy lowScale, Energy2 S); + + /** + * Evaluate the matching + */ + void evaluateMatching(Energy EWScale,Energy2 S); + +public: + + /** + * The operator to be integrated + */ + InvEnergy operator ()(Energy mu) const { + if(high_) return highScaleIntegrand(mu); + else return lowScaleIntegrand(mu); + } + /** Argument type for GaussianIntegrator */ + typedef Energy ArgType; + /** Return type for GaussianIntegrator */ + typedef InvEnergy ValType; + +public: + + /** @name Functions used by the persistent I/O system. */ + //@{ + /** + * Function used to write out object persistently. + * @param os the persistent output stream written to. + */ + void persistentOutput(PersistentOStream & os) const; + + /** + * Function used to read in object persistently. + * @param is the persistent input stream read from. + * @param version the version number of the object when written. + */ + void persistentInput(PersistentIStream & is, int version); + //@} + + /** + * The standard Init function used to initialize the interfaces. + * Called exactly once for each class by the class description system + * before the main function starts or + * when this class is dynamically loaded. + */ + static void Init(); + +protected: + + /** + * The integral of the high scale part of the Sudakov + */ + Complex highScaleIntegral(bool SU3, bool SU2, double Y, + Energy2 s, Energy mu_h, Energy mu_l, bool fermion, + bool longitudinal, double yukFactor); + + /** + * the integral of the low scale part of the Sudakov + */ + Complex lowScaleIntegral(bool SU3, double Q, Energy2 s, + Energy mu_h, Energy mu_l, bool fermion, + double boostFactor); + +protected: + + /** + * High-scale integrand + */ + InvEnergy highScaleIntegrand(Energy mu) const; + + /** + * Low-scale integrand + */ + InvEnergy lowScaleIntegrand(Energy mu) const; + + /** + * Calculate the wavefunction corrections + */ + WaveFunctionCorrections waveFunctionCorrections(Energy EWScale); + + /** + * Collinear matiching for W + */ + Complex CollinearDw(Energy2 s, Energy EWScale); + + /** + * Collinear matching for Z + */ + Complex CollinearDz(Energy2 s, Energy EWScale); + +protected: + + /** @name Clone Methods. */ + //@{ + /** + * Make a simple clone of this object. + * @return a pointer to the new object. + */ + virtual IBPtr clone() const; + + /** Make a clone of this object, possibly modifying the cloned object + * to make it sane. + * @return a pointer to the new object. + */ + virtual IBPtr fullclone() const; + //@} + + +// If needed, insert declarations of virtual function defined in the +// InterfacedBase class here (using ThePEG-interfaced-decl in Emacs). + + +private: + + /** + * The assignment operator is private and must never be called. + * In fact, it should not even be implemented. + */ + CollinearSudakov & operator=(const CollinearSudakov &) = delete; +private: + + /** + * Parameters for the integrand + */ + //@{ + /** + * Whether high or low scale + */ + bool high_; + + /** + * Whether real of imaginary part + */ + bool real_; + + /** + * \f$SU(3)\f$ + */ + bool SU3_; + + /** + * + */ + bool SU2_; + + /** + * + */ + double Y_; + + /** + * + */ + Energy2 s_; + + /** + * + */ + bool fermion_; + + /** + * + */ + bool longitudinal_; + + /** + * + */ + double yukFactor_; + + /** + * + */ + double boostFactor_; + + /** + * + */ + double Q_; + //@} + + /** + * Parameters + */ + //@{ + /** + * Order for the K terms + */ + int K_ORDER_; + + /** + * Order for the B terms + */ + int B_ORDER_; + //@} + + /** + * Integrator + */ + GSLIntegrator integrator_; + +private: + + /** + * Storage of the high scale pieces + */ + //@{ + /** + * + */ + Complex highColW_; + + /** + * + */ + Complex highColB_; + + /** + * + */ + Complex highColG_; + + /** + * + */ + Complex highColQ_; + + /** + * + */ + Complex highColQt_; + + /** + * + */ + Complex highColU_; + + /** + * + */ + Complex highColtR_; + + /** + * + */ + Complex highColD_; + + /** + * + */ + Complex highColL_; + + /** + * + */ + Complex highColE_; + + /** + * + */ + Complex highColPhi_; + //@} + + /** + * Storage of the low scale pieces + */ + //@{ + /** + * + */ + complex lowColW_; + + /** + * + */ + Complex lowColA_; + + /** + * + */ + Complex lowColG_; + + /** + * + */ + Complex lowColU_; + + /** + * + */ + Complex lowColt_; + + /** + * + */ + Complex lowColD_; + + /** + * + */ + Complex lowColE_; + //@} + + /** + * Storage of the matching parameters + */ + //@{ + /** + * + */ + Complex ULcollinearCorr_; + + /** + * + */ + Complex DLcollinearCorr_; + + /** + * + */ + Complex URcollinearCorr_; + + /** + * + */ + Complex DRcollinearCorr_; + + /** + * + */ + Complex tLcollinearCorr_; + + /** + * + */ + Complex tRcollinearCorr_; + + /** + * + */ + Complex bLcollinearCorr_; + + /** + * + */ + Complex nuLcollinearCorr_; + + /** + * + */ + Complex ELcollinearCorr_; + + /** + * + */ + Complex ERcollinearCorr_; + + /** + * + */ + Complex WtoWcollinearCorr_; + + /** + * + */ + Complex WtoZcollinearCorr_; + + /** + * + */ + Complex WtoAcollinearCorr_; + + /** + * + */ + Complex BtoZcollinearCorr_; + + /** + * + */ + Complex BtoAcollinearCorr_; + + /** + * + */ + Complex PhitoWcollinearCorr_; + + /** + * + */ + Complex PhitoZcollinearCorr_; + + /** + * + */ + Complex PhitoHcollinearCorr_; + + /** + * + */ + Complex GcollinearCorr_; + //@} +}; + +} + +#endif /* Herwig_CollinearSudakov_H */ diff --git a/MatrixElement/EW/EWCouplings.cc b/MatrixElement/EW/EWCouplings.cc new file mode 100644 --- /dev/null +++ b/MatrixElement/EW/EWCouplings.cc @@ -0,0 +1,734 @@ +// -*- C++ -*- +// +// This is the implementation of the non-inlined, non-templated member +// functions of the EWCouplings class. +// + +#include "EWCouplings.h" +#include "ThePEG/Interface/ClassDocumentation.h" +#include "ThePEG/Interface/Parameter.h" +#include "ThePEG/Interface/Switch.h" +#include "ThePEG/EventRecord/Particle.h" +#include "ThePEG/Repository/UseRandom.h" +#include "ThePEG/Repository/EventGenerator.h" +#include "ThePEG/Utilities/DescribeClass.h" +#include "ThePEG/Persistency/PersistentOStream.h" +#include "ThePEG/Persistency/PersistentIStream.h" +#include + +using namespace Herwig; + +namespace { + +Complex trace(boost::numeric::ublas::matrix M) { + assert(M.size1()==M.size2()); + Complex output(0.); + for(unsigned int ix=0;ixmaximumCMEnergy(); + // set the particle masses + if(massChoice_) { + mZ_ = getParticleData(ParticleID::Z0 )->mass(); + mW_ = getParticleData(ParticleID::Wplus)->mass(); + mT_ = getParticleData(ParticleID::t )->mass(); + mH_ = getParticleData(ParticleID::h0 )->mass(); + } + // logs of scales + double logEWScale = log(ewScale_/GeV); + double logHighScale = log(highScale_/GeV); + // step size + double stepsize = (logHighScale - logEWScale)/double(highSteps_); + // Initialize parameters at the ewScale + // 32 parameters, mostly zero due massless quarks + unsigned int N = 32; + vector y(N,0.), dydx(N,0.), yout(N,0.); + initializeCouplings(y); + double x = logEWScale; + derivatives(x,y,dydx); + // energy scale + 6 parameters: g1,g2,g3,y_t,lambda,vev + table_ = boost::numeric::ublas::matrix(highSteps_+1,7); + table_(0,0) = logEWScale; + for (unsigned int i=1; i=29) table_(0,i-25) = y[i].real(); + } + int counter = 1; + + // Use 4th order runge-kutta to integrate to highScale + int steps = highSteps_; + while (steps > 0) { + RK4(y,dydx,x,stepsize,yout); + + // Advance x and calculate derivatives at new starting point + for(unsigned int j=0; j=29) table_(counter,i-25) = y[i].real(); + } + + steps--; + counter++; + } + // Initialize couplings at mu < 91.1876 GeV + initializeLow(); +} + +EWCouplings::~EWCouplings() {} + +IBPtr EWCouplings::clone() const { + return new_ptr(*this); +} + +IBPtr EWCouplings::fullclone() const { + return new_ptr(*this); +} + +void EWCouplings::persistentOutput(PersistentOStream & os) const { + os << ounit(ewScale_,GeV) << ounit(highScale_,GeV) << ounit(lowScale_,GeV) + << includeSU3_ << includeEW_ << ounit(mZ_,GeV) << ounit(mW_,GeV) + << ounit(mT_,GeV) << ounit(mH_,GeV) << massChoice_ << initialized_ + << loops_ << highSteps_ << lowSteps_ + << a1MZ_ << a2MZ_ << aSMZ_ << lambdat_; + os << table_.size1() << table_.size2(); + for(unsigned int ix=0;ix> iunit(ewScale_,GeV) >> iunit(highScale_,GeV) >> iunit(lowScale_,GeV) + >> includeSU3_ >> includeEW_ >> iunit(mZ_,GeV) >> iunit(mW_,GeV) + >> iunit(mT_,GeV) >> iunit(mH_,GeV) >> massChoice_ >> initialized_ + >> loops_ >> highSteps_ >> lowSteps_ + >> a1MZ_ >> a2MZ_ >> aSMZ_ >> lambdat_; + unsigned int size1,size2; + is >> size1 >> size2; + table_.resize(size1,size2); + for(unsigned int ix=0;ix> table_(ix,iy); + is >> size1 >> size2; + lowTable_.resize(size1,size2); + for(unsigned int ix=0;ix> lowTable_(ix,iy); +} + + +//The following static variable is needed for the type +// description system in ThePEG. +DescribeClass +describeHerwigEWCouplings("Herwig::EWCouplings", "HwMEEW.so"); + +void EWCouplings::Init() { + + static ClassDocumentation documentation + ("The EWCouplings class implements"); + + static Switch interfaceMassChoice + ("MassChoice", + "Where to get the SM particle masses from", + &EWCouplings::massChoice_, false, false, false); + static SwitchOption interfaceMassChoiceLocal + (interfaceMassChoice, + "Local", + "Use local values", + false); + static SwitchOption interfaceMassChoiceParticleData + (interfaceMassChoice, + "ParticleData", + "Get the values from the ParticleData object", + true); + + static Parameter interfaceEWScale + ("EWScale", + "The electroweak scale for matching between high and low energy running", + &EWCouplings::ewScale_, GeV, 91.1876*GeV, 10.0*GeV, 10000.0*GeV, + false, false, Interface::limited); + + static Parameter interfaceLowScale + ("LowScale", + "The low energy scale at which to stop the running", + &EWCouplings::lowScale_, GeV, 10.*GeV, 1.0*GeV, 100.0*GeV, + false, false, Interface::limited); + + static Parameter interfacemZ + ("mZ", + "The mass of the Z boson", + &EWCouplings::mZ_, 91.1876*GeV, 90.*GeV, 92.*GeV, + false, false, Interface::limited); + + static Parameter interfacemW + ("mW", + "The mass of the W boson", + &EWCouplings::mW_, 80.399*GeV, 75.*GeV, 85.*GeV, + false, false, Interface::limited); + + static Parameter interfacemT + ("mT", + "The mass of the top quark", + &EWCouplings::mT_, 173.1*GeV, 100.*GeV, 1000.*GeV, + false, false, Interface::limited); + + static Parameter interfacemH + ("mH", + "The mass of the Higgs boson", + &EWCouplings::mH_, 125.*GeV, 100.*GeV, 1000.*GeV, + false, false, Interface::limited); + + static Parameter interfaceLoops + ("Loops", + "The number of loops", + &EWCouplings::loops_, 2, 1, 3, + false, false, Interface::limited); + + static Parameter interfaceHighSteps + ("HighSteps", + "The number of steps for the Runga-Kutta and interpolation of the couplings above mZ", + &EWCouplings::highSteps_, 200, 10, 1000000, + false, false, Interface::limited); + + static Parameter interfaceLowSteps + ("LowSteps", + "The number of steps for the Runga-Kutta and interpolation of the couplings below mZ", + &EWCouplings::lowSteps_, 200, 10, 1000000, + false, false, Interface::limited); + + static Parameter interfacea1MZ + ("Alpha1MZ", + "The value of a1(MZ)", + &EWCouplings::a1MZ_, 0.01017054, 0.0, 1., + false, false, Interface::limited); + + static Parameter interfacea2MZ + ("Alpha2MZ", + "The value of a2(MZ)", + &EWCouplings::a2MZ_, 0.03378168, 0.0, 1., + false, false, Interface::limited); + + static Parameter interfaceasMZ + ("AlphasMZ", + "The value of as(MZ)", + &EWCouplings::aSMZ_, 0.1176, 0.0, 1., + false, false, Interface::limited); + + static Parameter interfaceLambdaT + ("LambdaT", + "The top quark Yukawa at the matching scale", + &EWCouplings::lambdat_, 0.991172, 0.5, 2.0, + false, false, Interface::limited); + +} + + + +void EWCouplings::initializeLow() { + using Constants::pi; + // For scales less than ewScale, the only couplings calculated here are those of + // alpha_EW and alpha3: + + double logEWScale = log(ewScale_ /GeV); + double loglowScale = log(lowScale_/GeV); + + double stepsize = (loglowScale - logEWScale)/double(lowSteps_); + int steps = lowSteps_; + + // Initialize parameters at the ewScale + unsigned int N=2; // Total # of parameters = 2 + vector y(N), dydx(N), yout(N); + for (unsigned int i=0; i 0) { + RK4(y,dydx,x,stepsize,yout); + // Advance x and calculate derivatives at new starting point + for(unsigned int j=0; j &y, vector &dydx, + const double x, const double h, vector &yout) { + + unsigned int n = y.size(); + std::vector dym(n), dyt(n), yt(n); + double hh = h*0.5; + double h6 = h/6.0; + double xh = x + hh; + const Complex I(0,1.0); + + for(unsigned int i=0; i & y) { + using Constants::pi; + // \todo make these values parameters so they can be changed + InvEnergy2 gFermi = 1.16637*pow(10.0,-5)/GeV2; + Energy vev = 1.0/(sqrt(sqrt(2.0)*gFermi)); // vev = 246.221 + + y[0] = sqrt(5./3.*4.*pi*a1MZ_); // g1 = Sqrt[5/3] * Sqrt[4*pi*a1] + y[1] = sqrt(4.*pi*a2MZ_); // g2 = Sqrt[4*pi*a2] + y[2] = sqrt(4.*pi*aSMZ_); // g3 = Sqrt[4*pi*as] + // Note lambda_t = sqrt(2.0)*mt/vev only valid for mt(mt); need mt(mZ) here + // Top Yukawa lambda from Manohar + //Complex lambda_t = 1.02858; + // Top Yukawa lambda from Sascha + double lambda_t =lambdat_; + // Quartic coupling lambda (need to multiply by a factor of 2 when accessing the quartic coupling) + double lambda = (mH_/vev)*(mH_/vev); + y[29] = lambda_t; + y[30] = lambda; + y[31] = vev/GeV; +} + +void EWCouplings::derivatives(const double x, vector & y, + vector &dydx) { + // zero the output + for (unsigned int i=0; i &y, vector & dydx) { + using Constants::pi; + using boost::numeric::ublas::axpy_prod; + using boost::numeric::ublas::herm; + const Complex I(0,1.0); + // Yukawa + boost::numeric::ublas::matrix Yuk_u(3,3), Yuk_d(3,3), Yuk_e(3,3); + for(unsigned int ix=0;ix<3;++ix) { + for(unsigned int iy=0;iy<3;++iy) { + Yuk_u(ix,iy) = y[21+3*ix+iy]; + Yuk_d(ix,iy) = y[12+3*ix+iy]; + Yuk_e(ix,iy) = y[ 3+3*ix+iy]; + } + } + // gauge + boost::numeric::ublas::vector gauge(3); + for(unsigned int l=0; l<3; l++) gauge[l] = y[l]; + // Evaluate beta functions for gauge couplings + double Ng = 0.5*numberOfFlavours(x); + boost::numeric::ublas::vector b(3), g2(3), gc(3), Cu(3), Cd(3), Ce(3); + boost::numeric::ublas::matrix B1(3,3),B2(3,3), B3(3,3), B(3,3); + b[0] = -4.0/3.0*Ng - 1.0/10.0; + b[1] = 22.0/3.0 - 4.0/3.0*Ng - 1.0/6.0; + b[2] = 11.0 - 4.0/3.0*Ng; + for(unsigned int ix=0;ix<3;++ix) { + for(unsigned int iy=0;iy<3;++iy) { + B1(ix,iy) = 0.; + B2(ix,iy) = 0.; + B3(ix,iy) = 0.; + } + } + B1(1,1) = 136.0/3.0; + B1(2,2) = 102.0; + B2(0,0) = 19.0/15.0; + B2(0,1) = 1.0/5.0; + B2(0,2) = 11.0/30.0; + B2(1,0) = 3.0/5.0; + B2(1,1) = 49.0/3.0; + B2(1,2) = 3.0/2.0 ; + B2(2,0) = 44.0/15.0; + B2(2,1) = 4.0; + B2(2,2) = 76.0/3.0; + B3(0,0) = 9.0/50.0; + B3(0,1) = 3.0/10.0; + B3(1,0) = 9.0/10.0; + B3(1,1) = 13.0/6.0; + B = B1 - Ng*B2 - B3; + Cu[0] = 17.0/10.0; + Cu[1] = 3.0/2.0; + Cu[2] = 2.0; + Cd[0] = 1.0/2.0; + Cd[1] = 3.0/2.0; + Cd[2] = 2.0; + Ce[0] = 3.0/2.0; + Ce[1] = 1.0/2.0; + Ce[2] = 0.0; + for (int i=0; i<3; i++) { + g2(i) = pow(gauge(i),2); + } + // gc = trans(g2) * B + axpy_prod(g2, B, gc, true); + // compute the answer + if(loops_ >= 1) { + for(int l=0; l<3; l++) { + dydx[l] = -b(l)*pow(gauge(l),3)/(16.0*pow(pi,2)); + } + if (loops_ >= 2) { + boost::numeric::ublas::matrix temp(3,3); + axpy_prod(herm(Yuk_u),Yuk_u,temp); + Complex tr1 = trace(temp); + axpy_prod(herm(Yuk_d),Yuk_d,temp); + Complex tr2 = trace(temp); + axpy_prod(herm(Yuk_e),Yuk_e,temp); + Complex tr3 = trace(temp); + for(int l=0; l<3; l++) { + dydx[l] += -pow(gauge(l),3)/pow(16.0*pow(pi,2),2)* + (gc(l) + Cu(l)*tr1 + Cd(l)*tr2 + Ce(l)*tr3 ); + } + } + } +} + +void EWCouplings::lowBetaGauge(const double, vector &y, + vector &dydx) { + using Constants::pi; + const Complex I(0,1.0); + Complex e = y[0], g3 = y[1]; + // Evaluate beta functions for gauge couplings + double Nu = 2.0, Nd = 3.0, Nl = 3.0; + if(loops_ >=1) { + dydx[0] += (16.0/9.0*Nu + 4.0/9.0*Nd + 4.0/3.0*Nl)*pow(e,3)/pow(4.0*pi,2); + dydx[1] += (2.0/3.0*(Nu+Nd)-11.0)*pow(g3,3)/pow(4.0*pi,2); + // Note this also includes the three-loop contribution for alpha_3 + if (loops_ >= 2) { + dydx[0] += (64.0/27.0*Nu+4.0/27.0*Nd+4.0*Nl)*pow(e,5)/pow(4.0*pi,4) + + (64.0/9.0*Nu+16.0/9.0*Nd)*pow(e,3)*pow(g3,2)/pow(4.0*pi,4); + dydx[1] += (38.0/3.0*(Nu+Nd)-102.0)*pow(g3,5)/pow(4.0*pi,4) + + (8.0/9.0*Nu+2.0/9.0*Nd)*pow(g3,3)*pow(e,2)/pow(4.0*pi,4) + + (5033.0/18.0*(Nu+Nd)-325.0/54.0*(Nu+Nd)*(Nu+Nd)-2857.0/2.0)*pow(g3,7)/pow(4.0*pi,6); + } + } +} + +void EWCouplings::betaYukawa(const double x, vector< Complex > &y, vector &dydx) { + using Constants::pi; + const Complex I(0,1.0); + boost::numeric::ublas::identity_matrix Id(3,3); + // Yukawa + boost::numeric::ublas::matrix Yuk_u(3,3), Yuk_d(3,3), Yuk_e(3,3); + for(unsigned int ix=0;ix<3;++ix) { + for(unsigned int iy=0;iy<3;++iy) { + Yuk_u(ix,iy) = y[21+3*ix+iy]; + Yuk_d(ix,iy) = y[12+3*ix+iy]; + Yuk_e(ix,iy) = y[ 3+3*ix+iy]; + } + } + // gauge + double Ng = 0.5*numberOfFlavours(x); + boost::numeric::ublas::vector gauge(3); + for(unsigned int l=0; l<3; l++) gauge[l] = y[l]; + Complex lambda = y[30]; + // traces of yukawa matrices + boost::numeric::ublas::matrix mTemp(3,3),MUU(3,3),MDD(3,3),MLL(3,3), + MUU2(3,3),MDD2(3,3),MLL2(3,3),MUUDD(3,3),MDDUU(3,3); + axpy_prod(herm(Yuk_u),Yuk_u,MUU); + Complex trU = trace( MUU); + axpy_prod(MUU,MUU,MUU2); + Complex trUU = trace(MUU2); + axpy_prod(herm(Yuk_d),Yuk_d,MDD); + Complex trD = trace( MDD); + axpy_prod(MDD,MDD,MDD2); + Complex trDD = trace(MDD2); + axpy_prod(MUU,MDD,MUUDD); + Complex trUD = trace(MUUDD); + axpy_prod(MDD,MUU,MDDUU); + axpy_prod(herm(Yuk_e),Yuk_e,MLL); + Complex trL = trace( MLL); + axpy_prod(MLL,MLL,MLL2); + Complex trLL = trace(MLL2); + Complex g02 = sqr(gauge[0]); + Complex g12 = sqr(gauge[1]); + Complex g22 = sqr(gauge[2]); + // Evaluate beta functions for yukawa couplings + boost::numeric::ublas::zero_matrix zero3x3(3,3); + boost::numeric::ublas::matrix dYuk_udx(zero3x3), dYuk_ddx(zero3x3), dYuk_edx(zero3x3), beta1_u(zero3x3), + beta1_d(zero3x3), beta1_e(zero3x3), beta2_u(zero3x3), beta2_d(zero3x3), beta2_e(zero3x3); + Complex Y2 = 3.0*trU+3.0*trD + trL; + Complex Y4 = (17.0/20.0*g02 + 9.0/4.0*g12 + 8.0*g22)*trU + + (1.0/4.0*g02 + 9.0/4.0*g12 + 8.0*g22)*trD + 3.0/4.0*(g02 + g12)*trL; + Complex chi4 = 27.0/4.0*trUU + 27.0/4.0*trDD + 9.0/4.0*trLL - 6.0/4.0*trUD; + if(loops_ >= 1) { + beta1_u = 3.0/2.0*(MUU - MDD) + (Y2 - 17.0/20.0*g02 - 9.0/4.0*g12 - 8.0*g22)*Id; + beta1_d = 3.0/2.0*(MDD - MUU) + (Y2 - 1.0/4.0*g02 - 9.0/4.0*g12 - 8.0*g22)*Id; + beta1_e = 3.0/2.0*(MLL) + (Y2 - 9.0/4.0*g02 - 9.0/4.0*g12)*Id; + + axpy_prod(Yuk_u,beta1_u,mTemp); + dYuk_udx += (1.0/(16.0*pow(pi,2)))*mTemp; + axpy_prod(Yuk_d,beta1_d,mTemp); + dYuk_ddx += (1.0/(16.0*pow(pi,2)))*mTemp; + axpy_prod(Yuk_e,beta1_e,mTemp); + dYuk_edx += (1.0/(16.0*pow(pi,2)))*mTemp; + + if (loops_ >= 2) { + Complex l2=sqr(lambda); + beta2_u = 3.0/2.0*MUU2 - MUUDD - 1.0/4.0*MDDUU + 11.0/4.0*MDD2 + Y2*(5.0/4.0*MDD - 9.0/4.0*MUU) + + (-chi4 + 3.0/2.0*l2)*Id - 2.0*lambda*(3.0*MUU + MDD) + + (223.0/80.0*g02 + 135.0/16.0*g12 + 16.0*g22)*(MUU) - + (43.0/80.0*g02 - 9.0/16.0*g12 + 16.0*g22)*(MDD) + 5.0/2.0*Y4*Id + + ((9.0/200.0 + 29.0/45.0*Ng)*pow(gauge[0],4) - 9.0/20.0*pow(gauge[0]*gauge[1],2) + + 19.0/15.0*pow(gauge[0]*gauge[2],2) - (35.0/4.0 - Ng)*pow(gauge[1],4) + 9.0*pow(gauge[1]*gauge[2],2) - + (404.0/3.0 - 80.0/9.0*Ng)*pow(gauge[2],4))*Id; + beta2_d = 3.0/2.0*MDD2 - MDDUU - 1.0/4.0*MUUDD + 11.0/4.0*MUU2 + Y2*(5.0/4.0*MUU - 9.0/4.0*MDD) + (-chi4 + 3.0/2.0*l2)*Id - 2.0*lambda*(3.0*MDD + MUU) + (187.0/80.0*g02 + 135.0/16.0*g12 + 16.0*g22)*(MDD) - (79.0/80.0*g02 - 9.0/16.0*g12 + 16.0*g22)*(MUU) + 5.0/2.0*Y4*Id - ((29.0/200.0 + 1.0/45.0*Ng)*pow(gauge[0],4) - 27.0/20.0*pow(gauge[0]*gauge[1],2) + 31.0/15.0*pow(gauge[0]*gauge[2],2) - (35.0/4.0 - Ng)*pow(gauge[1],4) + 9.0*pow(gauge[1]*gauge[2],2) - (404.0/3.0 - 80.0/9.0*Ng)*pow(gauge[2],4))*Id; + beta2_e = 3.0/2.0*MLL2 - 9.0/4.0*Y2*MLL + (-chi4 + 3.0/2.0*l2)*Id - 6.0*lambda*(MLL) + (387.0/80.0*g02 + 135.0/15.0*g12)*(MLL) + 5.0/2.0*Y4*Id + ((51.0/200.0 + 11.0/5.0*Ng)*pow(gauge[0],4) + 27.0/20.0*pow(gauge[0]*gauge[1],2) - (35.0/4.0 - Ng)*pow(gauge[1],4))*Id; + + axpy_prod(Yuk_u,beta2_u,mTemp); + dYuk_udx += (1.0/pow(16.0*pow(pi,2),2))*mTemp; + axpy_prod(Yuk_d,beta2_d,mTemp); + dYuk_ddx += (1.0/pow(16.0*pow(pi,2),2))*mTemp; + axpy_prod(Yuk_e,beta2_e,mTemp); + dYuk_edx += (1.0/pow(16.0*pow(pi,2),2))*mTemp; + } + } + + boost::numeric::ublas::vector temp(27); + + for(unsigned int ix=0;ix<3;++ix) { + for(unsigned int iy=0;iy<3;++iy) { + dydx[ 3+ix+3*iy] = dYuk_edx(ix,iy); + dydx[12+ix+3*iy] = dYuk_ddx(ix,iy); + dydx[21+ix+3*iy] = dYuk_udx(ix,iy); + } + } +} + +void EWCouplings::betaHiggs(const double x, vector &y, + vector &dydx) { + using Constants::pi; + const Complex I(0,1.0); + double Ng = 0.5*numberOfFlavours(x); + // Yukawa + boost::numeric::ublas::matrix Yuk_u(3,3), Yuk_d(3,3), Yuk_e(3,3); + for(unsigned int ix=0;ix<3;++ix) { + for(unsigned int iy=0;iy<3;++iy) { + Yuk_u(ix,iy) = y[21+3*ix+iy]; + Yuk_d(ix,iy) = y[12+3*ix+iy]; + Yuk_e(ix,iy) = y[ 3+3*ix+iy]; + } + } + // gauge + boost::numeric::ublas::vector gauge(3); + for(int l=0; l<3; l++) gauge(l) = y[l]; + Complex lambda = y[30]; + complex vev = y[31]*GeV; + // Evaluate beta functions for higgs coupling + Complex beta1_lambda(0.), beta2_lambda(0.), gamma1_vev(0.), gamma2_vev(0.), + Y2(0.), H(0.), Y4(0.), chi4(0.); + // traces of yukawa matrices + boost::numeric::ublas::matrix temp(3,3),temp2(3,3),MUU(3,3),MDD(3,3),MLL(3,3); + axpy_prod(herm(Yuk_u),Yuk_u,MUU); + Complex trU = trace( MUU); + axpy_prod(MUU,MUU,temp); + Complex trUU = trace(temp); + axpy_prod(MUU,temp,temp2); + Complex trUUU = trace(temp2); + axpy_prod(herm(Yuk_d),Yuk_d,MDD); + Complex trD = trace( MDD); + axpy_prod(MDD,MDD,temp); + Complex trDD = trace(temp); + axpy_prod(MDD,temp,temp2); + Complex trDDD = trace(temp2); + axpy_prod(MUU,MDD,temp); + Complex trUD = trace(temp); + axpy_prod(herm(Yuk_e),Yuk_e,MLL); + Complex trL = trace( MLL); + axpy_prod(MLL,MLL,temp); + Complex trLL = trace(temp); + axpy_prod(MLL,temp,temp2); + Complex trLLL = trace(temp2); + axpy_prod(MUU+MDD,MDD,temp); + axpy_prod(MUU,temp,temp2); + Complex trUUDD = trace(temp2); + + Complex g02 = sqr(gauge[0]); + Complex g12 = sqr(gauge[1]); + Complex g22 = sqr(gauge[2]); + Complex g04 = sqr(g02); + Complex g14 = sqr(g12); + double pi2 = sqr(pi); + Y2 = 3.0*trU+3.0*trD + trL; + Y4 = (17.0/20.0*g02 + 9.0/4.0*g12 + 8.0*g22)*(trU) + (1.0/4.0*g02 + 9.0/4.0*g12 + 8.0*g22)*(trD) + 3.0/4.0*(g02 + g12)*(trL); + chi4 = 27.0/4.0*trUU + 27.0/4.0*trDD + 9.0/4.0*trLL - 6.0/4.0*trUD; + H = 3.0*trUU + 3.0*trDD + trLL; + + if(loops_ >= 1) { + Complex l2=sqr(lambda); + beta1_lambda = 12.0*l2 - (9.0/5.0*g02 + 9.0*g12)*lambda + 9.0/4.0*(3.0/25.0*g04+2.0/5.0*g02*g12 + g14) + 4.0*Y2*lambda - 4.0*H; + gamma1_vev = 9.0/4.0*(1.0/5.0*g02+g12)-Y2; + + dydx[30] += 1.0/(16.0*pi2)*beta1_lambda; + dydx[31] += vev/(16.0*pi2)*gamma1_vev/GeV; + + if (loops_ >= 2) { + beta2_lambda = -78.0*lambda*l2 + 18.0*(3.0/5.0*g02 + 3.0*g12)*l2 - + ( (313.0/8.0 - 10.0*Ng)*g14 - 117.0/20.0*g02*g12 + 9.0/25.0*(229.0/4.0+50.0/9.0*Ng)*g04 )*lambda + + (497.0/8.0 - 8.0*Ng)*g14*g12 - 3.0/5.0*(97.0/24.0 + 8.0/3.0*Ng)*g02*g14 - + 9.0/25.0*(239.0/24.0 + 40.0/9.0*Ng)*g04*g12 - 27.0/125.0*(59.0/24.0 + 40.0/9.0*Ng)*g04*g02 - + 64.0*g22*(trUU + trDD) - 8.0/5.0*g02*(2.0*trUU - trDD + 3.0*trLL) - 3.0/2.0*g14*Y4 + + 10.0*lambda*( (17.0/20.0*g02 + 9.0/4.0*g12 + 8.0*g22)*trU + (1.0/4.0*g02 + 9.0/4.0*g12 + 8.0*g22)*trD + 3.0/4.0*(g02 + g12)*trL ) + + 3.0/5.0*g02*( (-57.0/10.0*g02 + 21.0*g12 )*trU + (3.0/2.0*g02 + 9.0*g12)*trD + (-15.0/2.0*g02 + 11.0*g12)*trL ) - 24.0*l2*Y2 - lambda*H + + 6.0*lambda*trUD + 20.0*(3.0*trUUU + 3.0*trDDD + trLLL) - 12.0*trUUDD; + gamma2_vev = -3.0/2.0*l2 - 5.0/2.0*Y4 + chi4 - 27.0/80.0*g02*g12 - + (93.0/800.0 + 1.0/2.0*Ng)*g04 + (511.0/32.0 - 5.0/2.0*Ng)*g14; + + dydx[30] += 1.0/pow(16.0*pi2,2)*beta2_lambda; + dydx[31] += vev/pow(16.0*pi2,2)*gamma2_vev/GeV; + } + } +} + +double EWCouplings::interpolate(double t, int paramIndex) { + double stepsize = table_(1,0)-table_(0,0); + double tol = 0.001*stepsize; + + double logewScale = log(ewScale_/GeV); + double loghighScale = log(highScale_/GeV); + + if (tloghighScale+tol) { + cerr << "Stepsize: " << stepsize << std::endl; + cerr << "tol: " << tol << std::endl; + cerr << "logewScale: " << logewScale << std::endl; + cerr << "loghighScale: " << loghighScale << std::endl; + cerr << "paramIndex: " << paramIndex << std::endl; + cerr << "t: " << t << std::endl; + + cerr << "Couplings::_Interp(double t, int parmIndex) trying to obtain parameter "; + cerr << "value outside the available range. Returning zero." << std::endl; + assert(false); + } + + // return value at EW scale + if (abs(t-logewScale)logewScale+tol) { + cerr<< "Couplings::_LowInterp(double t, int parmIndex) trying to obtain parameter "; + cerr << "value outside the available range. Returning zero." << std::endl; + assert(false); + } + + if (abs(t-logewScale) +#if (BOOST_VERSION / 100 >= 1064) +#include +#endif +#include +#include +#include "EWCouplings.fh" + +namespace Herwig { + +using namespace ThePEG; + +/** + * Here is the documentation of the EWCouplings class. + * + * @see \ref EWCouplingsInterfaces "The interfaces" + * defined for EWCouplings. + */ +class EWCouplings: public Interfaced { + +public: + + /** @name Standard constructors and destructors. */ + //@{ + /** + * The default constructor. + */ + EWCouplings(unsigned int loops=2, unsigned int steps=200, Energy lowScale=10.*GeV); + + /** + * The destructor. + */ + virtual ~EWCouplings(); + //@} + + /** + * Initialize the running couplings + */ + void initialize(); + + /** + * Number of dynamical quarks at $\log\mu = x$ (in GeV) + * N.B.Integrate out top quark at Mz, not at Mt. + */ + unsigned int numberOfFlavours(double x) { + return x >= std::log(ewScale_/GeV) ? 6 : 5; + } + +public: + + /** + * Set whether or not to include \f$SU(3)\f$ running + */ + void SU3(bool includeSU3) {includeSU3_ = includeSU3;} + + /** + * Whether or not to include \f$SU(3)\f$ running + */ + bool SU3() { return includeSU3_;} + + /** + * Set whether or not to include EW running + */ + void EW(bool includeEW) {includeEW_ = includeEW;} + + /** + * Whether or not to include EW running + */ + bool EW() { return includeEW_;} + + /** + * alpha for the U1 gauge coupling at energy mu (in GeV): + */ + double a1(Energy mu) { + if (includeEW_) { + if (mu>=ewScale_) { + return (3.0/5.0)*interpolate(log(mu/GeV),1); + } + return interpolateLow(log(mu/GeV),1); + } + else + return 0.0; + } + + /** + * alpha for the SU2 gauge coupling at energy mu (in GeV): + */ + double a2(Energy mu) { + if (includeEW_) { + if (mu=ewScale_) { + return interpolate(log(mu/GeV),3); + } + else { + return interpolateLow(log(mu/GeV),2); + } + } + else + return 0.0; + } + + /** + * alpha for EM + */ + double aEM(Energy mu) { + if (includeEW_) { + if (mu<=ewScale_) { + return interpolateLow(log(mu/GeV),1); + } + else { + double alpha1=a1(mu); + double alpha2=a2(mu); + return alpha1*alpha2/(alpha1+alpha2); + } + } + return 0.0; + } + + double aS(Energy mu) { + if(includeSU3_) { + if (mu<=ewScale_) { + return interpolateLow(log(mu/GeV),2); + } + else { + return interpolate(log(mu/GeV),3); + } + } + else return 0.0; + } + + /** + * Top quark Yukawa coupling + */ + double y_t(Energy mu) { + if (includeEW_) { + if(mu & y); + + /** + * Assigns numerical values to beta functions + * Takes in a point x = log(mu) and the values of y[i] at x and assigns dydx[i] the + * value beta[i](mu). The function Derivs farms out the plugging in to the three + * functions BetaGauge, BetaYukawa, and BetaHiggs, which evaluates the beta functions + * for the gauge couplings, yukawa matrices, and higgs quartic coupling/vev, respectively. + */ + void derivatives(const double x, vector< Complex > &y, + vector< Complex > & dydx); + + /** + * Beta function for the gauge interactions + */ + void betaGauge(const double x, vector &y, vector &dydx); + + /** + * Beta function for the gauge interactions at low scales + */ + void lowBetaGauge(const double x, vector &y, vector &dydx); + + /** + * Beta function for the Yukawa interactions + */ + void betaYukawa(const double x, vector &y, vector &dydx); + + /** + * Beta function for the Higgs interactions + */ + void betaHiggs(const double x, vector &y, vector &dydx); + + /** + * Update the couplings using 4-th order RK + * Takes in a vector y[i] of function values at a point x and the values of the + * first derivatives dydx[i] ( = dy[i]/dx ) alon with a step size stepsize. The + * function then defines assigns the value of y[i](x+stepsize) to the variable yout[i]. + * (Adapted from sample code in Numerical Recipes in C++ Press, Teukolsky, et. al.) + */ + void RK4(vector & y, vector &dydx, const double x, + const double stepsize, vector &yout); + + /** + * Initialize the low energy parameters + */ + void initializeLow(); + + /** + * Interpolate the table, t = ln(mu) + */ + double interpolate(double t, int paramIndex); + + /** + * Interpolate the tabel, t = ln(mu) + */ + double interpolateLow(double t, int paramIndex); + +private: + + /** + * The assignment operator is private and must never be called. + * In fact, it should not even be implemented. + */ + EWCouplings & operator=(const EWCouplings &) = delete; + +private: + + /** + * Electoweak Scale + */ + Energy ewScale_; + + /** + * High Scale + */ + Energy highScale_; + + /** + * Low Scale + */ + Energy lowScale_; + + /** + * Whether or not to include SU3 + */ + bool includeSU3_; + + /** + * Whether or not to include EW + */ + bool includeEW_; + + /** + * Whether or not the running couplings have been initialized + */ + bool initialized_; + + /** + * Masses of Standard Model particles + */ + //@{ + /** + * Mass Choice + */ + bool massChoice_; + + /** + * Z mass + */ + Energy mZ_; + + /** + * W mass + */ + Energy mW_; + + /** + * Top mass + */ + Energy mT_; + + /** + * Higgs boson mass + */ + Energy mH_; + //@} + + /** + * Number of loops + */ + unsigned int loops_; + + /** + * Number of steps for Runga-Kutta (High scale) + */ + unsigned int highSteps_; + + /** + * Number of steps for Runga-Kutta (Low scale) + */ + unsigned int lowSteps_; + + /** + * Matrix to store the parameters + */ + boost::numeric::ublas::matrix table_; + + /** + * Matrix to store the low energy parameters. + * This will hold only aEM and a3 at mu lowTable_; + + /** + * Input values of the couplings + */ + //@{ + /** + * \f%\alpha_1(M_Z)\f$ + */ + double a1MZ_; + + /** + * \f%\alpha_2(M_Z)\f$ + */ + double a2MZ_; + + /** + * \f%\alpha_S(M_Z)\f$ + */ + double aSMZ_; + + /** + * \f$\lambda_t\f$ + */ + double lambdat_; + //@} + +}; + +} + +#endif /* Herwig_EWCouplings_H */ diff --git a/MatrixElement/EW/EWProcess.h b/MatrixElement/EW/EWProcess.h new file mode 100644 --- /dev/null +++ b/MatrixElement/EW/EWProcess.h @@ -0,0 +1,69 @@ +// -*- C++ -*- +// +// EWProcess.h is a part of Herwig - A multi-purpose Monte Carlo event generator +// +// Herwig is licenced under version 2 of the GPL, see COPYING for details. +// Please respect the MCnet academic guidelines, see GUIDELINES for details. +// +// +// +#ifndef HERWIG_EWProcess_H +#define HERWIG_EWProcess_H + +namespace Herwig { + +namespace EWProcess { + + /** + * Enumerates the processes for which we have SCET Wilson Coefficients + */ + enum Process { QQQQ, + QQQQiden, + QtQtQQ, + QQUU, + QtQtUU, + QQtRtR, + QQDD, + QtQtDD, + QQLL, + QQEE, + UUUU, + UUUUiden, + tRtRUU, + UUDD, + tRtRDD, + UULL, + UUEE, + DDDD, + DDDDiden, + DDLL, + DDEE, + LLLL, + LLLLiden, + LLEE, + EEEE, + EEEEiden, + QQWW, + QQPhiPhi, + QQWG, + QQBG, + QQGG, + QtQtGG, + LLWW, + LLPhiPhi, + UUBB, + UUPhiPhi, + UUBG, + UUGG, + tRtRGG, + DDBB, + DDPhiPhi, + DDBG, + DDGG, + EEBB, + EEPhiPhi, + LAST}; +} +} + +#endif // HERWIG_EWProcess_H diff --git a/MatrixElement/EW/ElectroWeakMatching.cc b/MatrixElement/EW/ElectroWeakMatching.cc new file mode 100644 --- /dev/null +++ b/MatrixElement/EW/ElectroWeakMatching.cc @@ -0,0 +1,1015 @@ +// -*- C++ -*- +// +// ElectroWeakMatching.cc is a part of Herwig - A multi-purpose Monte Carlo event generator +// +// Herwig is licenced under version 2 of the GPL, see COPYING for details. +// Please respect the MCnet academic guidelines, see GUIDELINES for details. +// +// +// +#include "ElectroWeakMatching.h" +#include "ElectroWeakReweighter.h" +#include "GroupInvariants.h" +#include +#include + +using namespace Herwig; +using namespace ElectroWeakMatching; +using namespace GroupInvariants; +using namespace EWProcess; + +boost::numeric::ublas::matrix +ElectroWeakMatching::electroWeakMatching(Energy mu, + Energy2 s, Energy2 t, Energy2 u, + Herwig::EWProcess::Process process, + bool oneLoop,unsigned int iswap) { + static const Complex I(0,1.0); + using Constants::pi; + Complex T = getT(s,t); + Complex U = getU(s,u); + // Z-Couplings + double g_Lu = ElectroWeakReweighter::coupling()->g_Lu(mu); + double g_Ld = ElectroWeakReweighter::coupling()->g_Ld(mu); + double g_Le = ElectroWeakReweighter::coupling()->g_Le(mu); + double g_Lnu = ElectroWeakReweighter::coupling()->g_Lnu(mu); + double g_Ru = ElectroWeakReweighter::coupling()->g_Ru(mu); + double g_Rd = ElectroWeakReweighter::coupling()->g_Rd(mu); + double g_Re = ElectroWeakReweighter::coupling()->g_Re(mu); + double g_W = ElectroWeakReweighter::coupling()->g_W(mu); + double g_phiPlus = ElectroWeakReweighter::coupling()->g_phiPlus(mu); + // Weinberg Angle: + double cos2 = ElectroWeakReweighter::coupling()->Cos2thW(mu); + double sin2 = 1.0-cos2; + double cos = sqrt(cos2); + double sin = sqrt(sin2); + + boost::numeric::ublas::matrix R0,G2,Dw,Dz; + + switch (process) { + case QQQQ: + case QQQQiden: + case QtQtQQ: + { + unsigned int numGauge = 4, numBrokenGauge = 12; + R0=boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + G2=boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw=boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz=boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,1) = R0(1,1) = R0(2,1) = R0(3,1) = 1.0; + R0(0,0) = R0(3,0) = 0.25; + R0(1,0) = R0(2,0) = -0.25; + R0(4,0) = R0(5,0) = 0.5; + R0(6,3) = R0(7,3) = R0(8,3) = R0(9,3) = 1.0; + R0(6,2) = R0(9,2) = 0.25; + R0(7,2) = R0(8,2) = -0.25; + R0(10,2) = R0(11,2) = 0.5; + if (oneLoop) { + double g11 = g_Lu; + double g12 = g_Ld; + double g21 = g_Lu; + double g22 = g_Ld; + Complex w0(0.),w1(0.),w2(0.); + Complex z1(0.),z2(0.),z3(0.),z4(0.),z5(0.); + boost::numeric::ublas::matrix gam2; + if(iswap==0) { + w0 = 0.5*I*pi; + w1 = -0.5*(T-U); + w2 = -0.5*(T+U); + z1 = 2.0*g11*g21*(T-U) - I*pi*(g11*g11+g21*g21); + z2 = 2.0*g21*g12*(T-U) - I*pi*(g21*g21+g12*g12); + z3 = 2.0*g22*g11*(T-U) - I*pi*(g22*g22+g11*g11); + z4 = 2.0*g12*g22*(T-U) - I*pi*(g12*g12+g22*g22); + z5 = (g11*g21+g12*g22)*T - (g21*g12+g11*g22)*U + - 0.5*I*pi*(g11*g11+g12*g12+g21*g21+g22*g22); + gam2 = Gamma2(U,T); + } + else if(iswap==1) { + w0 = -0.5*(T-I*pi); + w1 = 0.5*U; + w2 = -0.5*(U-2.*T); + z1 = 2.0*g11*g21*(-U) + ( T- I*pi)*(g11*g11+g21*g21); + z2 = 2.0*g21*g12*(-U) + ( T- I*pi)*(g21*g21+g12*g12); + z3 = 2.0*g22*g11*(-U) + ( T- I*pi)*(g22*g22+g11*g11); + z4 = 2.0*g12*g22*(-U) + ( T- I*pi)*(g12*g12+g22*g22); + z5 = -(g11*g21+g12*g22)*T - (g21*g12+g11*g22)*(U-T) + + 0.5*(T-I*pi)*(g11*g11+g12*g12+g21*g21+g22*g22); + gam2 = Gamma2ST(U,T); + } + else if(iswap==2) { + w0 = -0.5*(U-I*pi); + w1 = -0.5*T; + w2 = -0.5*(T-2.*U); + z1 = 2.0*g11*g21*T +(U-I*pi)*(g11*g11+g21*g21); + z2 = 2.0*g21*g12*T +(U-I*pi)*(g21*g21+g12*g12); + z3 = 2.0*g22*g11*T +(U-I*pi)*(g22*g22+g11*g11); + z4 = 2.0*g12*g22*T +(U-I*pi)*(g12*g12+g22*g22); + z5 = (g11*g21+g12*g22)*(T-U) + (g21*g12+g11*g22)*U + + 0.5*(U-I*pi)*(g11*g11+g12*g12+g21*g21+g22*g22); + gam2 = Gamma2SU(U,T); + } + else + assert(false); + // Dw + for(unsigned int ix=0;ix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,0) = R0(1,0) = R0(2,1) = R0(3,1) = 1.0; + if (oneLoop) { + double g11 = g_Lu; + double g12 = g_Ld; + //double g21 = g_Ru; + double g22 = g_Ru; + Complex w1(0.),z1(0.),z2(0.); + if(iswap==0) { + w1 = 0.25*I*pi; + z1 = 2.0*g11*g22*(T-U) - I*pi*(g11*g11+g22*g22); + z2 = 2.0*g12*g22*(T-U) - I*pi*(g12*g12+g22*g22); + G2 = Gamma2Singlet(); + } + else if(iswap==1) { + w1 = -0.25*(T-I*pi); + z1 = -2.0*g11*g22*U +(T-I*pi)*(g11*g11+g22*g22); + z2 = -2.0*g12*g22*U +(T-I*pi)*(g12*g12+g22*g22); + G2 = Gamma2SingletST(T); + } + else if(iswap==2) { + w1 = -0.25*(U-I*pi); + z1 = 2.0*g11*g22*T +(U-I*pi)*(g11*g11+g22*g22); + z2 = 2.0*g12*g22*T +(U-I*pi)*(g12*g12+g22*g22); + G2 = Gamma2SingletSU(U); + } + else + assert(false); + for(unsigned int ix=0;ix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,0) = R0(1,0) = R0(2,1) = R0(3,1) = 1.0; + if (oneLoop) { + double g11 = g_Lu; + double g12 = g_Ld; + //double g21 = g_Rd; + double g22 = g_Rd; + Complex w1(0.),z1(0.),z2(0.); + if(iswap==0) { + w1 = 0.25*I*pi; + z1 = 2.0*g11*g22*(T-U) - I*pi*(g11*g11+g22*g22); + z2 = 2.0*g12*g22*(T-U) - I*pi*(g12*g12+g22*g22); + G2 = Gamma2Singlet(); + } + else if(iswap==1) { + w1 =-0.25*(T-I*pi); + z1 =-2.0*g11*g22*U + (T-I*pi)*(g11*g11+g22*g22); + z2 =-2.0*g12*g22*U + (T-I*pi)*(g12*g12+g22*g22); + G2 = Gamma2SingletST(T); + } + else if(iswap==2) { + w1 =-0.25*(U-I*pi); + z1 = 2.0*g11*g22*T + (U-I*pi)*(g11*g11+g22*g22); + z2 = 2.0*g12*g22*T + (U-I*pi)*(g12*g12+g22*g22); + G2 = Gamma2Singlet(); + } + else + assert(false); + for(unsigned int ix=0;ix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,1) = R0(1,1) = R0(2,1) = R0(3,1) = 1.0; + R0(0,0) = R0(3,0) = 0.25; + R0(1,0) = R0(2,0) = -0.25; + R0(4,0) = R0(5,0) = 0.5; + if (oneLoop) { + double g11 = g_Lu; + double g12 = g_Ld; + double g21 = g_Lnu; + double g22 = g_Le; + + for (unsigned int i=0; i<6; ++i) { + Dw(i,i) = 0.5*I*pi; + } + Complex w1 = (-1.0/2.0)*(T-U); + Complex w2 = (-1.0/2.0)*(T+U); + Dw(0,0) += w1; + Dw(3,3) += w1; + Dw(1,1) += -1.0*w1; + Dw(2,2) += -1.0*w1; + Dw(4,4) += w2; + Dw(5,5) += w2; + + Complex z1 = 2.0*g11*g21*(T-U) - I*pi*(g11*g11+g21*g21); + Complex z2 = 2.0*g21*g12*(T-U) - I*pi*(g21*g21+g12*g12); + Complex z3 = 2.0*g22*g11*(T-U) - I*pi*(g22*g22+g11*g11); + Complex z4 = 2.0*g12*g22*(T-U) - I*pi*(g12*g12+g22*g22); + Complex z5 = (g11*g21+g12*g22)*T - (g21*g12+g11*g22)*U + - 0.5*I*pi*(g11*g11+g12*g12+g21*g21+g22*g22); + Dz(0,0) = z1; + Dz(1,1) = z2; + Dz(2,2) = z3; + Dz(3,3) = z4; + Dz(4,4) = Dz(5,5) = z5; + + G2 = Gamma2(U,T); + } + } + break; + case QQEE: + { + assert(iswap==0); + unsigned int numGauge = 1, numBrokenGauge = 2; + R0 = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,0) = R0(1,0) = 1.0; + if (oneLoop) { + double g11 = g_Lu; + double g12 = g_Ld; + //double g21 = g_Re; + double g22 = g_Re; + + Complex w1 = 0.25*I*pi; + Dw(0,0) = Dw(1,1) = w1; + + Complex z1 = 2.0*g11*g22*(T-U) - I*pi*(g11*g11+g22*g22); + Complex z2 = 2.0*g12*g22*(T-U) - I*pi*(g12*g12+g22*g22); + Dz(0,0) = z1; + Dz(1,1) = z2; + + G2(0,0) = Gamma2Singlet()(0,0); + } + } + break; + case UUUU: + case UUUUiden: + case tRtRUU: + { + unsigned int numGauge = 2, numBrokenGauge = 2; + R0 = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,0) = R0(1,1) = 1.0; + if (oneLoop) { + double g11 = g_Ru; + //double g12 = g_Ru; + //double g21 = g_Ru; + double g22 = g_Ru; + // There is no Dw contribution for two SU(2) singlets. + Complex z1(0.); + if(iswap==0) { + z1 = 2.0*g11*g22*(T-U) - I*pi*(g11*g11+g22*g22); + } + else if(iswap==1) { + z1 =-2.0*g11*g22*U + (T-I*pi)*(g11*g11+g22*g22); + } + else if(iswap==2) { + z1 = 2.0*g11*g22*T + (U-I*pi)*(g11*g11+g22*g22); + } + Dz(0,0) = Dz(1,1) = z1; + } + } + break; + case UUDD: + case tRtRDD: + { + unsigned int numGauge = 2, numBrokenGauge = 2; + R0 = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,0) = R0(1,1) = 1.0; + if (oneLoop) { + double g11 = g_Ru; + //double g12 = g_Ru; + //double g21 = g_Rd; + double g22 = g_Rd; + // There is no Dw contribution for two SU(2) singlets. + Complex z1(0.); + if(iswap==0) { + z1 = 2.0*g11*g22*(T-U) - I*pi*(g11*g11+g22*g22); + } + else if(iswap==1) { + z1 =-2.0*g11*g22*U + (T-I*pi)*(g11*g11+g22*g22); + } + else if(iswap==2) { + z1 = 2.0*g11*g22*T + (U-I*pi)*(g11*g11+g22*g22); + } + else + assert(false); + Dz(0,0) = Dz(1,1) = z1; + } + } + break; + case UULL: + { + assert(iswap==0); + unsigned int numGauge = 1, numBrokenGauge = 2; + R0 = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,0) = R0(1,0) = 1.0; + if (oneLoop) { + double g11 = g_Lnu; + double g12 = g_Le; + //double g21 = g_Ru; + double g22 = g_Ru; + + Complex w1 = 0.25*I*pi; + Dw(0,0) = Dw(1,1) = w1; + + Complex z1 = 2.0*g11*g22*(T-U) - I*pi*(g11*g11+g22*g22); + Complex z2 = 2.0*g12*g22*(T-U) - I*pi*(g12*g12+g22*g22); + Dz(0,0) = z1; + Dz(1,1) = z2; + + G2(0,0) = Gamma2Singlet()(0,0); + } + } + break; + case UUEE: + { + assert(iswap==0); + unsigned int numGauge = 1, numBrokenGauge = 1; + R0 = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,0) = 1.0; + if (oneLoop) { + double g11 = g_Ru; + //double g12 = g_Ru; + //double g21 = g_Re; + double g22 = g_Re; + // There is no Dw contribution for two SU(2) singlets. + Complex z1 = 2.0*g11*g22*(T-U) - I*pi*(g11*g11+g22*g22); + Dz(0,0) = z1; + } + } + break; + case DDDD: + case DDDDiden: + { + unsigned int numGauge = 2, numBrokenGauge = 2; + R0 = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,0) = R0(1,1) = 1.0; + if (oneLoop) { + double g11 = g_Rd; + //double g12 = g_Rd; + //double g21 = g_Rd; + double g22 = g_Rd; + // There is no Dw contribution for two SU(2) singlets. + Complex z1(0.); + if(iswap==0) { + z1 = 2.0*g11*g22*(T-U) - I*pi*(g11*g11+g22*g22); + } + else if(iswap==1) { + z1 =-2.0*g11*g22*U +(T-I*pi)*(g11*g11+g22*g22); + } + else if(iswap==2) { + z1 = 2.0*g11*g22*T +(U-I*pi)*(g11*g11+g22*g22); + } + else + assert(false); + Dz(0,0) = Dz(1,1) = z1; + } + } + break; + case DDLL: + { + assert(iswap==0); + unsigned int numGauge = 1, numBrokenGauge = 2; + R0 = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,0) = R0(1,0) = 1.0; + if (oneLoop) { + double g11 = g_Lnu; + double g12 = g_Le; + //double g21 = g_Rd; + double g22 = g_Rd; + + Complex w1 = 0.25*I*pi; + Dw(0,0) = Dw(1,1) = w1; + + Complex z1 = 2.0*g11*g22*(T-U) - I*pi*(g11*g11+g22*g22); + Complex z2 = 2.0*g12*g22*(T-U) - I*pi*(g12*g12+g22*g22); + Dz(0,0) = z1; + Dz(1,1) = z2; + + G2(0,0) = Gamma2Singlet()(0,0); + } + } + break; + case DDEE: + { + assert(iswap==0); + unsigned int numGauge = 1, numBrokenGauge = 1; + R0 = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0 *= 0.0; Dw = Dz *= 0.0; + R0(0,0) = 1.0; + if (oneLoop) { + double g11 = g_Rd; + //double g12 = g_Rd; + //double g21 = g_Re; + double g22 = g_Re; + // There is no Dw contribution for two SU(2) singlets. + Complex z1 = 2.0*g11*g22*(T-U) - I*pi*(g11*g11+g22*g22); + Dz(0,0) = z1; + } + } + break; + case LLLL: + case LLLLiden: + { + assert(iswap==0); + unsigned int numGauge = 2, numBrokenGauge = 6; + R0 = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,1) = R0(1,1) = R0(2,1) = R0(3,1) = 1.0; + R0(0,0) = R0(3,0) = 0.25; + R0(1,0) = R0(2,0) = -0.25; + R0(4,0) = R0(5,0) = 0.5; + if (oneLoop) { + double g11 = g_Lnu; + double g12 = g_Le; + double g21 = g_Lnu; + double g22 = g_Le; + + for (int i=0; i<6; i++) { + Dw(i,i) = 0.5*I*pi; + } + Complex w1 = (-1.0/2.0)*(T-U); + Complex w2 = (-1.0/2.0)*(T+U); + Dw(0,0) += w1; + Dw(3,3) += w1; + Dw(1,1) += -1.0*w1; + Dw(2,2) += -1.0*w1; + Dw(4,4) += w2; + Dw(5,5) += w2; + + Complex z1 = 2.0*g11*g21*(T-U) - I*pi*(g11*g11+g21*g21); + Complex z2 = 2.0*g21*g12*(T-U) - I*pi*(g21*g21+g12*g12); + Complex z3 = 2.0*g22*g11*(T-U) - I*pi*(g22*g22+g11*g11); + Complex z4 = 2.0*g12*g22*(T-U) - I*pi*(g12*g12+g22*g22); + Complex z5 = (g11*g21+g12*g22)*T - (g21*g12+g11*g22)*U + - 0.5*I*pi*(g11*g11+g12*g12+g21*g21+g22*g22); + Dz(0,0) = z1; + Dz(1,1) = z2; + Dz(2,2) = z3; + Dz(3,3) = z4; + Dz(4,4) = Dz(5,5) = z5; + + G2 = Gamma2(U,T); + } + } + break; + case LLEE: + { + assert(iswap==0); + unsigned int numGauge = 1, numBrokenGauge = 2; + R0 = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,0) = R0(1,0) = 1.0; + if (oneLoop) { + double g11 = g_Lnu; + double g12 = g_Le; + //double g21 = g_Re; + double g22 = g_Re; + + Complex w1 = 0.25*I*pi; + Dw(0,0) = Dw(1,1) = w1; + + Complex z1 = 2.0*g11*g22*(T-U) - I*pi*(g11*g11+g22*g22); + Complex z2 = 2.0*g12*g22*(T-U) - I*pi*(g12*g12+g22*g22); + Dz(0,0) = z1; + Dz(1,1) = z2; + + G2(0,0) = Gamma2Singlet()(0,0); + } + } + break; + case EEEE: + case EEEEiden: + { + assert(iswap==0); + unsigned int numGauge = 1, numBrokenGauge = 1; + R0 = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,0) = 1.0; + if (oneLoop) { + double g11 = g_Re; + //double g12 = g_Re; + //double g21 = g_Re; + double g22 = g_Re; + // There is no Dw contribution for two SU(2) singlets. + Complex z1 = 2.0*g11*g22*(T-U) - I*pi*(g11*g11+g22*g22); + Dz(0,0) = z1; + } + } + break; + case QQWW: + case LLWW: + { + assert(iswap==0); + unsigned int numGauge = 5, numBrokenGauge = 20; + R0 = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,0) = 1.0; R0(0,1) = 0.5; + R0(1,0) = 1.0; R0(1,1) = -0.5; + R0(2,0) = cos2; R0(2,2) = -0.5*sin*cos; R0(2,3) = -0.5*sin*cos; R0(2,4) = sin2; + R0(3,0) = sin*cos; R0(3,2) = 0.5*cos2; R0(3,3) = -0.5*sin2; R0(3,4) = -sin*cos; + R0(4,0) = sin*cos; R0(4,2) = -0.5*sin2; R0(4,3) = 0.5*cos2; R0(4,4) = -sin*cos; + R0(5,0) = sin2; R0(5,2) = 0.5*sin*cos; R0(5,3) = 0.5*sin*cos; R0(5,4) = cos2; + R0(6,0) = 1.0; R0(6,1) = -0.5; + R0(7,0) = 1.0; R0(7,1) = 0.5; + R0(8,0) = cos2; R0(8,2) = 0.5*sin*cos; R0(8,3) = 0.5*sin*cos; R0(8,4) = sin2; + R0(9,0) = sin*cos; R0(9,2) = -0.5*cos2; R0(9,3) = 0.5*sin2; R0(9,4) = -sin*cos; + R0(10,0) = sin*cos; R0(10,2) = 0.5*sin2; R0(10,3) = -0.5*cos2; R0(10,4) = -sin*cos; + R0(11,0) = sin2; R0(11,2) = -0.5*sin*cos; R0(11,3) = -0.5*sin*cos; R0(11,4) = cos2; + R0(12,1) = -cos/sqrt(2.0); R0(12,3) = -sin/sqrt(2.0); + R0(13,1) = -sin/sqrt(2.0); R0(13,3) = cos/sqrt(2.0); + R0(14,1) = cos/sqrt(2.0); R0(14,2) = -sin/sqrt(2.0); + R0(15,1) = sin/sqrt(2.0); R0(15,2) = cos/sqrt(2.0); + R0(16,1) = -cos/sqrt(2.0); R0(16,2) = -sin/sqrt(2.0); + R0(17,1) = -sin/sqrt(2.0); R0(17,2) = cos/sqrt(2.0); + R0(18,1) = cos/sqrt(2.0); R0(18,3) = -sin/sqrt(2.0); + R0(19,1) = sin/sqrt(2.0); R0(19,3) = cos/sqrt(2.0); + if (oneLoop) { + double gW = g_W; + double g1(0.),g2(0.); + if (process==QQWW) { + g1 = g_Lu; + g2 = g_Ld; + } + else if (process==LLWW) { + g1 = g_Lnu; + g2 = g_Le; + } + + Complex w1 = T-U+5.0/4.0*I*pi; + Complex w2 = -T+U+5.0/4.0*I*pi; + Complex w3 = -0.5*(T+U) + 3.0/4.0*I*pi; + Complex w4 = 0.25*I*pi; + Dw(0,0) = Dw(7,7) = w1; + Dw(1,1) = Dw(6,6) = w2; + for (unsigned int i=12; i<20; i++) { + Dw(i,i) = w3; + } + Dw(2,2) = Dw(3,3) = Dw(4,4) = Dw(5,5) = w4; + Dw(8,8) = Dw(9,9) = Dw(10,10) = Dw(11,11) = w4; + + Complex z1 = 2.0*g1*gW*(U-T) - I*pi*(g1*g1+gW*gW); + Complex z2 = 2.0*g1*gW*(T-U) - I*pi*(g1*g1+gW*gW); + Complex z3 = 2.0*g2*gW*(U-T) - I*pi*(g2*g2+gW*gW); + Complex z4 = 2.0*g2*gW*(T-U) - I*pi*(g2*g2+gW*gW); + Complex z5 = -(g2*gW)*T + (g1*gW)*U - I*pi*(g1*g2+g1*gW-g2*gW); + Complex z6 = (g1*gW)*T - (g2*gW)*U - I*pi*(g1*g2+g1*gW-g2*gW); + Complex z7 = -I*pi*g1*g1; + Complex z8 = -I*pi*g2*g2; + Dz(0,0) = z1; + Dz(1,1) = z2; + Dz(2,2) = Dz(3,3) = Dz(4,4) = Dz(5,5) = z7; + Dz(6,6) = z3; + Dz(7,7) = z4; + Dz(8,8) = Dz(9,9) = Dz(10,10) = Dz(11,11) = z8; + Dz(12,12) = Dz(13,13) = Dz(16,16) = Dz(17,17) = z5; + Dz(14,14) = Dz(15,15) = Dz(18,18) = Dz(19,19) = z6; + + G2 = Gamma2w(U,T); + } + } + break; + case QQPhiPhi: + case LLPhiPhi: + { + assert(iswap==0); + unsigned int numGauge = 2, numBrokenGauge = 14; + R0 = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,0) = 0.25; R0(0,1) = 1.0; + R0(1,0) = -1.0/8.0; R0(1,1) = 0.5; + R0(2,0) = I/8.0; R0(2,1) = -I/2.0; + R0(3,0) = -I/8.0; R0(3,1) = I/2.0; + R0(4,0) = -1.0/8.0; R0(4,1) = 1.0/2.0; + R0(5,0) = -1.0/4.0; R0(5,1) = 1.0; + R0(6,0) = 1.0/8.0; R0(6,1) = 1.0/2.0; + R0(7,0) = -I/8.0; R0(7,1) = -I/2.0; + R0(8,0) = I/8.0; R0(8,1) = I/2.0; + R0(9,0) = 1.0/8.0; R0(9,1) = 1.0/2.0; + R0(10,0) = -1.0/(2.0*sqrt(2.0)); + R0(11,0) = I/(2.0*sqrt(2.0)); + R0(12,0) = -1.0/(2.0*sqrt(2.0)); + R0(13,0) = -I/(2.0*sqrt(2.0)); + + if (oneLoop) { + double g1(0.),g2(0.); + if (process==QQPhiPhi) { + g1 = g_Lu; + g2 = g_Ld; + } + else if (process==LLPhiPhi) { + g1 = g_Lnu; + g2 = g_Le; + } + else + assert(false); + double g3 = g_phiPlus; + + Complex w0 = 0.25*I*pi; + Complex w1 = 0.5*(T-U) + 0.5*I*pi; + Complex w2 = -0.5*(T-U) + 0.5*I*pi; + Complex w3 = 0.25*I*(T-U); + Complex w4 = -0.25*(T+U) + 0.25*I*pi; + Dw(0,0) = w2; + Dw(1,1) = w0; Dw(1,2) = w3; Dw(1,3) = -w3; Dw(1,4) = w0; + Dw(2,1) = -w3; Dw(2,2) = w0; Dw(2,3) = -w0; Dw(2,4) = -w3; + Dw(3,1) = w3; Dw(3,2) = -w0; Dw(3,3) = w0; Dw(3,4) = w3; + Dw(4,1) = w0; Dw(4,2) = w3; Dw(4,3) = -w3; Dw(4,4) = w0; + Dw(5,5) = w1; + Dw(6,6) = w0; Dw(6,7) = -w3; Dw(6,8) = w3; Dw(6,9) = w0; + Dw(7,6) = w3; Dw(7,7) = w0; Dw(7,8) = -w0; Dw(7,9) = w3; + Dw(8,6) = -w3; Dw(8,7) = -w0; Dw(8,8) = w0; Dw(8,9) = -w3; + Dw(9,6) = w0; Dw(9,7) = -w3; Dw(9,8) = w3; Dw(9,9) = w0; + Dw(10,10) = w4; Dw(10,11) = I*w4; + Dw(11,10) = -I*w4; Dw(11,11) = w4; + Dw(12,12) = w4; Dw(12,13) = -I*w4; + Dw(13,12) = I*w4; Dw(13,13) = w4; + + Complex z1 = 2.0*g3*g1*(T-U) - I*pi*(g3*g3+g1*g1); + Complex z2 = 2.0*g3*g2*(T-U) - I*pi*(g3*g3+g2*g2); + Complex z3 = -I*pi*g1*g1; + Complex z4 = 0.5*I*g1*(T-U); + Complex z5 = 0.25*I*pi; + Complex z6 = -I*pi*g2*g2; + Complex z7 = 0.5*I*g2*(T-U); + Complex z8 = g3*g1*T-g3*g2*U-I*pi*(g1*g2-g2*g3+g1*g3); + Complex z9 = 0.5*I*g2*T-0.5*I*g1*U+pi/2.0*g2-pi/2.0*g1+pi/2.0*g3; + Dz(0,0) = z1; + Dz(1,1) = z3; Dz(1,2) = -z4; Dz(1,3) = z4; Dz(1,4) = -z5; + Dz(2,1) = z4; Dz(2,2) = z3; Dz(2,3) = z5; Dz(2,4) = z4; + Dz(3,1) = -z4; Dz(3,2) = z5; Dz(3,3) = z3; Dz(3,4) = -z4; + Dz(4,1) = -z5; Dz(4,2) = -z4; Dz(4,3) = z4; Dz(4,4) = z3; + Dz(5,5) = z2; + Dz(6,6) = z6; Dz(6,7) = -z7; Dz(6,8) = z7; Dz(6,9) = -z5; + Dz(7,6) = z7; Dz(7,7) = z6; Dz(7,8) = z5; Dz(7,9) = z7; + Dz(8,6) = -z7; Dz(8,7) = z5; Dz(8,8) = z6; Dz(8,9) = -z7; + Dz(9,6) = -z5; Dz(9,7) = -z7; Dz(9,8) = z7; Dz(9,9) = z6; + Dz(10,10) = z8; Dz(10,11) = -z9; + Dz(11,10) = z9; Dz(11,11) = z8; + Dz(12,12) = z8; Dz(12,13) = z9; + Dz(13,12) = -z9; Dz(13,13) = z8; + + G2 = Gamma2(U,T); + } + } + break; + case QQWG: + { + assert(iswap==0); + unsigned int numGauge = 1, numBrokenGauge = 6; + R0 = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,0) = 1.0/sqrt(2); + R0(1,0) = 1.0/sqrt(2); + R0(2,0) = cos/2.0; + R0(3,0) = sin/2.0; + R0(4,0) = -cos/2.0; + R0(5,0) = -sin/2.0; + if (oneLoop) { + double g1 = g_Lu; + double g2 = g_Ld; + double gW = g_W; + + Complex w1 = -0.5*(T+U) + 0.75*I*pi; + Complex w2 = 0.25*I*pi; + Dw(0,0) = Dw(1,1) = w1; + Dw(2,2) = Dw(3,3) = Dw(4,4) = Dw(5,5) = w2; + + Complex z1 = gW*g1*T - gW*g2*U - I*pi*(g1*g2+g1*gW-g2*gW); + Complex z2 = gW*g1*U - gW*g2*T - I*pi*(g2*g1+g1*gW-g2*gW); + Complex z3 = -I*pi*g1*g1; + Complex z4 = -I*pi*g2*g2; + Dz(0,0) = z1; + Dz(1,1) = z2; + Dz(2,2) = z3; + Dz(3,3) = z3; + Dz(4,4) = z4; + Dz(5,5) = z4; + + G2(0,0) = -7.0/4.0*I*pi + (U+T); + } + } + break; + case QQBG: + { + assert(iswap==0); + unsigned int numGauge = 1, numBrokenGauge = 4; + R0 = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,0) = -sin; + R0(1,0) = cos; + R0(2,0) = -sin; + R0(3,0) = cos; + if (oneLoop) { + double g1 = g_Lu; + double g2 = g_Ld; + Complex w2 = 0.25*I*pi; + Dw(0,0) = Dw(1,1) = Dw(2,2) = Dw(3,3) = w2; + Complex z3 = -I*pi*g1*g1; + Complex z4 = -I*pi*g2*g2; + Dz(0,0) = z3; + Dz(1,1) = z3; + Dz(2,2) = z4; + Dz(3,3) = z4; + G2(0,0) = Gamma2Singlet()(0,0); + } + } + break; + case QQGG: + case QtQtGG: + { + unsigned int numGauge = 3, numBrokenGauge = 6; + R0 = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,0) = R0(3,0) = 1.0; + R0(1,1) = R0(4,1) = 1.0; + R0(2,2) = R0(5,2) = 1.0; + double g1 = g_Lu; + double g2 = g_Ld; + Complex w2(0.),z3(0.),z4(0.); + if (oneLoop) { + if(iswap==0) { + w2 = 0.25*I*pi; + z3 = -I*pi*g1*g1; + z4 = -I*pi*g2*g2; + G2(0,0) = G2(1,1) = G2(2,2) = Gamma2Singlet()(0,0); + } + else if(iswap==1) { + w2 = 0.25*(-T+I*pi); + z3 = (T-I*pi)*sqr(g1); + z4 = (T-I*pi)*sqr(g2); + G2(0,0) = G2(1,1) = G2(2,2) = Gamma2SingletST(T)(0,0); + } + else if(iswap==2) { + w2 = 0.25*(-U+I*pi); + z3 = (U-I*pi)*g1*g1; + z4 = (U-I*pi)*g2*g2; + G2(0,0) = G2(1,1) = G2(2,2) = Gamma2SingletSU(U)(0,0); + } + else + assert(false); + Dw(0,0) = Dw(1,1) = Dw(2,2) = Dw(3,3) = Dw(4,4) = Dw(5,5) = w2; + Dz(0,0) = Dz(1,1) = Dz(2,2) = z3; + Dz(3,3) = Dz(4,4) = Dz(5,5) = z4; + } + } + break; + case UUBB: + case DDBB: + case EEBB: + { + assert(iswap==0); + unsigned int numGauge = 1, numBrokenGauge = 4; + R0 = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,0) = sin2; + R0(1,0) = -sin*cos; + R0(2,0) = -sin*cos; + R0(3,0) = cos2; + if (oneLoop) { + double g1(0.); + if (process==UUBB) { + g1 = g_Ru; + } + else if (process==DDBB) { + g1 = g_Rd; + } + else if (process==EEBB) { + g1 = g_Re; + } + else + assert(false); + // There is no Dw contribution for two SU(2) singlets. + Complex z1 = -I*pi*g1*g1; + Dz(0,0) = Dz(1,1) = Dz(2,2) = Dz(3,3) = z1; + } + } + break; + case UUPhiPhi: + case DDPhiPhi: + case EEPhiPhi: + { + assert(iswap==0); + unsigned int numGauge = 1, numBrokenGauge = 5; + R0 = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,0) = 1.0; + R0(1,0) = 0.5; + R0(2,0) = -0.5*I; + R0(3,0) = 0.5*I; + R0(4,0) = 0.5; + if (oneLoop) { + double g1(0.); + if (process==UUPhiPhi) { + g1 = g_Ru; + } + else if (process==DDPhiPhi) { + g1 = g_Rd; + } + else if (process==EEPhiPhi) { + g1 = g_Re; + } + double g3 = g_phiPlus; + Dw(0,0) = Dw(1,4) = Dw(4,1) = 0.25*I*pi; + Dw(2,3) = Dw(3,2) = -0.25*I*pi; + Complex z1 = 2.0*g3*g1*(T-U) - I*pi*(g3*g3+g1*g1); + Complex z2 = 0.5*I*g1*g1; + Complex z3 = -I*pi*g1*g1; + Complex z4 = 0.25*I*pi; + Dz(0,0) = z1; + Dz(1,1) = z3; Dz(1,2) = -z2; Dz(1,3) = z2; Dz(1,4) = -z4; + Dz(2,1) = z2; Dz(2,2) = z3; Dz(2,3) = z4; Dz(2,4) = z2; + Dz(3,1) = -z2; Dz(3,2) = z4; Dz(3,3) = z3; Dz(3,4) = -z2; + Dz(4,1) = -z4; Dz(4,2) = -z2; Dz(4,3) = z2; Dz(4,4) = z3; + G2(0,0) = Gamma2Singlet()(0,0); + } + } + break; + case UUBG: + case DDBG: + { + assert(iswap==0); + unsigned int numGauge = 1, numBrokenGauge = 2; + R0 = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,0) = -sin; + R0(1,0) = cos; + if (oneLoop) { + double g1(0.); + if (process==UUBG) { + g1 = g_Ru; + } + else if (process==DDBG) { + g1 = g_Rd; + } + else + assert(false); + // There is no Dw contribution for two SU(2) singlets. + Complex z1 = -I*pi*g1*g1; + Dz(0,0) = Dz(1,1) = z1; + } + } + break; + case UUGG: + case tRtRGG: + case DDGG: + { + unsigned int numGauge = 3, numBrokenGauge = 3; + R0 = boost::numeric::ublas::zero_matrix(numBrokenGauge,numGauge); + G2 = boost::numeric::ublas::zero_matrix(numGauge,numGauge); + Dw = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + Dz = boost::numeric::ublas::zero_matrix(numBrokenGauge,numBrokenGauge); + R0(0,0) = R0(1,1) = R0(2,2) = 1.0; + if (oneLoop) { + double g1(0.); + if ((process==UUGG)||(process==tRtRGG)) { + g1 = g_Ru; + } + else if (process==DDGG) { + g1 = g_Rd; + } + else + assert(false); + Complex z1(0.); + // There is no Dw contribution for two SU(2) singlets. + if(iswap==0) { + z1 = -I*pi*sqr(g1); + } + else if(iswap==1) { + z1 = (T-I*pi)*sqr(g1); + } + else if(iswap==2) { + z1 = (U-I*pi)*sqr(g1); + } + else + assert(false); + Dz(0,0) = Dz(1,1) = Dz(2,2) = z1; + } + } + break; + default: + assert(false); + } + + double aW = ElectroWeakReweighter::coupling()->aW(mu); + double aZ = ElectroWeakReweighter::coupling()->aZ(mu); + Energy mZ = ElectroWeakReweighter::coupling()->mZ(); + Energy mW = ElectroWeakReweighter::coupling()->mW(); + + if (!oneLoop) { + return R0; + } + boost::numeric::ublas::matrix output(R0); + boost::numeric::ublas::matrix temp(R0.size1(),R0.size2()); + boost::numeric::ublas::axpy_prod(R0,G2,temp); + output+=aW/(4.0*pi)*4.0*log(mW/mu)*temp; + boost::numeric::ublas::axpy_prod(Dw,R0,temp); + output+=aW/(4.0*pi)*4.0*log(mW/mu)*temp; + boost::numeric::ublas::axpy_prod(Dz,R0,temp); + output+=aZ/(4.0*pi)*4.0*log(mZ/mu)*temp; + return output; +} diff --git a/MatrixElement/EW/ElectroWeakMatching.h b/MatrixElement/EW/ElectroWeakMatching.h new file mode 100644 --- /dev/null +++ b/MatrixElement/EW/ElectroWeakMatching.h @@ -0,0 +1,37 @@ +// -*- C++ -*- +// +// ElectroWeakMatching.h is a part of Herwig - A multi-purpose Monte Carlo event generator +// +// Herwig is licenced under version 2 of the GPL, see COPYING for details. +// Please respect the MCnet academic guidelines, see GUIDELINES for details. +// +// +// +#ifndef HERWIG_ElectroWeakMatching_H +#define HERWIG_ElectroWeakMatching_H +#include "ThePEG/Config/ThePEG.h" +#include "ThePEG/Config/Unitsystem.h" +#include "EWProcess.h" +// work around a Boost 1.64 bug where ublas headers would fail otherwise +#include +#if (BOOST_VERSION / 100 >= 1064) +#include +#endif +#include + +namespace Herwig { +using namespace ThePEG; + +namespace ElectroWeakMatching { + + /** + * The high energy matching + */ + boost::numeric::ublas::matrix + electroWeakMatching(Energy mu, Energy2 s, Energy2 t, Energy2 u, + Herwig::EWProcess::Process process, + bool oneLoop,unsigned int iswap); +} +} + +#endif // HERWIG_ElectroWeakMatching_H diff --git a/MatrixElement/EW/ElectroWeakReweighter.cc b/MatrixElement/EW/ElectroWeakReweighter.cc new file mode 100644 --- /dev/null +++ b/MatrixElement/EW/ElectroWeakReweighter.cc @@ -0,0 +1,1994 @@ +// -*- C++ -*- +// +// This is the implementation of the non-inlined, non-templated member +// functions of the ElectroWeakReweighter class. +// + +#include "ElectroWeakReweighter.h" +#include "ThePEG/Interface/ClassDocumentation.h" +#include "ThePEG/Interface/Reference.h" +#include "ThePEG/Interface/Switch.h" +#include "ThePEG/EventRecord/Particle.h" +#include "ThePEG/Repository/UseRandom.h" +#include "ThePEG/Repository/EventGenerator.h" +#include "ThePEG/Utilities/DescribeClass.h" +#include "ThePEG/Persistency/PersistentOStream.h" +#include "ThePEG/Persistency/PersistentIStream.h" +#include "boost/numeric/ublas/matrix.hpp" +#include "boost/numeric/ublas/operation.hpp" +#include "EWProcess.h" +#include "HighEnergyMatching.h" +#include "ElectroWeakMatching.h" +#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" +#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" +#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" +#include "ThePEG/Helicity/epsilon.h" +#include "Herwig/MatrixElement/Matchbox/Base/SubtractedME.h" +#include "Herwig/MatrixElement/Matchbox/MatchboxFactory.h" +#include "ThePEG/Handlers/StandardXComb.h" + +using namespace Herwig; + +tEWCouplingsPtr ElectroWeakReweighter::staticEWCouplings_ = tEWCouplingsPtr(); + + +ElectroWeakReweighter::ElectroWeakReweighter() : testing_(false) +{} + +ElectroWeakReweighter::~ElectroWeakReweighter() {} + +IBPtr ElectroWeakReweighter::clone() const { + return new_ptr(*this); +} + +IBPtr ElectroWeakReweighter::fullclone() const { + return new_ptr(*this); +} + +void ElectroWeakReweighter::persistentOutput(PersistentOStream & os) const { + os << EWCouplings_ << collinearSudakov_ << softSudakov_ << testing_; +} + +void ElectroWeakReweighter::persistentInput(PersistentIStream & is, int) { + is >> EWCouplings_ >> collinearSudakov_ >> softSudakov_ >> testing_; +} + + +// The following static variable is needed for the type +// description system in ThePEG. +DescribeClass +describeHerwigElectroWeakReweighter("Herwig::ElectroWeakReweighter", "HwMEEW.so"); + +void ElectroWeakReweighter::Init() { + + static ClassDocumentation documentation + ("There is no documentation for the ElectroWeakReweighter class"); + + static Reference interfaceEWCouplings + ("EWCouplings", + "The object to calculate the electroweak couplings", + &ElectroWeakReweighter::EWCouplings_, false, false, true, false, false); + + static Reference interfaceCollinearSudakov + ("CollinearSudakov", + "The collinear Sudakov", + &ElectroWeakReweighter::collinearSudakov_, false, false, true, false, false); + + static Reference interfaceSoftSudakov + ("SoftSudakov", + "The soft Sudakov", + &ElectroWeakReweighter::softSudakov_, false, false, true, false, false); + + static Switch interfaceTesting + ("Testing", + "Whether or not to output testing information", + &ElectroWeakReweighter::testing_, false, false, false); + static SwitchOption interfaceTestingYes + (interfaceTesting, + "Yes", + "Output the information", + true); + static SwitchOption interfaceTestingNo + (interfaceTesting, + "No", + "Don't output the information", + false); + +} + +void ElectroWeakReweighter::doinit() { + ReweightBase::doinit(); + if(!testing_) return; + // testing output + cerr << "aEM\n"; + for(Energy scale=10.*GeV; scale<10*TeV; scale *= 1.1) { + cerr << scale/GeV << " " + << EWCouplings_->aEM(scale) << "\n"; + } + cerr << "aS\n"; + for(Energy scale=10.*GeV; scale<10*TeV; scale *= 1.4) { + cerr << scale/GeV << " " + << EWCouplings_->aS(scale) << "\n"; + } + cerr << "y_t\n"; + for(Energy scale=10.*GeV; scale<10*TeV; scale *= 1.4) { + cerr << scale/GeV << " " + << EWCouplings_->y_t(scale) << "\n"; + } + cerr << "lambda\n"; + for(Energy scale=91.2*GeV; scale<10*TeV; scale *= 1.4) { + cerr << scale/GeV << " " + << EWCouplings_->lambda(scale) << "\n"; + } + cerr << "vev\n"; + for(Energy scale=91.2*GeV; scale<10*TeV; scale *= 1.4) { + cerr << scale/GeV << " " + << EWCouplings_->vev(scale)/GeV << "\n"; + } + collinearSudakov_->makePlots(); + Energy2 s = sqr(5000.*GeV); + Energy2 t = -0.25*s; + Energy2 u = -0.75*s; + testEvolution(s,t,u); +} + +namespace { +// #ifdef ThePEG_HAS_UNITS_CHECKING +void axpy_prod_local(const boost::numeric::ublas::matrix & A, + const boost::numeric::ublas::matrix > & B, + boost::numeric::ublas::matrix > & C) { + assert(A.size2()==B.size1()); + C.resize(A.size1(),B.size2()); + for(unsigned int ix=0;ix > & A, + const boost::numeric::ublas::vector > & B, + boost::numeric::ublas::vector & C) { + assert(A.size2()==B.size()); + C.resize(A.size1()); + for(unsigned int ix=0;ix > & A, + const boost::numeric::ublas::matrix & B, + boost::numeric::ublas::matrix > & C) { + assert(A.size2()==B.size1()); + C.resize(A.size1(),B.size2()); + for(unsigned int ix=0;ix & A, +// const boost::numeric::ublas::matrix & B, +// boost::numeric::ublas::matrix & C) { +// assert(A.size2()==B.size1()); +// C.resize(A.size1(),B.size2()); +// axpy_prod(A,B,C); +// } + +// void axpy_prod_local(const boost::numeric::ublas::matrix & A, +// const boost::numeric::ublas::vector & B, +// boost::numeric::ublas::vector & C) { +// assert(A.size2()==B.size()); +// C.resize(A.size1()); +// axpy_prod(A,B,C); +// } +// #endif + +} + +double ElectroWeakReweighter::weight() const { + EWCouplings_->initialize(); + staticEWCouplings_ = EWCouplings_; + // cast the XComb + Ptr::ptr sxc = dynamic_ptr_cast::ptr>(lastXCombPtr()); + // if the Herwig XComb + if(sxc) { + // get information about the type of event + Ptr::tptr subme = dynamic_ptr_cast::tptr>(sxc->matrixElement()); + Ptr::tptr me = dynamic_ptr_cast::tptr>(sxc->matrixElement()); + Ptr::tptr dipme = dynamic_ptr_cast::tptr>(sxc->matrixElement()); + bool isHEvent(false),isSEvent(false); + if(subme) { + if ( subme->realShowerSubtraction() ) + isHEvent = true; + else if ( subme->virtualShowerSubtraction() || subme->loopSimSubtraction() ) + isSEvent = true; + } + // H or S event of virtual return 1. + if(isHEvent || isSEvent || (me && me->oneLoopNoBorn())) + return 1.; + // cerr << "testing after type check\n"; + // cerr << "testing pointers " << subme << " " << me << " " << dipme << "\n"; + // cerr << "testing event type " << isHEvent << " " << isSEvent << " " << "\n"; + // if(subme) cerr << subme->fullName() << "\n"; + // if( me) { + // cerr << me->fullName() << "\n"; + // cerr << me->oneLoopNoBorn() << " " << me->oneLoopNoLoops() << "\n"; + // } + // if(dipme) cerr << dipme->fullName() << "\n"; + } + // cerr << subProcess() << "\n"; + // cerr << *subProcess() << "\n"; + // only 2->2 processes + if(subProcess()->outgoing().size()!=2) return 1.; + // processes with gg initial-state + if(subProcess()->incoming().first->id()==ParticleID::g && + subProcess()->incoming().second->id()==ParticleID::g) { + if(subProcess()->outgoing()[0]->id()==ParticleID::g && + subProcess()->outgoing()[1]->id()==ParticleID::g) + return 1.; + else if(abs(subProcess()->outgoing()[0]->id())<=6 && + subProcess()->outgoing()[0]->id()==-subProcess()->outgoing()[1]->id()) { + return reweightggqqbar(); + } + else + assert(false); + } + // processes with q qbar initial-state + else if((subProcess()->incoming().first ->id() > 0 && + subProcess()->incoming().first ->id()<= 5 && + subProcess()->incoming().second->id() < 0 && + subProcess()->incoming().second->id()>=-5) || + (subProcess()->incoming().second->id() > 0 && + subProcess()->incoming().second->id()<= 5 && + subProcess()->incoming().first ->id() < 0 && + subProcess()->incoming().first ->id()>=-5)) { + // identical flavour q qbar + if(subProcess()->incoming().first ->id() == -subProcess()->incoming().second->id()) { + // q qbar -> gg + if(subProcess()->outgoing()[0]->id()==ParticleID::g && + subProcess()->outgoing()[1]->id()==ParticleID::g) + return reweightqqbargg(); + // q qbar -> q' q'bar + else if(subProcess()->outgoing()[0]->id() == -subProcess()->outgoing()[1]->id() && + abs(subProcess()->outgoing()[0]->id())<=6) + return reweightqqbarqqbarS(); + } + // different flavour q qbar + else { + if((subProcess()->outgoing()[0]->id() > 0 && + subProcess()->outgoing()[0]->id()<= 5 && + subProcess()->outgoing()[1]->id() < 0 && + subProcess()->outgoing()[1]->id()>=-5) || + (subProcess()->outgoing()[1]->id() > 0 && + subProcess()->outgoing()[1]->id()<= 5 && + subProcess()->outgoing()[0]->id() < 0 && + subProcess()->outgoing()[0]->id()>=-5)) { + return reweightqqbarqqbarT(); + } + else + assert(false); + } + } + // processes with q g initial-state + else if((subProcess()->incoming().first ->id()> 0 && + subProcess()->incoming().first ->id()<=5 && + subProcess()->incoming().second->id()==ParticleID::g) || + (subProcess()->incoming().second->id()> 0 && + subProcess()->incoming().second->id()<=5 && + subProcess()->incoming().first ->id()==ParticleID::g)) { + // qg -> qg + if((subProcess()->outgoing()[0]->id()> 0 && + subProcess()->outgoing()[0]->id()<=5 && + subProcess()->outgoing()[1]->id()==ParticleID::g) || + (subProcess()->outgoing()[1]->id()> 0 && + subProcess()->outgoing()[1]->id()<=5 && + subProcess()->outgoing()[0]->id()==ParticleID::g)) + return reweightqgqg(); + // unknown + else + assert(false); + } + // processes with qbar g initial-state + else if((subProcess()->incoming().first ->id()>=-5 && + subProcess()->incoming().first ->id()< 0 && + subProcess()->incoming().second->id()==ParticleID::g) || + (subProcess()->incoming().second->id()>=-5 && + subProcess()->incoming().second->id()< 0 && + subProcess()->incoming().first ->id()==ParticleID::g)) { + if((subProcess()->outgoing()[0]->id()>=-5 && + subProcess()->outgoing()[0]->id()< 0 && + subProcess()->outgoing()[1]->id()==ParticleID::g) || + (subProcess()->outgoing()[1]->id()>=-5 && + subProcess()->outgoing()[1]->id()< 0 && + subProcess()->outgoing()[0]->id()==ParticleID::g)) + return reweightqbargqbarg(); + else + assert(false); + } + // processes with q q initial-state + else if( subProcess()->incoming().first ->id()> 0 && + subProcess()->incoming().first ->id()<=5 && + subProcess()->incoming().second->id()> 0 && + subProcess()->incoming().second->id()<=5 ) { + if(subProcess()->outgoing()[0]->id()> 0 && + subProcess()->outgoing()[0]->id()<=5 && + subProcess()->outgoing()[1]->id()> 0 && + subProcess()->outgoing()[1]->id()<=5) + return reweightqqqq(); + else + assert(false); + } + // processes with qbar qbar initial-state + else if( subProcess()->incoming().first ->id()< 0 && + subProcess()->incoming().first ->id()>= -5 && + subProcess()->incoming().second->id()< 0 && + subProcess()->incoming().second->id()>= -5 ) { + if(subProcess()->outgoing()[0]->id()< 0 && + subProcess()->outgoing()[0]->id()>= -5 && + subProcess()->outgoing()[1]->id()< 0 && + subProcess()->outgoing()[1]->id()>= -5) + return reweightqbarqbarqbarqbar(); + else + assert(false); + } + // unknown initial-state + else + assert(false); + assert(false); + staticEWCouplings_ = tEWCouplingsPtr(); +} + +void ElectroWeakReweighter::testEvolution(Energy2 s,Energy2 t, Energy2 u) const { + Energy highScale = sqrt(s); + Energy ewScale = coupling()->mZ(); + Energy lowScale = 50.0*GeV; + for (unsigned int i=0; i<45;++i) { + EWProcess::Process process = (EWProcess::Process)i; + cerr << "process " << process << "\n"; + // result for all EW and QCD SCET contributions: + boost::numeric::ublas::matrix > highMatch_val + = HighEnergyMatching::highEnergyMatching(highScale,s,t,u,process,true,true); + boost::numeric::ublas::matrix highRunning_val + = softSudakov_->highEnergyRunning(highScale,ewScale,s,t,u,process,0); + boost::numeric::ublas::matrix ewMatch_val = + ElectroWeakMatching::electroWeakMatching(ewScale,s,t,u,process,true,0); + boost::numeric::ublas::matrix lowRunning_val = + softSudakov_->lowEnergyRunning(ewScale,lowScale,s,t,u,process,0); + boost::numeric::ublas::matrix collinearHighRunning_val = + collinearSudakov_->highEnergyRunning(highScale,ewScale,s,process,false); + boost::numeric::ublas::matrix collinearEWMatch_val = + collinearSudakov_->electroWeakMatching(ewScale,s,process,true); + boost::numeric::ublas::matrix collinearLowRunning_val = + collinearSudakov_->lowEnergyRunning(ewScale,lowScale,s,process); + boost::numeric::ublas::matrix lowMatchTemp_val = + boost::numeric::ublas::zero_matrix(ewMatch_val.size1(),ewMatch_val.size2()); + for (unsigned int ii=0; ii temp(highRunning_val.size1(),collinearHighRunning_val.size2()); + boost::numeric::ublas::axpy_prod(highRunning_val,collinearHighRunning_val,temp); + boost::numeric::ublas::matrix temp2(collinearLowRunning_val.size1(),lowRunning_val.size2()); + boost::numeric::ublas::axpy_prod(collinearLowRunning_val,lowRunning_val,temp2); + boost::numeric::ublas::matrix temp3(temp2.size1(),lowMatchTemp_val.size2()); + boost::numeric::ublas::axpy_prod(temp2,lowMatchTemp_val,temp3); + temp2.resize(temp3.size1(),temp.size2()); + boost::numeric::ublas::axpy_prod(temp3,temp,temp2); + boost::numeric::ublas::matrix > result(temp2.size1(),highMatch_val.size2()); + axpy_prod_local(temp2,highMatch_val,result); + for(unsigned int ix=0;ix > & eps3, + vector > & eps4, + unsigned int iopt) { + static const Complex I(0.,1.); + // p1 is p-, p2 is p+ + // p3 is k-, p4 is k+ + // both final-state + if(iopt==0) { + // swap t and u due Aneesh's defn + Energy3 den1 = sqrt((u*t-sqr(m2))*(s-4.*m2)); + Energy3 den2 = sqrt(s*(u*t-sqr(m2))); + LorentzVector eps3Para = (m2+t)/den1*p1 -(m2+u)/den1*p2 +(u-t)/den1*p3; + LorentzVector eps3Perp = 2./den2*epsilon(p1,p2,p3); + LorentzVector eps4Para = (m2+t)/den1*p2 -(m2+u)/den1*p1 +(u-t)/den1*p4; + LorentzVector eps4Perp = 2./den2*epsilon(p1,p2,p4); + eps3.push_back(sqrt(0.5)*(eps3Para+I*eps3Perp)); + eps3.push_back(sqrt(0.5)*(eps3Para-I*eps3Perp)); + eps4.push_back(sqrt(0.5)*(eps4Para+I*eps4Perp)); + eps4.push_back(sqrt(0.5)*(eps4Para-I*eps4Perp)); + if(m2!=ZERO) assert(false); + } + // both initial-state + else if(iopt==1) { + if(m2!=ZERO) assert(false); + LorentzVector eps3Para( 1., 0.,0.,0.); + LorentzVector eps3Perp( 0.,-1.,0.,0.); + LorentzVector eps4Para(-1.,0.,0., 0.); + LorentzVector eps4Perp( 0., 1.,0.,0.); + eps3.push_back(sqrt(0.5)*(eps3Para+I*eps3Perp)); + eps3.push_back(sqrt(0.5)*(eps3Para-I*eps3Perp)); + eps4.push_back(sqrt(0.5)*(eps4Para+I*eps4Perp)); + eps4.push_back(sqrt(0.5)*(eps4Para-I*eps4Perp)); + } + else if(iopt==2) { + // rotation into the 2,3 Breit frame + Lorentz5Momentum pa = p3-p2; + Axis axis(pa.vect().unit()); + LorentzRotation rot; + double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); + if ( sinth > 1.e-9 ) + rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); + rot.rotateX(Constants::pi); + rot.boostZ( pa.e()/pa.vect().mag()); + Lorentz5Momentum ptemp=rot*p2; + Boost trans = -1./ptemp.e()*ptemp.vect(); + trans.setZ(0.); + rot.boost(trans); + LorentzVector eps3Para( 1., 0.,0.,0.); + LorentzVector eps3Perp( 0.,-1.,0.,0.); + LorentzVector eps4Para(-1.,0.,0., 0.); + LorentzVector eps4Perp( 0., 1.,0.,0.); + eps3.push_back(sqrt(0.5)*(eps3Para+I*eps3Perp)); + eps3.push_back(sqrt(0.5)*(eps3Para-I*eps3Perp)); + eps4.push_back(sqrt(0.5)*(eps4Para+I*eps4Perp)); + eps4.push_back(sqrt(0.5)*(eps4Para-I*eps4Perp)); + rot = rot.invert(); + for(unsigned int ix=0;ix<2;++ix) { + eps3[ix] *=rot; + eps4[ix] *=rot; + } + } + else if(iopt==3) { + // rotation into the 1,4 Breit frame + Lorentz5Momentum pa = p4-p1; + Axis axis(pa.vect().unit()); + LorentzRotation rot; + double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); + if ( sinth > 1.e-9 ) + rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); + rot.rotateX(Constants::pi); + rot.boostZ( pa.e()/pa.vect().mag()); + Lorentz5Momentum ptemp=rot*p1; + Boost trans = -1./ptemp.e()*ptemp.vect(); + trans.setZ(0.); + rot.boost(trans); + LorentzVector eps3Para( 1., 0.,0.,0.); + LorentzVector eps3Perp( 0.,-1.,0.,0.); + LorentzVector eps4Para(-1.,0.,0., 0.); + LorentzVector eps4Perp( 0., 1.,0.,0.); + eps3.push_back(sqrt(0.5)*(eps3Para+I*eps3Perp)); + eps3.push_back(sqrt(0.5)*(eps3Para-I*eps3Perp)); + eps4.push_back(sqrt(0.5)*(eps4Para+I*eps4Perp)); + eps4.push_back(sqrt(0.5)*(eps4Para-I*eps4Perp)); + rot = rot.invert(); + for(unsigned int ix=0;ix<2;++ix) { + eps3[ix] *=rot; + eps4[ix] *=rot; + } + } + else + assert(false); +} + +} + +double ElectroWeakReweighter::reweightqqbargg() const { + // momenta and invariants + Lorentz5Momentum p1 = subProcess()->incoming().first ->momentum(); + tcPDPtr q = subProcess()->incoming().first ->dataPtr(); + Lorentz5Momentum p2 = subProcess()->incoming().second->momentum(); + tcPDPtr qbar = subProcess()->incoming().second->dataPtr(); + if(subProcess()->incoming().first->id()<0) { + swap(p1,p2 ); + swap(q ,qbar); + } + Lorentz5Momentum p3 = subProcess()->outgoing()[0]->momentum(); + Lorentz5Momentum p4 = subProcess()->outgoing()[1]->momentum(); + tcPDPtr g = subProcess()->outgoing()[1]->dataPtr(); + Energy2 s = (p1+p2).m2(); + Energy2 t = (p1-p4).m2(); + Energy2 u = (p1-p3).m2(); + // boost to partonci rest frame + Lorentz5Momentum psum=p1+p2; + LorentzRotation boost(-psum.boostVector()); + p1 *= boost; + p2 *= boost; + p3 *= boost; + p4 *= boost; + // LO and EW corrected matrix element coefficients + boost::numeric::ublas::matrix > + bornQQGGweights,bornRRGGweights,EWQQGGweights,EWRRGGweights; + // quark left doublet + if(q->id()!=5) { + bornQQGGweights = evaluateRunning(EWProcess::QQGG,s,t,u,true ,0); + EWQQGGweights = evaluateRunning(EWProcess::QQGG,s,t,u,false,0); + } + else { + bornQQGGweights = evaluateRunning(EWProcess::QtQtGG,s,t,u,true ,0); + EWQQGGweights = evaluateRunning(EWProcess::QtQtGG,s,t,u,false,0); + } + // quark right singlet + if(abs(subProcess()->incoming().first->id())%2==0) { + bornRRGGweights = evaluateRunning(EWProcess::UUGG,s,t,u,true ,0); + EWRRGGweights = evaluateRunning(EWProcess::UUGG,s,t,u,false,0); + } + else { + bornRRGGweights = evaluateRunning(EWProcess::DDGG,s,t,u,true ,0); + EWRRGGweights = evaluateRunning(EWProcess::DDGG,s,t,u,false,0); + } + SpinorWaveFunction qw(p1,q ,incoming); + SpinorBarWaveFunction qbarw(p2,qbar,incoming); + vector > eps3,eps4; + SackGluonPolarizations(p1,p2,p3,p4,s,t,u,ZERO,eps3,eps4,0); + boost::numeric::ublas::matrix + bornME = boost::numeric::ublas::zero_matrix(3,3), + EWME = boost::numeric::ublas::zero_matrix(3,3); + for(unsigned int iq=0;iq<2;++iq) { + if(iq==0) { + qw.reset (0); + qbarw.reset(1); + } + else { + qw.reset (1); + qbarw.reset(0); + } + LorentzVector > current = iq==0 ? + qw.dimensionedWave(). leftCurrent(qbarw.dimensionedWave()) : + qw.dimensionedWave().rightCurrent(qbarw.dimensionedWave()); + for(unsigned int i1=0;i1<2;++i1) { + complex d31 = eps3[i1].dot(p1); + LorentzVector > + temp = qw.dimensionedWave().slash(eps3[i1]).slash(p4-p2).vectorCurrent(qbarw.dimensionedWave()); + for(unsigned int i2=0;i2<2;++i2) { + boost::numeric::ublas::vector > M(5); + Complex d34 = eps3[i1].dot(eps4[i2]); + complex d42 = eps4[i2].dot(p2); + // M0 in paper + M(0) = temp.dot(eps4[i2]); + // M4 in paper + M(2) = current.dot(eps4[i2])*d31; + // M5 in paper + M(3) = -current.dot(eps3[i1])*d42; + // M1 in paper (missing factor) + M(1) = current.dot(p4); + // M6 in paper + M(4) = M(1)*d31*d42/GeV2; + // M1 final factor + M(1) *= d34; + // coefficient of different contributions + boost::numeric::ublas::vector Cborn(3),CEW(3),Ctest(3); + + + // Ctest(0) = 1./6.*( MEU+MET); + // Ctest(1) = 0.5*( MEU+MET); + // Ctest(2) = 0.5*(MEU+MES-MET+MES); + if(iq==0) { + axpy_prod_local(bornQQGGweights,M,Cborn); + axpy_prod_local(EWQQGGweights ,M,CEW ); + } + else { + axpy_prod_local(bornRRGGweights,M,Cborn); + axpy_prod_local(EWRRGGweights ,M,CEW ); + } + unsigned int ioff = (Cborn.size()==6 && q->id()%2!=0) ? 3 : 0; + for(unsigned int ix=0;ix<3;++ix) { + for(unsigned int iy=0;iy<3;++iy) { + bornME(ix,iy) += Cborn(ix+ioff)*conj(Cborn(iy+ioff)); + EWME (ix,iy) += CEW (ix+ioff)*conj(CEW (iy+ioff)); + } + } + } + } + } + double born = 24.*real(bornME(0,0))+20./3.*real(bornME(1,1))+12.*real(bornME(2,2)); + double EW = 24.*real(EWME(0,0))+20./3.*real(EWME(1,1))+12.*real(EWME(2,2)); + return EW/born; +} + +boost::numeric::ublas::matrix > +ElectroWeakReweighter::evaluateRunning(EWProcess::Process process, Energy2 s, + Energy2 t, Energy2 u, bool born, + unsigned int iswap) const { + using namespace boost::numeric::ublas; + bool SU3save = coupling()->SU3(); + bool EWsave = coupling()-> EW(); + Energy highScale = sqrt(s); + Energy ewScale = coupling()->mZ(); + Energy lowScale = ewScale; + // result for all EW and QCD SCET contributions: + // MATCHING CONTRIBUTIONS + // high energy matching + matrix > highMatch_val; + if(iswap==0) + highMatch_val = HighEnergyMatching::highEnergyMatching(highScale,s,t,u,process,!born,false); + else if(iswap==1) + highMatch_val = HighEnergyMatching::highEnergyMatching(highScale,t,s,u,process,!born,false); + else if(iswap==2) + highMatch_val = HighEnergyMatching::highEnergyMatching(highScale,u,t,s,process,!born,false); + else + assert(false); + // low energy matching + matrix + ewMatch_val = ElectroWeakMatching::electroWeakMatching(ewScale,s,t,u,process,!born,iswap); + matrix collinearEWMatch_val = + collinearSudakov_->electroWeakMatching(ewScale,s,process,!born); + // EVOLUTION + matrix highRunning_val,lowRunning_val, + collinearHighRunning_val,collinearLowRunning_val; + // born process + if(born) { + highRunning_val = identity_matrix(softSudakov_->numberGauge(process)); + lowRunning_val = identity_matrix(softSudakov_->numberBrokenGauge(process)); + collinearHighRunning_val = identity_matrix(softSudakov_->numberGauge(process)); + collinearLowRunning_val = identity_matrix(softSudakov_->numberBrokenGauge(process)); + } + // EW corrected + else { + coupling()->SU3(false); + coupling()-> EW( true); + highRunning_val = softSudakov_->highEnergyRunning(highScale, ewScale,s,t,u,process,iswap); + lowRunning_val = softSudakov_->lowEnergyRunning ( ewScale,lowScale,s,t,u,process,iswap); + collinearHighRunning_val = collinearSudakov_->highEnergyRunning(highScale,ewScale,s,process,false); + collinearLowRunning_val = collinearSudakov_->lowEnergyRunning(ewScale,lowScale,s,process); + }; + matrix lowMatchTemp_val = + zero_matrix(ewMatch_val.size1(),ewMatch_val.size2()); + for (unsigned int ii=0; ii temp(highRunning_val.size1(),collinearHighRunning_val.size2()); + axpy_prod(highRunning_val,collinearHighRunning_val,temp); + matrix temp2(collinearLowRunning_val.size1(),lowRunning_val.size2()); + axpy_prod(collinearLowRunning_val,lowRunning_val,temp2); + matrix temp3(temp2.size1(),lowMatchTemp_val.size2()); + axpy_prod(temp2,lowMatchTemp_val,temp3); + temp2.resize(temp3.size1(),temp.size2()); + axpy_prod(temp3,temp,temp2); + matrix > result(temp2.size1(),highMatch_val.size2()); + axpy_prod_local(temp2,highMatch_val,result); + // reset the couplings + coupling()->SU3(SU3save); + coupling()-> EW( EWsave); + // return the answer + return result; +} + + +double ElectroWeakReweighter::reweightggqqbar() const { + // momenta and invariants + Lorentz5Momentum p1 = subProcess()->incoming().first ->momentum(); + Lorentz5Momentum p2 = subProcess()->incoming().second->momentum(); + Lorentz5Momentum p3 = subProcess()->outgoing()[0]->momentum(); + Lorentz5Momentum p4 = subProcess()->outgoing()[1]->momentum(); + tcPDPtr qbar = subProcess()->outgoing()[0]->dataPtr(); + tcPDPtr q = subProcess()->outgoing()[1]->dataPtr(); + if(q->id()<0) { + swap(p3,p4 ); + swap(q ,qbar); + } + Energy2 s = (p1+p2).m2(); + Energy2 t = (p1-p4).m2(); + Energy2 u = (p1-p3).m2(); + // boost to partonic rest frame and rescale momenta of outgoing + // so zero mass + Lorentz5Momentum psum=p1+p2; + LorentzRotation boost(-psum.boostVector()); + p1 *= boost; + p2 *= boost; + p3 *= boost; + p4 *= boost; + p3.setMass(ZERO); + p3.rescaleRho(); + p4.setMass(ZERO); + p4.rescaleRho(); + // LO and EW matrix element coefficents + boost::numeric::ublas::matrix > + bornQQGGweights,bornRRGGweights,EWQQGGweights,EWRRGGweights; + // quark left doublet + if(q->id()<5) { + bornQQGGweights = evaluateRunning(EWProcess::QQGG,s,t,u,true ,0); + EWQQGGweights = evaluateRunning(EWProcess::QQGG,s,t,u,false,0); + } + else { + bornQQGGweights = evaluateRunning(EWProcess::QtQtGG,s,t,u,true ,0); + EWQQGGweights = evaluateRunning(EWProcess::QtQtGG,s,t,u,false,0); + } + // quark right singlet + if(q->id()==0) { + if(q->id()==6) { + bornRRGGweights = evaluateRunning(EWProcess::tRtRGG,s,t,u,true ,0); + EWRRGGweights = evaluateRunning(EWProcess::tRtRGG,s,t,u,false,0); + } + else { + bornRRGGweights = evaluateRunning(EWProcess::UUGG,s,t,u,true ,0); + EWRRGGweights = evaluateRunning(EWProcess::UUGG,s,t,u,false,0); + } + } + else { + bornRRGGweights = evaluateRunning(EWProcess::DDGG,s,t,u,true ,0); + EWRRGGweights = evaluateRunning(EWProcess::DDGG,s,t,u,false,0); + } + SpinorWaveFunction qw(p4,qbar,incoming); + SpinorBarWaveFunction qbarw(p3,q ,incoming); + vector > eps1,eps2; + SackGluonPolarizations(p1,p2,p3,p4,s,t,u,ZERO,eps1,eps2,1); + boost::numeric::ublas::matrix + bornME = boost::numeric::ublas::zero_matrix(3,3), + EWME = boost::numeric::ublas::zero_matrix(3,3); + // helicities of outgoing quarks + for(unsigned int iq=0;iq<2;++iq) { + if(iq==0) { + qw.reset (0); + qbarw.reset(1); + } + else { + qw.reset (1); + qbarw.reset(0); + } + LorentzVector > current = iq==0 ? + qw.dimensionedWave(). leftCurrent(qbarw.dimensionedWave()) : + qw.dimensionedWave().rightCurrent(qbarw.dimensionedWave()); + for(unsigned int i1=0;i1<2;++i1) { + complex d31 = eps1[i1].dot(p3); + LorentzVector > temp = + qw.dimensionedWave().slash(eps1[i1]) + .slash(p2-p4).vectorCurrent(qbarw.dimensionedWave()); + for(unsigned int i2=0;i2<2;++i2) { + boost::numeric::ublas::vector > M(5); + Complex d34 = eps1[i1].dot(eps2[i2]); + complex d42 = eps2[i2].dot(p4); + // M0 in paper + M(0) = temp.dot(eps2[i2]); + // M4 in paper + M(2) = current.dot(eps2[i2])*d31; + // M5 in paper + M(3) = -current.dot(eps1[i1])*d42; + // M1 in paper (missing factor) + M(1) = current.dot(p2); + // M6 in paper + M(4) = M(1)*d31*d42/GeV2; + // M1 final factor + M(1) *= d34; + // coefficient of different contributions + boost::numeric::ublas::vector Cborn(3),CEW(3); + if(iq==0) { + axpy_prod_local(bornQQGGweights,M,Cborn); + axpy_prod_local(EWQQGGweights ,M,CEW ); + } + else { + axpy_prod_local(bornRRGGweights,M,Cborn); + axpy_prod_local(EWRRGGweights ,M,CEW ); + } + unsigned int ioff = (Cborn.size()==6 && q->id()%2!=0) ? 3 : 0; + for(unsigned int ix=0;ix<3;++ix) { + for(unsigned int iy=0;iy<3;++iy) { + bornME(ix,iy) += Cborn(ix+ioff)*conj(Cborn(iy+ioff)); + EWME (ix,iy) += CEW (ix+ioff)*conj(CEW (iy+ioff)); + } + } + } + } + } + double born = 24.*real(bornME(0,0))+20./3.*real(bornME(1,1))+12.*real(bornME(2,2)); + double EW = 24.*real(EWME(0,0))+20./3.*real(EWME(1,1))+12.*real(EWME(2,2)); + return EW/born; +} + +double ElectroWeakReweighter::reweightqgqg() const { + // momenta and invariants + Lorentz5Momentum p1 = subProcess()->incoming().first ->momentum(); + Lorentz5Momentum p2 = subProcess()->incoming().second->momentum(); + tcPDPtr q; + if(subProcess()->incoming().first->id()!=ParticleID::g) { + q = subProcess()->incoming().first ->dataPtr(); + } + else { + q = subProcess()->incoming().second->dataPtr(); + swap(p1,p2); + } + Lorentz5Momentum p3 = subProcess()->outgoing()[0]->momentum(); + Lorentz5Momentum p4 = subProcess()->outgoing()[1]->momentum(); + if(subProcess()->outgoing()[0]->id()!=ParticleID::g) + swap(p3,p4); + Energy2 s = (p1+p2).m2(); + Energy2 t = (p1-p4).m2(); + Energy2 u = (p1-p3).m2(); + // boost to partonic rest frame + Lorentz5Momentum psum=p1+p2; + LorentzRotation boost(-psum.boostVector()); + p1 *= boost; + p2 *= boost; + p3 *= boost; + p4 *= boost; + // LO and EW corrected matrix element coefficients + boost::numeric::ublas::matrix > + bornQQGGweights,bornRRGGweights,EWQQGGweights,EWRRGGweights; + // quark left doublet + if(q->id()!=5) { + bornQQGGweights = evaluateRunning(EWProcess::QQGG,s,t,u,true ,1); + EWQQGGweights = evaluateRunning(EWProcess::QQGG,s,t,u,false,1); + } + else { + bornQQGGweights = evaluateRunning(EWProcess::QtQtGG,s,t,u,true ,1); + EWQQGGweights = evaluateRunning(EWProcess::QtQtGG,s,t,u,false,1); + } + // quark right singlet + if(abs(q->id())%2==0) { + bornRRGGweights = evaluateRunning(EWProcess::UUGG,s,t,u,true ,1); + EWRRGGweights = evaluateRunning(EWProcess::UUGG,s,t,u,false,1); + } + else { + bornRRGGweights = evaluateRunning(EWProcess::DDGG,s,t,u,true ,1); + EWRRGGweights = evaluateRunning(EWProcess::DDGG,s,t,u,false,1); + } + SpinorWaveFunction qw(p1,q,incoming); + SpinorBarWaveFunction qbarw(p4,q,outgoing); + vector > eps2,eps3; + SackGluonPolarizations(p1,p2,p3,p4,s,t,u,ZERO,eps2,eps3,2); + // compute the matrix elements + boost::numeric::ublas::matrix + bornME = boost::numeric::ublas::zero_matrix(3,3), + EWME = boost::numeric::ublas::zero_matrix(3,3), + testME = boost::numeric::ublas::zero_matrix(3,3); + for(unsigned int iq=0;iq<2;++iq) { + if(iq==0) { + qw.reset (0); + qbarw.reset(0); + } + else { + qw.reset (1); + qbarw.reset(1); + } + LorentzVector > current = iq==0 ? + qw.dimensionedWave(). leftCurrent(qbarw.dimensionedWave()) : + qw.dimensionedWave().rightCurrent(qbarw.dimensionedWave()); + for(unsigned int i1=0;i1<2;++i1) { + complex d31 = eps3[i1].dot(p1); + LorentzVector> temp = + qw.dimensionedWave().slash(eps3[i1]) + .slash(p2-p4).vectorCurrent(qbarw.dimensionedWave()); + for(unsigned int i2=0;i2<2;++i2) { + boost::numeric::ublas::vector > M(5); + Complex d34 = eps3[i1].dot(eps2[i2]); + complex d42 = eps2[i2].dot(p4); + // M0 in paper + M(0) = temp.dot(eps2[i2]); + // M4 in paper + M(2) = current.dot(eps2[i2])*d31; + // M5 in paper + M(3) = -current.dot(eps3[i1])*d42; + // M1 in paper (missing factor) + M(1) = current.dot(p2); + // M6 in paper + M(4) = M(1)*d31*d42/GeV2; + // M1 final factor + M(1) *= d34; + // coefficient of different contributions + boost::numeric::ublas::vector Cborn(3),CEW(3); + if(iq==0) { + axpy_prod_local(bornQQGGweights,M,Cborn); + axpy_prod_local(EWQQGGweights ,M,CEW ); + } + else { + axpy_prod_local(bornRRGGweights,M,Cborn); + axpy_prod_local(EWRRGGweights ,M,CEW ); + } + unsigned int ioff = (Cborn.size()==6 && q->id()%2!=0) ? 3 : 0; + for(unsigned int ix=0;ix<3;++ix) { + for(unsigned int iy=0;iy<3;++iy) { + bornME(ix,iy) += Cborn(ix+ioff)*conj(Cborn(iy+ioff)); + EWME (ix,iy) += CEW (ix+ioff)*conj(CEW (iy+ioff)); + } + } + } + } + } + double born = 24.*real(bornME(0,0))+20./3.*real(bornME(1,1))+12.*real(bornME(2,2)); + double EW = 24.*real(EWME(0,0))+20./3.*real(EWME(1,1))+12.*real(EWME(2,2)); + return EW/born; +} + +double ElectroWeakReweighter::reweightqbargqbarg() const { + // momenta and invariants + Lorentz5Momentum p1 = subProcess()->incoming().first ->momentum(); + Lorentz5Momentum p2 = subProcess()->incoming().second->momentum(); + tcPDPtr qbar; + if(subProcess()->incoming().first->id()==ParticleID::g) { + qbar = subProcess()->incoming().second->dataPtr(); + } + else { + qbar = subProcess()->incoming().first ->dataPtr(); + swap(p1,p2); + } + Lorentz5Momentum p3 = subProcess()->outgoing()[0]->momentum(); + Lorentz5Momentum p4 = subProcess()->outgoing()[1]->momentum(); + if(subProcess()->outgoing()[0]->id()==ParticleID::g) + swap(p3,p4); + Energy2 s = (p1+p2).m2(); + Energy2 t = (p1-p4).m2(); + Energy2 u = (p1-p3).m2(); + // boost to partonci rest frame + Lorentz5Momentum psum=p1+p2; + LorentzRotation boost(-psum.boostVector()); + p1 *= boost; + p2 *= boost; + p3 *= boost; + p4 *= boost; + // LO and EW corrected matrix element coefficients + boost::numeric::ublas::matrix > + bornQQGGweights,bornRRGGweights,EWQQGGweights,EWRRGGweights; + // quark left doublet + if(qbar->id()!=-5) { + bornQQGGweights = evaluateRunning(EWProcess::QQGG,s,t,u,true ,1); + EWQQGGweights = evaluateRunning(EWProcess::QQGG,s,t,u,false,1); + } + else { + bornQQGGweights = evaluateRunning(EWProcess::QtQtGG,s,t,u,true ,1); + EWQQGGweights = evaluateRunning(EWProcess::QtQtGG,s,t,u,false,1); + } + // quark right singlet + if(abs(qbar->id())%2==0) { + bornRRGGweights = evaluateRunning(EWProcess::UUGG,s,t,u,true ,1); + EWRRGGweights = evaluateRunning(EWProcess::UUGG,s,t,u,false,1); + } + else { + bornRRGGweights = evaluateRunning(EWProcess::DDGG,s,t,u,true ,1); + EWRRGGweights = evaluateRunning(EWProcess::DDGG,s,t,u,false,1); + } + SpinorWaveFunction qw(p3,qbar,outgoing); + SpinorBarWaveFunction qbarw(p2,qbar,incoming); + vector > eps1,eps4; + SackGluonPolarizations(p1,p2,p3,p4,s,t,u,ZERO,eps1,eps4,3); + boost::numeric::ublas::matrix + bornME = boost::numeric::ublas::zero_matrix(3,3), + EWME = boost::numeric::ublas::zero_matrix(3,3); + for(unsigned int iq=0;iq<2;++iq) { + if(iq==0) { + qw.reset (1); + qbarw.reset(1); + } + else { + qw.reset (0); + qbarw.reset(0); + } + LorentzVector > current = iq==0 ? + qw.dimensionedWave(). leftCurrent(qbarw.dimensionedWave()) : + qw.dimensionedWave().rightCurrent(qbarw.dimensionedWave()); + for(unsigned int i1=0;i1<2;++i1) { + complex d31 = eps1[i1].dot(p3); + LorentzVector > temp = + qw.dimensionedWave().slash(eps1[i1]) + .slash(p4-p2).vectorCurrent(qbarw.dimensionedWave()); + for(unsigned int i2=0;i2<2;++i2) { + boost::numeric::ublas::vector > M(5); + Complex d34 = eps1[i1].dot(eps4[i2]); + complex d42 = eps4[i2].dot(p2); + // M0 in paper + M(0) = temp.dot(eps4[i2]); + // M4 in paper + M(2) = current.dot(eps4[i2])*d31; + // M5 in paper + M(3) = -current.dot(eps1[i1])*d42; + // M1 in paper (missing factor) + M(1) = current.dot(p4); + // M6 in paper + M(4) = M(1)*d31*d42/GeV2; + // M1 final factor + M(1) *= d34; + // coefficient of different contributions + boost::numeric::ublas::vector Cborn(3),CEW(3); + if(iq==0) { + axpy_prod_local(bornQQGGweights,M,Cborn); + axpy_prod_local(EWQQGGweights ,M,CEW ); + } + else { + axpy_prod_local(bornRRGGweights,M,Cborn); + axpy_prod_local(EWRRGGweights ,M,CEW ); + } + unsigned int ioff = (Cborn.size()==6 && abs(qbar->id())%2!=0) ? 3 : 0; + for(unsigned int ix=0;ix<3;++ix) { + for(unsigned int iy=0;iy<3;++iy) { + bornME(ix,iy) += Cborn(ix+ioff)*conj(Cborn(iy+ioff)); + EWME (ix,iy) += CEW (ix+ioff)*conj(CEW (iy+ioff)); + } + } + } + } + } + double born = 24.*real(bornME(0,0))+20./3.*real(bornME(1,1))+12.*real(bornME(2,2)); + double EW = 24.*real(EWME(0,0))+20./3.*real(EWME(1,1))+12.*real(EWME(2,2)); + return EW/born; +} + +double ElectroWeakReweighter::reweightqqbarqqbarS() const { + // momenta and invariants + Lorentz5Momentum p1 = subProcess()->incoming().first ->momentum(); + tcPDPtr q1 = subProcess()->incoming().first ->dataPtr(); + Lorentz5Momentum p2 = subProcess()->incoming().second->momentum(); + tcPDPtr q1bar = subProcess()->incoming().second->dataPtr(); + if(q1->id()<0) { + swap(p1,p2 ); + swap(q1 ,q1bar); + } + Lorentz5Momentum p3 = subProcess()->outgoing()[0]->momentum(); + tcPDPtr q2bar = subProcess()->outgoing()[0]->dataPtr(); + Lorentz5Momentum p4 = subProcess()->outgoing()[1]->momentum(); + tcPDPtr q2 = subProcess()->outgoing()[1]->dataPtr(); + if(q2bar->id()>0) { + swap(p3,p4 ); + swap(q2 ,q2bar); + } + Energy2 s = (p1+p2).m2(); + Energy2 t = (p1-p4).m2(); + Energy2 u = (p1-p3).m2(); + // boost to partonci rest frame + Lorentz5Momentum psum=p1+p2; + LorentzRotation boost(-psum.boostVector()); + p1 *= boost; + p2 *= boost; + p3 *= boost; + p4 *= boost; + p3.setMass(ZERO); + p3.rescaleRho(); + p4.setMass(ZERO); + p4.rescaleRho(); + // LO and EW corrected matrix element coefficients + boost::numeric::ublas::matrix > + bornLLLLWeights,bornLLRRWeights,bornRRLLWeights,bornRRRRWeights, + EWLLLLWeights,EWLLRRWeights,EWRRLLWeights,EWRRRRWeights; + bool ident = q1->id()==q2->id(); + // LL -> LL + if((q1->id()<=4&& q2->id()<=4)|| (q1->id()==5 && q2->id()==5)) { + if(!ident) { + bornLLLLWeights = evaluateRunning(EWProcess::QQQQ,s,t,u,true ,0); + EWLLLLWeights = evaluateRunning(EWProcess::QQQQ,s,t,u,false,0); + } + else { + bornLLLLWeights = evaluateRunning(EWProcess::QQQQiden,s,t,u,true ,0); + EWLLLLWeights = evaluateRunning(EWProcess::QQQQiden,s,t,u,false,0); + } + } + else if(q1->id()==5 || q2->id()>=5) { + bornLLLLWeights = evaluateRunning(EWProcess::QtQtQQ,s,t,u,true ,0); + EWLLLLWeights = evaluateRunning(EWProcess::QtQtQQ,s,t,u,false,0); + } + else + assert(false); + // RR -> LL + if(q1->id()%2==0) { + if(q2->id()<5) { + bornRRLLWeights = evaluateRunning(EWProcess::QQUU,s,t,u,true ,0); + EWRRLLWeights = evaluateRunning(EWProcess::QQUU,s,t,u,false,0); + } + else { + bornRRLLWeights = evaluateRunning(EWProcess::QtQtUU,s,t,u,true ,0); + EWRRLLWeights = evaluateRunning(EWProcess::QtQtUU,s,t,u,false,0); + } + } + else { + if(q2->id()<5) { + bornRRLLWeights = evaluateRunning(EWProcess::QQDD,s,t,u,true ,0); + EWRRLLWeights = evaluateRunning(EWProcess::QQDD,s,t,u,false,0); + } + else { + bornRRLLWeights = evaluateRunning(EWProcess::QtQtDD,s,t,u,true ,0); + EWRRLLWeights = evaluateRunning(EWProcess::QtQtDD,s,t,u,false,0); + } + } + // LL -> RR + if(q1->id()<=4) { + if(q2->id()%2!=0) { + bornLLRRWeights = evaluateRunning(EWProcess::QQDD,s,t,u,true ,0); + EWLLRRWeights = evaluateRunning(EWProcess::QQDD,s,t,u,false,0); + } + else if (q2->id()==6) { + bornLLRRWeights = evaluateRunning(EWProcess::QQtRtR,s,t,u,true ,0); + EWLLRRWeights = evaluateRunning(EWProcess::QQtRtR,s,t,u,false,0); + } + else { + bornLLRRWeights = evaluateRunning(EWProcess::QQUU,s,t,u,true ,0); + EWLLRRWeights = evaluateRunning(EWProcess::QQUU,s,t,u,false,0); + } + } + else { + if(q2->id()%2!=0) { + bornLLRRWeights = evaluateRunning(EWProcess::QtQtDD,s,t,u,true ,0); + EWLLRRWeights = evaluateRunning(EWProcess::QtQtDD,s,t,u,false,0); + } + else { + bornLLRRWeights = evaluateRunning(EWProcess::QtQtUU,s,t,u,true ,0); + EWLLRRWeights = evaluateRunning(EWProcess::QtQtUU,s,t,u,false,0); + } + } + // RR -> RR + if(q1->id()%2==0) { + if(q2->id()==6) { + bornRRRRWeights = evaluateRunning(EWProcess::tRtRUU,s,t,u,true ,0); + EWRRRRWeights = evaluateRunning(EWProcess::tRtRUU,s,t,u,false,0); + } + else if(q2->id()%2==0) { + if(ident) { + bornRRRRWeights = evaluateRunning(EWProcess::UUUUiden,s,t,u,true ,0); + EWRRRRWeights = evaluateRunning(EWProcess::UUUUiden,s,t,u,false,0); + } + else { + bornRRRRWeights = evaluateRunning(EWProcess::UUUU,s,t,u,true ,0); + EWRRRRWeights = evaluateRunning(EWProcess::UUUU,s,t,u,false,0); + } + } + else { + bornRRRRWeights = evaluateRunning(EWProcess::UUDD,s,t,u,true ,0); + EWRRRRWeights = evaluateRunning(EWProcess::UUDD,s,t,u,false,0); + } + } + else { + if(q2->id()==6) { + bornRRRRWeights = evaluateRunning(EWProcess::tRtRDD,s,t,u,true ,0); + EWRRRRWeights = evaluateRunning(EWProcess::tRtRDD,s,t,u,false,0); + } + else if(q2->id()%2==0) { + bornRRRRWeights = evaluateRunning(EWProcess::UUDD,s,t,u,true ,0); + EWRRRRWeights = evaluateRunning(EWProcess::UUDD,s,t,u,false,0); + } + else { + if(ident) { + bornRRRRWeights = evaluateRunning(EWProcess::DDDDiden,s,t,u,true ,0); + EWRRRRWeights = evaluateRunning(EWProcess::DDDDiden,s,t,u,false,0); + } + else { + bornRRRRWeights = evaluateRunning(EWProcess::DDDD,s,t,u,true ,0); + EWRRRRWeights = evaluateRunning(EWProcess::DDDD,s,t,u,false,0); + } + } + } + // extra terms for identical particles + boost::numeric::ublas::matrix > + borntChannelWeights,EWtChannelWeights; + if(ident) { + if(q1->id()%2==0) { + borntChannelWeights = evaluateRunning(EWProcess::QQUU,s,t,u,true ,1); + EWtChannelWeights = evaluateRunning(EWProcess::QQUU,s,t,u,false,1); + } + else if(q1->id()==5) { + borntChannelWeights = evaluateRunning(EWProcess::QtQtDD,s,t,u,true ,1); + EWtChannelWeights = evaluateRunning(EWProcess::QtQtDD,s,t,u,false,1); + } + else { + borntChannelWeights = evaluateRunning(EWProcess::QQDD,s,t,u,true ,1); + EWtChannelWeights = evaluateRunning(EWProcess::QQDD,s,t,u,false,1); + } + } + SpinorWaveFunction q1w(p1,q1 ,incoming); + SpinorBarWaveFunction q1barw(p2,q1bar,incoming); + SpinorWaveFunction q2barw(p3,q2bar,outgoing); + SpinorBarWaveFunction q2w(p4,q2 ,outgoing); + boost::numeric::ublas::matrix + bornME = boost::numeric::ublas::zero_matrix(2,2), + EWME = boost::numeric::ublas::zero_matrix(2,2); + for(unsigned int iq1=0;iq1<2;++iq1) { + if(iq1==0) { + q1w.reset (0); + q1barw.reset(1); + } + else { + q1w.reset (1); + q1barw.reset(0); + } + LorentzVector > current1 = + q1w.dimensionedWave().vectorCurrent(q1barw.dimensionedWave()); + for(unsigned int iq2=0;iq2<2;++iq2) { + if(iq2==0) { + q2w.reset (0); + q2barw.reset(1); + } + else { + q2w.reset (1); + q2barw.reset(0); + } + LorentzVector > current2 = + q2barw.dimensionedWave().vectorCurrent(q2w.dimensionedWave()); + complex amp = current1.dot(current2); + vector Cborn(2),CEW(2); + // amplitudes + if(iq1==0) { + // LL + if(iq2==0) { + unsigned int ioff; + if(q1->id()%2==0) { + ioff = q2->id()%2==0 ? 0 : 2; + } + else { + ioff = q2->id()%2==0 ? 1 : 3; + } + for(unsigned int ix=0;ix<2;++ix) { + Cborn[ix] = Complex(amp*bornLLLLWeights(6*ix+ioff,0)); + CEW [ix] = Complex(amp* EWLLLLWeights(6*ix+ioff,0)); + } + } + // LR + else { + unsigned int ioff = q1->id()%2==0 ? 0 : 1; + for(unsigned int ix=0;ix<2;++ix) { + Cborn[ix] = Complex(amp*bornLLRRWeights(2*ix+ioff,0)); + CEW [ix] = Complex(amp* EWLLRRWeights(2*ix+ioff,0)); + } + } + } + else { + if(iq2==0) { + unsigned int ioff=q2->id()%2==0 ? 0 : 1; + for(unsigned int ix=0;ix<2;++ix) { + Cborn[ix] = Complex(amp*bornRRLLWeights(2*ix+ioff,0)); + CEW [ix] = Complex(amp* EWRRLLWeights(2*ix+ioff,0)); + } + } + else { + for(unsigned int ix=0;ix<2;++ix) { + Cborn[ix] = Complex(amp*bornRRRRWeights(ix,0)); + CEW [ix] = Complex(amp* EWRRRRWeights(ix,0)); + } + } + } + // square + for(unsigned int ix=0;ix<2;++ix) { + for(unsigned int iy=0;iy<2;++iy) { + bornME(ix,iy) += Cborn[ix]*conj(Cborn[iy]); + EWME (ix,iy) += CEW [ix]*conj(CEW [iy]); + } + } + } + } + // extra t-channel pieces if identical flavours + if(ident) { + for(unsigned int iq1=0;iq1<2;++iq1) { + q1w.reset(iq1); + q2w.reset(iq1); + LorentzVector > current1 = + q1w.dimensionedWave().vectorCurrent(q2w.dimensionedWave()); + q1barw.reset(iq1); + q2barw.reset(iq1); + LorentzVector > current2 = + q2barw.dimensionedWave().vectorCurrent(q1barw.dimensionedWave()); + complex amp = current1.dot(current2); + vector Cborn(2),CEW(2); + unsigned int ioff = q1->id()%2==0 ? 0 : 1; + for(unsigned int ix=0;ix<2;++ix) { + Cborn[ix] = Complex(amp*borntChannelWeights(2*ix+ioff,0)); + CEW [ix] = Complex(amp*EWtChannelWeights(2*ix+ioff,0)); + } + // square + for(unsigned int ix=0;ix<2;++ix) { + for(unsigned int iy=0;iy<2;++iy) { + bornME(ix,iy) += Cborn[ix]*conj(Cborn[iy]); + EWME (ix,iy) += CEW [ix]*conj(CEW [iy]); + } + } + } + } + // colour factors + double born = 2.*real(bornME(0,0))+9.*real(bornME(1,1)); + double EW = 2.*real( EWME(0,0))+9.*real( EWME(1,1)); + return EW/born; +} + +double ElectroWeakReweighter::reweightqqbarqqbarT() const { + // momenta and invariants + Lorentz5Momentum p1 = subProcess()->incoming().first ->momentum(); + tcPDPtr q1 = subProcess()->incoming().first ->dataPtr(); + Lorentz5Momentum p2 = subProcess()->incoming().second->momentum(); + tcPDPtr q1bar = subProcess()->incoming().second->dataPtr(); + if(q1->id()<0) { + swap(p1,p2 ); + swap(q1 ,q1bar); + } + Lorentz5Momentum p3 = subProcess()->outgoing()[0]->momentum(); + tcPDPtr q2bar = subProcess()->outgoing()[0]->dataPtr(); + Lorentz5Momentum p4 = subProcess()->outgoing()[1]->momentum(); + tcPDPtr q2 = subProcess()->outgoing()[1]->dataPtr(); + if(q2bar->id()>0) { + swap(p3,p4 ); + swap(q2 ,q2bar); + } + Energy2 s = (p1+p2).m2(); + Energy2 t = (p1-p4).m2(); + Energy2 u = (p1-p3).m2(); + // boost to partonci rest frame + Lorentz5Momentum psum=p1+p2; + LorentzRotation boost(-psum.boostVector()); + p1 *= boost; + p2 *= boost; + p3 *= boost; + p4 *= boost; + p3.setMass(ZERO); + p3.rescaleRho(); + p4.setMass(ZERO); + p4.rescaleRho(); + assert(q1==q2 && q1bar==q2bar); + assert( q1->id() != -q1bar->id() && q2->id() != -q2bar->id() ); + // LO and EW corrected matrix element coefficients + boost::numeric::ublas::matrix > + bornLLLLWeights,bornLLRRWeights,bornRRLLWeights,bornRRRRWeights, + EWLLLLWeights,EWLLRRWeights,EWRRLLWeights,EWRRRRWeights; + // LL + if( q1->id() == ParticleID::b || + q1bar->id() == ParticleID::bbar ) { + bornLLLLWeights = evaluateRunning(EWProcess::QtQtQQ,s,t,u,true ,1); + EWLLLLWeights = evaluateRunning(EWProcess::QtQtQQ,s,t,u,false,1); + } + else { + bornLLLLWeights = evaluateRunning(EWProcess::QQQQ,s,t,u,true ,1); + EWLLLLWeights = evaluateRunning(EWProcess::QQQQ,s,t,u,false,1); + } + // RR -> LL + if(q1->id()%2==0) { + if(q1bar->id()==ParticleID::bbar) { + bornRRLLWeights = evaluateRunning(EWProcess::QtQtUU,s,t,u,true ,1); + EWRRLLWeights = evaluateRunning(EWProcess::QtQtUU,s,t,u,false,1); + } + else { + bornRRLLWeights = evaluateRunning(EWProcess::QQUU,s,t,u,true ,1); + EWRRLLWeights = evaluateRunning(EWProcess::QQUU,s,t,u,false,1); + } + } + else { + if(q1bar->id()==ParticleID::bbar) { + bornRRLLWeights = evaluateRunning(EWProcess::QtQtDD,s,t,u,true ,1); + EWRRLLWeights = evaluateRunning(EWProcess::QtQtDD,s,t,u,false,1); + } + else { + bornRRLLWeights = evaluateRunning(EWProcess::QQDD,s,t,u,true ,1); + EWRRLLWeights = evaluateRunning(EWProcess::QQDD,s,t,u,false,1); + } + } + // LL -> RR + if(abs(q1bar->id())%2==0) { + if(q1->id()==ParticleID::b) { + bornLLRRWeights = evaluateRunning(EWProcess::QtQtUU,s,t,u,true ,1); + EWLLRRWeights = evaluateRunning(EWProcess::QtQtUU,s,t,u,false,1); + } + else { + bornLLRRWeights = evaluateRunning(EWProcess::QQUU,s,t,u,true ,1); + EWLLRRWeights = evaluateRunning(EWProcess::QQUU,s,t,u,false,1); + } + } + else { + if(q1->id()==ParticleID::b) { + bornLLRRWeights = evaluateRunning(EWProcess::QtQtDD,s,t,u,true ,1); + EWLLRRWeights = evaluateRunning(EWProcess::QtQtDD,s,t,u,false,1); + } + else { + bornLLRRWeights = evaluateRunning(EWProcess::QQDD,s,t,u,true ,1); + EWLLRRWeights = evaluateRunning(EWProcess::QQDD,s,t,u,false,1); + } + } + // RR -> RR + if(q1->id()%2==0) { + if(abs(q1bar->id())%2==0) { + bornRRRRWeights = evaluateRunning(EWProcess::UUUU,s,t,u,true ,1); + EWRRRRWeights = evaluateRunning(EWProcess::UUUU,s,t,u,false,1); + } + else { + bornRRRRWeights = evaluateRunning(EWProcess::UUDD,s,t,u,true ,1); + EWRRRRWeights = evaluateRunning(EWProcess::UUDD,s,t,u,false,1); + } + } + else { + if(abs(q1bar->id())%2==0) { + bornRRRRWeights = evaluateRunning(EWProcess::UUDD,s,t,u,true ,1); + EWRRRRWeights = evaluateRunning(EWProcess::UUDD,s,t,u,false,1); + } + else { + bornRRRRWeights = evaluateRunning(EWProcess::DDDD,s,t,u,true ,1); + EWRRRRWeights = evaluateRunning(EWProcess::DDDD,s,t,u,false,1); + } + } + // calculate the spinors + SpinorWaveFunction q1w(p1,q1 ,incoming); + SpinorBarWaveFunction q1barw(p2,q1bar,incoming); + SpinorWaveFunction q2barw(p3,q2bar,outgoing); + SpinorBarWaveFunction q2w(p4,q2 ,outgoing); + boost::numeric::ublas::matrix + bornME = boost::numeric::ublas::zero_matrix(2,2), + EWME = boost::numeric::ublas::zero_matrix(2,2); + for(unsigned int iq1=0;iq1<2;++iq1) { + q1w.reset(iq1); + q2w.reset(iq1); + LorentzVector > current1 = + q1w.dimensionedWave().vectorCurrent(q2w.dimensionedWave()); + for(unsigned int iq2=0;iq2<2;++iq2) { + q1barw.reset(iq2); + q2barw.reset(iq2); + LorentzVector > current2 = + q2barw.dimensionedWave().vectorCurrent(q1barw.dimensionedWave()); + // calculate the amplitude + complex amp = current1.dot(current2); + vector Cborn(2),CEW(2); + if(iq1==0) { + // LL RR + if(iq2==0) { + unsigned int ioff = q1->id()%2==0 ? 0 : 1; + for(unsigned int ix=0;ix<2;++ix) { + Cborn[ix] = Complex(amp*bornLLRRWeights(2*ix+ioff,0)); + CEW [ix] = Complex(amp* EWLLRRWeights(2*ix+ioff,0)); + } + } + // LL LL + else { + unsigned int ioff; + if(q1->id()%2==0) { + ioff = abs(q1bar->id())%2==0 ? 0 : 2; + } + else { + ioff = abs(q1bar->id())%2==0 ? 1 : 3; + } + for(unsigned int ix=0;ix<2;++ix) { + Cborn[ix] = Complex(amp*bornLLLLWeights(6*ix+ioff,0)); + CEW [ix] = Complex(amp* EWLLLLWeights(6*ix+ioff,0)); + } + } + } + else { + // RR RR + if(iq2==0) { + for(unsigned int ix=0;ix<2;++ix) { + Cborn[ix] = Complex(amp*bornRRRRWeights(ix,0)); + CEW [ix] = Complex(amp* EWRRRRWeights(ix,0)); + } + } + // RR LL + else { + unsigned int ioff=abs(q1bar->id())%2==0 ? 0 : 1; + for(unsigned int ix=0;ix<2;++ix) { + Cborn[ix] = Complex(amp*bornRRLLWeights(2*ix+ioff,0)); + CEW [ix] = Complex(amp* EWRRLLWeights(2*ix+ioff,0)); + } + } + } + // square + for(unsigned int ix=0;ix<2;++ix) { + for(unsigned int iy=0;iy<2;++iy) { + bornME(ix,iy) += Cborn[ix]*conj(Cborn[iy]); + EWME (ix,iy) += CEW [ix]*conj(CEW [iy]); + } + } + } + } + // colour factors + double born = 2.*real(bornME(0,0))+9.*real(bornME(1,1)); + double EW = 2.*real( EWME(0,0))+9.*real( EWME(1,1)); + return EW/born; +} + +double ElectroWeakReweighter::reweightqqqq() const { + // momenta and invariants + Lorentz5Momentum p1 = subProcess()->incoming().first ->momentum(); + tcPDPtr q1 = subProcess()->incoming().first ->dataPtr(); + Lorentz5Momentum p2 = subProcess()->incoming().second->momentum(); + tcPDPtr q2 = subProcess()->incoming().second->dataPtr(); + Lorentz5Momentum p3 = subProcess()->outgoing()[0] ->momentum(); + tcPDPtr q3 = subProcess()->outgoing()[0] ->dataPtr(); + Lorentz5Momentum p4 = subProcess()->outgoing()[1] ->momentum(); + tcPDPtr q4 = subProcess()->outgoing()[1] ->dataPtr(); + if(q1->id()!=q3->id()) { + swap(q3,q4); + swap(p3,p4); + } + assert(q1->id()==q3->id()); + assert(q2->id()==q4->id()); + Energy2 s = (p1+p2).m2(); + Energy2 t = (p1-p4).m2(); + Energy2 u = (p1-p3).m2(); + // boost to partonci rest frame + Lorentz5Momentum psum=p1+p2; + LorentzRotation boost(-psum.boostVector()); + p1 *= boost; + p2 *= boost; + p3 *= boost; + p4 *= boost; + p3.setMass(ZERO); + p3.rescaleRho(); + p4.setMass(ZERO); + p4.rescaleRho(); + // LO and EW corrected matrix element coefficients + boost::numeric::ublas::matrix > + bornLLLLWeights,bornLLRRWeights,bornRRLLWeights,bornRRRRWeights, + EWLLLLWeights,EWLLRRWeights,EWRRLLWeights,EWRRRRWeights; + bool ident = q1->id()==q2->id(); + // LL -> LL + if((q1->id()<=4&& q2->id()<=4)|| (q1->id()==5 && q2->id()==5)) { + if(!ident) { + bornLLLLWeights = evaluateRunning(EWProcess::QQQQ,s,t,u,true ,2); + EWLLLLWeights = evaluateRunning(EWProcess::QQQQ,s,t,u,false,2); + } + else { + bornLLLLWeights = evaluateRunning(EWProcess::QQQQiden,s,t,u,true ,2); + EWLLLLWeights = evaluateRunning(EWProcess::QQQQiden,s,t,u,false,2); + } + } + else if(q1->id()==5 || q2->id()==5) { + bornLLLLWeights = evaluateRunning(EWProcess::QtQtQQ,s,t,u,true ,2); + EWLLLLWeights = evaluateRunning(EWProcess::QtQtQQ,s,t,u,false,2); + } + else + assert(false); + // RR -> LL + if(q1->id()%2==0) { + if(q2->id()<5) { + bornRRLLWeights = evaluateRunning(EWProcess::QQUU,s,t,u,true ,2); + EWRRLLWeights = evaluateRunning(EWProcess::QQUU,s,t,u,false,2); + } + else { + bornRRLLWeights = evaluateRunning(EWProcess::QtQtUU,s,t,u,true ,2); + EWRRLLWeights = evaluateRunning(EWProcess::QtQtUU,s,t,u,false,2); + } + } + else { + if(q2->id()<5) { + bornRRLLWeights = evaluateRunning(EWProcess::QQDD,s,t,u,true ,2); + EWRRLLWeights = evaluateRunning(EWProcess::QQDD,s,t,u,false,2); + } + else { + bornRRLLWeights = evaluateRunning(EWProcess::QtQtDD,s,t,u,true ,2); + EWRRLLWeights = evaluateRunning(EWProcess::QtQtDD,s,t,u,false,2); + } + } + // LL -> RR + if(q1->id()<=4) { + if(q2->id()%2!=0) { + bornLLRRWeights = evaluateRunning(EWProcess::QQDD,s,t,u,true ,2); + EWLLRRWeights = evaluateRunning(EWProcess::QQDD,s,t,u,false,2); + } + else { + bornLLRRWeights = evaluateRunning(EWProcess::QQUU,s,t,u,true ,2); + EWLLRRWeights = evaluateRunning(EWProcess::QQUU,s,t,u,false,2); + } + } + else { + if(q2->id()%2!=0) { + bornLLRRWeights = evaluateRunning(EWProcess::QtQtDD,s,t,u,true ,2); + EWLLRRWeights = evaluateRunning(EWProcess::QtQtDD,s,t,u,false,2); + } + else { + bornLLRRWeights = evaluateRunning(EWProcess::QtQtUU,s,t,u,true ,2); + EWLLRRWeights = evaluateRunning(EWProcess::QtQtUU,s,t,u,false,2); + } + } + // RR -> RR + if(q1->id()%2==0) { + if(q2->id()%2==0) { + if(ident) { + bornRRRRWeights = evaluateRunning(EWProcess::UUUUiden,s,t,u,true ,2); + EWRRRRWeights = evaluateRunning(EWProcess::UUUUiden,s,t,u,false,2); + } + else { + bornRRRRWeights = evaluateRunning(EWProcess::UUUU,s,t,u,true ,2); + EWRRRRWeights = evaluateRunning(EWProcess::UUUU,s,t,u,false,2); + } + } + else { + bornRRRRWeights = evaluateRunning(EWProcess::UUDD,s,t,u,true ,2); + EWRRRRWeights = evaluateRunning(EWProcess::UUDD,s,t,u,false,2); + } + } + else { + if(q2->id()%2==0) { + bornRRRRWeights = evaluateRunning(EWProcess::UUDD,s,t,u,true ,2); + EWRRRRWeights = evaluateRunning(EWProcess::UUDD,s,t,u,false,2); + } + else { + if(ident) { + bornRRRRWeights = evaluateRunning(EWProcess::DDDDiden,s,t,u,true ,2); + EWRRRRWeights = evaluateRunning(EWProcess::DDDDiden,s,t,u,false,2); + } + else { + bornRRRRWeights = evaluateRunning(EWProcess::DDDD,s,t,u,true ,2); + EWRRRRWeights = evaluateRunning(EWProcess::DDDD,s,t,u,false,2); + } + } + } + // extra terms for identical particles + boost::numeric::ublas::matrix > + borntChannelWeights,EWtChannelWeights; + if(ident) { + if(q1->id()%2==0) { + borntChannelWeights = evaluateRunning(EWProcess::QQUU,s,u,t,true ,2); + EWtChannelWeights = evaluateRunning(EWProcess::QQUU,s,u,t,false,2); + } + else if(q1->id()==5) { + borntChannelWeights = evaluateRunning(EWProcess::QtQtDD,s,u,t,true ,2); + EWtChannelWeights = evaluateRunning(EWProcess::QtQtDD,s,u,t,false,2); + } + else { + borntChannelWeights = evaluateRunning(EWProcess::QQDD,s,u,t,true ,2); + EWtChannelWeights = evaluateRunning(EWProcess::QQDD,s,u,t,false,2); + } + } + SpinorWaveFunction q1w(p1,q1,incoming); + SpinorWaveFunction q2w(p2,q2,incoming); + SpinorBarWaveFunction q3w(p3,q3,outgoing); + SpinorBarWaveFunction q4w(p4,q4,outgoing); + boost::numeric::ublas::matrix + bornME = boost::numeric::ublas::zero_matrix(2,2), + EWME = boost::numeric::ublas::zero_matrix(2,2); + for(unsigned int iq1=0;iq1<2;++iq1) { + q1w.reset(iq1); + q3w.reset(iq1); + LorentzVector > current1 = + q1w.dimensionedWave().vectorCurrent(q3w.dimensionedWave()); + for(unsigned int iq2=0;iq2<2;++iq2) { + q2w.reset(iq2); + q4w.reset(iq2); + LorentzVector > current2 = + q2w.dimensionedWave().vectorCurrent(q4w.dimensionedWave()); + complex amp = current1.dot(current2); + vector Cborn(2),CEW(2); + // amplitudes + if(iq1==0) { + // LL + if(iq2==0) { + unsigned int ioff; + if(q1->id()%2==0) { + ioff = q2->id()%2==0 ? 0 : 2; + } + else { + ioff = q2->id()%2==0 ? 1 : 3; + } + for(unsigned int ix=0;ix<2;++ix) { + Cborn[ix] = Complex(amp*bornLLLLWeights(6*ix+ioff,0)); + CEW [ix] = Complex(amp*EWLLLLWeights(6*ix+ioff,0)); + } + } + // LR + else { + unsigned int ioff = q1->id()%2==0 ? 0 : 1; + for(unsigned int ix=0;ix<2;++ix) { + Cborn[ix] = Complex(amp*bornLLRRWeights(2*ix+ioff,0)); + CEW [ix] = Complex(amp* EWLLRRWeights(2*ix+ioff,0)); + } + } + } + else { + if(iq2==0) { + unsigned int ioff=q2->id()%2==0 ? 0 : 1; + for(unsigned int ix=0;ix<2;++ix) { + Cborn[ix] = Complex(amp*bornRRLLWeights(2*ix+ioff,0)); + CEW [ix] = Complex(amp* EWRRLLWeights(2*ix+ioff,0)); + } + } + else { + for(unsigned int ix=0;ix<2;++ix) { + Cborn[ix] = Complex(amp*bornRRRRWeights(ix,0)); + CEW [ix] = Complex(amp* EWRRRRWeights(ix,0)); + } + } + } + // square + for(unsigned int ix=0;ix<2;++ix) { + for(unsigned int iy=0;iy<2;++iy) { + bornME(ix,iy) += Cborn[ix]*conj(Cborn[iy]); + EWME (ix,iy) += CEW [ix]*conj(CEW [iy]); + } + } + } + } + // extra u-channel pieces if identical flavours + if(ident) { + for(unsigned int iq1=0;iq1<2;++iq1) { + q1w.reset(iq1); + q4w.reset(iq1); + LorentzVector > current1 = + q1w.dimensionedWave().vectorCurrent(q4w.dimensionedWave()); + if(iq1==0) { + q2w.reset(1); + q3w.reset(1); + } + else { + q2w.reset(0); + q3w.reset(0); + } + LorentzVector > current2 = + q2w.dimensionedWave().vectorCurrent(q3w.dimensionedWave()); + complex amp = current1.dot(current2); + vector Cborn(2),CEW(2); + unsigned int ioff = q1->id()%2==0 ? 0 : 1; + for(unsigned int ix=0;ix<2;++ix) { + Cborn[ix] = Complex(amp*borntChannelWeights(2*ix+ioff,0)); + CEW [ix] = Complex(amp*EWtChannelWeights(2*ix+ioff,0)); + } + // square + for(unsigned int ix=0;ix<2;++ix) { + for(unsigned int iy=0;iy<2;++iy) { + bornME(ix,iy) += Cborn[ix]*conj(Cborn[iy]); + EWME (ix,iy) += CEW [ix]*conj(CEW [iy]); + } + } + } + } + // colour factors + double born = 2.*real(bornME(0,0))+9.*real(bornME(1,1)); + double EW = 2.*real( EWME(0,0))+9.*real( EWME(1,1)); + return EW/born; +} + +double ElectroWeakReweighter::reweightqbarqbarqbarqbar() const { + // momenta and invariants + Lorentz5Momentum p1 = subProcess()->incoming().first ->momentum(); + tcPDPtr qbar1 = subProcess()->incoming().first ->dataPtr(); + Lorentz5Momentum p2 = subProcess()->incoming().second->momentum(); + tcPDPtr qbar2 = subProcess()->incoming().second->dataPtr(); + Lorentz5Momentum p3 = subProcess()->outgoing()[0] ->momentum(); + tcPDPtr qbar3 = subProcess()->outgoing()[0] ->dataPtr(); + Lorentz5Momentum p4 = subProcess()->outgoing()[1] ->momentum(); + tcPDPtr qbar4 = subProcess()->outgoing()[1] ->dataPtr(); + if(qbar1->id()!=qbar3->id()) { + swap(qbar3,qbar4); + swap(p3,p4); + } + assert(qbar1->id()==qbar3->id()); + assert(qbar2->id()==qbar4->id()); + Energy2 s = (p1+p2).m2(); + Energy2 t = (p1-p4).m2(); + Energy2 u = (p1-p3).m2(); + // boost to partonic rest frame + Lorentz5Momentum psum=p1+p2; + LorentzRotation boost(-psum.boostVector()); + p1 *= boost; + p2 *= boost; + p3 *= boost; + p4 *= boost; + p3.setMass(ZERO); + p3.rescaleRho(); + p4.setMass(ZERO); + p4.rescaleRho(); + // LO and EW corrected matrix element coefficients + boost::numeric::ublas::matrix > + bornLLLLWeights,bornLLRRWeights,bornRRLLWeights,bornRRRRWeights, + EWLLLLWeights,EWLLRRWeights,EWRRLLWeights,EWRRRRWeights; + bool ident = qbar1->id()==qbar2->id(); + // LL -> LL + if((abs(qbar1->id())<=4 && abs(qbar2->id())<=4) || + (abs(qbar1->id())==5 && abs(qbar2->id())==5)) { + if(!ident) { + bornLLLLWeights = evaluateRunning(EWProcess::QQQQ,s,t,u,true ,2); + EWLLLLWeights = evaluateRunning(EWProcess::QQQQ,s,t,u,false,2); + } + else { + bornLLLLWeights = evaluateRunning(EWProcess::QQQQiden,s,t,u,true ,2); + EWLLLLWeights = evaluateRunning(EWProcess::QQQQiden,s,t,u,false,2); + } + } + else if(abs(qbar1->id())==5 || abs(qbar2->id())==5) { + bornLLLLWeights = evaluateRunning(EWProcess::QtQtQQ,s,t,u,true ,2); + EWLLLLWeights = evaluateRunning(EWProcess::QtQtQQ,s,t,u,false,2); + } + else + assert(false); + // RR -> LL + if(abs(qbar1->id())%2==0) { + if(abs(qbar2->id())<5) { + bornRRLLWeights = evaluateRunning(EWProcess::QQUU,s,t,u,true ,2); + EWRRLLWeights = evaluateRunning(EWProcess::QQUU,s,t,u,false,2); + } + else { + bornRRLLWeights = evaluateRunning(EWProcess::QtQtUU,s,t,u,true ,2); + EWRRLLWeights = evaluateRunning(EWProcess::QtQtUU,s,t,u,false,2); + } + } + else { + if(abs(qbar2->id())<5) { + bornRRLLWeights = evaluateRunning(EWProcess::QQDD,s,t,u,true ,2); + EWRRLLWeights = evaluateRunning(EWProcess::QQDD,s,t,u,false,2); + } + else { + bornRRLLWeights = evaluateRunning(EWProcess::QtQtDD,s,t,u,true ,2); + EWRRLLWeights = evaluateRunning(EWProcess::QtQtDD,s,t,u,false,2); + } + } + // LL -> RR + if(abs(qbar1->id())<=4) { + if(abs(qbar2->id())%2!=0) { + bornLLRRWeights = evaluateRunning(EWProcess::QQDD,s,t,u,true ,2); + EWLLRRWeights = evaluateRunning(EWProcess::QQDD,s,t,u,false,2); + } + else { + bornLLRRWeights = evaluateRunning(EWProcess::QQUU,s,t,u,true ,2); + EWLLRRWeights = evaluateRunning(EWProcess::QQUU,s,t,u,false,2); + } + } + else { + if(abs(qbar2->id())%2!=0) { + bornLLRRWeights = evaluateRunning(EWProcess::QtQtDD,s,t,u,true ,2); + EWLLRRWeights = evaluateRunning(EWProcess::QtQtDD,s,t,u,false,2); + } + else { + bornLLRRWeights = evaluateRunning(EWProcess::QtQtUU,s,t,u,true ,2); + EWLLRRWeights = evaluateRunning(EWProcess::QtQtUU,s,t,u,false,2); + } + } + // RR -> RR + if(abs(qbar1->id())%2==0) { + if(abs(qbar2->id())%2==0) { + if(ident) { + bornRRRRWeights = evaluateRunning(EWProcess::UUUUiden,s,t,u,true ,2); + EWRRRRWeights = evaluateRunning(EWProcess::UUUUiden,s,t,u,false,2); + } + else { + bornRRRRWeights = evaluateRunning(EWProcess::UUUU,s,t,u,true ,2); + EWRRRRWeights = evaluateRunning(EWProcess::UUUU,s,t,u,false,2); + } + } + else { + bornRRRRWeights = evaluateRunning(EWProcess::UUDD,s,t,u,true ,2); + EWRRRRWeights = evaluateRunning(EWProcess::UUDD,s,t,u,false,2); + } + } + else { + if(abs(qbar2->id())%2==0) { + bornRRRRWeights = evaluateRunning(EWProcess::UUDD,s,t,u,true ,2); + EWRRRRWeights = evaluateRunning(EWProcess::UUDD,s,t,u,false,2); + } + else { + if(ident) { + bornRRRRWeights = evaluateRunning(EWProcess::DDDDiden,s,t,u,true ,2); + EWRRRRWeights = evaluateRunning(EWProcess::DDDDiden,s,t,u,false,2); + } + else { + bornRRRRWeights = evaluateRunning(EWProcess::DDDD,s,t,u,true ,2); + EWRRRRWeights = evaluateRunning(EWProcess::DDDD,s,t,u,false,2); + } + } + } + // extra terms for identical particles + boost::numeric::ublas::matrix > + borntChannelWeights,EWtChannelWeights; + if(ident) { + if(abs(qbar1->id())%2==0) { + borntChannelWeights = evaluateRunning(EWProcess::QQUU,s,u,t,true ,2); + EWtChannelWeights = evaluateRunning(EWProcess::QQUU,s,u,t,false,2); + } + else if(abs(qbar1->id())==5) { + borntChannelWeights = evaluateRunning(EWProcess::QtQtDD,s,u,t,true ,2); + EWtChannelWeights = evaluateRunning(EWProcess::QtQtDD,s,u,t,false,2); + } + else { + borntChannelWeights = evaluateRunning(EWProcess::QQDD,s,u,t,true ,2); + EWtChannelWeights = evaluateRunning(EWProcess::QQDD,s,u,t,false,2); + } + } + SpinorBarWaveFunction qbar1w(p1,qbar1,incoming); + SpinorBarWaveFunction qbar2w(p2,qbar2,incoming); + SpinorWaveFunction qbar3w(p3,qbar3,outgoing); + SpinorWaveFunction qbar4w(p4,qbar4,outgoing); + boost::numeric::ublas::matrix + bornME = boost::numeric::ublas::zero_matrix(2,2), + EWME = boost::numeric::ublas::zero_matrix(2,2); + for(unsigned int iq1=0;iq1<2;++iq1) { + qbar1w.reset(iq1); + qbar3w.reset(iq1); + LorentzVector > current1 = + qbar3w.dimensionedWave().vectorCurrent(qbar1w.dimensionedWave()); + for(unsigned int iq2=0;iq2<2;++iq2) { + qbar2w.reset(iq2); + qbar4w.reset(iq2); + LorentzVector > current2 = + qbar4w.dimensionedWave().vectorCurrent(qbar2w.dimensionedWave()); + complex amp = current1.dot(current2); + vector Cborn(2),CEW(2); + // amplitudes + if(iq1==1) { + // LL + if(iq2==1) { + unsigned int ioff; + if(abs(qbar1->id())%2==0) { + ioff = abs(qbar2->id())%2==0 ? 0 : 2; + } + else { + ioff = abs(qbar2->id())%2==0 ? 1 : 3; + } + for(unsigned int ix=0;ix<2;++ix) { + Cborn[ix] = Complex(amp*bornLLLLWeights(6*ix+ioff,0)); + CEW [ix] = Complex(amp* EWLLLLWeights(6*ix+ioff,0)); + } + } + // LR + else { + unsigned int ioff = abs(qbar1->id())%2==0 ? 0 : 1; + for(unsigned int ix=0;ix<2;++ix) { + Cborn[ix] = Complex(amp*bornLLRRWeights(2*ix+ioff,0)); + CEW [ix] = Complex(amp* EWLLRRWeights(2*ix+ioff,0)); + } + } + } + else { + if(iq2==1) { + unsigned int ioff=abs(qbar2->id())%2==0 ? 0 : 1; + for(unsigned int ix=0;ix<2;++ix) { + Cborn[ix] = Complex(amp*bornRRLLWeights(2*ix+ioff,0)); + CEW [ix] = Complex(amp* EWRRLLWeights(2*ix+ioff,0)); + } + } + else { + for(unsigned int ix=0;ix<2;++ix) { + Cborn[ix] = Complex(amp*bornRRRRWeights(ix,0)); + CEW [ix] = Complex(amp* EWRRRRWeights(ix,0)); + } + } + } + // square + for(unsigned int ix=0;ix<2;++ix) { + for(unsigned int iy=0;iy<2;++iy) { + bornME(ix,iy) += Cborn[ix]*conj(Cborn[iy]); + EWME (ix,iy) += CEW [ix]*conj(CEW [iy]); + } + } + } + } + // extra u-channel pieces if identical flavours + if(ident) { + for(unsigned int iq1=0;iq1<2;++iq1) { + qbar1w.reset(iq1); + qbar4w.reset(iq1); + LorentzVector > current1 = + qbar4w.dimensionedWave().vectorCurrent(qbar1w.dimensionedWave()); + if(iq1==0) { + qbar2w.reset(1); + qbar3w.reset(1); + } + else { + qbar2w.reset(0); + qbar3w.reset(0); + } + LorentzVector > current2 = + qbar3w.dimensionedWave().vectorCurrent(qbar2w.dimensionedWave()); + complex amp = current1.dot(current2); + vector Cborn(2),CEW(2); + unsigned int ioff = abs(qbar1->id())%2==0 ? 0 : 1; + for(unsigned int ix=0;ix<2;++ix) { + Cborn[ix] = Complex(amp*borntChannelWeights(2*ix+ioff,0)); + CEW [ix] = Complex(amp*EWtChannelWeights(2*ix+ioff,0)); + } + // square + for(unsigned int ix=0;ix<2;++ix) { + for(unsigned int iy=0;iy<2;++iy) { + bornME(ix,iy) += Cborn[ix]*conj(Cborn[iy]); + EWME (ix,iy) += CEW [ix]*conj(CEW [iy]); + } + } + } + } + // colour factors + double born = 2.*real(bornME(0,0))+9.*real(bornME(1,1)); + double EW = 2.*real( EWME(0,0))+9.*real( EWME(1,1)); + return EW/born; +} diff --git a/MatrixElement/EW/ElectroWeakReweighter.h b/MatrixElement/EW/ElectroWeakReweighter.h new file mode 100644 --- /dev/null +++ b/MatrixElement/EW/ElectroWeakReweighter.h @@ -0,0 +1,212 @@ +// -*- C++ -*- +#ifndef Herwig_ElectroWeakReweighter_H +#define Herwig_ElectroWeakReweighter_H +// +// This is the declaration of the ElectroWeakReweighter class. +// + +#include "ThePEG/MatrixElement/ReweightBase.h" +#include "EWCouplings.h" +#include "CollinearSudakov.h" +#include "SoftSudakov.h" + +namespace Herwig { + +using namespace ThePEG; + +/** + * The ElectroWeakReweighter class. + * + * @see \ref ElectroWeakReweighterInterfaces "The interfaces" + * defined for ElectroWeakReweighter. + */ +class ElectroWeakReweighter: public ReweightBase { + +public: + + /** @name Standard constructors and destructors. */ + //@{ + /** + * The default constructor. + */ + ElectroWeakReweighter(); + + /** + * The destructor. + */ + virtual ~ElectroWeakReweighter(); + //@} + +public: + + /** + * Return the weight for the kinematical configuation provided by + * the assigned XComb object (in the LastXCombInfo base class). + */ + virtual double weight() const; + + /** + * + */ + static tEWCouplingsPtr coupling() { + assert(staticEWCouplings_); + return staticEWCouplings_; + } + +public: + + /** @name Functions used by the persistent I/O system. */ + //@{ + /** + * Function used to write out object persistently. + * @param os the persistent output stream written to. + */ + void persistentOutput(PersistentOStream & os) const; + + /** + * Function used to read in object persistently. + * @param is the persistent input stream read from. + * @param version the version number of the object when written. + */ + void persistentInput(PersistentIStream & is, int version); + //@} + + /** + * The standard Init function used to initialize the interfaces. + * Called exactly once for each class by the class description system + * before the main function starts or + * when this class is dynamically loaded. + */ + static void Init(); + +protected: + + /** + * Functions to reweight specific processes + */ + //@{ + /** + * Reweight \f$g g\to q\bar{q}\f$ + */ + double reweightggqqbar() const; + + /** + * Reweight \f$q\bar{q}\to g g\f$ + */ + double reweightqqbargg() const; + + /** + * Reweight \f$q g\to qg\f$ + */ + double reweightqgqg() const; + + /** + * Reweight \f$q g\to qg\f$ + */ + double reweightqbargqbarg() const; + + /** + * Reweight \f$q\bar{q}\to q'\bar{q'}\f$ (s-channel) + */ + double reweightqqbarqqbarS() const; + + /** + * Reweight \f$q\bar{q}\to q'\bar{q'}\f$ (t-channel) + */ + double reweightqqbarqqbarT() const; + + /** + * Reweight \f$qq \to qq\f$ + */ + double reweightqqqq() const; + + /** + * Reweight \f$\bar{q}\bar{q} \to \bar{q}\bar{q}\f$ + */ + double reweightqbarqbarqbarqbar() const; + //@} + +protected: + + /** + * Check the evolution for a fixed s,t,u + */ + void testEvolution(Energy2 s,Energy2 t, Energy2 u) const; + + /** + * Evalaute the running + */ + boost::numeric::ublas::matrix > + evaluateRunning(EWProcess::Process process, Energy2 s, + Energy2 t, Energy2 u, bool born, + unsigned int iswap) const; + +protected: + + /** @name Standard Interfaced functions. */ + //@{ + /** + * Initialize this object after the setup phase before saving an + * EventGenerator to disk. + * @throws InitException if object could not be initialized properly. + */ + virtual void doinit(); + //@} + +protected: + + /** @name Clone Methods. */ + //@{ + /** + * Make a simple clone of this object. + * @return a pointer to the new object. + */ + virtual IBPtr clone() const; + + /** Make a clone of this object, possibly modifying the cloned object + * to make it sane. + * @return a pointer to the new object. + */ + virtual IBPtr fullclone() const; + //@} + +private: + + /** + * The assignment operator is private and must never be called. + * In fact, it should not even be implemented. + */ + ElectroWeakReweighter & operator=(const ElectroWeakReweighter &) = delete; + +private: + + /** + * The Electroweak Couplings + */ + EWCouplingsPtr EWCouplings_; + + /** + * The Collinear Sudakov + */ + CollinearSudakovPtr collinearSudakov_; + + /** + * The Soft Sudakov + */ + SoftSudakovPtr softSudakov_; + + /** + * The couplings to allow global access + */ + static tEWCouplingsPtr staticEWCouplings_; + + /** + * Whether or not to output testing information + */ + bool testing_; + +}; + +} + +#endif /* Herwig_ElectroWeakReweighter_H */ diff --git a/MatrixElement/EW/GroupInvariants.cc b/MatrixElement/EW/GroupInvariants.cc new file mode 100644 --- /dev/null +++ b/MatrixElement/EW/GroupInvariants.cc @@ -0,0 +1,268 @@ +// -*- C++ -*- +// +// GroupInvariants.cc is a part of Herwig - A multi-purpose Monte Carlo event generator +// +// Herwig is licenced under version 2 of the GPL, see COPYING for details. +// Please respect the MCnet academic guidelines, see GUIDELINES for details. +// +// +// +#include "GroupInvariants.h" +#include "ElectroWeakReweighter.h" + +using namespace Herwig; +using namespace GroupInvariants; + +double GroupInvariants::K_Factor(unsigned int i, + unsigned int N, bool high) { + using Constants::pi; + using Constants::zeta3; + // Find K_i for SU(N) (or, for U(1) if N==1) + // Relevent for finding the cusp anom. dim. + if (N!=1 && N!=2 && N!=3) { + std::cerr << "Error. In AnomDim, function K_Factor, N!={1,2,3}" + << std::endl; + assert(false); + } + + double CA = C_A(N); + double CF = C_F(N); + double nF = n_F(N,high); + double nS = n_S(N,high); + double TF = T_F(N,high); + double tS = t_S(N,high); + + if (i==1) { + return (67.0/9.0-1.0/3.0*pi*pi)*CA - 20.0/9.0*nF*TF - 8.0/9.0*tS*nS; + } + else if (i==2) { + return (245.0/6.0-134.0/27.0*pi*pi+22.0/3.0*zeta3+11.0/45.0*pi*pi*pi*pi)*CA*CA + + (-418.0/27.0+40.0/27.0*pi*pi-56.0/3.0*zeta3)*CA*TF*nF + + (-55.0/3.0+16.0*zeta3)*CF*TF*nF - 16.0/27.0*TF*TF*nF*nF; + } + else { + std::cerr << "Error. In AnomDim, function K_Factor, i!={1,2}" << std::endl; + assert(false); + } +} + +GaugeContributions GroupInvariants::cuspContributions(Energy mu, int K_ORDER, + bool high) { + using ThePEG::Constants::pi; + if (K_ORDER > 3) { + std::cerr << "Cusp anom dim. requested for K_ORDER>3.\n"; + assert(false); + } + // couplings (alphas) for U1, SU2, and SU3 + double a[3]; + if (high) { + a[0] = ElectroWeakReweighter::coupling()->a1(mu)/(4.0*pi); + a[1] = ElectroWeakReweighter::coupling()->a2(mu)/(4.0*pi); + a[2] = ElectroWeakReweighter::coupling()->a3(mu)/(4.0*pi); + } + else { + a[0] = ElectroWeakReweighter::coupling()->aEM(mu)/(4.0*pi); + a[1] = 0.0; + a[2] = ElectroWeakReweighter::coupling()->aS(mu)/(4.0*pi); + } + + // gammaN[0] is really 4.0*C_F, but there is a factor of C_F included in the + // G1-G3 matrices passed from HighRunning.h to the soft integrator. + double gamma1[3]; + gamma1[0] = 4.0; + gamma1[1] = K_Factor(1,1,high)*gamma1[0]; + gamma1[2] = K_Factor(2,1,high)*gamma1[0]; + double gamma2[3]; + gamma2[0] = 4.0; + gamma2[1] = K_Factor(1,2,high)*gamma2[0]; + gamma2[2] = K_Factor(2,2,high)*gamma2[0]; + double gamma3[3]; + gamma3[0] = 4.0; + gamma3[1] = K_Factor(1,3,high)*gamma3[0]; + gamma3[2] = K_Factor(2,3,high)*gamma3[0]; + + GaugeContributions result; + if (K_ORDER==0) { + return result; + } + // LO bit + if (K_ORDER>=1) { + result.U1 += a[0]*gamma1[0]; + result.SU2 += a[1]*gamma2[0]; + result.SU3 += a[2]*gamma3[0]; + } + // NLO bit + if (K_ORDER>=2) { + result.U1 += a[0]*a[0]*gamma1[1]; + result.SU2 += a[1]*a[1]*gamma2[1]; + result.SU3 += a[2]*a[2]*gamma3[1]; + } + // NNLO bit + if (K_ORDER>=3) { + result.U1 += a[0]*a[0]*a[0]*gamma1[2]; + result.SU2 += a[1]*a[1]*a[1]*gamma2[2]; + result.SU3 += a[2]*a[2]*a[2]*gamma3[2]; + } + return result; +} + +double GroupInvariants::B_Factor(int i, int N, bool fermion, + bool longitudinal) { + using Constants::pi; + using Constants::zeta3; + // Find B_i for SU(N) (or, for U(1) if N==1) + // Relevent for finding the collinear non-cusp anom. dim. + if (N!=1 && N!=2 && N!=3) { + std::cerr << "Error. In AnomDim, function B_Factor, N!={1,2,3}\n"; + assert(false); + } + + double CA = C_A(N); + double CF = C_F(N); + double nF = n_F(N,true); + double nS = n_S(N,true); + double TF = T_F(N,true); + double tS = t_S(N,true); + + if (longitudinal) { + if (i==1) return -8.0*CF; + // Two loop non-cusp not known for scalars + else if (i==2) return 0.0; + else assert(false); + } + else if (fermion) { + if (i==1) return -6.0*CF; + else if (i==2) { + return (4.0*pi*pi - 48.0*zeta3 - 3.0)*CF*CF + + (52.0*zeta3 - 11.0*pi*pi/3.0 - 961.0/27.0)*CA*CF + + (4.0*pi*pi/3.0 + 260.0/27.0)*CF*TF*nF + + (pi*pi/6.0 + 167.0/54.0)*CF*nS*tS*2.0; + } + else + assert(false); + } + else { + if (i==1) { + return -2.0*( 11.0*CA/3.0 - 4.0*TF*nF/3.0 - nS*tS/3.0 ); + } + else if (i==2) { + return CA*CA*(11.0*pi*pi/9.0+4.0*zeta3-1384.0/27.0) + + 2.0*CA*nF*TF*(256.0/27.0-2.0*pi*pi/9.0) + 8.0*CF*nF*TF; + } + else assert(false); + } +} + +double GroupInvariants::B_Factor_Low(int i, int N, bool fermion, + double boostFactor) { + using Constants::pi; + using Constants::zeta3; + // Find B_i for SU(N) (or, for U(1) if N==1) + // Relevent for finding the collinear non-cusp anom. dim. + if (N!=1 && N!=2 && N!=3) { + std::cerr << "Error. In AnomDim, function B_Factor, N!={1,2,3}\n"; + assert(false); + } + + double CA = C_A(N); + double CF = C_F(N); + double nF = n_F(N,false); + double nS = n_S(N,false); + double TF = T_F(N,false); + double tS = t_S(N,false); + + if (abs(boostFactor)>0.001) { + if (i==1) return -4.0*CF; + // Two loop non-cusp not known for bHQET top, W_L, and W_T fields. + else if (i==2) return 0.0; + else assert(false); + } + else if (fermion) { + if (i==1) return -6.0*CF; + else if (i==2) { + return (4.0*pi*pi - 48.0*zeta3 - 3.0)*CF*CF + + (52.0*zeta3 - 11.0*pi*pi/3.0 - 961.0/27.0)*CA*CF + + (4.0*pi*pi/3.0 + 260.0/27.0)*CF*TF*nF + + (pi*pi/6.0 + 167.0/54.0)*CF*nS*tS*2.0; + } + else + assert(false); + } + // Gluon and Photon are the only things left... use Gauge Boson NonCusps: + else { + if (i==1) return -2.0*( 11.0*CA/3.0 - 4.0*TF*nF/3.0 - nS*tS/3.0 ); + else if (i==2) { + return CA*CA*(11.0*pi*pi/9.0+4.0*zeta3-1384.0/27.0) + + 2.0*CA*nF*TF*(256.0/27.0-2.0*pi*pi/9.0) + 8.0*CF*nF*TF; + } + else + assert(false); + } +} + +GaugeContributions GroupInvariants::BContributions(Energy mu, + int B_ORDER, + bool fermion, + bool longitudinal) { + using Constants::pi; + // NOTE! THIS RETURNS 2*Gamma+sigma, AND SHOULD BE MULTIPLIED BY 1/2 IN + // THE COLLINEAR ANOMALOUS DIMENSION INTEGRAND + if (B_ORDER>2) { + std::cerr << "Non-cusp collinear anom dim. requested for B_ORDER>2.\n"; + assert(false); + } + + double a[3]; // alpha/(4pi) for U1, SU2, and SU3 + + a[0] = ElectroWeakReweighter::coupling()->a1(mu)/(4.0*pi); + a[1] = ElectroWeakReweighter::coupling()->a2(mu)/(4.0*pi); + a[2] = ElectroWeakReweighter::coupling()->a3(mu)/(4.0*pi); + + GaugeContributions result; + if (B_ORDER==0) { + return result; + } + if (B_ORDER>=1) { + result.SU3 += a[2]*B_Factor(1,3,fermion,longitudinal); + result.SU2 += a[1]*B_Factor(1,2,fermion,longitudinal); + result.U1 += a[0]*B_Factor(1,1,fermion,longitudinal); + } + if (B_ORDER>=2) { + result.SU3 += a[2]*a[2]*B_Factor(2,3,fermion,longitudinal); + result.SU2 += a[1]*a[1]*B_Factor(2,2,fermion,longitudinal); + result.U1 += a[0]*a[0]*B_Factor(2,1,fermion,longitudinal); + } + return result; +} + +GaugeContributions GroupInvariants::BContributionsLow(Energy mu, + int B_ORDER, + bool fermion, + double boostFactor) { + using Constants::pi; + // NOTE! THIS RETURNS 2*Gamma+sigma, AND SHOULD BE MULTIPLIED BY 1/2 IN + // THE COLLINEAR ANOMALOUS DIMENSION INTEGRAND + if (B_ORDER>2) { + std::cerr << "Non-cusp collinear anom dim. requested for B_ORDER>2.\n"; + } + // alpha/(4pi) for U1, SU2, and SU3 + double a[3]; + a[0] = ElectroWeakReweighter::coupling()->aEM(mu)/(4.0*pi); + a[1] = 0.0; + a[2] = ElectroWeakReweighter::coupling()->aS(mu)/(4.0*pi); + GaugeContributions result; + if (B_ORDER==0) { + return result; + } + if (B_ORDER>=1) { + result.SU3 += a[2]*B_Factor_Low(1,3,fermion,boostFactor); + result.SU2 += a[1]*B_Factor_Low(1,2,fermion,boostFactor); + result.U1 += a[0]*B_Factor_Low(1,1,fermion,boostFactor); + } + if (B_ORDER>=2) { + result.SU3 += a[2]*a[2]*B_Factor_Low(2,3,fermion,boostFactor); + result.SU2 += a[1]*a[1]*B_Factor_Low(2,2,fermion,boostFactor); + result.U1 += a[0]*a[0]*B_Factor_Low(2,1,fermion,boostFactor); + } + return result; +} diff --git a/MatrixElement/EW/GroupInvariants.h b/MatrixElement/EW/GroupInvariants.h new file mode 100644 --- /dev/null +++ b/MatrixElement/EW/GroupInvariants.h @@ -0,0 +1,500 @@ +// -*- C++ -*- +// +// GroupInvariants.h is a part of Herwig - A multi-purpose Monte Carlo event generator +// +// Herwig is licenced under version 2 of the GPL, see COPYING for details. +// Please respect the MCnet academic guidelines, see GUIDELINES for details. +// +// +// +#ifndef HERWIG_GroupInvariants_H +#define HERWIG_GroupInvariants_H +#include "ThePEG/Config/ThePEG.h" +#include "ThePEG/Config/Unitsystem.h" +#include +// work around a Boost 1.64 bug where ublas headers would fail otherwise +#include +#if (BOOST_VERSION / 100 >= 1064) +#include +#endif +#include + +namespace Herwig { +using namespace ThePEG; + +namespace GroupInvariants { + + /** + * Simple struct for storing the different gauge contributions + */ + struct GaugeContributions { + + /** + * Default Constructor + */ + GaugeContributions(double inSU3=0., + double inSU2=0., double inU1=0.) + : SU3(inSU3),SU2(inSU2),U1(inU1) + {} + /** + * \f$SU(3)\f$ + */ + double SU3; + + /** + * \f$SU(2)\f$ + */ + double SU2; + + /** + * \f$U(1)\f$ + */ + double U1; + }; + + + /** + * The \f$SU(N)\f$ \f$C_A\f$ + */ + inline double C_A(unsigned int N) { + return N !=1 ? double(N) : 0.; + } + + /** + * The \f$SU(N)\f$ \f$C_F\f$ + */ + inline double C_F(unsigned int N) { + return N !=1 ? 0.5*(double(N*N)-1.)/double(N) : 1.; + } + + /* + * The \f$SU(N)\f$ \f$C_d\f$ + */ + inline double C_d(unsigned int N) { + return (double(N*N)-4.)/double(N); + } + + /** + * The \f$SU(N)\f$\f$C_1\f$ + */ + inline double C_1(unsigned int N) { + double N2(N*N); + return 0.25*(N2-1.0)/N2; + } + + /** + * \f$T_F\f$ + */ + inline double T_F(unsigned int N, bool high) { + if(high) { + return N !=1 ? 0.5 : 5.0/3.0; + } + else { + return N !=1 ? 0.5 : 20.0/3.0; + } + } + + /** + * \f$t_S\f$ + */ + inline double t_S(unsigned int, bool ) { + return 0.5; + } + + /** + * / Number of complex scalars in the fundamental rep. of SU(N)/U(1) + */ + inline double n_S(unsigned int N, bool high) { + if(high) { + if(N==2 || N==1) return 1.0; + else if(N==3) return 0.0; + else assert(false); + } + else { + if(N>=1&&N<=3) return 0.; + else assert(false); + } + } + + /** + * Number of Dirac Fermions in the fund. rep. of SU(N) (or U(1) for N==1) + */ + inline double n_F(unsigned int N, bool high) { + if(high) { + if(N==1) return 3.0; + else if(N==2 || N==3) return 6.0; + else assert(false); + } + else { + if(N==1) return 1.0; + else if(N==2) return 0.0; + else if(N==3) return 5.0; + else assert(false); + } + } + + /** + * Find K_i for gauge group N. high=false for running at mu0.0) + return log(arg); + else if (arg<0.0) + return log(-arg)+I*Constants::pi; + else + assert(false); + } + + inline Complex MinusLog(double arg) { + static const Complex I(0,1.0); + if (arg>0.0) + return log(arg); + else if (arg<0.0) + return log(-arg)-I*Constants::pi; + else + assert(false); + } + + inline Complex getT(Energy2 s, Energy2 t) { + return MinusLog(-t/GeV2) - MinusLog(-s/GeV2); + } + + inline Complex getU(Energy2 s, Energy2 u) { + return MinusLog(-u/GeV2) - MinusLog(-s/GeV2); + } + + inline boost::numeric::ublas::matrix Gamma2(Complex U, Complex T) { + boost::numeric::ublas::matrix output(2,2); + static const Complex I(0,1.0); + using Constants::pi; + output(0,0) = (-3.0/2.0)*I*pi + (T+U); + output(1,1) = (-3.0/2.0)*I*pi; + output(0,1) = 2.0*(T-U); + output(1,0) = (3.0/8.0)*(T-U); + return output; + } + + inline boost::numeric::ublas::matrix Gamma2ST(Complex U, Complex T) { + boost::numeric::ublas::matrix output(2,2); + static const Complex I(0,1.0); + using Constants::pi; + output(0,0) = 3./2.*(T-I*pi) + U -2.*T; + output(1,1) = 3./2.*(T-I*pi); + output(0,1) = -2.0*U; + output(1,0) = -(3.0/8.0)*U; + return output; + } + + inline boost::numeric::ublas::matrix Gamma2SU(Complex U, Complex T) { + boost::numeric::ublas::matrix output(2,2); + static const Complex I(0,1.0); + using Constants::pi; + output(0,0) = 3./2.*(U-I*pi) + T - 2.*U; + output(1,1) = 3./2.*(U-I*pi); + output(0,1) = 2.0*T; + output(1,0) = (3.0/8.0)*T; + return output; + } + + inline boost::numeric::ublas::matrix Gamma2w(Complex U, Complex T) { + boost::numeric::ublas::matrix output = boost::numeric::ublas::zero_matrix(5,5); + static const Complex I(0,1.0); + using Constants::pi; + output(0,0) += -I*pi*11.0/4.0; + output(0,1) += U-T; + output(1,0) += 2.0*(U-T); + output(1,1) += -I*pi*11.0/4.0 + (T+U); + output(2,2) += -7.0/4.0*I*pi + (U+T); + output(3,3) += -7.0/4.0*I*pi + (U+T); + output(4,4) += -3.0/4.0*I*pi; + return output; + } + + inline boost::numeric::ublas::matrix Gamma2Singlet() { + using namespace boost::numeric::ublas; + matrix output = zero_matrix(2,2); + static const Complex I(0,1.0); + using Constants::pi; + output(0,0) = output(1,1) = -0.75*I*pi; + return output; + } + + inline boost::numeric::ublas::matrix Gamma2SingletST(Complex T) { + using namespace boost::numeric::ublas; + matrix output = zero_matrix(2,2); + static const Complex I(0,1.0); + using Constants::pi; + output(0,0) = output(1,1) = 0.75*(T-I*pi); + return output; + } + + inline boost::numeric::ublas::matrix Gamma2SingletSU(Complex U) { + using namespace boost::numeric::ublas; + matrix output = zero_matrix(2,2); + static const Complex I(0,1.0); + using Constants::pi; + output(0,0) = output(1,1) = 0.75*(U-I*pi); + return output; + } + + inline Complex Gamma1(double hypercharge) { + Complex I(0,1.0); + return -I*Constants::pi*sqr(hypercharge); + } + + inline Complex Gamma1ST(double hypercharge,Complex T) { + Complex I(0,1.0); + return (T-I*Constants::pi)*sqr(hypercharge); + } + + inline Complex Gamma1SU(double hypercharge,Complex U) { + Complex I(0,1.0); + return (U-I*Constants::pi)*sqr(hypercharge); + } + + inline Complex Gamma1(double y1, double y2, Complex T, Complex U) { + Complex I(0,1.0); + return -I*Constants::pi*(y1*y1+y2*y2) + 2.0*y1*y2*(T-U); + } + + inline Complex Gamma1ST(double y1, double y2, Complex T, Complex U) { + Complex I(0,1.0); + return (T-I*Constants::pi)*(y1*y1+y2*y2) - 2.0*y1*y2*U; + } + + inline Complex Gamma1SU(double y1, double y2, Complex T, Complex U) { + Complex I(0,1.0); + return (U-I*Constants::pi)*(y1*y1+y2*y2) + 2.0*y1*y2*T; + } + + inline Complex Gamma1(double y1, double y2, double y3, double y4, + Complex T, Complex U) { + Complex I(0,1.0); + return -I*Constants::pi*(y1*y1+y2*y2+y3*y3+y4*y4)/2.0 + + (y1*y4+y2*y3)*T - (y1*y3+y2*y4)*U; + } + + inline Complex Gamma1ST(double y1, double y2, double y3, double y4, + Complex T, Complex U) { + Complex I(0,1.0); + return (T-I*Constants::pi)*(y1*y1+y2*y2+y3*y3+y4*y4)/2.0 - + (y1*y4+y2*y3)*T - (y1*y3+y2*y4)*(U-T); + } + + inline Complex Gamma1SU(double y1, double y2, double y3, double y4, + Complex T, Complex U) { + Complex I(0,1.0); + return (U-I*Constants::pi)*(y1*y1+y2*y2+y3*y3+y4*y4)/2.0 + + (y1*y4+y2*y3)*(T-U) + (y1*y3+y2*y4)*U; + } + + inline boost::numeric::ublas::matrix Gamma3(Complex U, Complex T) { + boost::numeric::ublas::matrix output = boost::numeric::ublas::zero_matrix(2,2); + static const Complex I(0,1.0); + using Constants::pi; + output(0,0) = -(8.0/3.0)*I*pi; + output(1,1) = -(8.0/3.0)*I*pi; + output(0,0) += (7.0/3.0)*T + (2.0/3.0)*U; + output(0,1) = 2.0*(T-U); + output(1,0) = (4.0/9.0)*(T-U); + return output; + } + + inline boost::numeric::ublas::matrix Gamma3ST(Complex U, Complex T) { + boost::numeric::ublas::matrix output = boost::numeric::ublas::zero_matrix(2,2); + static const Complex I(0,1.0); + using Constants::pi; + output(0,0) = 8./3.*(T-I*pi); + output(1,1) = 8./3.*(T-I*pi); + output(0,0) += -3.*T + 2./3.*U; + output(0,1) = -2.*U; + output(1,0) = -4./9.*U; + return output; + } + + inline boost::numeric::ublas::matrix Gamma3SU(Complex U, Complex T) { + boost::numeric::ublas::matrix output = boost::numeric::ublas::zero_matrix(2,2); + static const Complex I(0,1.0); + using Constants::pi; + output(0,0) = 8./3.*(U-I*pi); + output(1,1) = 8./3.*(U-I*pi); + output(0,0) += 7./3.*T -3.*U; + output(0,1) = 2.*T; + output(1,0) = 4./9.*T; + return output; + } + + inline boost::numeric::ublas::matrix Gamma3g(Complex U, Complex T) { + boost::numeric::ublas::matrix output = boost::numeric::ublas::zero_matrix(3,3); + static const Complex I(0,1.0); + using Constants::pi; + output(0,2) = U-T; + output(1,1) = 3.0/2.0*(T+U); + output(1,2) = 3.0/2.0*(U-T); + output(2,0) = 2.0*(U-T); + output(2,1) = 5.0/6.0*(U-T); + output(2,2) = 3.0/2.0*(T+U); + for (unsigned int i=0; i<3; i++) { + output(i,i) += -13.0/3.0*I*pi; + } + return output; + } + + inline boost::numeric::ublas::matrix Gamma3gST(Complex U, Complex T) { + boost::numeric::ublas::matrix output = boost::numeric::ublas::zero_matrix(3,3); + static const Complex I(0,1.0); + using Constants::pi; + output(0,2) = U; + output(1,1) = 3.0/2.0*(U-2.*T); + output(1,2) = 3.0/2.0*U; + output(2,0) = 2.0*U; + output(2,1) = 5.0/6.0*U; + output(2,2) = 3.0/2.0*(U-2.*T); + for (unsigned int i=0; i<3; i++) { + output(i,i) += 13.0/3.0*(T-I*pi); + } + return output; + } + + inline boost::numeric::ublas::matrix Gamma3gSU(Complex U, Complex T) { + boost::numeric::ublas::matrix output = boost::numeric::ublas::zero_matrix(3,3); + static const Complex I(0,1.0); + using Constants::pi; + output(0,2) = -T; + output(1,1) = 3./2.*(T-2.*U); + output(1,2) = -3./2.*T; + output(2,0) = -2.0*T; + output(2,1) =-5./6.*T; + output(2,2) = 3./2.*(T-2.*U); + for (unsigned int i=0; i<3; i++) { + output(i,i) += 13./3.*(U-I*pi); + } + return output; + } + + inline boost::numeric::ublas::matrix Gamma3Singlet() { + boost::numeric::ublas::matrix output = boost::numeric::ublas::zero_matrix(2,2); + static const Complex I(0,1.0); + using Constants::pi; + output(0,0) = output(1,1) = -4.0/3.0*I*pi; + return output; + } + + /** + * Number of fermion generations (only used in gauge boson HighCMatching) + */ + inline double n_g() { return 3.0; } + + /** + * Number of complex scalars in the fundamental rep. of SU(N) + */ + inline double nSWeyl(unsigned int N, bool high) { + if(high) { + if(N==2 || N==1) return 1.0; + else if (N==3) return 0.0; + else assert(false); + } + else { + if( N==1 || N==3 ) return 0.0; + else assert(false); + } + } + + /** + * Number of Weyl Fermions in the fundamental rep. of SU(N) + */ + inline double nFWeyl(unsigned int N, bool high) { + if(high) { + if(N==2 || N==3) return 12.0; + else assert(false); + } + else { + if(N==3) return 10.0; + else if(N==1) return 2.0; + else assert(false); + } + } + + inline double TFWeyl(unsigned int) { + return 0.5; + } + + inline double tSWeyl(unsigned int) { + return 0.5; + } + + inline Complex WFunction(Energy mu, Energy2 s) { + using Constants::pi; + assert(abs(s)>ZERO); + Complex ln = MinusLog(-s/(mu*mu)); + return (-1.0*ln*ln + 3.0*ln+pi*pi/6.0-8.0); + } + + /** + * \fX_N\f% function, v is either t or u + */ + inline Complex XNFunction(unsigned int N, Energy mu, Energy2 s, Energy2 v) { + using Constants::pi; + assert(abs(s)>ZERO); + Complex ls = MinusLog(-s/(mu*mu)); + return (2.0*C_F(N)*WFunction(mu,s) + + C_A(N)*(2.0*ls*ls - 2.0*MinusLog((s+v)/(mu*mu))*ls - + 11.0/3.0*ls + pi*pi + 85.0/9.0) + + (2.0/3.0*ls - 10.0/9.0) * TFWeyl(N) * nFWeyl(N,true) + + (1.0/3.0*ls - 8.0/9.0) * TFWeyl(N) * nSWeyl(N,true)); + } + + /** + * \f$\Pi_1\f$ function + */ + inline Complex PI1_function(Energy mu, Energy2 s) { + assert(abs(s)>ZERO); + return ((41.0/6.0)*MinusLog(-s/(mu*mu))-104.0/9.0); + } + + /** + * \f$\tilde{f}\f$ function, v is either t or u + */ + inline Complex fTildeFunction(Energy mu, Energy2 s, Energy2 v) { + using Constants::pi; + assert(abs(s)>ZERO); + Complex ls = MinusLog(-s/GeV2), lv = MinusLog(-v/GeV2); + Complex lsv = MinusLog((s+v)/GeV2); + return (-2.0*double(s/(s+v))*(lv-ls) + + double(s*(s+2.0*v)/((s+v)*(s+v))) * ((lv-ls)*(lv-ls) + pi*pi) + + 4.0*MinusLog(-s/(mu*mu))*(lv-lsv)); + } +} +} + +#endif // HERWIG_GroupInvariants_H diff --git a/MatrixElement/EW/HighEnergyMatching.cc b/MatrixElement/EW/HighEnergyMatching.cc new file mode 100644 --- /dev/null +++ b/MatrixElement/EW/HighEnergyMatching.cc @@ -0,0 +1,1181 @@ +// -*- C++ -*- +// +// HighEnergyMatching.cc is a part of Herwig - A multi-purpose Monte Carlo event generator +// +// Herwig is licenced under version 2 of the GPL, see COPYING for details. +// Please respect the MCnet academic guidelines, see GUIDELINES for details. +// +// +// +#include "HighEnergyMatching.h" +#include "ElectroWeakReweighter.h" +#include "GroupInvariants.h" +#include +#include + +using namespace Herwig; +using namespace HighEnergyMatching; +using namespace GroupInvariants; +using namespace EWProcess; + +namespace { + +/** + * \f$M_N\f$, this matrix is used for identical particle scattering + */ +boost::numeric::ublas::matrix M_N(unsigned int suN) { + double N(suN); + boost::numeric::ublas::matrix M(2,2); + M(0,0) = -1.0/N; + M(0,1) = 2.0; + M(1,0) = 0.5 - 1.0/(2.0*N*N); + M(1,1) = 1.0/N; + return M; +} + +// #ifdef ThePEG_HAS_UNITS_CHECKING +void axpy_prod_local(const boost::numeric::ublas::matrix & A, + const boost::numeric::ublas::matrix > & B, + boost::numeric::ublas::matrix > & C) { + assert(A.size2()==B.size1()); + C.resize(A.size1(),B.size2()); + for(unsigned int ix=0;ix > & A, + const boost::numeric::ublas::matrix & B, + boost::numeric::ublas::matrix > & C) { + assert(A.size2()==B.size1()); + C.resize(A.size1(),B.size2()); + for(unsigned int ix=0;ix & A, +// const boost::numeric::ublas::matrix & B, +// boost::numeric::ublas::matrix & C) { +// assert(A.size2()==B.size1()); +// C.resize(A.size1(),B.size2()); +// axpy_prod(A,B,C); +// } +// #endif + +} + +boost::numeric::ublas::matrix > +HighEnergyMatching::highEnergyMatching(Energy highScale, + Energy2 s, Energy2 t, Energy2 u, + EWProcess::Process process, + bool oneLoop, bool includeAlphaS2) { + switch (process) { + case QQQQ: case QQQQiden: + case QtQtQQ: case QQUU: + case QtQtUU: case QQtRtR: + case QQDD: case QtQtDD: + case QQLL: case QQEE: + case UUUU: case UUUUiden: + case tRtRUU: case UUDD: + case tRtRDD: case UULL: + case UUEE: case DDDD: + case DDDDiden: case DDLL: + case DDEE: case LLLL: + case LLLLiden: case LLEE: + case EEEE: case EEEEiden: + return SpinHalfMatching(highScale,s,t,u,process,oneLoop,includeAlphaS2); + break; + case QQWW: + case QQWG: + case QQBG: + case QQGG: + case QtQtGG: + case LLWW: + case UUBB: + case UUBG: + case UUGG: + case tRtRGG: + case DDBB: + case DDBG: + case DDGG: + case EEBB: + return Spin1HighMatching(highScale,s,t,u,process,oneLoop,includeAlphaS2); + break; + case QQPhiPhi: + case LLPhiPhi: + case UUPhiPhi: + case DDPhiPhi: + case EEPhiPhi: + return Spin0HighMatching(highScale,s,t,u,process,oneLoop,includeAlphaS2); + break; + default: + assert(false); + break; + } +} + +boost::numeric::ublas::matrix > +HighEnergyMatching::SpinHalfMatching(Energy highScale, + Energy2 s, Energy2 t, Energy2 u, + EWProcess::Process process, + bool oneLoop, bool includeAlphaS2) { + using Constants::pi; + boost::numeric::ublas::matrix > highC; + Energy Q = highScale; + double a1 = ElectroWeakReweighter::coupling()->a1(Q); + double a2 = ElectroWeakReweighter::coupling()->a2(Q); + double a3 = ElectroWeakReweighter::coupling()->a3(Q); + double y_t = ElectroWeakReweighter::coupling()->y_t(Q); + unsigned int order = !oneLoop ? 0 : 1; + double Yi(0.),Yf(0.); + + Complex Ls = MinusLog(-s/(Q*Q)); + + double C_A_2 = C_A(2); + double C_A_3 = C_A(3); + double C_F_2 = C_F(2); + double C_F_3 = C_F(3); + double C_d_2 = C_d(2); + double C_d_3 = C_d(3); + double C_1_2 = C_1(2); + double C_1_3 = C_1(3); + Complex W = WFunction(Q,s); + Complex X_2_st = XNFunction(2,Q,s,t); + //Complex X_2_su = XNFunction(2,Q,s,u); + Complex X_3_st = XNFunction(3,Q,s,t); + Complex X_3_su = XNFunction(3,Q,s,u); + Complex PI1 = PI1_function(Q,s); + Complex fTilde_st = fTildeFunction(Q,s,t); + Complex fTilde_su = fTildeFunction(Q,s,u); + + switch (process) { + + case QQQQ: + // NOTE this 4x1 column vector highC is given by (C_11,C_21,C_12,C_22), + // where C_12 is the coeff. for the term that transforms under SU(2) but not SU(3) + Yi = Yf = 1./6.; + highC.resize(4,1); + highC(0,0) = ZERO; + highC(2,0) = 4.0*pi*a2 / s; + highC(1,0) = 4.0*pi*a3 / s; + highC(3,0) = 4.0*pi*a1*Yi*Yf / s; + if (order >= 1) { + highC(0,0) += (1.0/s)*(-2.0*a2*a3*fTilde_st); + highC(2,0) += (1.0/s)*(a2*a2*(X_2_st-(C_d_2+C_A_2)/4.0*fTilde_st) + + 2.0*(a1*a2*Yi*Yf+a2*a3*C_F_3)*W - + 2.0*a1*a2*Yi*Yf*fTilde_st); + highC(1,0) += (1.0/s)*(2.0*(a1*a3*Yi*Yf+a2*a3*C_F_2)*W - + 2.0*a1*a3*Yi*Yf*fTilde_st); + highC(3,0) += (1.0/s)*(-1.0*(a2*a2*C_1_2+a1*a1*Yi*Yi*Yf*Yf)*fTilde_st + + a1*a1*Yi*Yf*PI1 + + 2.0*(a1*a3*Yi*Yf*C_F_3+a1*a2*Yi*Yf*C_F_2+a1*a1*Yi*Yi*Yf*Yf)*W); + if (includeAlphaS2) { + highC(1,0) += (1.0/s)*(a3*a3*(X_3_st-(C_d_3+C_A_3)/4.0*fTilde_st)); + + highC(3,0) += (1.0/s)*(-1.0*(a3*a3*C_1_3)*fTilde_st); + } + } + break; + + case QQQQiden: + { + Process parentCase = QQQQ; + boost::numeric::ublas::matrix > + highCs_st = highEnergyMatching(Q,s,t,u,parentCase,oneLoop,includeAlphaS2); + boost::numeric::ublas::matrix > + highCs_ts = highEnergyMatching(Q,t,s,u,parentCase,oneLoop,includeAlphaS2); + boost::numeric::ublas::matrix > highCt_st(4,1); + boost::numeric::ublas::matrix > highCs_ts_2x2(2,2); + highCs_ts_2x2(0,0) = highCs_ts(0,0); + highCs_ts_2x2(1,0) = highCs_ts(1,0); + highCs_ts_2x2(0,1) = highCs_ts(2,0); + highCs_ts_2x2(1,1) = highCs_ts(3,0); + boost::numeric::ublas::matrix temp(2,2); + temp = boost::numeric::ublas::trans(M_N(3)); + boost::numeric::ublas::matrix > highCt_st_2x2(2,2),temp2(2,2); + axpy_prod_local(highCs_ts_2x2,temp,temp2); + axpy_prod_local(M_N(2),temp2,highCt_st_2x2); + highCt_st(0,0) = highCt_st_2x2(0,0); + highCt_st(1,0) = highCt_st_2x2(1,0); + highCt_st(2,0) = highCt_st_2x2(0,1); + highCt_st(3,0) = highCt_st_2x2(1,1); + highC = highCs_st + highCt_st; + } + break; + case QtQtQQ: + { + highC.resize(4,1); + Process parentCase = QQQQ; + highC = highEnergyMatching(Q,s,t,u,parentCase,oneLoop,includeAlphaS2); + double Y = 1.0/6.0; // Hypercharge of the non-3rd-gen doublet (still a quark doublet). + if (order >= 1) { + highC(2,0) += y_t*y_t*a2/(4.0*pi*s)*(3.0/2.0-0.5*Ls); + highC(1,0) += y_t*y_t*a3/(4.0*pi*s)*(1.0/2.0-0.5*Ls); + highC(3,0) += y_t*y_t*a1*Y/(4.0*pi*s)*(-5.0/12.0-1.0/12.0*Ls); + } + } + break; + case QQUU: + Yi = 1./6.; Yf = 2./3.; + highC.resize(2,1); + highC(0,0) = 4.0*pi*a3 / s; + highC(1,0) = 4.0*pi*a1*Yi*Yf / s; + if (order >= 1) { + highC(0,0) += (1.0/s)*((a1*a3*(Yi*Yi+Yf*Yf)+a2*a3*C_F_2)*W + + 2.0*a1*a3*Yi*Yf*fTilde_su); + highC(1,0) += (1.0/s)*(a1*a1*Yi*Yf*PI1 + + (a1*a2*Yi*Yf*C_F_2+2.0*a1*a3*Yi*Yf*C_F_3+ + a1*a1*(Yi*Yi*Yi*Yf+Yf*Yf*Yf*Yi))*W); + if (includeAlphaS2) { + highC(0,0) += (1.0/s)*(a3*a3*(X_3_su+(C_d_3-C_A_3)/4.0*fTilde_su)); + highC(1,0) += (1.0/s)*((a3*a3*C_1_3+a1*a1*Yi*Yi*Yf*Yf)*fTilde_su); + } + } + break; + case QtQtUU: + { + highC.resize(2,1); + Process parentCase = QQUU; + highC = highEnergyMatching(Q,s,t,u,parentCase,oneLoop,includeAlphaS2); + double Y = 2./3.; + if (order >= 1) { + highC(0,0) += y_t*y_t*a3/(4.0*pi*s)*(1.0/2.0-0.5*Ls); + highC(1,0) += y_t*y_t*a1*Y/(4.0*pi*s)*(-5.0/12.0-1.0/12.0*Ls); + } + } + break; + case QQtRtR: + { + highC.resize(2,1); + Process parentCase = QQUU; + highC = highEnergyMatching(Q,s,t,u,parentCase,oneLoop,includeAlphaS2); + double Y = 1.0/6.0; + if (order >= 1) { + highC(0,0) += y_t*y_t*a3/(4.0*pi*s)*(1.0-Ls); + highC(1,0) += y_t*y_t*a1*Y/(4.0*pi*s)*(5.0/3.0-2.0/3.0*Ls); + } + } + break; + case QQDD: + Yi = 1./6.; Yf = -1./3.; + highC.resize(2,1); + highC(0,0) = 4.0*pi*a3 / s; + highC(1,0) = 4.0*pi*a1*Yi*Yf / s; + if (order >= 1) { + highC(0,0) += (1.0/s)*((a1*a3*(Yi*Yi+Yf*Yf)+a2*a3*C_F_2)*W + + 2.0*a1*a3*Yi*Yf*fTilde_su); + highC(1,0) += (1.0/s)*(a1*a1*Yi*Yf*PI1 + + (a1*a2*Yi*Yf*C_F_2+2.0*a1*a3*Yi*Yf*C_F_3+ + a1*a1*(Yi*Yi*Yi*Yf+Yf*Yf*Yf*Yi))*W); + if (includeAlphaS2) { + highC(0,0) += (1.0/s)*(a3*a3*(X_3_su+(C_d_3-C_A_3)/4.0*fTilde_su)); + highC(1,0) += (1.0/s)*((a3*a3*C_1_3+a1*a1*Yi*Yi*Yf*Yf)*fTilde_su); + } + } + break; + case QtQtDD: + { + highC.resize(2,1); + Process parentCase = QQDD; + highC = highEnergyMatching(Q,s,t,u,parentCase,oneLoop,includeAlphaS2); + double Y = -1./3.; + if (order >= 1) { + highC(0,0) += y_t*y_t*a3/(4.0*pi*s)*(1.0/2.0-0.5*Ls); + highC(1,0) += y_t*y_t*a1*Y/(4.0*pi*s)*(-5.0/12.0-1.0/12.0*Ls); + } + } + break; + case QQLL: + Yi = 1./6.; Yf = -1./2.; + highC.resize(2,1); + highC(0,0) = 4.0*pi*a2 / s; + highC(1,0) = 4.0*pi*a1*Yi*Yf / s; + if (order >= 1) { + highC(0,0) += (1.0/s)*(a2*a2*(X_2_st-(C_d_2+C_A_2)/4.0*fTilde_st) + + (a2*a3*C_F_3 + a1*a2*(Yi*Yi+Yf*Yf))*W - + 2.0*a1*a2*Yi*Yf*fTilde_st); + highC(1,0) += (1.0/s)*(-1.0*(a2*a2*C_1_2+a1*a1*Yi*Yi*Yf*Yf)*fTilde_st + + a1*a1*Yi*Yf*PI1 + + (a1*a3*Yi*Yf*C_F_3+2.0*a1*a2*Yi*Yf*C_F_2+ + a1*a1*(Yi*Yi*Yi*Yf+Yf*Yf*Yf*Yi))*W); + } + break; + case QQEE: + Yi = 1./6.; Yf = -1.; + highC.resize(1,1); + highC(0,0) = 4.0*pi*a1*Yi*Yf / s; + if (order >= 1) { + highC(0,0) += (1.0/s)*(a1*a1*Yi*Yi*Yf*Yf*fTilde_su + a1*a1*Yi*Yf*PI1 + + (a1*a3*Yi*Yf*C_F_3 + a1*a2*Yi*Yf*C_F_2 + + a1*a1*(Yi*Yi*Yi*Yf+Yf*Yf*Yf*Yi))*W); + } + break; + case UUUU: + Yi = Yf = 2./3.; + highC.resize(2,1); + highC(0,0) = 4.0*pi*a3 / s; + highC(1,0) = 4.0*pi*a1*Yi*Yf / s; + if (order >= 1) { + highC(0,0) += (1.0/s)*(-2.0*a1*a3*Yi*Yf*fTilde_st + + a1*a3*(Yi*Yi+Yf*Yf)*W); + highC(1,0) += (1.0/s)*(-1.0*(a1*a1*Yi*Yi*Yf*Yf)*fTilde_st + + a1*a1*Yi*Yf*PI1 + + (2.0*a1*a3*Yi*Yf*C_F_3+a1*a1*(Yi*Yi*Yi*Yf+Yf*Yf*Yf*Yi))*W); + if (includeAlphaS2) { + highC(0,0) += (1.0/s)*(a3*a3*(X_3_st-(C_d_3+C_A_3)/4.0*fTilde_st)); + highC(1,0) += (1.0/s)*(-1.0*(a3*a3*C_1_3)*fTilde_st); + } + } + break; + case UUUUiden: + { + Process parentCase = UUUU; + boost::numeric::ublas::matrix > + highCs_st = highEnergyMatching(Q,s,t,u,parentCase,oneLoop,includeAlphaS2); + boost::numeric::ublas::matrix > + highCs_ts = highEnergyMatching(Q,t,s,u,parentCase,oneLoop,includeAlphaS2); + boost::numeric::ublas::matrix > highCt_st; + axpy_prod_local(M_N(3),highCs_ts,highCt_st); + highC = highCs_st + highCt_st; + } + break; + case tRtRUU: + { + highC.resize(2,1); + Process parentCase = UUUU; + highC = highEnergyMatching(Q,s,t,u,parentCase,oneLoop,includeAlphaS2); + double Y = 2./3.; + if (order >= 1) { + highC(0,0) += y_t*y_t*a3/(4.0*pi*s)*(1.0-Ls); + highC(1,0) += y_t*y_t*a1*Y/(4.0*pi*s)*(5.0/3.0-2.0/3.0*Ls); + } + } + break; + case UUDD: + Yi = 2./3.; Yf = -1./3.; + highC.resize(2,1); + highC(0,0) = 4.0*pi*a3 / s; + highC(1,0) = 4.0*pi*a1*Yi*Yf / s; + if (order >= 1) { + highC(0,0) += (1.0/s)*(-2.0*a1*a3*Yi*Yf*fTilde_st + + a1*a3*(Yi*Yi+Yf*Yf)*W); + highC(1,0) += (1.0/s)*(-1.0*(a1*a1*Yi*Yi*Yf*Yf)*fTilde_st + + a1*a1*Yi*Yf*PI1 + + (2.0*a1*a3*Yi*Yf*C_F_3+a1*a1*(Yi*Yi*Yi*Yf+Yf*Yf*Yf*Yi))*W); + if (includeAlphaS2) { + highC(0,0) += (1.0/s)*(a3*a3*(X_3_st-(C_d_3+C_A_3)/4.0*fTilde_st)); + highC(1,0) += (1.0/s)*(-1.0*(a3*a3*C_1_3)*fTilde_st); + } + } + break; + case tRtRDD: + { + highC.resize(2,1); + Process parentCase = UUDD; + highC = highEnergyMatching(Q,s,t,u,parentCase,oneLoop,includeAlphaS2); + double Y = -1./3.; + if (order >= 1) { + highC(0,0) += y_t*y_t*a3/(4.0*pi*s)*(1.0-Ls); + highC(1,0) += y_t*y_t*a1*Y/(4.0*pi*s)*(5.0/3.0-2.0/3.0*Ls); + } + } + break; + case UULL: + Yi = 2./3.; Yf = -0.5; + highC.resize(1,1); + highC(0,0) = 4.0*pi*a1*Yi*Yf / s; + if (order >= 1) { + highC(0,0) += (1.0/s)*(a1*a1*Yi*Yi*Yf*Yf*fTilde_su + a1*a1*Yi*Yf*PI1 + + (a1*a3*Yi*Yf*C_F_3 + a1*a2*Yi*Yf*C_F_2 + + a1*a1*(Yi*Yi*Yi*Yf+Yf*Yf*Yf*Yi))*W); + } + break; + case UUEE: + Yi = 2./3.; Yf = -1.; + highC.resize(1,1); + highC(0,0) = 4.0*pi*a1*Yi*Yf / s; + if (order >= 1) { + highC(0,0) += (1.0/s)*(-1.0*a1*a1*Yi*Yi*Yf*Yf*fTilde_st + a1*a1*Yi*Yf*PI1 + + (a1*a3*Yi*Yf*C_F_3 + + a1*a1*(Yi*Yi*Yi*Yf+Yf*Yf*Yf*Yi))*W); + } + break; + case DDDD: + Yi = Yf = -1./3.; + highC.resize(2,1); + highC(0,0) = 4.0*pi*a3 / s; + highC(1,0) = 4.0*pi*a1*Yi*Yf / s; + if (order >= 1) { + highC(0,0) += (1.0/s)*(-2.0*a1*a3*Yi*Yf*fTilde_st + + a1*a3*(Yi*Yi+Yf*Yf)*W); + highC(1,0) += (1.0/s)*(-1.0*(a1*a1*Yi*Yi*Yf*Yf)*fTilde_st + + a1*a1*Yi*Yf*PI1 + + (2.0*a1*a3*Yi*Yf*C_F_3+a1*a1*(Yi*Yi*Yi*Yf+Yf*Yf*Yf*Yi))*W); + if (includeAlphaS2) { + highC(0,0) += (1.0/s)*(a3*a3*(X_3_st-(C_d_3+C_A_3)/4.0*fTilde_st)); + highC(1,0) += (1.0/s)*(-1.0*(a3*a3*C_1_3)*fTilde_st); + } + } + break; + case DDDDiden: + { + Process parentCase = DDDD; + boost::numeric::ublas::matrix > + highCs_st = highEnergyMatching(Q,s,t,u,parentCase,oneLoop,includeAlphaS2); + boost::numeric::ublas::matrix > + highCs_ts = highEnergyMatching(Q,t,s,u,parentCase,oneLoop,includeAlphaS2); + boost::numeric::ublas::matrix > highCt_st; + axpy_prod_local(M_N(3),highCs_ts,highCt_st); + highC = highCs_st + highCt_st; + } + break; + case DDLL: + Yi = -1./3.; Yf = -0.5; + highC.resize(1,1); + highC(0,0) = 4.0*pi*a1*Yi*Yf / s; + if (order >= 1) { + highC(0,0) += (1.0/s)*(a1*a1*Yi*Yi*Yf*Yf*fTilde_su + a1*a1*Yi*Yf*PI1 + + (a1*a3*Yi*Yf*C_F_3 + a1*a2*Yi*Yf*C_F_2 + + a1*a1*(Yi*Yi*Yi*Yf+Yf*Yf*Yf*Yi))*W); + } + break; + case DDEE: + Yi = -1./3.; Yf = -1.; + highC.resize(1,1); + highC(0,0) = 4.0*pi*a1*Yi*Yf / s; + if (order >= 1) { + highC(0,0) += (1.0/s)*(-1.0*a1*a1*Yi*Yi*Yf*Yf*fTilde_st + a1*a1*Yi*Yf*PI1 + + (a1*a3*Yi*Yf*C_F_3 + + a1*a1*(Yi*Yi*Yi*Yf+Yf*Yf*Yf*Yi))*W); + } + break; + case LLLL: + Yi = Yf = -0.5; + highC.resize(2,1); + highC(0,0) = 4.0*pi*a2 / s; + highC(1,0) = 4.0*pi*a1*Yi*Yf / s; + if (order >= 1) { + highC(0,0) += (1.0/s)*(a2*a2*(X_2_st-(C_d_2+C_A_2)/4.0*fTilde_st) + + 2.0*a1*a2*Yi*Yf*W - + 2.0*a1*a2*Yi*Yf*fTilde_st); + highC(1,0) += (1.0/s)*(-1.0*(a2*a2*C_1_2+a1*a1*Yi*Yi*Yf*Yf)*fTilde_st + + a1*a1*Yi*Yf*PI1 + + 2.0*(a1*a2*Yi*Yf*C_F_2+a1*a1*Yi*Yi*Yf*Yf)*W); + } + break; + case LLLLiden: + { + Process parentCase = LLLL; + boost::numeric::ublas::matrix > + highCs_st = highEnergyMatching(Q,s,t,u,parentCase,oneLoop,includeAlphaS2); + boost::numeric::ublas::matrix > + highCs_ts = highEnergyMatching(Q,t,s,u,parentCase,oneLoop,includeAlphaS2); + boost::numeric::ublas::matrix > highCt_st; + axpy_prod_local(M_N(2), highCs_ts, highCt_st); + highC = highCs_st + highCt_st; + } + break; + case LLEE: + Yi = -0.5; Yf = -1.; + highC.resize(1,1); + highC(0,0) = 4.0*pi*a1*Yi*Yf / s; + if (order >= 1) { + highC(0,0) += (1.0/s)*(a1*a1*Yi*Yi*Yf*Yf*fTilde_su + a1*a1*Yi*Yf*PI1 + + (a1*a2*Yi*Yf*C_F_2 + + a1*a1*(Yi*Yi*Yi*Yf+Yf*Yf*Yf*Yi))*W); + } + break; + case EEEE: + Yi = Yf = -1.; + highC.resize(1,1); + highC(0,0) = 4.0*pi*a1*Yi*Yf / s; + if (order >= 1) { + highC(0,0) += (1.0/s)*(-1.0*a1*a1*Yi*Yi*Yf*Yf*fTilde_st + a1*a1*Yi*Yf*PI1 + + 2.0*a1*a1*Yi*Yi*Yf*Yf*W); + } + break; + case EEEEiden: + { + Process parentCase = EEEE; + boost::numeric::ublas::matrix > + highCs_st = highEnergyMatching(Q,s,t,u,parentCase,oneLoop,includeAlphaS2); + boost::numeric::ublas::matrix > + highCs_ts = highEnergyMatching(Q,t,s,u,parentCase,oneLoop,includeAlphaS2); + boost::numeric::ublas::matrix > + highCt_st = highCs_ts; + highC = highCs_st + highCt_st; + } + break; + default: + assert(false); + } + return highC; +} + +boost::numeric::ublas::matrix > +HighEnergyMatching::Spin1HighMatching(Energy highScale, + Energy2 s, Energy2 t, Energy2 u, + EWProcess::Process process, + bool oneLoop, bool includeAlphaS2) { + using Constants::pi; + + unsigned int order = !oneLoop ? 0 : 1; + // (If crossed graphs, swap s and t here) + Complex L_s = MinusLog(-s/(highScale*highScale)); + Complex L_t = MinusLog(-t/(highScale*highScale)); + Complex L_u = MinusLog(-u/(highScale*highScale)); + Complex L_s2 = L_s*L_s; + Complex L_t2 = L_t*L_t; + Complex L_u2 = L_u*L_u; + + // Tree-Level: + // Topology types defined. Note each of these is a vector of 5 entries. They are the coefficients + // for the dirac structures M_0, M_1, M_4, M_5, and M_6 for vector boson production. + boost::numeric::ublas::vector > R1(5); + for(unsigned int ix=0;ix<5;++ix) R1[ix] = ZERO; + R1[0] = -1.0/t; + R1[1] = -2.0/t; + R1[2] = ZERO; + R1[3] = ZERO; + R1[4] = ZERO; + boost::numeric::ublas::vector > R1_bar(5); + for(unsigned int ix=0;ix<5;++ix) R1_bar[ix] = ZERO; + R1_bar[0] = -1.0/u; + boost::numeric::ublas::vector > R2(5); + for(unsigned int ix=0;ix<5;++ix) R2[ix] = ZERO; + R2[1] = -1.0/s*2.0; + // Topologies T1: + boost::numeric::ublas::vector > T1a(5); + for(unsigned int ix=0;ix<5;++ix) T1a[ix] = ZERO; + T1a[0] = 1.0/(t*u)*(-3.0*t*L_s2-(s+4.0*t)*L_t2+2.0*(s+4.0*t)*L_s*L_t+2.0*u*L_t- + pi*pi*(7.0/6.0*s+25.0/6.0*t)-4.0*u); + T1a[1] = 1.0/(u*u*t*s)*(0.5*t*(9.0*s*s+14.0*s*t+7.0*t*t)*L_s2+s*(2.0*s+t)*(s+2.0*t)*L_t2- + 2.0*(2.0*s*s*s+9.0*s*s*t+10.0*s*t*t+4.0*t*t*t)*L_s*L_t- + 2.0*t*t*u*L_s-2.0*u*s*(2.0*s+3.0*t)*L_t+ + pi*pi*(7.0/3.0*s*s*s+125.0/12.0*s*s*t+71.0/6.0*s*t*t+ + 19.0/4.0*t*t*t)- + 8.0*s*s*s-20.0*s*s*t-16.0*s*t*t-4.0*t*t*t); + T1a[2] = 1.0/(t*u*u)*(-t*(3.0*s+4.0*t)*L_s2-(s*s+5.0*s*t+5.0*t*t)*L_t2+ + 2.0*t*(3.0*s+4.0*t)*L_s*L_t+2.0*u*t*(2.0*s+t)*L_s/s- + 2.0*u*t*L_t+pi*pi*(s*s/6.0-8.0/3.0*s*t-23.0/6.0*t*t)+ + 4.0*t*t*t/s+4.0*s*t+8.0*t*t); + T1a[3] = T1a[2]; + T1a[4] = GeV2/(t*u*u*u)*(-4.0*t*(s+2.0*t)*(L_s-L_t)*(L_s-L_t)+ + 4.0*u*(3.0*s+5.0*t)*(L_s-L_t)-4.0*pi*pi*t*(s+2.0*t)-4.0*u*u); + boost::numeric::ublas::vector > T1b(5); + for(unsigned int ix=0;ix<5;++ix) T1b[ix] = ZERO; + T1b[0] = 1.0/(t*u*s*s)*(-s*t*(2.0*s+3.0*t)*L_u2+s*u*(s+3.0*t)*L_t2+ + 2.0*s*(s*s+3.0*s*t+3.0*t*t)*L_u*L_t+s*s*t*L_u+s*s*u*L_t- + pi*pi*(7.0/6.0*s*s*s+3.0*s*s*t+3.0*s*t*t)+2.0*s*s*s); + T1b[1] = 1.0/(t*s*s*u)*(3.0*s*t*u*L_u2+s*u*(2.0*s+3.0*t)*L_t2- + 2.0*s*u*(2.0*s+3.0*t)*L_u*L_t+2.0*s*s*u*L_t- + pi*pi*(7.0/3.0*s*s*s+16.0/3.0*s*s*t+3.0*s*t*t)+ + 4.0*s*s*s+4.0*s*s*t); + T1b[2] = 1.0/(t*u*s*s)*(-3.0*s*t*u*(L_u-L_t)*(L_u-L_t)+4.0*s*s*t*L_u+4.0*s*s*u*L_t+ + pi*pi*(3.0*s*s*t+3.0*s*t*t)+8.0*s*s*s); + T1b[3] = 1.0/(t*u*s*s)*(s*t*(2.0*s+3.0*t)*L_u2-s*u*(s+3.0*t)*L_t2+6.0*s*t*u*L_u*L_t+ + pi*pi*(-1.0/6.0*s*s*s+3.0*s*s*t+3.0*s*t*t)); + T1b[4] = 12.0*GeV2/(t*u)*(L_t-L_u); + boost::numeric::ublas::vector > T1c(5); + for(unsigned int ix=0;ix<5;++ix) T1c[ix] = ZERO; + T1c[0] = 1.0/t*(2.0*L_s*L_t-7.0*pi*pi/6.0-L_t2); + T1c[1] = 1.0/(t*u*u)*(s*t*L_s2-(2.0*s*s+3.0*s*t+2.0*t*t)*L_t2+ + 2.0*(2.0*s*s+3.0*s*t+2.0*t*t)*L_s*L_t+2.0*t*u*(L_s-L_t)- + pi*pi*(7.0/3.0*s*s+11.0/3.0*s*t+7.0/3.0*t*t)); + T1c[2] = 1.0/(t*u*u)*(t*(3.0*s+2.0*t)*(L_s-L_t)*(L_s-L_t)+2.0*u*t*L_s+ + 2.0*u*(2.0*s+t)*L_t+pi*pi*t*(3.0*s+2.0*t)+8.0*u*u); + T1c[3] = T1c[2]; + T1c[4] = GeV2/(t*u*u*u)*(4.0*t*(2.0*s+t)*(L_s-L_t)*(L_s-L_t)-4.0*u*(3.0*s+t)*(L_s-L_t)+ + 4.0*pi*pi*t*(2.0*s+t)-4.0*u*u); + boost::numeric::ublas::vector > T1d(5); + for(unsigned int ix=0;ix<5;++ix) T1d[ix] = ZERO; + T1d[2] = 1.0/s*(-2.0*L_s+4.0); + T1d[3] = T1d[2]; + boost::numeric::ublas::vector > T1a_bar(5); + for(unsigned int ix=0;ix<5;++ix) T1a_bar[ix] = ZERO; + T1a_bar[0] = 1.0/(u*t)*(-3.0*u*L_s2-(s+4.0*u)*L_u2+2.0*(s+4.0*u)*L_s*L_u+2.0*t*L_u- + pi*pi*(7.0/6.0*s+25.0/6.0*u)-4.0*t); + T1a_bar[1] = 2.0*T1a_bar[0] - + 1.0/(t*t*u*s)*(0.5*u*(9.0*s*s+14.0*s*u+7.0*u*u)*L_s2+s*(2.0*s+u)*(s+2.0*u)*L_u2- + 2.0*(2.0*s*s*s+9.0*s*s*u+10.0*s*u*u+4.0*u*u*u)*L_s*L_u- + 2.0*u*u*t*L_s-2.0*t*s*(2.0*s+3.0*u)*L_u+ + pi*pi*(7.0/3.0*s*s*s+125.0/12.0*s*s*u+71.0/6.0*s*u*u+ + 19.0/4.0*u*u*u)- + 8.0*s*s*s-20.0*s*s*u-16.0*s*u*u-4.0*u*u*u); + T1a_bar[2] = 1.0/(u*t*t)*(-u*(3.0*s+4.0*u)*L_s2-(s*s+5.0*s*u+5.0*u*u)*L_u2+ + 2.0*u*(3.0*s+4.0*u)*L_s*L_u+2.0*t*u*(2.0*s+u)*L_s/s- + 2.0*t*u*L_u+pi*pi*(s*s/6.0-8.0/3.0*s*u-23.0/6.0*u*u)+ + 4.0*u*u*u/s+4.0*s*u+8.0*u*u); + T1a_bar[3] = T1a_bar[2]; + T1a_bar[4] = -GeV2/(u*t*t*t)*(-4.0*u*(s+2.0*u)*(L_s-L_u)*(L_s-L_u)+ + 4.0*t*(3.0*s+5.0*u)*(L_s-L_u)-4.0*pi*pi*u*(s+2.0*u)-4.0*t*t); + boost::numeric::ublas::vector > T1b_bar(5); + for(unsigned int ix=0;ix<5;++ix) T1b_bar[ix] = ZERO; + T1b_bar[0] = 1.0/(u*t*s*s)*(-s*u*(2.0*s+3.0*u)*L_t2+s*t*(s+3.0*u)*L_u2+ + 2.0*s*(s*s+3.0*s*u+3.0*u*u)*L_t*L_u+ + s*s*u*L_t+s*s*t*L_u- + pi*pi*(7.0/6.0*s*s*s+3.0*s*s*u+3.0*s*u*u)+2.0*s*s*s); + T1b_bar[1] = 2.0*T1b_bar[0] - + 1.0/(u*s*s*t)*(3.0*s*u*t*L_t2+s*t*(2.0*s+3.0*u)*L_u2- + 2.0*s*t*(2.0*s+3.0*u)*L_t*L_u+2.0*s*s*t*L_u- + pi*pi*(7.0/3.0*s*s*s+16.0/3.0*s*s*u+3.0*s*u*u)+ + 4.0*s*s*s+4.0*s*s*u); + T1b_bar[3] = 1.0/(u*t*s*s)*(-3.0*s*u*t*(L_t-L_u)*(L_t-L_u)+4.0*s*s*u*L_t+4.0*s*s*t*L_u+ + pi*pi*(3.0*s*s*u+3.0*s*u*u)+8.0*s*s*s); + T1b_bar[2] = 1.0/(u*t*s*s)*(s*u*(2.0*s+3.0*u)*L_t2-s*t*(s+3.0*u)*L_u2+6.0*s*u*t*L_t*L_u+ + pi*pi*(-1.0/6.0*s*s*s+3.0*s*s*u+3.0*s*u*u)); + T1b_bar[4] = -12.0*GeV2/(u*t)*(L_u-L_t); + boost::numeric::ublas::vector > T1c_bar(5); + for(unsigned int ix=0;ix<5;++ix) T1c_bar[ix] = ZERO; + T1c_bar[0] = 1.0/u*(2.0*L_s*L_u-7.0*pi*pi/6.0-L_u2); + T1c_bar[1] = 2.0*T1c_bar[0] - + 1.0/(u*t*t)*(s*u*L_s2-(2.0*s*s+3.0*s*u+2.0*u*u)*L_u2+ + 2.0*(2.0*s*s+3.0*s*u+2.0*u*u)*L_s*L_u+2.0*u*t*(L_s-L_u)- + pi*pi*(7.0/3.0*s*s+11.0/3.0*s*u+7.0/3.0*u*u)); + T1c_bar[2] = 1.0/(u*t*t)*(u*(3.0*s+2.0*u)*(L_s-L_u)*(L_s-L_u)+2.0*t*u*L_s+ + 2.0*t*(2.0*s+u)*L_u+pi*pi*u*(3.0*s+2.0*u)+8.0*t*t); + T1c_bar[3] = T1c_bar[2]; + T1c_bar[4] = -GeV2/(u*t*t*t)*(4.0*u*(2.0*s+u)*(L_s-L_u)*(L_s-L_u)-4.0*t*(3.0*s+u)*(L_s-L_u)+ + 4.0*pi*pi*u*(2.0*s+u)-4.0*t*t); + // Topologies T2: + boost::numeric::ublas::vector > T2a(5); + for(unsigned int ix=0;ix<5;++ix) T2a[ix] = ZERO; + T2a[1] = 1.0/s*(L_s/6.0-11.0/18.0); + boost::numeric::ublas::vector > T2b(5); + for(unsigned int ix=0;ix<5;++ix) T2b[ix] = ZERO; + T2b[1] = 1.0/s*(-2.0/3.0*L_s+22.0/9.0); + boost::numeric::ublas::vector > T2c(5); + for(unsigned int ix=0;ix<5;++ix) T2c[ix] = ZERO; + T2c[1] = 1.0/s*(3.0/2.0*L_s2-17.0/2.0*L_s-pi*pi/4.0+95.0/6.0); + boost::numeric::ublas::vector > T2d(5); + for(unsigned int ix=0;ix<5;++ix) T2d[ix] = ZERO; + T2d[1] = 1.0/s*(-4.0/3.0*L_s+14.0/9.0); + // Topologies T3: + boost::numeric::ublas::vector > T3a(5); + for(unsigned int ix=0;ix<5;++ix) T3a[ix] = ZERO; + T3a[0] = 1.0/t*(L_t2-pi*pi/6.0); + T3a[1] = 2.0*T3a[0]; + T3a[3] = 1.0/t*(-L_t2+pi*pi/6.0+2.0); + boost::numeric::ublas::vector > T3b(5); + for(unsigned int ix=0;ix<5;++ix) T3b[ix] = ZERO; + T3b[0] = 1.0/t*(-L_t+4.0); + T3b[1] = 2.0*T3b[0]; + T3b[3] = 1.0/t*(4.0*L_t-10.0); + boost::numeric::ublas::vector > T3a_bar(5); + for(unsigned int ix=0;ix<5;++ix) T3a_bar[ix] = ZERO; + T3a_bar[0] = 1.0/u*(L_u2-pi*pi/6.0); + T3a_bar[2] = 1.0/u*(-L_u2+pi*pi/6.0+2.0); + boost::numeric::ublas::vector > T3b_bar(5); + for(unsigned int ix=0;ix<5;++ix) T3b_bar[ix] = ZERO; + T3b_bar[0] = 1.0/u*(-L_u+4.0); + T3b_bar[2] = 1.0/u*(4.0*L_u-10.0); + // Topologies T4: + boost::numeric::ublas::vector > T4a(5); + for(unsigned int ix=0;ix<5;++ix) T4a[ix] = ZERO; + T4a[0] = 1.0/t*(L_t2-pi*pi/6.0); + T4a[1] = 2.0*T4a[0]; + T4a[2] = 1.0/t*(-L_t2+pi*pi/6.0+2.0); + boost::numeric::ublas::vector > T4b(5); + for(unsigned int ix=0;ix<5;++ix) T4b[ix] = ZERO; + T4b[0] = 1.0/t*(-L_t+4.0); + T4b[1] = 2.0*T4b[0]; + T4b[2] = 1.0/t*(4.0*L_t-10.0); + boost::numeric::ublas::vector > T4a_bar(5); + for(unsigned int ix=0;ix<5;++ix) T4a_bar[ix] = ZERO; + T4a_bar[0] = 1.0/u*(L_u2-pi*pi/6.0); + T4a_bar[3] = 1.0/u*(-L_u2+pi*pi/6.0+2.0); + boost::numeric::ublas::vector > T4b_bar(5); + for(unsigned int ix=0;ix<5;++ix) T4b_bar[ix] = ZERO; + T4b_bar[0] = 1.0/u*(-L_u+4.0); + T4b_bar[3] = 1.0/u*(4.0*L_u-10.0); + // Topologies T5: + boost::numeric::ublas::vector > T5a(5); + for(unsigned int ix=0;ix<5;++ix) T5a[ix] = ZERO; + T5a[1] = 1.0/s*(2.0*L_s-4.0); + boost::numeric::ublas::vector > T5b(5); + for(unsigned int ix=0;ix<5;++ix) T5b[ix] = ZERO; + T5b[1] = 1.0/s*(-2.0*L_s2+6.0*L_s-16.0+pi*pi/3.0); + // Topologies T6: + boost::numeric::ublas::vector > T6a(5); + for(unsigned int ix=0;ix<5;++ix) T6a[ix] = ZERO; + T6a[1] = 1.0/s*(-19.0/6.0*L_s+58.0/9.0); + boost::numeric::ublas::vector > T6b(5); + for(unsigned int ix=0;ix<5;++ix) T6b[ix] = ZERO; + T6b[1] = 1.0/s*(-1.0/6.0*L_s+4.0/9.0); + boost::numeric::ublas::vector > T6c(5); + for(unsigned int ix=0;ix<5;++ix) T6c[ix] = ZERO; + T6c[1] = 1.0/s*(2.0/3.0*L_s-16.0/9.0); + boost::numeric::ublas::vector > T6d(5); + for(unsigned int ix=0;ix<5;++ix) T6d[ix] = ZERO; + T6d[1] = 1.0/s*(4.0/3.0*L_s-20.0/9.0); + // Topology T7: + boost::numeric::ublas::vector > T7(5); + for(unsigned int ix=0;ix<5;++ix) T7[ix] = ZERO; + T7[0] = 1.0/t*(-L_t+1.0); + T7[1] = 2.0*T7[0]; + boost::numeric::ublas::vector > T7_bar(5); + for(unsigned int ix=0;ix<5;++ix) T7_bar[ix] = ZERO; + T7_bar[0] = 1.0/u*(-L_u+1.0); + // Group Theory Factors / SM parameters needed for matrix elements: + double a1 = ElectroWeakReweighter::coupling()->a1(highScale); + double a2 = ElectroWeakReweighter::coupling()->a2(highScale); + double a3 = ElectroWeakReweighter::coupling()->a3(highScale); + double y_t = ElectroWeakReweighter::coupling()->y_t(highScale); + // Traces over complex scalars and weyl fermions. + double T_CS_3 = 0.0; + double T_CS_2 = 0.5; + //double T_CS_1 = 0.5; + double T_WF_3 = 2.0*3.0; + double T_WF_2 = 2.0*3.0; + //double T_WF_1 = 10.0/3.0*3.0; + double C_A_3 = 3.0; + double C_A_2 = 2.0; + double C_A_1 = 0.0; + double C_F_3 = 4.0/3.0; + double C_F_2 = 3.0/4.0; + double C_F_1 = 1.0; + // This is the coefficient of the delta term in G_TT + double G_TT = 0.5; + // This is the coeffidient of d^ABC in G_TT (non-zero for SU(3)) + double G_TT_3_D = 0.25*C_A_3; + double G_f = 1.0; + // Factors TBD after fermion helicity is specified: + double Y_Q(0.), G_Plus_U1(0.); + double G_Plus_SU2 = 0.25; + double G_Plus_SU3 = 1./6.; + double G_Plus_SU3_D = 0.5; + double Lambda_Q(0.); + // the _s and _ew are the alpha3 and alpha1/2 parts of Lambda_Q + double Lambda_Q_s(0.); + double Lambda_Q_ew(0.); + double rho12(0.), rho13(0.); + double rho23 = sqrt(a2*a3); + double tRorQ = 1.0; + boost::numeric::ublas::matrix > highC(1,1); + switch (process) { + case QQWW: case LLWW: + { + // Finish Group Theory Factors: + if (process==QQWW) { + Y_Q = 1.0/6.0; + G_Plus_U1 = Y_Q*Y_Q; + Lambda_Q = C_F_3*a3 + C_F_2*a2 + Y_Q*Y_Q*C_F_1*a1; + rho12 = Y_Q*sqrt(a1*a2); + } + else if (process==LLWW) { + Y_Q = -1.0/2.0; + G_Plus_U1 = Y_Q*Y_Q; + Lambda_Q = C_F_2*a2 + Y_Q*Y_Q*C_F_1*a1; + rho12 = Y_Q*sqrt(a1*a2); + } + highC.resize(5,5); + for (int i=0; i<5; i++) { + highC(0,i) = G_Plus_SU2*(4.0*pi*a2)*(R1[i]+R1_bar[i]); + highC(1,i) = G_f*4.0*pi*a2*(-0.5*R1[i]+0.5*R1_bar[i]-R2[i]); + highC(2,i) = rho12*4.0*pi*(R1[i]+R1_bar[i]); + highC(3,i) = rho12*4.0*pi*(R1[i]+R1_bar[i]); + highC(4,i) = G_Plus_U1*(4.0*pi*a1)*(R1[i]+R1_bar[i]); + if (order>=1) { + highC(0,i) += G_Plus_SU2*((-0.5*a2*a2*C_A_2)*(T1b[i]+T1b_bar[i])+ + a2*(Lambda_Q-a2*C_A_2)*(T1c[i]+T1c_bar[i])+ + 0.5*a2*a2*C_A_2*(T3a[i]+T3a_bar[i])+ + a2*(Lambda_Q-0.5*a2*C_A_2)*(T3b[i]+T3b_bar[i])+ + 0.5*a2*a2*C_A_2*(T4a[i]+T4a_bar[i])+ + a2*(Lambda_Q-0.5*a2*C_A_2)*(T4b[i]+T4b_bar[i])+ + a2*Lambda_Q*(T7[i]+T7_bar[i])) + + G_TT*(-a2*a2*(T1a[i]+T1a_bar[i])+a2*a2*(T1b[i]+T1b_bar[i])+ + a2*a2*(T1c[i]+T1c_bar[i])+2.0*a2*a2*T1d[i]); + highC(1,i) += G_f*(0.25*a2*a2*C_A_2*(T1a[i]-T1a_bar[i])+ + a2*(0.25*a2*C_A_2-0.5*Lambda_Q)*(T1c[i]-T1c_bar[i])+ + 0.5*a2*a2*C_A_2*T2a[i]+a2*a2*T_CS_2*T2b[i]- + 0.5*a2*a2*C_A_2*T2c[i]+a2*a2*T_WF_2*T2d[i]- + 0.25*a2*a2*C_A_2*(T3a[i]-T3a_bar[i])- + 0.5*a2*(Lambda_Q-0.5*a2*C_A_2)*(T3b[i]-T3b_bar[i])- + 0.25*a2*a2*C_A_2*(T4a[i]-T4a_bar[i])- + 0.5*a2*(Lambda_Q-0.5*a2*C_A_2)*(T4b[i]-T4b_bar[i])+ + 0.5*a2*a2*C_A_2*T5a[i]+a2*(Lambda_Q-0.5*a2*C_A_2)*T5b[i]+ + a2*a2*C_A_2*T6a[i]+a2*a2*C_A_2*T6b[i]+ + a2*a2*T_CS_2*T6c[i]+a2*a2*T_WF_2*T6d[i]- + 0.5*a2*Lambda_Q*(T7[i]-T7_bar[i])); + highC(2,i) += rho12*(-0.5*a1*C_A_1*T1b[i]-0.5*a2*C_A_2*T1b_bar[i]+ + (Lambda_Q-0.5*a1*C_A_1-0.5*a2*C_A_2)*(T1c[i]+T1c_bar[i])+ + 0.5*a1*C_A_1*T3a[i]+0.5*a2*C_A_2*T3a_bar[i]+ + (Lambda_Q-0.5*a1*C_A_1)*T3b[i]+(Lambda_Q-0.5*a2*C_A_2)*T3b_bar[i]+ + 0.5*a2*C_A_2*T4a[i]+0.5*a1*C_A_1*T4a_bar[i]+ + (Lambda_Q-0.5*a2*C_A_2)*T4b[i]+(Lambda_Q-0.5*a1*C_A_1)*T4b_bar[i]+ + Lambda_Q*(T7[i]+T7_bar[i])); + highC(3,i) += rho12*(-0.5*a2*C_A_2*T1b[i]-0.5*a1*C_A_1*T1b_bar[i]+ + (Lambda_Q-0.5*a2*C_A_2-0.5*a1*C_A_1)*(T1c[i]+T1c_bar[i])+ + 0.5*a2*C_A_2*T3a[i]+0.5*a1*C_A_1*T3a_bar[i]+ + (Lambda_Q-0.5*a2*C_A_2)*T3b[i]+(Lambda_Q-0.5*a1*C_A_1)*T3b_bar[i]+ + 0.5*a1*C_A_1*T4a[i]+0.5*a2*C_A_2*T4a_bar[i]+ + (Lambda_Q-0.5*a1*C_A_1)*T4b[i]+(Lambda_Q-0.5*a2*C_A_2)*T4b_bar[i]+ + Lambda_Q*(T7[i]+T7_bar[i])); + highC(4,i) += G_Plus_U1*((-0.5*a1*a1*C_A_1)*(T1b[i]+T1b_bar[i])+ + a1*(Lambda_Q-a1*C_A_1)*(T1c[i]+T1c_bar[i])+ + 0.5*a1*a1*C_A_1*(T3a[i]+T3a_bar[i])+ + a1*(Lambda_Q-0.5*a1*C_A_1)*(T3b[i]+T3b_bar[i])+ + 0.5*a1*a1*C_A_1*(T4a[i]+T4a_bar[i])+ + a1*(Lambda_Q-0.5*a1*C_A_1)*(T4b[i]+T4b_bar[i])+ + a1*Lambda_Q*(T7[i]+T7_bar[i])); + } + } + } + break; + case UUBB: case DDBB: case EEBB: + { + // Finish Group Theory Factors: + if (process==UUBB) { + Y_Q = 2.0/3.0; + G_Plus_U1 = Y_Q*Y_Q; + Lambda_Q = C_F_3*a3 + Y_Q*Y_Q*C_F_1*a1; + } + else if (process==DDBB) { + Y_Q = -1.0/3.0; + G_Plus_U1 = Y_Q*Y_Q; + Lambda_Q = C_F_3*a3 + Y_Q*Y_Q*C_F_1*a1; + } + else if (process==EEBB) { + Y_Q = -1.0; + G_Plus_U1 = Y_Q*Y_Q; + Lambda_Q = Y_Q*Y_Q*C_F_1*a1; + } + highC.resize(1,5); + for (int i=0; i<5; i++) { + highC(0,i) = G_Plus_U1*(4.0*pi*a1)*(R1[i]+R1_bar[i]); + if (order>=1) { + highC(0,i) += G_Plus_U1*((-0.5*a1*a1*C_A_1)*(T1b[i]+T1b_bar[i])+ + a1*(Lambda_Q-a1*C_A_1)*(T1c[i]+T1c_bar[i])+ + 0.5*a1*a1*C_A_1*(T3a[i]+T3a_bar[i])+ + a1*(Lambda_Q-0.5*a1*C_A_1)*(T3b[i]+T3b_bar[i])+ + 0.5*a1*a1*C_A_1*(T4a[i]+T4a_bar[i])+ + a1*(Lambda_Q-0.5*a1*C_A_1)*(T4b[i]+T4b_bar[i])+ + a1*Lambda_Q*(T7[i]+T7_bar[i])); + } + } + } + break; + case QQWG: + { + // Finish Group Theory Factors: + Y_Q = 1./6.; + Lambda_Q = C_F_3*a3 + C_F_2*a2 + Y_Q*Y_Q*C_F_1*a1; + + highC.resize(1,5); + + for (int i=0; i<5; i++) { + highC(0,i) = rho23*4.0*pi*(R1[i]+R1_bar[i]); + + if (order>=1) { + + highC(0,i) += rho23*(-0.5*a3*C_A_3*T1b[i]-0.5*a2*C_A_2*T1b_bar[i]+ + (Lambda_Q-0.5*a3*C_A_3-0.5*a2*C_A_2)*(T1c[i]+T1c_bar[i])+ + 0.5*a3*C_A_3*T3a[i]+0.5*a2*C_A_2*T3a_bar[i]+ + (Lambda_Q-0.5*a3*C_A_3)*T3b[i]+(Lambda_Q-0.5*a2*C_A_2)*T3b_bar[i]+ + 0.5*a2*C_A_2*T4a[i]+0.5*a3*C_A_3*T4a_bar[i]+ + (Lambda_Q-0.5*a2*C_A_2)*T4b[i]+(Lambda_Q-0.5*a3*C_A_3)*T4b_bar[i]+ + Lambda_Q*(T7[i]+T7_bar[i])); + } + } + } + break; + case QQBG: + { + // Finish Group Theory Factors: + Y_Q = 1.0/6.0; + Lambda_Q = C_F_3*a3 + C_F_2*a2 + Y_Q*Y_Q*C_F_1*a1; + rho13 = Y_Q*sqrt(a1*a3); + + highC.resize(1,5); + + for (int i=0; i<5; i++) { + highC(0,i) = rho13*4.0*pi*(R1[i]+R1_bar[i]); + + if (order>=1) { + + highC(0,i) += rho13*(-0.5*a3*C_A_3*T1b[i]-0.5*a1*C_A_1*T1b_bar[i]+ + (Lambda_Q-0.5*a3*C_A_3-0.5*a1*C_A_1)*(T1c[i]+T1c_bar[i])+ + 0.5*a3*C_A_3*T3a[i]+0.5*a1*C_A_1*T3a_bar[i]+ + (Lambda_Q-0.5*a3*C_A_3)*T3b[i]+(Lambda_Q-0.5*a1*C_A_1)*T3b_bar[i]+ + 0.5*a1*C_A_1*T4a[i]+0.5*a3*C_A_3*T4a_bar[i]+ + (Lambda_Q-0.5*a1*C_A_1)*T4b[i]+(Lambda_Q-0.5*a3*C_A_3)*T4b_bar[i]+ + Lambda_Q*(T7[i]+T7_bar[i])); + } + } + } + break; + case UUBG: case DDBG: + { + // Finish Group Theory Factors: + if (process==UUBG) { + Y_Q = 2.0/3.0; + Lambda_Q = C_F_3*a3 + Y_Q*Y_Q*C_F_1*a1; + rho13 = Y_Q*sqrt(a1*a3); + } + else if (process==DDBG) { + Y_Q = -1.0/3.0; + Lambda_Q = C_F_3*a3 + Y_Q*Y_Q*C_F_1*a1; + rho13 = Y_Q*sqrt(a1*a3); + } + + highC.resize(1,5); + + for (int i=0; i<5; i++) { + highC(0,i) = rho13*4.0*pi*(R1[i]+R1_bar[i]); + + if (order>=1) { + + highC(0,i) += rho13*(-0.5*a3*C_A_3*T1b[i]-0.5*a1*C_A_1*T1b_bar[i]+ + (Lambda_Q-0.5*a3*C_A_3-0.5*a1*C_A_1)*(T1c[i]+T1c_bar[i])+ + 0.5*a3*C_A_3*T3a[i]+0.5*a1*C_A_1*T3a_bar[i]+ + (Lambda_Q-0.5*a3*C_A_3)*T3b[i]+(Lambda_Q-0.5*a1*C_A_1)*T3b_bar[i]+ + 0.5*a1*C_A_1*T4a[i]+0.5*a3*C_A_3*T4a_bar[i]+ + (Lambda_Q-0.5*a1*C_A_1)*T4b[i]+(Lambda_Q-0.5*a3*C_A_3)*T4b_bar[i]+ + Lambda_Q*(T7[i]+T7_bar[i])); + } + } + } + break; + case QQGG: case QtQtGG: case UUGG: + case tRtRGG: case DDGG: + { + // Finish Group Theory Factors: + if (process==QQGG || process==QtQtGG) { + Y_Q = 1.0/6.0; + Lambda_Q = C_F_3*a3 + C_F_2*a2 + Y_Q*Y_Q*C_F_1*a1; + Lambda_Q_s = C_F_3*a3; + Lambda_Q_ew = C_F_2*a2 + Y_Q*Y_Q*C_F_1*a1; + } + else if (process==UUGG || process==tRtRGG) { + Y_Q = 2.0/3.0; + Lambda_Q = C_F_3*a3 + Y_Q*Y_Q*C_F_1*a1; + Lambda_Q_s = C_F_3*a3; + Lambda_Q_ew = Y_Q*Y_Q*C_F_1*a1; + } + else if (process==DDGG || process==tRtRGG) { + Y_Q = -1.0/3.0; + Lambda_Q = C_F_3*a3 + Y_Q*Y_Q*C_F_1*a1; + Lambda_Q_s = C_F_3*a3; + Lambda_Q_ew = Y_Q*Y_Q*C_F_1*a1; + } + + highC.resize(3,5); + + for (int i=0; i<5; i++) { + highC(0,i) = G_Plus_SU3*(4.0*pi*a3)*(R1[i]+R1_bar[i]); + highC(1,i) = G_Plus_SU3_D*(4.0*pi*a3)*(R1[i]+R1_bar[i]); + highC(2,i) = G_f*4.0*pi*a3*(-0.5*R1[i]+0.5*R1_bar[i]-R2[i]); + + if (order>=1) { + highC(0,i) += G_Plus_SU3*(a3*(Lambda_Q_ew)*(T1c[i]+T1c_bar[i])+ + a3*(Lambda_Q_ew)*(T3b[i]+T3b_bar[i])+ + a3*(Lambda_Q_ew)*(T4b[i]+T4b_bar[i])+ + a3*Lambda_Q_ew*(T7[i]+T7_bar[i])); + highC(1,i) += G_Plus_SU3_D*(a3*(Lambda_Q_ew)*(T1c[i]+T1c_bar[i])+ + a3*(Lambda_Q_ew)*(T3b[i]+T3b_bar[i])+ + a3*(Lambda_Q_ew)*(T4b[i]+T4b_bar[i])+ + a3*Lambda_Q_ew*(T7[i]+T7_bar[i])); + highC(2,i) += G_f*(a3*(-0.5*Lambda_Q_ew)*(T1c[i]-T1c_bar[i])- + 0.5*a3*(Lambda_Q_ew)*(T3b[i]-T3b_bar[i])- + 0.5*a3*(Lambda_Q_ew)*(T4b[i]-T4b_bar[i])+ + a3*(Lambda_Q_ew)*T5b[i]- + 0.5*a3*Lambda_Q_ew*(T7[i]-T7_bar[i])); + if (includeAlphaS2) { + highC(0,i) += G_Plus_SU3*((-0.5*a3*a3*C_A_3)*(T1b[i]+T1b_bar[i])+ + a3*(Lambda_Q_s-a3*C_A_3)*(T1c[i]+T1c_bar[i])+ + 0.5*a3*a3*C_A_3*(T3a[i]+T3a_bar[i])+ + a3*(Lambda_Q_s-0.5*a3*C_A_3)*(T3b[i]+T3b_bar[i])+ + 0.5*a3*a3*C_A_3*(T4a[i]+T4a_bar[i])+ + a3*(Lambda_Q_s-0.5*a3*C_A_3)*(T4b[i]+T4b_bar[i])+ + a3*Lambda_Q_s*(T7[i]+T7_bar[i])) + + G_TT*(-a3*a3*(T1a[i]+T1a_bar[i])+a3*a3*(T1b[i]+T1b_bar[i])+ + a3*a3*(T1c[i]+T1c_bar[i])+2.0*a3*a3*T1d[i]); + highC(1,i) += G_Plus_SU3_D*((-0.5*a3*a3*C_A_3)*(T1b[i]+T1b_bar[i])+ + a3*(Lambda_Q_s-a3*C_A_3)*(T1c[i]+T1c_bar[i])+ + 0.5*a3*a3*C_A_3*(T3a[i]+T3a_bar[i])+ + a3*(Lambda_Q_s-0.5*a3*C_A_3)*(T3b[i]+T3b_bar[i])+ + 0.5*a3*a3*C_A_3*(T4a[i]+T4a_bar[i])+ + a3*(Lambda_Q_s-0.5*a3*C_A_3)*(T4b[i]+T4b_bar[i])+ + a3*Lambda_Q_s*(T7[i]+T7_bar[i])) + + G_TT_3_D*(-a3*a3*(T1a[i]+T1a_bar[i])+a3*a3*(T1b[i]+T1b_bar[i])+ + a3*a3*(T1c[i]+T1c_bar[i])+2.0*a3*a3*T1d[i]); + highC(2,i) += G_f*(0.25*a3*a3*C_A_3*(T1a[i]-T1a_bar[i])+ + a3*(0.25*a3*C_A_3-0.5*Lambda_Q_s)*(T1c[i]-T1c_bar[i])+ + 0.5*a3*a3*C_A_3*T2a[i]+a3*a3*T_CS_3*T2b[i]- + 0.5*a3*a3*C_A_3*T2c[i]+a3*a3*T_WF_3*T2d[i]- + 0.25*a3*a3*C_A_3*(T3a[i]-T3a_bar[i])- + 0.5*a3*(Lambda_Q_s-0.5*a3*C_A_3)*(T3b[i]-T3b_bar[i])- + 0.25*a3*a3*C_A_3*(T4a[i]-T4a_bar[i])- + 0.5*a3*(Lambda_Q_s-0.5*a3*C_A_3)*(T4b[i]-T4b_bar[i])+ + 0.5*a3*a3*C_A_3*T5a[i]+a3*(Lambda_Q_s-0.5*a3*C_A_3)*T5b[i]+ + a3*a3*C_A_3*T6a[i]+a3*a3*C_A_3*T6b[i]+ + a3*a3*T_CS_3*T6c[i]+a3*a3*T_WF_3*T6d[i]- + 0.5*a3*Lambda_Q_s*(T7[i]-T7_bar[i])); + } + } + } + + if ( (process==QtQtGG||process==tRtRGG) && order>=1) { + + if (process==tRtRGG) { + tRorQ = 2.0; + } + else { + tRorQ = 1.0; + } + highC(0,0) += tRorQ*(-1.0*(s*((s+t)*L_t - t*L_u)*y_t*y_t*a3)/(48.*pi*t*u*s)); + highC(0,1) += tRorQ*((s*L_t*y_t*y_t*a3)/(24.*pi*t*s)); + highC(0,2) += tRorQ*(-(s*s*y_t*y_t*a3)/((24.*pi*s*t+24.*pi*t*t)*s)); + highC(0,3) += tRorQ*(-(s*s*y_t*y_t*a3)/((24.*pi*s*t+24.*pi*t*t)*s)); + highC(1,0) += tRorQ*(-1.0*(s*((s+t)*L_t - t*L_u)*y_t*y_t*a3)/(16.*pi*t*u*s)); + highC(1,1) += tRorQ*((s*L_t*y_t*y_t*a3)/(8.*pi*t*s)); + highC(1,2) += tRorQ*(-(s*s*y_t*y_t*a3)/((8.*pi*s*t+8.*pi*t*t)*s)); + highC(1,3) += tRorQ*(-(s*s*y_t*y_t*a3)/((8.*pi*s*t+8.*pi*t*t)*s)); + highC(2,0) += tRorQ*((s*((s+t)*L_t + t*L_u)*y_t*y_t*a3)/(16.*pi*t*u*s)); + highC(2,1) += tRorQ*(((2.*t-2.*t*L_s-s*L_t)*y_t*y_t*a3)/(8.*pi*t*s)); + highC(2,2) += tRorQ*(-1.0*(s*(s+2.*t)*y_t*y_t*a3)/(8.*pi*t*u*s)); + highC(2,3) += tRorQ*(-1.0*(s*(s+2.*t)*y_t*y_t*a3)/(8.*pi*t*u*s)); + } + } + break; + default: + assert(false); + } + return highC; +} + +boost::numeric::ublas::matrix > +HighEnergyMatching::Spin0HighMatching(Energy highScale, + Energy2 s, Energy2 t, Energy2 u, + EWProcess::Process process, + bool oneLoop, bool ) { + using Constants::pi; + unsigned int order = !oneLoop? 0 : 1; + // (If crossed graphs, swap s and t here) + Complex L_s = MinusLog(-s/(highScale*highScale)); + Complex L_t = MinusLog(-t/(highScale*highScale)); + Complex L_u = MinusLog(-u/(highScale*highScale)); + Complex L_s2 = L_s*L_s; + Complex L_t2 = L_t*L_t; + Complex L_u2 = L_u*L_u; + + // Tree-Level: + complex S1 = 2.0/s; + + // Topology T1: + complex T1b = (-L_s2/(2.0*u)*(7.0*t/s+3.0)+2.0/u*L_t2+L_s*L_t*4.0/u*(t-u)/s+ + L_s*2.0/s-4.0/s-pi*pi/(4.0*u)*(11.0+19.0*t/s)); + complex T1b_bar = -1.0*(-L_s2/(2.0*t)*(7.0*u/s+3.0)+2.0/t*L_u2+L_s*L_u*4.0/t*(u-t)/s+ + L_s*2.0/s-4.0/s-pi*pi/(4.0*t)*(11.0+19.0*u/s)); + + // Topologies T2: + complex T2a = 1.0/s*(-2.0*L_s2+8.0*L_s-16.0+pi*pi/3.0); + complex T2b = 1.0/s*(0.5*L_s2+2.0*L_s-4.0-pi*pi/12.0); + + // Topologies T5: + complex T5a = 1.0/s*(-2.0*L_s2+6.0*L_s+pi*pi/3.0-16.0); + complex T5b = 1.0/s*(2.0*L_s-4.0); + + // Topologies T6: + complex T6a = 1.0/s*(-19.0/6.0*L_s+58.0/9.0); + complex T6b = 1.0/s*(-1.0/6.0*L_s+4.0/9.0); + complex T6c = 1.0/s*(2.0/3.0*L_s-16.0/9.0); + complex T6d = 1.0/s*(4.0/3.0*L_s-20.0/9.0); + + // Group Theory Factors / SM parameters needed for matrix elements: + double a1 = ElectroWeakReweighter::coupling()->a1(highScale); + double a2 = ElectroWeakReweighter::coupling()->a2(highScale); + double a3 = ElectroWeakReweighter::coupling()->a3(highScale); + double y_t = ElectroWeakReweighter::coupling()->y_t(highScale); + double Y_phi = 1.0/2.0; + double C_F_3 = 4.0/3.0; + double C_F_2 = 3.0/4.0; + double C_F_1 = 1.0; + double n_g = 3.0; + double n_S = 1.0; + // Factors TBD after fermion helicity is specified: + double Y_Q(0.), Lambda_Q(0.), Lambda_phi(0.); + boost::numeric::ublas::matrix > highC(1,1); + switch (process) { + + case QQPhiPhi: case LLPhiPhi: + // Finish Group Theory Factors: + if (process==QQPhiPhi) { + Y_Q = 1.0/6.0; + Lambda_Q = C_F_3*a3 + C_F_2*a2 + Y_Q*Y_Q*C_F_1*a1; + Lambda_phi = C_F_2*a2+Y_phi*Y_phi*a1; + } + else if (process==LLPhiPhi) { + Y_Q = -1.0/2.0; + Lambda_Q = C_F_2*a2 + Y_Q*Y_Q*C_F_1*a1; + Lambda_phi = C_F_2*a2+Y_phi*Y_phi*a1; + } + highC.resize(2,1); + highC(0,0) = S1*(4.0*pi*a2); + highC(1,0) = S1*(4.0*pi*a1*Y_Q*Y_phi); + if (order>=1) { + highC(0,0) += T1b*(0.5*a2*a2+2.0*a1*a2*Y_Q*Y_phi) + + T1b_bar*(-0.5*a2*a2+2.0*a1*a2*Y_Q*Y_phi) + + T2a*(-a2*a2+Lambda_phi*a2) + T2b*a2*a2 + + T5a*(-a2*a2+Lambda_Q*a2) + T5b*a2*a2 + + T6a*2.0*a2*a2 + T6b*2.0*a2*a2 + + T6c*0.5*a2*a2*n_S + T6d*2.0*a2*a2*n_g; + highC(1,0) += T1b*(3.0/16.0*a2*a2+a1*a1*Y_Q*Y_Q*Y_phi*Y_phi) + + T1b_bar*(3.0/16.0*a2*a2+a1*a1*Y_Q*Y_Q*Y_phi*Y_phi) + + T2a*(Lambda_phi*a1*Y_Q*Y_phi) + T5a*(Lambda_Q*a1*Y_Q*Y_phi) + + T6c*(2.0*a1*a1*n_S*Y_Q*Y_phi*Y_phi*Y_phi) + + T6d*(10.0/3.0*a1*a1*n_g*Y_Q*Y_phi); + // Top Quark contributions: + highC(0,0) += -3.0*y_t*y_t*a2/(4.0*pi)/s*(2.0*L_s-4.0); + highC(1,0) += -3.0*y_t*y_t*a1/(4.0*pi)*(Y_Q*Y_phi)/s*(2.0*L_s-4.0); + } + break; + case UUPhiPhi: case DDPhiPhi: case EEPhiPhi: + // Finish Group Theory Factors: + if (process==UUPhiPhi) { + Y_Q = 2.0/3.0; + Lambda_Q = C_F_3*a3 + Y_Q*Y_Q*C_F_1*a1; + Lambda_phi = C_F_2*a2 + Y_phi*Y_phi*a1; + } + else if (process==DDPhiPhi) { + Y_Q = -1.0/3.0; + Lambda_Q = C_F_3*a3 + Y_Q*Y_Q*C_F_1*a1; + Lambda_phi = C_F_2*a2 + Y_phi*Y_phi*a1; + } + else if (process==EEPhiPhi) { + Y_Q = -1.0; + Lambda_Q = Y_Q*Y_Q*C_F_1*a1; + Lambda_phi = C_F_2*a2 + Y_phi*Y_phi*a1; + } + + highC.resize(1,1); + highC(0,0) = ZERO; + + highC(0,0) = S1*(4.0*pi*a1*Y_Q*Y_phi); + + if (order>=1) { + highC(0,0) += T1b*(a1*a1*Y_Q*Y_Q*Y_phi*Y_phi) + + T1b_bar*(a1*a1*Y_Q*Y_Q*Y_phi*Y_phi) + + T2a*(Lambda_phi*a1*Y_Q*Y_phi) + T5a*(Lambda_Q*a1*Y_Q*Y_phi) + + T6c*(2.0*a1*a1*n_S*Y_Q*Y_phi*Y_phi*Y_phi) + + T6d*(10.0/3.0*a1*a1*n_g*Y_Q*Y_phi); + // Top Quark Contribution: + highC(0,0) += -3.0*y_t*y_t*a1/(4.0*pi)*(Y_Q*Y_phi)/s*(2.0*L_s-4.0); + } + break; + default: + assert(false); + } + return highC; +} diff --git a/MatrixElement/EW/HighEnergyMatching.h b/MatrixElement/EW/HighEnergyMatching.h new file mode 100644 --- /dev/null +++ b/MatrixElement/EW/HighEnergyMatching.h @@ -0,0 +1,64 @@ +// -*- C++ -*- +// +// HighEnergyMatching.h is a part of Herwig - A multi-purpose Monte Carlo event generator +// +// Herwig is licenced under version 2 of the GPL, see COPYING for details. +// Please respect the MCnet academic guidelines, see GUIDELINES for details. +// +// +// +#ifndef HERWIG_HighEnergyMatching_H +#define HERWIG_HighEnergyMatching_H +#include "ThePEG/Config/ThePEG.h" +#include "ThePEG/Config/Unitsystem.h" +#include "EWProcess.h" +// work around a Boost 1.64 bug where ublas headers would fail otherwise +#include +#if (BOOST_VERSION / 100 >= 1064) +#include +#endif +#include + +namespace Herwig { +using namespace ThePEG; + +namespace HighEnergyMatching { + + /** + * The high energy matching + */ + boost::numeric::ublas::matrix > + highEnergyMatching(Energy highScale, + Energy2 s, Energy2 t, Energy2 u, + Herwig::EWProcess::Process process, + bool oneLoop, bool includeAlphaS2); + + /** + * Spin\f$\frac12\f$ + */ + boost::numeric::ublas::matrix > + SpinHalfMatching(Energy highScale, + Energy2 s, Energy2 t, Energy2 u, + EWProcess::Process process, + bool oneLoop, bool includeAlphaS2); + + /** + * Spin\f$1\f$ + */ + boost::numeric::ublas::matrix > + Spin1HighMatching(Energy highScale, + Energy2 s, Energy2 t, Energy2 u, + EWProcess::Process process, + bool oneLoop, bool includeAlphaS2); + /** + * Spin\f$0\f$ + */ + boost::numeric::ublas::matrix > + Spin0HighMatching(Energy highScale, + Energy2 s, Energy2 t, Energy2 u, + EWProcess::Process process, + bool oneLoop, bool includeAlphaS2); +} +} + +#endif // HERWIG_HighEnergyMatching_H diff --git a/MatrixElement/Makefile.am b/MatrixElement/EW/Makefile.am copy from MatrixElement/Makefile.am copy to MatrixElement/EW/Makefile.am --- a/MatrixElement/Makefile.am +++ b/MatrixElement/EW/Makefile.am @@ -1,18 +1,10 @@ -SUBDIRS = General Lepton Hadron DIS Powheg Gamma Matchbox Reweighters - -if WANT_LIBFASTJET -SUBDIRS += FxFx -endif - -noinst_LTLIBRARIES = libHwME.la - -libHwME_la_SOURCES = \ -HwMEBase.h HwMEBase.fh HwMEBase.cc \ -MEMultiChannel.h MEMultiChannel.cc \ -MEfftoVH.h MEfftoVH.cc \ -MEfftoffH.h MEfftoffH.cc \ -HardVertex.fh HardVertex.h HardVertex.cc \ -ProductionMatrixElement.h ProductionMatrixElement.cc \ -DrellYanBase.h DrellYanBase.cc \ -BlobME.h BlobME.cc \ -MEMinBias.h MEMinBias.cc +pkglib_LTLIBRARIES = HwMEEW.la +HwMEEW_la_SOURCES = EWProcess.h GroupInvariants.h GroupInvariants.cc \ +ElectroWeakReweigter.h ElectroWeakReweighter.cc \ +SoftSudakov.h SoftSudakov.cc \ +CollinearSudakov.h CollinearSudakov.cc \ +HighEnergyMatching.h HighEnergyMatching.cc \ +ElectroWeakMatching.h ElectroWeakMatching.cc \ +EWCouplings.h EWCouplings.fh EWCouplings.cc \ +expm-1.hpp +HwMEEW_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 1:0:0 diff --git a/MatrixElement/EW/SoftSudakov.cc b/MatrixElement/EW/SoftSudakov.cc new file mode 100644 --- /dev/null +++ b/MatrixElement/EW/SoftSudakov.cc @@ -0,0 +1,1321 @@ +// -*- C++ -*- +// +// This is the implementation of the non-inlined, non-templated member +// functions of the SoftSudakov class. +// + +#include "SoftSudakov.h" +#include "ThePEG/Interface/ClassDocumentation.h" +#include "ThePEG/EventRecord/Particle.h" +#include "ThePEG/Repository/UseRandom.h" +#include "ThePEG/Repository/EventGenerator.h" +#include "ThePEG/Utilities/DescribeClass.h" +#include "GroupInvariants.h" +#include "ThePEG/Persistency/PersistentOStream.h" +#include "ThePEG/Persistency/PersistentIStream.h" +#include "expm-1.h" + +using namespace Herwig; +using namespace GroupInvariants; + +SoftSudakov::SoftSudakov() : K_ORDER_(3), integrator_(0.,1e-5,1000) {} + +SoftSudakov::~SoftSudakov() {} + +IBPtr SoftSudakov::clone() const { + return new_ptr(*this); +} + +IBPtr SoftSudakov::fullclone() const { + return new_ptr(*this); +} + +void SoftSudakov::persistentOutput(PersistentOStream & os) const { + os << K_ORDER_; +} + +void SoftSudakov::persistentInput(PersistentIStream & is, int) { + is >> K_ORDER_; +} + + +// The following static variable is needed for the type +// description system in ThePEG. +DescribeClass +describeHerwigSoftSudakov("Herwig::SoftSudakov", "HwMEEW.so"); + +void SoftSudakov::Init() { + + static ClassDocumentation documentation + ("The SoftSudakov class implements the soft EW Sudakov"); + +} + +InvEnergy SoftSudakov::operator ()(Energy mu) const { + // Include K-factor Contributions (Cusps): + GaugeContributions cusp = cuspContributions(mu,K_ORDER_,high_); + Complex gamma = cusp.SU3*G3_(row_,col_) + cusp.SU2*G2_(row_,col_) + cusp.U1*G1_(row_,col_); + if (real_) { + return gamma.real()/mu; + } + else { + return gamma.imag()/mu; + } +} + +boost::numeric::ublas::matrix +SoftSudakov::evaluateSoft(boost::numeric::ublas::matrix & G3, + boost::numeric::ublas::matrix & G2, + boost::numeric::ublas::matrix & G1, + Energy mu_h, Energy mu_l, bool high) { + assert( G3.size1() == G2.size1() && G3.size1() == G1.size1() && + G3.size2() == G2.size2() && G3.size2() == G1.size2() && + G3.size1() == G3.size2()); + G3_ = G3; + G2_ = G2; + G1_ = G1; + high_ = high; + unsigned int NN = G3_.size1(); + // gamma is the matrix to be numerically integrated to run the coefficients. + boost::numeric::ublas::matrix gamma(NN,NN); + for(row_=0;row_ +SoftSudakov::lowEnergyRunning(Energy EWScale, Energy lowScale, + Energy2 s, Energy2 t, Energy2 u, + Herwig::EWProcess::Process process, + unsigned int iswap) { + using namespace EWProcess; + using namespace boost::numeric::ublas; + using Constants::pi; + static const Complex I(0,1.0); + Complex T = getT(s,t), U = getU(s,u); + matrix G1, G2, G3; + unsigned int numBrokenGauge; + switch (process) { + case QQQQ: + case QQQQiden: + case QtQtQQ: + { + numBrokenGauge = 12; + G1 = zero_matrix(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + matrix gam3; + if(iswap==0) { + gam3 = Gamma3(U,T); + G1(0,0) = G1(6,6) = Gamma1(2.0/3.0,2.0/3.0,2.0/3.0,2.0/3.0,T,U); + G1(1,1) = G1(7,7) = Gamma1(-1.0/3.0,-1.0/3.0,2.0/3.0,2.0/3.0,T,U); + G1(2,2) = G1(8,8) = Gamma1(2.0/3.0,2.0/3.0,-1.0/3.0,-1.0/3.0,T,U); + G1(3,3) = G1(9,9) = Gamma1(-1.0/3.0,-1.0/3.0,-1.0/3.0,-1.0/3.0,T,U); + G1(4,4) = G1(10,10) = Gamma1(-1.0/3.0,2.0/3.0,2.0/3.0,-1.0/3.0,T,U); + G1(5,5) = G1(11,11) = Gamma1(2.0/3.0,-1.0/3.0,-1.0/3.0,2.0/3.0,T,U); + } + else if(iswap==1) { + gam3 = Gamma3ST(U,T); + G1(0,0) = G1(6,6) = Gamma1ST(2.0/3.0,2.0/3.0,2.0/3.0,2.0/3.0,T,U); + G1(1,1) = G1(7,7) = Gamma1ST(-1.0/3.0,-1.0/3.0,2.0/3.0,2.0/3.0,T,U); + G1(2,2) = G1(8,8) = Gamma1ST(2.0/3.0,2.0/3.0,-1.0/3.0,-1.0/3.0,T,U); + G1(3,3) = G1(9,9) = Gamma1ST(-1.0/3.0,-1.0/3.0,-1.0/3.0,-1.0/3.0,T,U); + G1(4,4) = G1(10,10) = Gamma1ST(-1.0/3.0,2.0/3.0,2.0/3.0,-1.0/3.0,T,U); + G1(5,5) = G1(11,11) = Gamma1ST(2.0/3.0,-1.0/3.0,-1.0/3.0,2.0/3.0,T,U); + } + else if(iswap==2) { + gam3 = Gamma3SU(U,T); + G1(0,0) = G1(6,6) = Gamma1SU( 2.0/3.0,2.0/3.0,2.0/3.0,2.0/3.0,T,U); + G1(1,1) = G1(7,7) = Gamma1SU(-1.0/3.0,-1.0/3.0,2.0/3.0,2.0/3.0,T,U); + G1(2,2) = G1(8,8) = Gamma1SU( 2.0/3.0,2.0/3.0,-1.0/3.0,-1.0/3.0,T,U); + G1(3,3) = G1(9,9) = Gamma1SU(-1.0/3.0,-1.0/3.0,-1.0/3.0,-1.0/3.0,T,U); + G1(4,4) = G1(10,10) = Gamma1SU(-1.0/3.0,2.0/3.0,2.0/3.0,-1.0/3.0,T,U); + G1(5,5) = G1(11,11) = Gamma1SU( 2.0/3.0,-1.0/3.0,-1.0/3.0,2.0/3.0,T,U); + } + else + assert(false); + for (unsigned int i=0; i(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + matrix gam3; + if(iswap==0) { + gam3 = Gamma3(U,T); + G1(0,0) = G1(2,2) = Gamma1(2.0/3.0,2.0/3.0,T,U); + G1(1,1) = G1(3,3) = Gamma1(2.0/3.0,-1.0/3.0,T,U); + } + else if(iswap==1) { + gam3 = Gamma3ST(U,T); + G1(0,0) = G1(2,2) = Gamma1ST(2.0/3.0,2.0/3.0,T,U); + G1(1,1) = G1(3,3) = Gamma1ST(2.0/3.0,-1.0/3.0,T,U); + } + else if(iswap==2) { + gam3 = Gamma3SU(U,T); + G1(0,0) = G1(2,2) = Gamma1SU(2.0/3.0,2.0/3.0,T,U); + G1(1,1) = G1(3,3) = Gamma1SU(2.0/3.0,-1.0/3.0,T,U); + } + else + assert(false); + + for (unsigned int i=0; i(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + matrix gam3; + if(iswap==0) { + gam3 = Gamma3(U,T); + G1(0,0) = G1(2,2) = Gamma1(-1.0/3.0,2.0/3.0,T,U); + G1(1,1) = G1(3,3) = Gamma1(-1.0/3.0,-1.0/3.0,T,U); + } + else if(iswap==1) { + gam3 = Gamma3ST(U,T); + G1(0,0) = G1(2,2) = Gamma1ST(-1.0/3.0,2.0/3.0,T,U); + G1(1,1) = G1(3,3) = Gamma1ST(-1.0/3.0,-1.0/3.0,T,U); + } + else if(iswap==2) { + gam3 = Gamma3SU(U,T); + G1(0,0) = G1(2,2) = Gamma1SU(-1.0/3.0,2.0/3.0,T,U); + G1(1,1) = G1(3,3) = Gamma1SU(-1.0/3.0,-1.0/3.0,T,U); + } + else + assert(false); + for (unsigned int i=0; i(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + Complex gam3s = Gamma3Singlet()(0,0); + for (unsigned int i=0; i(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + Complex gam3s = Gamma3Singlet()(0,0); + for (unsigned int i=0; i<2; i++) { + G3(i,i) += gam3s; + } + G1(0,0) = Gamma1(2.0/3.0,-1.0,T,U); + G1(1,1) = Gamma1(-1.0/3.0,-1.0,T,U); + } + break; + case UUUU: + case UUUUiden: + case tRtRUU: + numBrokenGauge = 2; + G1 = zero_matrix(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + if(iswap==0) { + G3 = Gamma3(U,T); + G1(0,0) = G1(1,1) = Gamma1(2.0/3.0,2.0/3.0,T,U); + } + else if(iswap==1) { + G3 = Gamma3ST(U,T); + G1(0,0) = G1(1,1) = Gamma1ST(2.0/3.0,2.0/3.0,T,U); + } + else if(iswap==2) { + G3 = Gamma3SU(U,T); + G1(0,0) = G1(1,1) = Gamma1SU(2.0/3.0,2.0/3.0,T,U); + } + else + assert(false); + break; + case UUDD: + case tRtRDD: + numBrokenGauge = 2; + G1 = zero_matrix(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + if(iswap==0) { + G3 = Gamma3(U,T); + G1(0,0) = G1(1,1) = Gamma1(-1.0/3.0,2.0/3.0,T,U); + } + else if(iswap==1) { + G3 = Gamma3ST(U,T); + G1(0,0) = G1(1,1) = Gamma1ST(-1.0/3.0,2.0/3.0,T,U); + } + else if(iswap==2) { + G3 = Gamma3SU(U,T); + G1(0,0) = G1(1,1) = Gamma1SU(-1.0/3.0,2.0/3.0,T,U); + } + else + assert(false); + break; + case UULL: + assert(iswap==0); + numBrokenGauge = 2; + G1 = zero_matrix(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3(0,0) = G3(1,1) = Gamma3Singlet()(0,0); + G1(0,0) = Gamma1(2.0/3.0,0.0,T,U); + G1(1,1) = Gamma1(2.0/3.0,-1.0,T,U); + break; + case UUEE: + assert(iswap==0); + numBrokenGauge = 1; + G1 = zero_matrix(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3(0,0) = Gamma3Singlet()(0,0); + G1(0,0) = Gamma1(2.0/3.0,-1.0,T,U); + break; + case DDDD: + case DDDDiden: + numBrokenGauge = 2; + G1 = zero_matrix(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + if(iswap==0) { + G3 = Gamma3(U,T); + G1(0,0) = G1(1,1) = Gamma1(-1.0/3.0,-1.0/3.0,T,U); + } + else if(iswap==1) { + G3 = Gamma3ST(U,T); + G1(0,0) = G1(1,1) = Gamma1ST(-1.0/3.0,-1.0/3.0,T,U); + } + else if(iswap==2) { + G3 = Gamma3SU(U,T); + G1(0,0) = G1(1,1) = Gamma1SU(-1.0/3.0,-1.0/3.0,T,U); + } + else + assert(false); + break; + case DDLL: + assert(iswap==0); + numBrokenGauge = 2; + G1 = zero_matrix(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3(0,0) = G3(1,1) = Gamma3Singlet()(0,0); + G1(0,0) = Gamma1(-1.0/3.0,0.0,T,U); + G1(1,1) = Gamma1(-1.0/3.0,-1.0,T,U); + break; + case DDEE: + assert(iswap==0); + numBrokenGauge = 1; + G1 = zero_matrix(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3(0,0) = Gamma3Singlet()(0,0); + G1(0,0) = Gamma1(-1.0/3.0,-1.0,T,U); + break; + case LLLL: + case LLLLiden: + assert(iswap==0); + numBrokenGauge = 6; + G1 = zero_matrix(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + G1(0,0) = Gamma1(0.0,0.0,0.0,0.0,T,U); + G1(1,1) = Gamma1(-1.0,-1.0,0.0,0.0,T,U); + G1(2,2) = Gamma1(0.0,0.0,-1.0,-1.0,T,U); + G1(3,3) = Gamma1(-1.0,-1.0,-1.0,-1.0,T,U); + G1(4,4) = Gamma1(-1.0,0.0,0.0,-1.0,T,U); + G1(5,5) = Gamma1(0.0,-1.0,-1.0,0.0,T,U); + break; + + case LLEE: + assert(iswap==0); + numBrokenGauge = 2; + G1 = zero_matrix(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + G1(0,0) = Gamma1(0.0,-1.0,T,U); + G1(1,1) = Gamma1(-1.0,-1.0,T,U); + break; + case EEEE: + case EEEEiden: + assert(iswap==0); + numBrokenGauge = 1; + G1 = zero_matrix(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + G1(0,0) = Gamma1(-1.0,-1.0,T,U); + break; + case QQWW: + { + assert(iswap==0); + numBrokenGauge = 20; + G1 = zero_matrix(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + Complex gam3s = Gamma3Singlet()(0,0); + for (unsigned int i=0; i(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + Complex gam3s = Gamma3Singlet()(0,0); + for (unsigned int i=0; i(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + for (unsigned int i=0; i(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + for (unsigned int i=0; i(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + matrix gam3g; + Complex gam1a(0.),gam1b(0.); + if(iswap==0) { + gam3g = Gamma3g(U,T); + gam1a = Gamma1( 2./3.,0.,T,U); + gam1b = Gamma1(-1./3.,0.,T,U); + } + else if(iswap==1) { + gam3g = Gamma3gST(U,T); + gam1a = Gamma1ST( 2./3.,0.,T,U); + gam1b = Gamma1ST(-1./3.,0.,T,U); + } + else if(iswap==2) { + gam3g = Gamma3gSU(U,T); + gam1a = Gamma1SU( 2./3.,0.,T,U); + gam1b = Gamma1SU(-1./3.,0.,T,U); + } + else + assert(false); + for(unsigned int ix=0;ix<3;++ix) { + for(unsigned int iy=0;iy<3;++iy) { + G3(ix ,iy ) = gam3g(ix,iy); + G3(ix+3,iy+3) = gam3g(ix,iy); + } + } + G1(0,0) = G1(1,1) = G1(2,2) = gam1a; + G1(3,3) = G1(4,4) = G1(5,5) = gam1b; + } + break; + case LLWW: + assert(iswap==0); + numBrokenGauge = 20; + G1 = zero_matrix(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + G1(0,0) = Gamma1(0.,0.,-1.,-1.,T,U); + G1(1,1) = Gamma1(0.,0.,1.,1.,T,U); + G1(2,2) = Gamma1(0.,0.,0.,0.,T,U); + G1(3,3) = Gamma1(0.,0.,0.,0.,T,U); + G1(4,4) = Gamma1(0.,0.,0.,0.,T,U); + G1(5,5) = Gamma1(0.,0.,0.,0.,T,U); + G1(6,6) = Gamma1(-1.,-1.,-1.,-1.,T,U); + G1(7,7) = Gamma1(-1.,-1.,1.,1.,T,U); + G1(8,8) = Gamma1(-1.,-1.,0.,0.,T,U); + G1(9,9) = Gamma1(-1.,-1.,0.,0.,T,U); + G1(10,10) = Gamma1(-1.,-1.,0.,0.,T,U); + G1(11,11) = Gamma1(-1.,-1.,0.,0.,T,U); + G1(12,12) = Gamma1(-1.,0.,0.,-1.,T,U); + G1(13,13) = Gamma1(-1.,0.,0.,-1.,T,U); + G1(14,14) = Gamma1(-1.,0.,1.,0.,T,U); + G1(15,15) = Gamma1(-1.,0.,1.,0.,T,U); + G1(16,16) = Gamma1(0.,-1.,-1.,0.,T,U); + G1(17,17) = Gamma1(0.,-1.,-1.,0.,T,U); + G1(18,18) = Gamma1(0.,-1.,0.,1.,T,U); + G1(19,19) = Gamma1(0.,-1.,0.,1.,T,U); + break; + case LLPhiPhi: + assert(iswap==0); + numBrokenGauge = 14; + G1 = zero_matrix(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + G1(0,0) = Gamma1(0.,0.,1.,1.,T,U); + G1(1,1) = Gamma1(0.,0.,0.,0.,T,U); + G1(2,2) = Gamma1(0.,0.,0.,0.,T,U); + G1(3,3) = Gamma1(0.,0.,0.,0.,T,U); + G1(4,4) = Gamma1(0.,0.,0.,0.,T,U); + G1(5,5) = Gamma1(-1.,-1.,1.,1.,T,U); + G1(6,6) = Gamma1(-1.,-1.,0.,0.,T,U); + G1(7,7) = Gamma1(-1.,-1.,0.,0.,T,U); + G1(8,8) = Gamma1(-1.,-1.,0.,0.,T,U); + G1(9,9) = Gamma1(-1.,-1.,0.,0.,T,U); + G1(10,10) = Gamma1(-1.,0.,1.,0.,T,U); + G1(11,11) = Gamma1(-1.,0.,1.,0.,T,U); + G1(12,12) = Gamma1(0.,-1.,0.,1.,T,U); + G1(13,13) = Gamma1(0.,-1.,0.,1.,T,U); + break; + case UUBB: + { + assert(iswap==0); + numBrokenGauge = 4; + G1 = zero_matrix(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + Complex gam3s = Gamma3Singlet()(0,0); + for (unsigned int i=0; i(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + Complex gam3s = Gamma3Singlet()(0,0); + for (unsigned int i=0; i(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + Complex gam1 = Gamma1(2./3.,0.,T,U); + for (unsigned int i=0; i(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + Complex gam1(0.); + double Y = process==DDGG ? -1./3. : 2./3.; + if(iswap==0) { + G3 = Gamma3g(U,T); + gam1 = Gamma1(Y,0.,T,U); + } + else if(iswap==1) { + G3 = Gamma3gST(U,T); + gam1 = Gamma1ST(Y,0.,T,U); + } + else if(iswap==2) { + G3 = Gamma3gSU(U,T); + gam1 = Gamma1SU(Y,0.,T,U); + } + else + assert(false); + G1(0,0) = G1(1,1) = G1(2,2) = gam1; + } + break; + case DDBB: + { + assert(iswap==0); + numBrokenGauge = 4; + G1 = zero_matrix(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + Complex gam3s = Gamma3Singlet()(0,0); + Complex gam1 = Gamma1(-1./3.,0.,T,U); + for (unsigned int i=0; i(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + Complex gam3s = Gamma3Singlet()(0,0); + for (unsigned int i=0; i(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + for (unsigned int i=0; i(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + Complex gam1 = Gamma1(-1.,0.,T,U); + for (unsigned int i=0; i(numBrokenGauge,numBrokenGauge); + G2 = zero_matrix(numBrokenGauge,numBrokenGauge); + G3 = zero_matrix(numBrokenGauge,numBrokenGauge); + G1(0,0) = Gamma1(-1.,1.,T,U); + G1(1,1) = G1(2,2) = G1(3,3) = G1(4,4) = Gamma1(-1.,0.,T,U); + break; + default: + assert(false); + } + // return the answer + if (EWScale==lowScale) { + return identity_matrix(G1.size1()); + } + else { + return evaluateSoft(G3,G2,G1,EWScale,lowScale,false); + } +} + +boost::numeric::ublas::matrix +SoftSudakov::highEnergyRunning(Energy highScale, Energy EWScale, + Energy2 s, Energy2 t, Energy2 u, + Herwig::EWProcess::Process process, + unsigned int iswap) { + using namespace EWProcess; + using namespace boost::numeric::ublas; + using Constants::pi; + static const Complex I(0,1.0); + Complex T = getT(s,t), U = getU(s,u); + matrix G1,G2,G3; + unsigned int numGauge; + switch (process) { + case QQQQ: + case QQQQiden: + case QtQtQQ: + { + numGauge = 4; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + G3 = zero_matrix(numGauge,numGauge); + matrix gam3,gam2; + if(iswap==0) { + gam3 = Gamma3(U,T); + gam2 = Gamma2(U,T); + G1(0,0) = G1(1,1) = G1(2,2) = G1(3,3) = Gamma1(1.0/6.0,1.0/6.0,T,U); + } + else if(iswap==1) { + gam3 = Gamma3ST(U,T); + gam2 = Gamma2ST(U,T); + G1(0,0) = G1(1,1) = G1(2,2) = G1(3,3) = Gamma1ST(1.0/6.0,1.0/6.0,T,U); + } + else if(iswap==2) { + gam3 = Gamma3SU(U,T); + gam2 = Gamma2SU(U,T); + G1(0,0) = G1(1,1) = G1(2,2) = G1(3,3) = Gamma1SU(1.0/6.0,1.0/6.0,T,U); + } + else + assert(false); + G3(0,0) += gam3(0,0); + G3(0,2) += gam3(0,1); + G3(2,0) += gam3(1,0); + G3(2,2) += gam3(1,1); + G3(1,1) += gam3(0,0); + G3(1,3) += gam3(0,1); + G3(3,1) += gam3(1,0); + G3(3,3) += gam3(1,1); + G2(0,0) += gam2(0,0); + G2(0,1) += gam2(0,1); + G2(1,0) += gam2(1,0); + G2(1,1) += gam2(1,1); + G2(2,2) += gam2(0,0); + G2(2,3) += gam2(0,1); + G2(3,2) += gam2(1,0); + G2(3,3) += gam2(1,1); + } + break; + case QQUU: + case QtQtUU: + case QQtRtR: + numGauge = 2; + G1 = zero_matrix(numGauge,numGauge); + if(iswap==0) { + G3 = Gamma3(U,T); + G2 = Gamma2Singlet(); + G1(0,0) = G1(1,1) = Gamma1(2.0/3.0,1.0/6.0,T,U); + } + else if(iswap==1) { + G3 = Gamma3ST(U,T); + G2 = Gamma2SingletST(T); + G1(0,0) = G1(1,1) = Gamma1ST(2.0/3.0,1.0/6.0,T,U); + } + else if(iswap==2) { + G3 = Gamma3SU(U,T); + G2 = Gamma2SingletSU(U); + G1(0,0) = G1(1,1) = Gamma1SU(2.0/3.0,1.0/6.0,T,U); + } + else + assert(false); + break; + case QQDD: + case QtQtDD: + numGauge = 2; + G1 = zero_matrix(numGauge,numGauge); + if(iswap==0) { + G3 = Gamma3(U,T); + G2 = Gamma2Singlet(); + G1(0,0) = G1(1,1) = Gamma1(-1.0/3.0,1.0/6.0,T,U); + } + else if(iswap==1) { + G3 = Gamma3ST(U,T); + G2 = Gamma2SingletST(T); + G1(0,0) = G1(1,1) = Gamma1ST(-1.0/3.0,1.0/6.0,T,U); + } + else if(iswap==2) { + G3 = Gamma3SU(U,T); + G2 = Gamma2SingletSU(U); + G1(0,0) = G1(1,1) = Gamma1SU(-1.0/3.0,1.0/6.0,T,U); + } + else + assert(false); + break; + case QQLL: + assert(iswap==0); + numGauge = 2; + G1 = zero_matrix(numGauge,numGauge); + G3 = Gamma3Singlet(); + G2 = Gamma2(U,T); + G1(0,0) = G1(1,1) = Gamma1(-1.0/2.0,1.0/6.0,T,U); + break; + case QQEE: + assert(iswap==0); + numGauge = 1; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + G3 = zero_matrix(numGauge,numGauge); + G3(0,0) = Gamma3Singlet()(0,0); + G2(0,0) = Gamma2Singlet()(0,0); + G1(0,0) = Gamma1(-1.0,1.0/6.0,T,U); + break; + case UUUU: + case UUUUiden: + case tRtRUU: + numGauge = 2; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + if(iswap==0) { + G3 = Gamma3(U,T); + G1(0,0) = G1(1,1) = Gamma1(2.0/3.0,2.0/3.0,T,U); + } + else if(iswap==1) { + G3 = Gamma3ST(U,T); + G1(0,0) = G1(1,1) = Gamma1ST(2.0/3.0,2.0/3.0,T,U); + } + else if(iswap==2) { + G3 = Gamma3SU(U,T); + G1(0,0) = G1(1,1) = Gamma1SU(2.0/3.0,2.0/3.0,T,U); + } + else + assert(false); + break; + case UUDD: + case tRtRDD: + numGauge = 2; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + if(iswap==0) { + G3 = Gamma3(U,T); + G1(0,0) = G1(1,1) = Gamma1(-1.0/3.0,2.0/3.0,T,U); + } + else if(iswap==1) { + G3 = Gamma3ST(U,T); + G1(0,0) = G1(1,1) = Gamma1ST(-1.0/3.0,2.0/3.0,T,U); + } + else if(iswap==2) { + G3 = Gamma3SU(U,T); + G1(0,0) = G1(1,1) = Gamma1SU(-1.0/3.0,2.0/3.0,T,U); + } + else + assert(false); + break; + case UULL: + assert(iswap==0); + numGauge = 1; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + G3 = zero_matrix(numGauge,numGauge); + G3(0,0) = Gamma3Singlet()(0,0); + G2(0,0) = Gamma2Singlet()(0,0); + G1(0,0) = Gamma1(-1.0/2.0,2.0/3.0,T,U); + break; + case UUEE: + assert(iswap==0); + numGauge = 1; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + G3 = zero_matrix(numGauge,numGauge); + G3(0,0) = Gamma3Singlet()(0,0); + G1(0,0) = Gamma1(-1.0,2.0/3.0,T,U); + break; + case DDDD: + case DDDDiden: + numGauge = 2; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + if(iswap==0) { + G3 = Gamma3(U,T); + G1(0,0) = G1(1,1) = Gamma1(-1.0/3.0,-1.0/3.0,T,U); + } + else if(iswap==1) { + G3 = Gamma3ST(U,T); + G1(0,0) = G1(1,1) = Gamma1ST(-1.0/3.0,-1.0/3.0,T,U); + } + else if(iswap==2) { + G3 = Gamma3SU(U,T); + G1(0,0) = G1(1,1) = Gamma1SU(-1.0/3.0,-1.0/3.0,T,U); + } + else + assert(false); + break; + case DDLL: + assert(iswap==0); + numGauge = 1; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + G3 = zero_matrix(numGauge,numGauge); + G3(0,0) = Gamma3Singlet()(0,0); + G2(0,0) = Gamma2Singlet()(0,0); + G1(0,0) = Gamma1(-1.0/2.0,-1.0/3.0,T,U); + break; + case DDEE: + assert(iswap==0); + numGauge = 1; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + G3 = zero_matrix(numGauge,numGauge); + G3(0,0) = Gamma3Singlet()(0,0); + G1(0,0) = Gamma1(-1.0,-1.0/3.0,T,U); + break; + case LLLL: + case LLLLiden: + assert(iswap==0); + numGauge = 2; + G1 = zero_matrix(numGauge,numGauge); + G3 = zero_matrix(numGauge,numGauge); + G2 = Gamma2(U,T); + G1(0,0) = G1(1,1) = Gamma1(-1.0/2.0,-1.0/2.0,T,U); + break; + case LLEE: + assert(iswap==0); + numGauge = 1; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + G3 = zero_matrix(numGauge,numGauge); + G2(0,0) = Gamma2Singlet()(0,0); + G1(0,0) = Gamma1(-1.0,-1.0/2.0,T,U); + break; + case EEEE: + case EEEEiden: + assert(iswap==0); + numGauge = 1; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + G3 = zero_matrix(numGauge,numGauge); + G1(0,0) = Gamma1(-1.0,-1.0,T,U); + break; + case QQWW: + { + assert(iswap==0); + numGauge = 5; + G1 = zero_matrix(numGauge,numGauge); + G3 = zero_matrix(numGauge,numGauge); + Complex gam3s = Gamma3Singlet()(0,0); + for (unsigned int i=0; i<5; i++) { + G3(i,i) = gam3s; + G1(i,i) = Gamma1(1.0/6.0); + } + G2 = Gamma2w(U,T); + } + break; + case QQPhiPhi: + assert(iswap==0); + numGauge = 2; + G1 = zero_matrix(numGauge,numGauge); + G3 = Gamma3Singlet(); + G2 = Gamma2(U,T); + G1(0,0) = G1(1,1) = Gamma1(1.0/2.0,1.0/6.0,T,U); + break; + case QQWG: + assert(iswap==0); + numGauge = 1; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + G3 = zero_matrix(numGauge,numGauge); + G3(0,0) = -17.0/6.0*I*pi + 3.0/2.0*(U+T); + G2(0,0) = -7.0/4.0*I*pi + (U+T); + G1(0,0) = Gamma1(1.0/6.0); + break; + case QQBG: + assert(iswap==0); + numGauge = 1; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + G3 = zero_matrix(numGauge,numGauge); + G3(0,0) = -4.0/3.0*I*pi + 3.0/2.0*(U+T-I*pi); + G2(0,0) = -3.0/4.0*I*pi; + G1(0,0) = Gamma1(1.0/6.0); + break; + case QQGG: + case QtQtGG: + { + numGauge = 3; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + Complex gam2s,gam1; + if(iswap==0) { + G3 = Gamma3g(U,T); + gam2s = Gamma2Singlet()(0,0); + gam1 = Gamma1(1.0/6.0); + } + else if(iswap==1) { + G3 = Gamma3gST(U,T); + gam2s = Gamma2SingletST(T)(0,0); + gam1 = Gamma1ST(1.0/6.0,T); + } + else if(iswap==2) { + G3 = Gamma3gSU(U,T); + gam2s = Gamma2SingletSU(U)(0,0); + gam1 = Gamma1SU(1.0/6.0,U); + } + else + assert(false); + for (unsigned int i=0; i<3; i++) { + G2(i,i) = gam2s; + G1(i,i) = gam1; + } + } + break; + case LLWW: + assert(iswap==0); + numGauge = 5; + G1 = zero_matrix(numGauge,numGauge); + G3 = zero_matrix(numGauge,numGauge); + for (unsigned int i=0; i<5; i++) { + G1(i,i) = Gamma1(-1.0/2.0); + } + G2 = Gamma2w(U,T); + break; + case LLPhiPhi: + assert(iswap==0); + numGauge = 2; + G1 = zero_matrix(numGauge,numGauge); + G3 = zero_matrix(numGauge,numGauge); + G2 = Gamma2(U,T); + G1(0,0) = G1(1,1) = Gamma1(1.0/2.0,-1.0/2.0,T,U); + break; + case UUBB: + assert(iswap==0); + numGauge = 1; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + G3 = zero_matrix(numGauge,numGauge); + G3(0,0) = Gamma3Singlet()(0,0); + G1(0,0) = Gamma1(2.0/3.0); + break; + case UUPhiPhi: + assert(iswap==0); + numGauge = 1; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + G3 = zero_matrix(numGauge,numGauge); + G3(0,0) = Gamma3Singlet()(0,0); + G2(0,0) = Gamma2Singlet()(0,0); + G1(0,0) = Gamma1(1.0/2.0,2.0/3.0,T,U); + break; + case UUBG: + assert(iswap==0); + numGauge = 1; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + G3 = zero_matrix(numGauge,numGauge); + G3(0,0) = -4.0/3.0*I*pi + 3.0/2.0*(U+T-I*pi); + G1(0,0) = Gamma1(2.0/3.0); + break; + case DDGG: + case UUGG: + case tRtRGG: + { + numGauge = 3; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + double Y = process==DDGG ? -1./3. : 2./3.; + Complex gam1(0.); + if(iswap==0) { + G3 = Gamma3g(U,T); + gam1 = Gamma1(Y); + } + else if(iswap==1) { + G3 = Gamma3gST(U,T); + gam1 = Gamma1ST(Y,T); + } + else if(iswap==2) { + G3 = Gamma3gSU(U,T); + gam1 = Gamma1SU(Y,U); + } + else + assert(false); + for (unsigned int i=0; i<3; i++) { + G1(i,i) = gam1; + } + } + break; + case DDBB: + assert(iswap==0); + numGauge = 1; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + G3 = zero_matrix(numGauge,numGauge); + G3(0,0) = Gamma3Singlet()(0,0); + G1(0,0) = Gamma1(-1.0/3.0); + break; + case DDPhiPhi: + assert(iswap==0); + numGauge = 1; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + G3 = zero_matrix(numGauge,numGauge); + G3(0,0) = Gamma3Singlet()(0,0); + G2(0,0) = Gamma2Singlet()(0,0); + G1(0,0) = Gamma1(1.0/2.0,-1.0/3.0,T,U); + break; + case DDBG: + assert(iswap==0); + numGauge = 1; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + G3 = zero_matrix(numGauge,numGauge); + G3(0,0) = -4.0/3.0*I*pi + 3.0/2.0*(U+T-I*pi); + G1(0,0) = Gamma1(-1.0/3.0); + break; + case EEBB: + assert(iswap==0); + numGauge = 1; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + G3 = zero_matrix(numGauge,numGauge); + G1(0,0) = Gamma1(-1.0); + break; + case EEPhiPhi: + assert(iswap==0); + numGauge = 1; + G1 = zero_matrix(numGauge,numGauge); + G2 = zero_matrix(numGauge,numGauge); + G3 = zero_matrix(numGauge,numGauge); + G2(0,0) = Gamma2Singlet()(0,0); + G1(0,0) = Gamma1(1.0/2.0,-1.0,T,U); + break; + default: + assert(false); + } + return evaluateSoft(G3,G2,G1,highScale,EWScale,true); +} + +unsigned int SoftSudakov::numberGauge(Herwig::EWProcess::Process process) { + using namespace EWProcess; + switch (process) { + case QQQQ: + case QQQQiden: + case QtQtQQ: + return 4; + case QQUU: + case QtQtUU: + case QQtRtR: + return 2; + case QQDD: + case QtQtDD: + return 2; + case QQLL: + return 2; + case QQEE: + return 1; + case UUUU: + case UUUUiden: + case tRtRUU: + return 2; + case UUDD: + case tRtRDD: + return 2; + case UULL: + return 1; + case UUEE: + return 1; + case DDDD: + case DDDDiden: + return 2; + case DDLL: + return 1; + case DDEE: + return 1; + case LLLL: + case LLLLiden: + return 2; + case LLEE: + return 1; + case EEEE: + case EEEEiden: + return 1; + case QQWW: + return 5; + case QQPhiPhi: + return 2; + case QQWG: + return 1; + case QQBG: + return 1; + case QQGG: + case QtQtGG: + return 3; + case LLWW: + return 5; + case LLPhiPhi: + return 2; + case UUBB: + return 1; + case UUPhiPhi: + return 1; + case UUBG: + return 1; + case UUGG: + case tRtRGG: + return 3; + case DDBB: + return 1; + case DDPhiPhi: + return 1; + case DDBG: + return 1; + case DDGG: + return 3; + case EEBB: + return 1; + case EEPhiPhi: + return 1; + default: + assert(false); + } +} + +unsigned int SoftSudakov::numberBrokenGauge(Herwig::EWProcess::Process process) { + using namespace EWProcess; + switch (process) { + case QQQQ: + case QQQQiden: + case QtQtQQ: + return 12; + case QQUU: + case QtQtUU: + case QQtRtR: + return 4; + case QQDD: + case QtQtDD: + return 4; + case QQLL: + return 6; + case QQEE: + return 2; + case UUUU: + case UUUUiden: + case tRtRUU: + return 2; + case UUDD: + case tRtRDD: + return 2; + case UULL: + return 2; + case UUEE: + return 1; + case DDDD: + case DDDDiden: + return 2; + case DDLL: + return 2; + case DDEE: + return 1; + case LLLL: + case LLLLiden: + return 6; + case EEEE: + case EEEEiden: + return 1; + case QQWW: + return 20; + case QQPhiPhi: + return 14; + case QQWG: + return 6; + case QQBG: + return 4; + case QQGG: + case QtQtGG: + return 6; + case LLWW: + return 20; + case LLPhiPhi: + return 14; + case UUBB: + return 4; + case UUPhiPhi: + return 5; + case UUBG: + return 2; + case UUGG: + case tRtRGG: + return 3; + case DDBB: + return 4; + case DDPhiPhi: + return 5; + case DDBG: + return 2; + case DDGG: + return 3; + case EEBB: + return 4; + case EEPhiPhi: + return 5; + default: + assert(false); + } +} diff --git a/MatrixElement/EW/SoftSudakov.fh b/MatrixElement/EW/SoftSudakov.fh new file mode 100644 --- /dev/null +++ b/MatrixElement/EW/SoftSudakov.fh @@ -0,0 +1,18 @@ +// -*- C++ -*- +// +// This is the forward declaration of the SoftSudakov class. +// +#ifndef Herwig_SoftSudakov_FH +#define Herwig_SoftSudakov_FH + +#include "ThePEG/Config/ThePEG.h" + +namespace Herwig { + +class SoftSudakov; + +ThePEG_DECLARE_POINTERS(Herwig::SoftSudakov,SoftSudakovPtr); + +} + +#endif diff --git a/MatrixElement/EW/SoftSudakov.h b/MatrixElement/EW/SoftSudakov.h new file mode 100644 --- /dev/null +++ b/MatrixElement/EW/SoftSudakov.h @@ -0,0 +1,198 @@ +// -*- C++ -*- +#ifndef Herwig_SoftSudakov_H +#define Herwig_SoftSudakov_H +// +// This is the declaration of the SoftSudakov class. +// + +#include "ThePEG/Interface/Interfaced.h" +#include "Herwig/Utilities/GSLIntegrator.h" +// work around a Boost 1.64 bug where ublas headers would fail otherwise +#include +#if (BOOST_VERSION / 100 >= 1064) +#include +#endif +#include +#include "EWProcess.h" +#include "SoftSudakov.fh" + +namespace Herwig { + +using namespace ThePEG; + +/** + * Here is the documentation of the SoftSudakov class. + * + * @see \ref SoftSudakovInterfaces "The interfaces" + * defined for SoftSudakov. + */ +class SoftSudakov: public Interfaced { + +public: + + /** @name Standard constructors and destructors. */ + //@{ + /** + * The default constructor. + */ + SoftSudakov(); + + /** + * The destructor. + */ + virtual ~SoftSudakov(); + //@} + +public: + + /** + * Low energy soft evolution + */ + boost::numeric::ublas::matrix + lowEnergyRunning(Energy EWScale, Energy lowScale, + Energy2 s, Energy2 t, Energy2 u, + Herwig::EWProcess::Process process, + unsigned int iswap); + + /** + * Evalaute the high energy running as a matrix + */ + boost::numeric::ublas::matrix + highEnergyRunning(Energy highScale, Energy EWScale, + Energy2 s, Energy2 t, Energy2 u, + Herwig::EWProcess::Process process, + unsigned int iswap); + + /** + * Number of operators for the broken theory at low energy + */ + unsigned int numberBrokenGauge(Herwig::EWProcess::Process process); + + /** + * Number of operators for the unbroken theory at high energy + */ + unsigned int numberGauge(Herwig::EWProcess::Process process); + +protected: + + /** + * Evaluate the soft evolution + */ + boost::numeric::ublas::matrix evaluateSoft(boost::numeric::ublas::matrix & G3, + boost::numeric::ublas::matrix & G2, + boost::numeric::ublas::matrix & G1, + Energy mu_h, Energy mu_l, bool high); + +public: + + /** + * The operator to be integrated + */ + InvEnergy operator ()(Energy mu) const; + /** Argument type for GaussianIntegrator */ + typedef Energy ArgType; + /** Return type for GaussianIntegrator */ + typedef InvEnergy ValType; + +public: + + /** @name Functions used by the persistent I/O system. */ + //@{ + /** + * Function used to write out object persistently. + * @param os the persistent output stream written to. + */ + void persistentOutput(PersistentOStream & os) const; + + /** + * Function used to read in object persistently. + * @param is the persistent input stream read from. + * @param version the version number of the object when written. + */ + void persistentInput(PersistentIStream & is, int version); + //@} + + /** + * The standard Init function used to initialize the interfaces. + * Called exactly once for each class by the class description system + * before the main function starts or + * when this class is dynamically loaded. + */ + static void Init(); + +protected: + + /** @name Clone Methods. */ + //@{ + /** + * Make a simple clone of this object. + * @return a pointer to the new object. + */ + virtual IBPtr clone() const; + + /** Make a clone of this object, possibly modifying the cloned object + * to make it sane. + * @return a pointer to the new object. + */ + virtual IBPtr fullclone() const; + //@} + +private: + + /** + * The assignment operator is private and must never be called. + * In fact, it should not even be implemented. + */ + SoftSudakov & operator=(const SoftSudakov &) = delete; + +private: + + /** + * Order for K + */ + unsigned int K_ORDER_; + + /** + * Integrator + */ + GSLIntegrator integrator_; + + /** + * Whether doing the high or low scale contribution + */ + bool high_; + + /** + * Column + */ + unsigned int row_; + + /** + * Row + */ + unsigned int col_; + + /** + * + */ + bool real_; + + /** + * + */ + boost::numeric::ublas::matrix G1_; + + /** + * + */ + boost::numeric::ublas::matrix G2_; + + /** + * + */ + boost::numeric::ublas::matrix G3_; +}; + +} + +#endif /* Herwig_SoftSudakov_H */ diff --git a/MatrixElement/EW/expm-1.h b/MatrixElement/EW/expm-1.h new file mode 100644 --- /dev/null +++ b/MatrixElement/EW/expm-1.h @@ -0,0 +1,148 @@ +// +// Copyright (c) 2007 +// Tsai, Dung-Bang +// National Taiwan University, Department of Physics +// +// E-Mail : dbtsai (at) gmail.com +// Begine : 2007/11/20 +// Last modify : 2007/11/22 +// Version : v0.1 +// +// EXPGM_PAD computes the matrix exponential exp(H) for general matrixs, +// including complex and real matrixs using the irreducible (p,p) degree +// rational Pade approximation to the exponential +// exp(z) = r(z)=(+/-)( I+2*(Q(z)/P(z))). +// +// Usage : +// +// U = expm_pad(H) +// U = expm_pad(H, p) +// +// where p is internally set to 6 (recommended and gererally satisfactory). +// +// See also MATLAB supplied functions, EXPM and EXPM1. +// +// Reference : +// EXPOKIT, Software Package for Computing Matrix Exponentials. +// ACM - Transactions On Mathematical Software, 24(1):130-156, 1998 +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. The authors make no representations +// about the suitability of this software for any purpose. +// It is provided "as is" without express or implied warranty. +// + +#ifndef _BOOST_UBLAS_EXPM_ +#define _BOOST_UBLAS_EXPM_ +#include +#include +#include +#include +#include + +namespace boost { namespace numeric { namespace ublas { + +template MATRIX expm_pad(const MATRIX &H, const int p = 6) { + typedef typename MATRIX::value_type value_type; + typedef typename MATRIX::size_type size_type; + typedef double real_value_type; // Correct me. Need to modify. + assert(H.size1() == H.size2()); + const size_type n = H.size1(); + const identity_matrix I(n); + matrix U(n,n),H2(n,n),P(n,n),Q(n,n); + real_value_type norm = 0.0; + + // Calcuate Pade coefficients (1-based instead of 0-based as in the c vector) + vector c(p+2); + c(1)=1; + for(size_type i = 1; i <= p; ++i) + c(i+1) = c(i) * ((p + 1.0 - i)/(i * (2.0 * p + 1 - i))); + // Calcuate the infinty norm of H, which is defined as the largest row sum of a matrix + for(size_type i=0; i(H(j,i)); // Correct me, if H is complex, can I use that abs? + norm = std::max(norm, temp); + } + if (norm == 0.0) + { + boost::throw_exception(boost::numeric::ublas::bad_argument()); + std::cerr<<"Error! Null input in the routine EXPM_PAD.\n"; + exit(0); + } + // Scaling, seek s such that || H*2^(-s) || < 1/2, and set scale = 2^(-s) + int s = 0; + real_value_type scale = 1.0; + if(norm > 0.5) { + s = std::max(0, static_cast((log(norm) / log(2.0) + 2.0))); + scale /= static_cast(std::pow(2.0, s)); + U.assign(scale * H); // Here U is used as temp value due to that H is const + } + else + U.assign(H); + // Horner evaluation of the irreducible fraction, see the following ref above. + // Initialise P (numerator) and Q (denominator) + H2.assign( prod(U, U) ); + Q.assign( c(p+1)*I ); + P.assign( c(p)*I ); + size_type odd = 1; + for( size_type k = p - 1; k > 0; --k) + { + if( odd == 1) + { + Q = ( prod(Q, H2) + c(k) * I ); + } + else + { + P = ( prod(P, H2) + c(k) * I ); + } + odd = 1 - odd; + } + if( odd == 1) + { + Q = ( prod(Q, U) ); + Q -= P ; + //U.assign( -(I + 2*(Q\P))); + } + else + { + P = (prod(P, U)); + Q -= P; + //U.assign( I + 2*(Q\P)); + } + // In origine expokit package, they use lapack ZGESV to obtain inverse matrix, + // and in that ZGESV routine, it uses LU decomposition for obtaing inverse matrix. + // Since in ublas, there is no matrix inversion template, I simply use the build-in + // LU decompostion package in ublas, and back substitute by myself. + // + //////////////// Implement Matrix Inversion /////////////////////// + permutation_matrix pm(n); + int res = lu_factorize(Q, pm); + if( res != 0) + { + std::cerr << "Error in the matrix inversion in template expm_pad.\n"; + exit(0); + } + H2 = I; // H2 is not needed anymore, so it is temporary used as identity matrix for substituting. + + lu_substitute(Q, pm, H2); + if( odd == 1) + U.assign( -(I + 2.0 * prod(H2, P))); + else + U.assign( I + 2.0 * prod(H2, P)); + // Squaring + for(size_t i = 0; i < s; ++i) + { + U = (prod(U,U)); + } + return U; + } + +}}} + + +#endif diff --git a/MatrixElement/Hadron/MEPP2Higgs.cc b/MatrixElement/Hadron/MEPP2Higgs.cc --- a/MatrixElement/Hadron/MEPP2Higgs.cc +++ b/MatrixElement/Hadron/MEPP2Higgs.cc @@ -1,1442 +1,1447 @@ // -*- C++ -*- // // MEPP2Higgs.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the MEPP2Higgs class. // #include "MEPP2Higgs.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/MatrixElement/Tree2toNDiagram.h" #include "ThePEG/Handlers/StandardXComb.h" #include "ThePEG/Cuts/Cuts.h" #include "Herwig/MatrixElement/HardVertex.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "Herwig/Utilities/Maths.h" #include "Herwig/Shower/RealEmissionProcess.h" using namespace Herwig; const complex MEPP2Higgs::epsi_ = complex(ZERO,-1.e-10*GeV2); MEPP2Higgs::MEPP2Higgs() : scaleopt_(1), mu_F_(100.*GeV), shapeOption_(2), processOption_(1), minFlavour_(4), maxFlavour_(5), mh_(ZERO), wh_(ZERO), minLoop_(6),maxLoop_(6),massOption_(0), mu_R_opt_(1),mu_F_opt_(1), channelwgtA_(0.45),channelwgtB_(0.15), ggPow_(1.6), qgPow_(1.6), enhance_(1.1), nover_(0), ntry_(0), ngen_(0), maxwgt_(0.), power_(2.0), pregg_(7.), preqg_(3.), pregqbar_(3.), minpT_(2.*GeV), spinCorrelations_(true) {} // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigMEPP2Higgs("Herwig::MEPP2Higgs", "HwMEHadron.so"); void MEPP2Higgs::persistentOutput(PersistentOStream & os) const { os << HGGVertex_ << HFFVertex_ << shapeOption_ << processOption_ << minFlavour_ << maxFlavour_ << hmass_ << ounit(mh_,GeV) << ounit(wh_,GeV) << minLoop_ << maxLoop_ << massOption_ << alpha_ << prefactor_ << power_ << pregg_ << preqg_ << pregqbar_ << ounit( minpT_, GeV ) << ggPow_ << qgPow_ << enhance_ << channelwgtA_ << channelwgtB_ << channelWeights_ << mu_R_opt_ << mu_F_opt_ << spinCorrelations_; } void MEPP2Higgs::persistentInput(PersistentIStream & is, int) { is >> HGGVertex_ >> HFFVertex_ >> shapeOption_ >> processOption_ >> minFlavour_ >> maxFlavour_ >> hmass_ >> iunit(mh_,GeV) >> iunit(wh_,GeV) >> minLoop_ >> maxLoop_ >> massOption_ >> alpha_ >> prefactor_ >> power_ >> pregg_ >> preqg_ >> pregqbar_ >> iunit( minpT_, GeV ) >> ggPow_ >> qgPow_ >> enhance_ >> channelwgtA_ >> channelwgtB_ >> channelWeights_ >> mu_R_opt_ >> mu_F_opt_ >> spinCorrelations_; } void MEPP2Higgs::Init() { static ClassDocumentation documentation ("The MEPP2Higgs class implements the matrix elements for" " Higgs production (with decay H->W-W+) in hadron-hadron collisions" " including the generation of additional hard QCD radiation in " "gg to h0 processes in the POWHEG scheme", "Hard QCD radiation for $gg\\to h^0$ processes in the" " POWHEG scheme \\cite{Hamilton:2009za}.", "%\\cite{Hamilton:2009za}\n" "\\bibitem{Hamilton:2009za}\n" " K.~Hamilton, P.~Richardson and J.~Tully,\n" " ``A Positive-Weight Next-to-Leading Order Monte Carlo Simulation for Higgs\n" " Boson Production,''\n" " JHEP {\\bf 0904}, 116 (2009)\n" " [arXiv:0903.4345 [hep-ph]].\n" " %%CITATION = JHEPA,0904,116;%%\n"); static Switch interfaceFactorizationScaleOption ("FactorizationScaleOption", "Option for the choice of factorization scale", &MEPP2Higgs::scaleopt_, 1, false, false); static SwitchOption interfaceDynamic (interfaceFactorizationScaleOption, "Dynamic", "Dynamic factorization scale equal to the current sqrt(sHat())", 1); static SwitchOption interfaceFixed (interfaceFactorizationScaleOption, "Fixed", "Use a fixed factorization scale set with FactorizationScaleValue", 2); static Parameter interfaceFactorizationScaleValue ("FactorizationScaleValue", "Value to use in the event of a fixed factorization scale", &MEPP2Higgs::mu_F_, GeV, 100.0*GeV, 50.0*GeV, 500.0*GeV, true, false, Interface::limited); static Reference interfaceCoupling ("Coupling", "Pointer to the object to calculate the coupling for the correction", &MEPP2Higgs::alpha_, false, false, true, false, false); static Switch interfaceShapeOption ("ShapeScheme", "Option for the treatment of the Higgs resonance shape", &MEPP2Higgs::shapeOption_, 1, false, false); static SwitchOption interfaceStandardShapeFixed (interfaceShapeOption, "FixedBreitWigner", "Breit-Wigner s-channel resonanse", 1); static SwitchOption interfaceStandardShapeRunning (interfaceShapeOption, "MassGenerator", "Use the mass generator to give the shape", 2); static Switch interfaceProcess ("Process", "Which subprocesses to include", &MEPP2Higgs::processOption_, 1, false, false); static SwitchOption interfaceProcessAll (interfaceProcess, "All", "Include all subprocesses", 1); static SwitchOption interfaceProcess1 (interfaceProcess, "qqbar", "Only include the incoming q qbar subprocess", 2); static SwitchOption interfaceProcessgg (interfaceProcess, "gg", "Only include the incoming gg subprocess", 3); static Parameter interfaceMinimumInLoop ("MinimumInLoop", "The minimum flavour of the quarks to include in the loops", &MEPP2Higgs::minLoop_, 6, 5, 6, false, false, Interface::limited); static Parameter interfaceMaximumInLoop ("MaximumInLoop", "The maximum flavour of the quarks to include in the loops", &MEPP2Higgs::maxLoop_, 6, 5, 6, false, false, Interface::limited); static Switch interfaceMassOption ("MassOption", "Option for the treatment of the masses in the loop diagrams", &MEPP2Higgs::massOption_, 0, false, false); static SwitchOption interfaceMassOptionFull (interfaceMassOption, "Full", "Include the full mass dependence", 0); static SwitchOption interfaceMassOptionLarge (interfaceMassOption, "Large", "Use the heavy mass limit", 1); static Parameter interfaceMinimumFlavour ("MinimumFlavour", "The minimum flavour of the incoming quarks in the hard process", &MEPP2Higgs::minFlavour_, 4, 3, 5, false, false, Interface::limited); static Parameter interfaceMaximumFlavour ("MaximumFlavour", "The maximum flavour of the incoming quarks in the hard process", &MEPP2Higgs::maxFlavour_, 5, 3, 5, false, false, Interface::limited); static Parameter interfaceQGChannelWeight ("QGChannelWeight", "The relative weights of the g g and q g channels for selection." " This is a technical parameter for the phase-space generation and " "should not affect the results only the efficiency and fraction" " of events with weight > 1.", &MEPP2Higgs::channelwgtA_, 0.45, 0., 1.e10, false, false, Interface::limited); static Parameter interfaceQbarGChannelWeight ("QbarGChannelWeight", "The relative weights of the g g abd qbar g channels for selection." " This is a technical parameter for the phase-space generation and " "should not affect the results only the efficiency and fraction", &MEPP2Higgs::channelwgtB_, 0.15, 0., 1.e10, false, false, Interface::limited); static Parameter interfaceGGPower ("GGPower", "Power for the phase-space sampling of the gg channel", &MEPP2Higgs::ggPow_, 1.6, 1.0, 3.0, false, false, Interface::limited); static Parameter interfaceQGPower ("QGPower", "Power for the phase-space sampling of the qg and qbarg channels", &MEPP2Higgs::qgPow_, 1.6, 1.0, 3.0, false, false, Interface::limited); static Parameter interfaceEnhancementFactor ("InitialEnhancementFactor", "The enhancement factor for initial-state radiation in the shower to ensure" " the weight for the matrix element correction is less than one.", &MEPP2Higgs::enhance_, 1.1, 1.0, 10.0, false, false, Interface::limited); static Parameter interfacePower ("Power", "The power for the sampling of the matrix elements", &MEPP2Higgs::power_, 2.0, 1.0, 10.0, false, false, Interface::limited); static Parameter interfacePrefactorgg ("Prefactorgg", "The prefactor for the sampling of the q qbar channel", &MEPP2Higgs::pregg_, 7.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacePrefactorqg ("Prefactorqg", "The prefactor for the sampling of the q g channel", &MEPP2Higgs::preqg_, 3.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacePrefactorgqbar ("Prefactorgqbar", "The prefactor for the sampling of the g qbar channel", &MEPP2Higgs::pregqbar_, 3.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacePtMin ("minPt", "The pt cut on hardest emision generation" "2*(1-Beta)*exp(-sqr(intrinsicpT/RMS))/sqr(RMS)", &MEPP2Higgs::minpT_, GeV, 2.*GeV, ZERO, 100000.0*GeV, false, false, Interface::limited); static Switch interface_mu_R_Option ("mu_R_Option", "Option to use pT or mT as the scale in alphaS", &MEPP2Higgs::mu_R_opt_, 1, false, false); static SwitchOption interface_mu_R_Option_mT (interface_mu_R_Option, "mT", "Use mT as the scale in alpha_S", 0); static SwitchOption interface_mu_R_Option_pT (interface_mu_R_Option, "pT", "Use pT as the scale in alpha_S", 1); static Switch interface_mu_F_Option ("mu_F_Option", "Option to use pT or mT as the factorization scale in the PDFs", &MEPP2Higgs::mu_F_opt_, 1, false, false); static SwitchOption interface_mu_F_Option_mT (interface_mu_F_Option, "mT", "Use mT as the scale in the PDFs", 0); static SwitchOption interface_mu_F_Option_pT (interface_mu_F_Option, "pT", "Use pT as the scale in the PDFs", 1); static Switch interfaceSpinCorrelations ("SpinCorrelations", "Which on/off spin correlations in the hard process", &MEPP2Higgs::spinCorrelations_, true, false, false); static SwitchOption interfaceSpinCorrelationsYes (interfaceSpinCorrelations, "Yes", "Switch correlations on", true); static SwitchOption interfaceSpinCorrelationsNo (interfaceSpinCorrelations, "No", "Switch correlations off", false); } void MEPP2Higgs::doinit() { HwMEBase::doinit(); // get the vertex pointers from the SM object tcHwSMPtr theSM = dynamic_ptr_cast(standardModel()); // do the initialisation if(!theSM) { throw InitException() << "Wrong type of StandardModel object in MEPP2Higgs::doinit()," << " the Herwig version must be used" << Exception::runerror; } HGGVertex_ = theSM->vertexHGG(); HFFVertex_ = theSM->vertexFFH(); // get the mass generator for the higgs PDPtr h0 = getParticleData(ParticleID::h0); mh_ = h0->mass(); wh_ = h0->generateWidth(mh_); if(h0->massGenerator()) { hmass_=dynamic_ptr_cast(h0->massGenerator()); } if(shapeOption_==2&&!hmass_) throw InitException() << "If using the mass generator for the line shape in MEPP2Higgs::doinit()" << "the mass generator must be an instance of the GenericMassGenerator class" << Exception::runerror; // stuff for the ME correction double total = 1.+channelwgtA_+channelwgtB_; channelWeights_.push_back(1./total); channelWeights_.push_back(channelWeights_.back()+channelwgtA_/total); channelWeights_.push_back(channelWeights_.back()+channelwgtB_/total); // insert the different prefactors in the vector for easy look up prefactor_.push_back(pregg_); prefactor_.push_back(preqg_); prefactor_.push_back(preqg_); prefactor_.push_back(pregqbar_); prefactor_.push_back(pregqbar_); } void MEPP2Higgs::dofinish() { HwMEBase::dofinish(); if(ntry_==0) return; generator()->log() << "MEPP2Higgs when applying the hard correction " << "generated " << ntry_ << " trial emissions of which " << ngen_ << " were accepted\n"; if(nover_==0) return; generator()->log() << "MEPP2Higgs when applying the hard correction " << nover_ << " weights larger than one were generated of which" << " the largest was " << maxwgt_ << "\n"; } unsigned int MEPP2Higgs::orderInAlphaS() const { return 2; } unsigned int MEPP2Higgs::orderInAlphaEW() const { return 1; } Energy2 MEPP2Higgs::scale() const { return scaleopt_ == 1 ? sHat() : sqr(mu_F_); } int MEPP2Higgs::nDim() const { return 0; } bool MEPP2Higgs::generateKinematics(const double *) { Lorentz5Momentum pout = meMomenta()[0] + meMomenta()[1]; pout.rescaleMass(); meMomenta()[2].setMass(pout.mass()); meMomenta()[2] = LorentzMomentum(pout.x(),pout.y(),pout.z(),pout.t()); jacobian(1.0); // check whether it passes all the cuts: returns true if it does vector out(1,meMomenta()[2]); tcPDVector tout(1,mePartonData()[2]); return lastCuts().passCuts(tout, out, mePartonData()[0], mePartonData()[1]); } void MEPP2Higgs::getDiagrams() const { tcPDPtr h0=getParticleData(ParticleID::h0); // gg -> H process if(processOption_==1||processOption_==3) { tcPDPtr g=getParticleData(ParticleID::g); add(new_ptr((Tree2toNDiagram(2), g, g, 1, h0, -1))); } // q qbar -> H processes if(processOption_==1||processOption_==2) { for ( int i = minFlavour_; i <= maxFlavour_; ++i ) { tcPDPtr q = getParticleData(i); tcPDPtr qb = q->CC(); add(new_ptr((Tree2toNDiagram(2), q, qb, 1, h0, -2))); } } } CrossSection MEPP2Higgs::dSigHatDR() const { using Constants::pi; InvEnergy2 bwfact; if(shapeOption_==1) { bwfact = mePartonData()[2]->generateWidth(sqrt(sHat()))*sqrt(sHat())/pi/ (sqr(sHat()-sqr(mh_))+sqr(mh_*wh_)); } else { bwfact = hmass_->BreitWignerWeight(sqrt(sHat())); } double cs = me2() * jacobian() * pi * double(UnitRemoval::E4 * bwfact/sHat()); return UnitRemoval::InvE2 * sqr(hbarc) * cs; } double MEPP2Higgs::me2() const { double output(0.0); ScalarWaveFunction hout(meMomenta()[2],mePartonData()[2],outgoing); // Safety code to garantee the reliable behaviour of Higgs shape limits // (important for heavy and broad Higgs resonance). Energy hmass = meMomenta()[2].m(); tcPDPtr h0 = mePartonData()[2]; Energy mass = h0->mass(); Energy halfmass = .5*mass; if (.0*GeV > hmass) return 0.0; // stricly speaking the condition is applicable if // h0->widthUpCut() == h0->widthLoCut()... if (h0->widthLoCut() > halfmass) { if ( mass + h0->widthUpCut() < hmass || mass - h0->widthLoCut() > hmass ) return 0.0; } else { if (mass + halfmass < hmass || halfmass > hmass) return 0.0; } if (mePartonData()[0]->id() == ParticleID::g && mePartonData()[1]->id() == ParticleID::g) { VectorWaveFunction gin1(meMomenta()[0],mePartonData()[0],incoming); VectorWaveFunction gin2(meMomenta()[1],mePartonData()[1],incoming); vector g1,g2; for(unsigned int i = 0; i < 2; ++i) { gin1.reset(2*i); g1.push_back(gin1); gin2.reset(2*i); g2.push_back(gin2); } output = ggME(g1,g2,hout,false); } else { if (mePartonData()[0]->id() == -mePartonData()[1]->id()) { SpinorWaveFunction qin (meMomenta()[0],mePartonData()[0],incoming); SpinorBarWaveFunction qbin(meMomenta()[1],mePartonData()[1],incoming); vector fin; vector ain; for (unsigned int i = 0; i < 2; ++i) { qin.reset(i); fin.push_back(qin); qbin.reset(i); ain.push_back(qbin); } output = qqME(fin,ain,hout,false); } else assert(false); } return output; } Selector MEPP2Higgs::diagrams(const DiagramVector & diags) const { Selector sel; for (DiagramIndex i = 0; i < diags.size(); ++i) sel.insert(1.0, i); return sel; } Selector MEPP2Higgs::colourGeometries(tcDiagPtr diag) const { // colour lines static const ColourLines line1("1 -2,2 -1"); static const ColourLines line2("1 -2"); // select the colour flow Selector sel; if (diag->id() == -1) { sel.insert(1.0, &line1); } else { sel.insert(1.0, &line2); } // return the answer return sel; } void MEPP2Higgs::constructVertex(tSubProPtr sub) { if(!spinCorrelations_) return; // extract the particles in the hard process ParticleVector hard; hard.push_back(sub->incoming().first); hard.push_back(sub->incoming().second); hard.push_back(sub->outgoing()[0]); if(hard[0]->id() < hard[1]->id()) { swap(hard[0],hard[1]); } // identify the process and calculate the matrix element if(hard[0]->id() == ParticleID::g && hard[1]->id() == ParticleID::g) { vector g1,g2; vector q; vector qbar; VectorWaveFunction (g1,hard[0],incoming,false,true,true); VectorWaveFunction (g2,hard[1],incoming,false,true,true); ScalarWaveFunction hout(hard[2],outgoing,true); g1[1] = g1[2]; g2[1] = g2[2]; ggME(g1,g2,hout,true); } else { vector q1; vector q2; SpinorWaveFunction (q1,hard[0],incoming,false,true); SpinorBarWaveFunction (q2,hard[1],incoming,false,true); ScalarWaveFunction hout(hard[2],outgoing,true); qqME(q1,q2,hout,true); } // construct the vertex HardVertexPtr hardvertex = new_ptr(HardVertex()); // set the matrix element for the vertex hardvertex->ME(me_); // set the pointers and to and from the vertex for(unsigned int i = 0; i < 3; ++i) hard[i]->spinInfo()->productionVertex(hardvertex); } double MEPP2Higgs::ggME(vector g1, vector g2, ScalarWaveFunction & in, bool calc) const { ProductionMatrixElement newme(PDT::Spin1,PDT::Spin1,PDT::Spin0); Energy2 s(sHat()); double me2(0.0); for(int i = 0; i < 2; ++i) { for(int j = 0; j < 2; ++j) { Complex diag = HGGVertex_->evaluate(s,g1[i],g2[j],in); me2 += norm(diag); if(calc) newme(2*i, 2*j, 0) = diag; } } if(calc) me_.reset(newme); // initial colour and spin factors: colour -> (8/64) and spin -> (1/4) return me2/32.; } double MEPP2Higgs::qqME(vector & fin, vector & ain, ScalarWaveFunction & in, bool calc) const { ProductionMatrixElement newme(PDT::Spin1Half,PDT::Spin1Half,PDT::Spin0); Energy2 s(scale()); double me2(0.0); for(int i = 0; i < 2; ++i) { for(int j = 0; j < 2; ++j) { Complex diag = HFFVertex_->evaluate(s,fin[i],ain[j],in); me2+=norm(diag); if(calc) newme(i, j, 0) = diag; } } if(calc) me_.reset(newme); // final colour/spin factors return me2/12.; } RealEmissionProcessPtr MEPP2Higgs::applyHardMatrixElementCorrection(RealEmissionProcessPtr born) { useMe(); assert(born->bornOutgoing().size()==1); if(born->bornIncoming()[0]->id()!=ParticleID::g) return RealEmissionProcessPtr(); // get gluons and Higgs // get the gluons ParticleVector incoming; vector beams; for(unsigned int ix=0;ixbornIncoming().size();++ix) { incoming.push_back(born->bornIncoming()[ix]); beams.push_back(dynamic_ptr_cast(born->hadrons()[ix]->dataPtr())); } pair xnew=born->x(); if(incoming[0]->momentum().z()bornOutgoing()[0]; // calculate the momenta unsigned int iemit,itype; vector pnew; // if not accepted return tPDPtr out; if(!applyHard(incoming,beams,higgs,iemit,itype,pnew,xnew,out)) return RealEmissionProcessPtr(); // fix the momentum of the higgs Boost boostv=born->bornOutgoing()[0]->momentum().findBoostToCM(); LorentzRotation trans(pnew[3].boostVector()); trans *=LorentzRotation(boostv); born->transformation(trans); born->outgoing().push_back(born->bornOutgoing()[0]->dataPtr()->produceParticle(pnew[3])); born->emitted(3); // if applying ME correction create the new particles if(itype==0) { // ensure gluon can be put on shell Lorentz5Momentum ptest(pnew[2]); if(ptest.boost(-(pnew[0]+pnew[1]).boostVector()).e() < getParticleData(ParticleID::g)->constituentMass()) return RealEmissionProcessPtr(); // create the new gluon PPtr newg= getParticleData(ParticleID::g)->produceParticle(pnew[2]); PPtr newg1 = incoming[0]->dataPtr()->produceParticle(pnew[0]); PPtr newg2 = incoming[1]->dataPtr()->produceParticle(pnew[1]); // set emitter and spectator if(born->bornIncoming()[0]->momentum().z()>ZERO) { born->incoming().push_back(newg1); born->incoming().push_back(newg2); if(iemit==0) { born->emitter(0); born->spectator(1); } else { born->emitter(1); born->spectator(0); } } else { born->incoming().push_back(newg2); born->incoming().push_back(newg1); if(iemit==0) { born->emitter(1); born->spectator(0); } else { born->emitter(0); born->spectator(1); } } bool colour = UseRandom::rndbool(); newg ->incomingColour(newg1,!colour); newg ->incomingColour(newg2, colour); newg1->colourConnect(newg2,!colour); born->outgoing().push_back(newg); } else if(itype==1) { // ensure outgoing quark can be put on-shell Lorentz5Momentum ptest(pnew[2]); if(ptest.boost(-(pnew[0]+pnew[1]).boostVector()).e() < out->constituentMass()) return RealEmissionProcessPtr(); // create the new particles PPtr newqout = out->produceParticle(pnew[2]); PPtr newqin,newg; if(iemit==0) { newqin = out ->produceParticle(pnew[0]); newg = incoming[1]->dataPtr()->produceParticle(pnew[1]); } else { newg = incoming[0]->dataPtr()->produceParticle(pnew[0]); newqin = out ->produceParticle(pnew[1]); } newqout->incomingColour(newg); newg->colourConnect(newqin); if((born->bornIncoming()[0]->momentum().z()>ZERO && iemit==0) || (born->bornIncoming()[0]->momentum().z()incoming().push_back(newqin); born->incoming().push_back(newg ); born->emitter(0); born->spectator(1); } else { born->incoming().push_back(newg ); born->incoming().push_back(newqin); born->emitter(1); born->spectator(0); } born->outgoing().push_back(newqout); } else if(itype==2) { // ensure outgoing antiquark can be put on-shell Lorentz5Momentum ptest(pnew[2]); if(ptest.boost(-(pnew[0]+pnew[1]).boostVector()).e() < incoming[0]->dataPtr()->constituentMass()) return RealEmissionProcessPtr(); // create the new particles PPtr newqout = out->produceParticle(pnew[2]); PPtr newqin,newg; if(iemit==0) { newqin = out ->produceParticle(pnew[0]); newg = incoming[1]->dataPtr()->produceParticle(pnew[1]); } else { newg = incoming[0]->dataPtr()->produceParticle(pnew[0]); newqin = out ->produceParticle(pnew[1]); } newqout->incomingAntiColour(newg); newg->colourConnect(newqin,true); if((born->bornIncoming()[0]->momentum().z()>ZERO && iemit==0) || (born->bornIncoming()[0]->momentum().z()incoming().push_back(newqin); born->incoming().push_back(newg ); born->emitter(0); born->spectator(1); } else { born->incoming().push_back(newg ); born->incoming().push_back(newqin); born->emitter(1); born->spectator(0); } born->outgoing().push_back(newqout); } if(born->bornIncoming()[0]->momentum().z()x(xnew); born->interaction(ShowerInteraction::QCD); return born; } bool MEPP2Higgs::softMatrixElementVeto(PPtr parent, PPtr progenitor, const bool & fs, const Energy & highestpT, const vector & ids, const double & z, const Energy & scale, const Energy & pT) { if(fs) return false; // check if me correction should be applied long id[2]={progenitor->id(),parent->id()}; // must have started as a gluon if(id[0]!=ParticleID::g) return false; // must be a gluon going into the hard process if(ids[1]->id()!=ParticleID::g) return false; // check if hardest so far if(pTid()==ParticleID::g&&ids[2]->id()==ParticleID::g) { double split = 6.*(z/(1.-z)+(1.-z)/z+z*(1.-z)); me = ggME(shat,that,uhat)/split; } // q g else if(ids[0]->id() >= 1 && ids[0]->id() <= 5 && ids[2]->id()==ids[0]->id()) { double split = 4./3./z*(1.+sqr(1.-z)); me = qgME(shat,uhat,that)/split; } // qbar g else if(ids[0]->id() <= -1 && ids[0]->id() >= -5 && ids[2]->id()==ids[0]->id()) { double split = 4./3./z*(1.+sqr(1.-z)); me = qbargME(shat,uhat,that)/split; } else { return false; } InvEnergy2 pre = 0.125/Constants::pi/loME()*sqr(mh2_)*that/shat/(shat+uhat); double wgt = -pre*me/enhance_; if(wgt<.0||wgt>1.) generator()->log() << "Soft ME correction weight too large or " << "negative in MEPP2Higgs::" << "softMatrixElementVeto()\n soft weight " << " sbar = " << shat/mh2_ << " tbar = " << that/mh2_ << "weight = " << wgt << " for " << ids[0]->id() << " " << ids[1]->id() << " " << ids[2]->id() << "\n"; // return whether or not vetoed return !UseRandom::rndbool(wgt); } RealEmissionProcessPtr MEPP2Higgs::generateHardest(RealEmissionProcessPtr born, ShowerInteraction inter) { - if(inter==ShowerInteraction::QED) return RealEmissionProcessPtr(); + // check if generating QCD radiation + if(inter!=ShowerInteraction::QCD && inter!=ShowerInteraction::QEDQCD && + inter!=ShowerInteraction::ALL) + return RealEmissionProcessPtr(); + if(born->bornIncoming()[0]->id()!=ParticleID::g) + return RealEmissionProcessPtr(); useMe(); // get the particles to be showered beams_.clear(); partons_.clear(); // find the incoming particles ParticleVector incoming; ParticleVector particlesToShower; for(unsigned int ix=0;ixbornIncoming().size();++ix) { incoming.push_back( born->bornIncoming()[ix] ); beams_.push_back( dynamic_ptr_cast(born->hadrons()[ix]->dataPtr())); partons_.push_back( born->bornIncoming()[ix]->dataPtr() ); particlesToShower.push_back( born->bornIncoming()[ix] ); } // find the higgs boson assert(born->bornOutgoing().size()==1); PPtr higgs = born->bornOutgoing()[0]; // calculate the rapidity of the higgs yh_ = 0.5 * log((higgs->momentum().e()+higgs->momentum().z())/ (higgs->momentum().e()-higgs->momentum().z())); mass_=higgs->mass(); mh2_ = sqr(mass_); vector pnew; int emission_type(-1); // generate the hard emission and return if no emission if(!getEvent(pnew,emission_type)) { born->pT()[ShowerInteraction::QCD] = minpT_; return born; } // construct the HardTree object needed to perform the showers ParticleVector newparticles(4); // create the partons int iemit=-1; // create the jet newparticles[3] = out_->produceParticle(pnew[3]); // g g -> h g if(emission_type==0) { newparticles[0] = partons_[0]->produceParticle(pnew[0]); newparticles[1] = partons_[1]->produceParticle(pnew[1]); iemit = pnew[0].z()/pnew[3].z()>0. ? 0 : 1; bool colour = UseRandom::rndbool(); newparticles[3]->incomingColour(newparticles[0],!colour); newparticles[3]->incomingColour(newparticles[1], colour); newparticles[0]-> colourConnect(newparticles[1],!colour); } // g q -> H q else if(emission_type==1) { newparticles[0] = partons_[0]->produceParticle(pnew[0]); newparticles[1] = out_ ->produceParticle(pnew[1]); iemit = 1; newparticles[3]->incomingColour(newparticles[0]); newparticles[0]->colourConnect (newparticles[1]); } // q g -> H q else if(emission_type==2) { newparticles[0] = out_ ->produceParticle(pnew[0]); newparticles[1] = partons_[1]->produceParticle(pnew[1]); iemit = 0; newparticles[3]->incomingColour(newparticles[1]); newparticles[1]->colourConnect (newparticles[0]); } // g qbar -> H qbar else if(emission_type==3) { newparticles[0] = partons_[0]->produceParticle(pnew[0]); newparticles[1] = out_ ->produceParticle(pnew[1]); iemit = 1; newparticles[3]->incomingAntiColour(newparticles[0]); newparticles[0]->colourConnect(newparticles[1],true); } // qbar g -> H qbar else if(emission_type==4) { newparticles[0] = out_ ->produceParticle(pnew[0]); newparticles[1] = partons_[1]->produceParticle(pnew[1]); iemit = 0; newparticles[3]->incomingAntiColour(newparticles[1]); newparticles[1]->colourConnect(newparticles[0],true); } unsigned int ispect = iemit==0 ? 1 : 0; // create the boson newparticles[2] = higgs->dataPtr()->produceParticle(pnew[2]); born->emitter (iemit); born->spectator(ispect); born->emitted(3); born->pT()[ShowerInteraction::QCD] = pt_; pair xnew; for(unsigned int ix=0;ix<2;++ix) { born->incoming().push_back(newparticles[ix]); if(ix==0) xnew.first = newparticles[ix]->momentum().rho()/born->hadrons()[ix]->momentum().rho(); else xnew.second = newparticles[ix]->momentum().rho()/born->hadrons()[ix]->momentum().rho(); } born->x(xnew); for(unsigned int ix=0;ix<2;++ix) born->outgoing().push_back(newparticles[ix+2]); // return the answer born->interaction(ShowerInteraction::QCD); return born; } bool MEPP2Higgs::applyHard(ParticleVector gluons, vector beams,PPtr higgs, unsigned int & iemit, unsigned int & itype, vector & pnew, pair & xout, tPDPtr & out) { ++ntry_; // calculate the limits on s Energy mh(higgs->mass()); mh2_=sqr(mh); Energy2 smin=mh2_; Energy2 s= (generator()->currentEvent()->incoming().first->momentum()+ generator()->currentEvent()->incoming().second->momentum()).m2(); Energy2 smax(s); // calculate the rapidity of the higgs double yH = 0.5*log((higgs->momentum().e()+higgs->momentum().z())/ (higgs->momentum().e()-higgs->momentum().z())); // if no phase-space return if(smaxpdf(); assert(pdf[ix]); fx[ix]=pdf[ix]->xfx(beams[ix],gluons[ix]->dataPtr(),mh2_,x[ix]); } // leading order ME Energy4 lome = loME(); // select the type of process and generate the kinematics double rn(UseRandom::rnd()); Energy2 shat(ZERO),uhat(ZERO),that(ZERO); double weight(0.),xnew[2]={1.,1.}; // gg -> H g if(rn=1.||xnew[1]<=0.||xnew[1]>=1.) return false; for(unsigned int ix=0;ix<2;++ix) fxnew[ix]=pdf[ix]->xfx(beams[ix],gluons[ix]->dataPtr(),scale,xnew[ix]); // jacobian and me parts of the weight weight = jacobian2*ggME(shat,uhat,that)/lome*mh2_/sqr(shat); // pdf part of the weight weight *=fxnew[0]*fxnew[1]*x[0]*x[1]/(fx[0]*fx[1]*xnew[0]*xnew[1]); // finally coupling and different channel pieces weight *= 1./16./sqr(Constants::pi)*alpha_->value(scale)/channelWeights_[0]; itype=0; iemit = that>uhat ? 0 : 1; out = getParticleData(ParticleID::g); } // incoming quark or antiquark else { // generate the value of s according to 1/s^n double rhomax(pow(smin/mh2_,1.-qgPow_)),rhomin(pow(smax/mh2_,1.-qgPow_)); double rho = rhomin+UseRandom::rnd()*(rhomax-rhomin); shat = mh2_*pow(rho,1./(1.-qgPow_)); Energy2 jacobian = mh2_/(qgPow_-1.)*(rhomax-rhomin)*pow(shat/mh2_,qgPow_); double sbar=shat/mh2_; // calculate limits on that Energy2 tmax=mh2_*kappa[0]*(1.-sbar)/(kappa[0]+sbar); Energy2 tmin=shat*(1.-sbar)/(kappa[1]+sbar); // calculate the limits on uhat Energy2 umax(mh2_-shat-tmin),umin(mh2_-shat-tmax); // check inside phase space if(tmax=1.||xnew[1]<=0.||xnew[1]>=1.) return false; if(rn H q if(!order) { out = quarkFlavour(pdf[0],scale,xnew[0],beams[0],fxnew[0],false); fxnew[1]=pdf[1]->xfx(beams[1],gluons[1]->dataPtr(),scale,xnew[1]); iemit = 0; mewgt = out ? qgME(shat,uhat,that)/lome*mh2_/sqr(shat) : ZERO; } // g q -> H q else { fxnew[0]=pdf[0]->xfx(beams[0],gluons[0]->dataPtr(),scale,xnew[0]); out = quarkFlavour(pdf[1],scale,xnew[1],beams[1],fxnew[1],false); iemit = 1; mewgt = out ? qgME(shat,that,uhat)/lome*mh2_/sqr(shat) : ZERO; } jacobian2 /= (channelWeights_[1]-channelWeights_[0]); } else { itype=2; // qbar g -> H qbar if(!order) { out = quarkFlavour(pdf[0],scale,xnew[0],beams[0],fxnew[0],true); fxnew[1]=pdf[1]->xfx(beams[1],gluons[1]->dataPtr(),scale,xnew[1]); iemit = 0; mewgt = out ? qbargME(shat,uhat,that)/lome*mh2_/sqr(shat) : ZERO; } // g qbar -> H qbar else { fxnew[0]=pdf[0]->xfx(beams[0],gluons[0]->dataPtr(),scale,xnew[0]); out = quarkFlavour(pdf[1],scale,xnew[1],beams[1],fxnew[1],true); iemit = 1; mewgt = out ? qbargME(shat,that,uhat)/lome*mh2_/sqr(shat) : ZERO; } jacobian2/=(channelWeights_[2]-channelWeights_[1]); } // weight (factor of 2 as pick q(bar)g or gq(bar) weight = 2.*jacobian2*mewgt; // pdf part of the weight weight *=fxnew[0]*fxnew[1]*x[0]*x[1]/(fx[0]*fx[1]*xnew[0]*xnew[1]); // finally coupling and different channel pieces weight *= 1./16./sqr(Constants::pi)*alpha_->value(scale); } // if me correction should be applied if(weight>1.) { ++nover_; maxwgt_ = max( maxwgt_ , weight); weight=1.; } if(UseRandom::rnd()>weight) return false; ++ngen_; // construct the momenta Energy roots = 0.5*sqrt(s); Energy pt = sqrt(uhat*that/shat); Energy mt = sqrt(uhat*that/shat+mh2_); Lorentz5Momentum pin[2]={Lorentz5Momentum(ZERO,ZERO, xnew[0]*roots,xnew[0]*roots), Lorentz5Momentum(ZERO,ZERO,-xnew[1]*roots,xnew[1]*roots)}; double phi = Constants::twopi*UseRandom::rnd(); Lorentz5Momentum pH(pt*cos(phi),pt*sin(phi),mt*sinh(yH),mt*cosh(yH)); Lorentz5Momentum pJ(pin[0]+pin[1]-pH); // momenta to be returned pnew.push_back(pin[0]); pnew.push_back(pin[1]); pnew.push_back(pJ); pnew.push_back(pH); xout.first = xnew[0]; xout.second = xnew[1]; return true; } Energy2 MEPP2Higgs::ggME(Energy2 s, Energy2 t, Energy2 u) { Energy2 output; if(massOption_==0) { complex me[2][2][2]; me[1][1][1] = ZERO; me[1][1][0] = ZERO; me[0][1][0] = ZERO; me[0][1][1] = ZERO; for(unsigned int ix=minLoop_; ix<=maxLoop_; ++ix ) { Energy2 mf2=sqr(getParticleData(long(ix))->mass()); bi_[1]=B(s,mf2); bi_[2]=B(u,mf2); bi_[3]=B(t,mf2); bi_[4]=B(mh2_,mf2); bi_[1]=bi_[1]-bi_[4]; bi_[2]=bi_[2]-bi_[4]; bi_[3]=bi_[3]-bi_[4]; ci_[1]=C(s,mf2); ci_[2]=C(u,mf2); ci_[3]=C(t,mf2); ci_[7]=C(mh2_,mf2); ci_[4]=(s*ci_[1]-mh2_*ci_[7])/(s-mh2_); ci_[5]=(u*ci_[2]-mh2_*ci_[7])/(u-mh2_); ci_[6]=(t*ci_[3]-mh2_*ci_[7])/(t-mh2_); di_[1]=D(t,u,s,mf2); di_[2]=D(s,t,u,mf2); di_[3]=D(s,u,t,mf2); me[1][1][1]+=me1(s,u,t,mf2,1,2,3,4,5,6); me[1][1][0]+=me2(s,u,t,mf2); me[0][1][0]+=me1(u,s,t,mf2,2,1,3,5,4,6); me[0][1][1]+=me1(t,u,s,mf2,3,2,1,6,5,4); } me[0][0][0]=-me[1][1][1]; me[0][0][1]=-me[1][1][0]; me[1][0][1]=-me[0][1][0]; me[1][0][0]=-me[0][1][1]; output = real(me[0][0][0]*conj(me[0][0][0])+ me[0][0][1]*conj(me[0][0][1])+ me[0][1][0]*conj(me[0][1][0])+ me[0][1][1]*conj(me[0][1][1])+ me[1][0][0]*conj(me[1][0][0])+ me[1][0][1]*conj(me[1][0][1])+ me[1][1][0]*conj(me[1][1][0])+ me[1][1][1]*conj(me[1][1][1])); output *= 3./8.; } else { output=32./3.* (pow<4,1>(s)+pow<4,1>(t)+pow<4,1>(u)+pow<4,1>(mh2_))/s/t/u; } // spin and colour factors return output/4./64.; } Energy2 MEPP2Higgs::qgME(Energy2 s, Energy2 t, Energy2 u) { Energy2 output; if(massOption_==0) { complex A(ZERO); Energy2 si(u-mh2_); for(unsigned int ix=minLoop_;ix<=maxLoop_;++ix) { Energy2 mf2=sqr(getParticleData(long(ix))->mass()); A += mf2*(2.+2.*double(u/si)*(B(u,mf2)-B(mh2_,mf2)) +double((4.*mf2-s-t)/si)*Complex(u*C(u,mf2)-mh2_*C(mh2_,mf2))); } output =-4.*(sqr(s)+sqr(t))/sqr(si)/u*real(A*conj(A)); } else{ output =-4.*(sqr(s)+sqr(t))/u/9.; } // final colour/spin factors return output/24.; } Energy2 MEPP2Higgs::qbargME(Energy2 s, Energy2 t, Energy2 u) { Energy2 output; if(massOption_==0) { complex A(ZERO); Energy2 si(u-mh2_); for(unsigned int ix=minLoop_;ix<=maxLoop_;++ix) { Energy2 mf2=sqr(getParticleData(long(ix))->mass()); A+=mf2*(2.+2.*double(u/si)*(B(u,mf2)-B(mh2_,mf2)) +double((4.*mf2-s-t)/si)*Complex(u*C(u,mf2)-mh2_*C(mh2_,mf2))); } output =-4.*(sqr(s)+sqr(t))/sqr(si)/u*real(A*conj(A)); } else { output =-4.*(sqr(s)+sqr(t))/u/9.; } // final colour/spin factors return output/24.; } Energy4 MEPP2Higgs::loME() const { Complex I(0); if(massOption_==0) { for(unsigned int ix=minLoop_;ix<=maxLoop_;++ix) { double x = sqr(getParticleData(long(ix))->mass())/mh2_; I += 3.*x*(2.+(4.*x-1.)*F(x)); } } else { I = 1.; } return sqr(mh2_)/576./Constants::pi*norm(I); } tPDPtr MEPP2Higgs::quarkFlavour(tcPDFPtr pdf, Energy2 scale, double x, tcBeamPtr beam, double & pdfweight, bool anti) { vector weights; vector partons; pdfweight = 0.; if(!anti) { for(unsigned int ix=1;ix<=5;++ix) { partons.push_back(getParticleData(long(ix))); weights.push_back(max(0.,pdf->xfx(beam,partons.back(),scale,x))); pdfweight += weights.back(); } } else { for(unsigned int ix=1;ix<=5;++ix) { partons.push_back(getParticleData(-long(ix))); weights.push_back(max(0.,pdf->xfx(beam,partons.back(),scale,x))); pdfweight += weights.back(); } } if(pdfweight==0.) return tPDPtr(); double wgt=UseRandom::rnd()*pdfweight; for(unsigned int ix=0;ix=ZERO&&rat<1.) output=2.-2.*sqrt(1./rat-1.)*asin(sqrt(rat)); else output=2.-sqrt(1.-1./rat)*(2.*log(sqrt(rat)+sqrt(rat-1.))-pii); return output; } complex MEPP2Higgs::C(Energy2 s,Energy2 mf2) const { complex output; const Complex pii(0.,Constants::pi); double rat=s/(4.*mf2); if(s=ZERO&&rat<1.) output=-2.*sqr(asin(sqrt(rat)))/s; else { double cosh=log(sqrt(rat)+sqrt(rat-1.)); output=2.*(sqr(cosh)-sqr(Constants::pi)/4.-pii*cosh)/s; } return output; } Complex MEPP2Higgs::dIntegral(Energy2 a, Energy2 b, double y0) const { Complex output; if(b==ZERO) output=0.; else { Complex y1=0.5*(1.+sqrt(1.-4.*(a+epsi_)/b)); Complex y2=1.-y1; Complex z1=y0/(y0-y1); Complex z2=(y0-1.)/(y0-y1); Complex z3=y0/(y0-y2); Complex z4=(y0-1.)/(y0-y2); output=Math::Li2(z1)-Math::Li2(z2)+Math::Li2(z3)-Math::Li2(z4); } return output; } complex MEPP2Higgs::D(Energy2 s,Energy2 t, Energy2, Energy2 mf2) const { Complex output; Energy4 st=s*t; Energy4 root=sqrt(sqr(st)-4.*st*mf2*(s+t-mh2_)); double xp=0.5*(st+root)/st,xm=1-xp; output = 2.*(-dIntegral(mf2,s,xp)-dIntegral(mf2,t,xp) +dIntegral(mf2,mh2_,xp)+log(-xm/xp) *(log((mf2+epsi_)/GeV2)-log((mf2+epsi_-s*xp*xm)/GeV2) +log((mf2+epsi_-mh2_*xp*xm)/GeV2)-log((mf2+epsi_-t*xp*xm)/GeV2))); return output/root; } complex MEPP2Higgs::me1(Energy2 s,Energy2 t,Energy2 u, Energy2 mf2, unsigned int i ,unsigned int j ,unsigned int k , unsigned int i1,unsigned int j1,unsigned int k1) const { Energy2 s1(s-mh2_),t1(t-mh2_),u1(u-mh2_); return mf2*4.*sqrt(2.*s*t*u)* (-4.*(1./(u*t)+1./(u*u1)+1./(t*t1)) -4.*((2.*s+t)*bi_[k]/sqr(u1)+(2.*s+u)*bi_[j]/sqr(t1))/s -(s-4.*mf2)*(s1*ci_[i1]+(u-s)*ci_[j1]+(t-s)*ci_[k1])/(s*t*u) -8.*mf2*(ci_[j1]/(t*t1)+ci_[k1]/(u*u1)) +0.5*(s-4.*mf2)*(s*t*di_[k]+u*s*di_[j]-u*t*di_[i])/(s*t*u) +4.*mf2*di_[i]/s -2.*Complex(u*ci_[k]+t*ci_[j]+u1*ci_[k1]+t1*ci_[j1]-u*t*di_[i])/sqr(s)); } complex MEPP2Higgs::me2(Energy2 s,Energy2 t,Energy2 u, Energy2 mf2) const { Energy2 s1(s-mh2_),t1(t-mh2_),u1(u-mh2_); return mf2*4.*sqrt(2.*s*t*u)*(4.*mh2_+(mh2_-4.*mf2)*(s1*ci_[4]+t1*ci_[5]+u1*ci_[6]) -0.5*(mh2_-4.*mf2)*(s*t*di_[3]+u*s*di_[2]+u*t*di_[1]) )/ (s*t*u); } Complex MEPP2Higgs::F(double x) const { if(x<.25) { double root = sqrt(1.-4.*x); const Complex pii(0.,Constants::pi); return 0.5*sqr(log((1.+root)/(1.-root))-pii); } else { return -2.*sqr(asin(0.5/sqrt(x))); } } bool MEPP2Higgs::getEvent(vector & pnew, int & emis_type){ // maximum pt (half of centre-of-mass energy) Energy maxp = 0.5*generator()->maximumCMEnergy(); // set pt of emission to zero pt_=ZERO; //Working Variables Energy pt; double yj; // limits on the rapidity of the jet double minyj = -8.0,maxyj = 8.0; bool reject; double wgt; emis_type=-1; tcPDPtr outParton; for(int j=0;j<5;++j) { pt = maxp; do { double a = alpha_->overestimateValue()*prefactor_[j]*(maxyj-minyj)/(power_-1.); // generate next pt pt=GeV/pow(pow(GeV/pt,power_-1)-log(UseRandom::rnd())/a,1./(power_-1.)); // generate rapidity of the jet yj=UseRandom::rnd()*(maxyj-minyj)+ minyj; // calculate rejection weight wgt=getResult(j,pt,yj,outParton); wgt/= prefactor_[j]*pow(GeV/pt,power_); reject = UseRandom::rnd()>wgt; //no emission event if p goes past p min - basically set to outside //of the histogram bounds (hopefully hist object just ignores it) if(pt1.0) { ostringstream s; s << "MEPP2Higgs::getEvent weight for channel " << j << "is " << wgt << " which is greater than 1"; generator()->logWarning( Exception(s.str(), Exception::warning) ); } } while(reject); // set pt of emission etc if(pt>pt_){ emis_type = j; pt_=pt; yj_=yj; out_ = outParton; } } //was this an (overall) no emission event? if(pt_maximumCMEnergy()); // transverse energy Energy et=sqrt(mh2_+sqr(pt_)); // first calculate all the kinematic variables // longitudinal real correction fractions double x = pt_*exp( yj_)/sqrt(s)+et*exp( yh_)/sqrt(s); double y = pt_*exp(-yj_)/sqrt(s)+et*exp(-yh_)/sqrt(s); // that and uhat // Energy2 th = -sqrt(s)*x*pt_*exp(-yj_); // Energy2 uh = -sqrt(s)*y*pt_*exp( yj_); // Energy2 sh = x*y*s; // reconstruct the momenta // incoming momenta pnew.push_back(Lorentz5Momentum(ZERO,ZERO, x*0.5*sqrt(s), x*0.5*sqrt(s),ZERO)); pnew.push_back(Lorentz5Momentum(ZERO,ZERO, -y*0.5*sqrt(s), y*0.5*sqrt(s),ZERO)); // outgoing momenta double phi(Constants::twopi*UseRandom::rnd()); double sphi(sin(phi)),cphi(cos(phi)); pnew.push_back(Lorentz5Momentum( cphi*pt_, sphi*pt_, et*sinh(yh_), et*cosh(yh_), mass_)); pnew.push_back(Lorentz5Momentum(-cphi*pt_,-sphi*pt_,pt_*sinh(yj_), pt_*cosh(yj_),ZERO)); return true; } double MEPP2Higgs::getResult(int emis_type, Energy pt, double yj, tcPDPtr & outParton) { Energy2 s=sqr(generator()->maximumCMEnergy()); Energy2 scale = mh2_+sqr(pt); Energy et=sqrt(scale); scale = mu_F_opt_==0 ? mh2_+sqr(pt) : sqr(pt) ; // longitudinal real correction fractions double x = pt*exp( yj)/sqrt(s)+et*exp( yh_)/sqrt(s); double y = pt*exp(-yj)/sqrt(s)+et*exp(-yh_)/sqrt(s); // reject if outside region if(x<0.||x>1.||y<0.||y>1.||x*ypdf()->xfx(beams_[0],partons_[0],mh2_,x1); pdf[1]=beams_[1]->pdf()->xfx(beams_[1],partons_[1],mh2_,y1); } else { // As in Nason and Ridolfi paper ... pdf[0]=beams_[0]->pdf()->xfx(beams_[0],partons_[0],scale,x1); pdf[1]=beams_[1]->pdf()->xfx(beams_[1],partons_[1],scale,y1); } // g g -> H g if(emis_type==0) { outParton = partons_[1]; pdf[2]=beams_[0]->pdf()->xfx(beams_[0],partons_[0],scale,x); pdf[3]=beams_[1]->pdf()->xfx(beams_[1],partons_[1],scale,y); res = ggME(sh,uh,th)/loME(); } // q g -> H q else if(emis_type==1) { outParton = quarkFlavour(beams_[0]->pdf(),scale,x,beams_[0],pdf[2],false); pdf[3]=beams_[1]->pdf()->xfx(beams_[1],partons_[1],scale,y); res = outParton ? qgME(sh,uh,th)/loME() : ZERO; } // g q -> H q else if(emis_type==2) { pdf[2]=beams_[0]->pdf()->xfx(beams_[0],partons_[0],scale,x); outParton = quarkFlavour(beams_[1]->pdf(),scale,y,beams_[1],pdf[3],false); res = outParton ? qgME(sh,th,uh)/loME() : ZERO; } // qbar g -> H qbar else if(emis_type==3) { outParton = quarkFlavour(beams_[0]->pdf(),scale,x,beams_[0],pdf[2],true); pdf[3]=beams_[1]->pdf()->xfx(beams_[1],partons_[1],scale,y); res = outParton ? qbargME(sh,uh,th)/loME() : ZERO; } // g qbar -> H qbar else if(emis_type==4) { pdf[2]=beams_[0]->pdf()->xfx(beams_[0],partons_[0],scale,x); outParton = quarkFlavour(beams_[1]->pdf(),scale,y,beams_[1],pdf[3],true); res = outParton ? qbargME(sh,th,uh)/loME() : ZERO; } //deals with pdf zero issue at large x if(pdf[0]<=0.||pdf[1]<=0.||pdf[2]<=0.||pdf[3]<=0.) { res = ZERO; } else { res *= pdf[2]*pdf[3]/pdf[0]/pdf[1]*mh2_/sh; } scale = mu_R_opt_==0 ? mh2_+sqr(pt) : sqr(pt) ; return alpha_->ratio(scale)/8./sqr(Constants::pi)*mh2_/sh*GeV*pt*res; } void MEPP2Higgs::initializeMECorrection(RealEmissionProcessPtr born, double & initial, double & final) { final = 1.; initial = born->bornIncoming()[0]->id()==ParticleID::g ? enhance_ : 1.; } diff --git a/MatrixElement/Hadron/MEPP2HiggsVBF.cc b/MatrixElement/Hadron/MEPP2HiggsVBF.cc --- a/MatrixElement/Hadron/MEPP2HiggsVBF.cc +++ b/MatrixElement/Hadron/MEPP2HiggsVBF.cc @@ -1,1459 +1,1462 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the MEPP2HiggsVBF class. // #include "MEPP2HiggsVBF.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/MatrixElement/Tree2toNDiagram.h" #include "ThePEG/PDT/StandardMatchers.h" #include #include "Herwig/Utilities/Maths.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "ThePEG/Repository/CurrentGenerator.h" #include "Herwig/Shower/RealEmissionProcess.h" using namespace Herwig; // namespace { // using namespace Herwig; // using namespace ThePEG; // using namespace ThePEG::Helicity; // void debuggingMatrixElement(bool BGF, // tcPDPtr partons1, tcPDPtr partons2, // tcPDPtr partons3, tcPDPtr partons4, // const Lorentz5Momentum & psystem0, // const Lorentz5Momentum & psystem1, // const Lorentz5Momentum & pother0, // const Lorentz5Momentum & pother1, // const Lorentz5Momentum & p0, // const Lorentz5Momentum & p1, // const Lorentz5Momentum & p2, // const Lorentz5Momentum & phiggs, // Energy2 Q12, Energy2 scale, // double old) { // // get the vertex and the boson // tcHwSMPtr hwsm=ThePEG::dynamic_ptr_cast // (CurrentGenerator::current().standardModel()); // assert(hwsm); // tcPDPtr boson; // AbstractFFVVertexPtr weakVertex; // AbstractFFVVertexPtr strongVertex = hwsm->vertexFFG(); // AbstractVVSVertexPtr higgsVertex = hwsm->vertexWWH(); // if(partons1->id()==partons2->id()) { // weakVertex = hwsm->vertexFFZ(); // boson = hwsm->getParticleData(ParticleID::Z0); // } // else { // weakVertex = hwsm->vertexFFW(); // boson = hwsm->getParticleData(ParticleID::Wplus); // } // tcPDPtr hdata = hwsm->getParticleData(ParticleID::h0); // tcPDPtr gluon = hwsm->getParticleData(ParticleID::g); // SpinorWaveFunction q1,q2; // SpinorBarWaveFunction qbar1,qbar2; // if(partons1->id()>0) { // q1 = SpinorWaveFunction (psystem0,partons1,incoming); // qbar1 = SpinorBarWaveFunction(psystem1,partons2,outgoing); // } // else { // q1 = SpinorWaveFunction (psystem1,partons2,outgoing); // qbar1 = SpinorBarWaveFunction(psystem0,partons1,incoming); // } // if(partons3->id()>0) { // q2 = SpinorWaveFunction (pother0,partons3,incoming); // qbar2 = SpinorBarWaveFunction(pother1,partons4,outgoing); // } // else { // q2 = SpinorWaveFunction (pother1,partons4,outgoing); // qbar2 = SpinorBarWaveFunction(pother0,partons3,incoming); // } // ScalarWaveFunction higgs(phiggs,hdata,outgoing); // if(!BGF) { // SpinorWaveFunction q1p; // SpinorBarWaveFunction qbar1p; // if(partons1->id()>0) { // q1p = SpinorWaveFunction (p0 ,partons1,incoming); // qbar1p = SpinorBarWaveFunction(p1 ,partons2,outgoing); // } // else { // q1p = SpinorWaveFunction (p1 ,partons2,outgoing); // qbar1p = SpinorBarWaveFunction(p0 ,partons1,incoming); // } // VectorWaveFunction gl(p2,gluon,outgoing); // double lome(0.),realme(0.); // for(unsigned int lhel1=0;lhel1<2;++lhel1) { // q2.reset(lhel1); // for(unsigned int lhel2=0;lhel2<2;++lhel2) { // qbar2.reset(lhel2); // VectorWaveFunction off1 // = weakVertex->evaluate(scale,3,boson,q2,qbar2); // VectorWaveFunction off2 // = higgsVertex->evaluate(scale,3,boson,off1,higgs); // for(unsigned int qhel1=0;qhel1<2;++qhel1) { // q1.reset(qhel1); // q1p.reset(qhel1); // for(unsigned int qhel2=0;qhel2<2;++qhel2) { // qbar1.reset(qhel2); // qbar1p.reset(qhel2); // Complex diag = weakVertex->evaluate(scale,q1,qbar1,off2); // lome += norm(diag); // for(unsigned int ghel=0;ghel<2;++ghel) { // gl.reset(2*ghel); // SpinorWaveFunction inter1 = // strongVertex->evaluate(Q12,5,q1p.particle(),q1p,gl); // Complex diag1 = weakVertex->evaluate(scale,inter1,qbar1p,off2); // SpinorBarWaveFunction inter2 = // strongVertex->evaluate(Q12,5,qbar1p.particle(),qbar1p,gl); // Complex diag2 = weakVertex->evaluate(scale,q1p,inter2,off2); // realme += norm(diag1+diag2); // } // } // } // } // } // double test1 = realme/lome/hwsm->alphaS(Q12)*Q12*UnitRemoval::InvE2; // cerr << "testing ratio A " << old/test1 << "\n"; // } // else { // SpinorWaveFunction q1p; // SpinorBarWaveFunction qbar1p; // if(partons1->id()>0) { // q1p = SpinorWaveFunction (p2,partons1->CC(),outgoing); // qbar1p = SpinorBarWaveFunction(p1,partons2 ,outgoing); // } // else { // q1p = SpinorWaveFunction (p1,partons2 ,outgoing); // qbar1p = SpinorBarWaveFunction(p2,partons1->CC(),outgoing); // } // VectorWaveFunction gl(p0,gluon,incoming); // double lome(0.),realme(0.); // for(unsigned int lhel1=0;lhel1<2;++lhel1) { // q2.reset(lhel1); // for(unsigned int lhel2=0;lhel2<2;++lhel2) { // qbar2.reset(lhel2); // VectorWaveFunction off1 // = weakVertex->evaluate(scale,3,boson,q2,qbar2); // VectorWaveFunction off2 // = higgsVertex->evaluate(scale,3,boson,off1,higgs); // for(unsigned int qhel1=0;qhel1<2;++qhel1) { // q1.reset(qhel1); // q1p.reset(qhel1); // for(unsigned int qhel2=0;qhel2<2;++qhel2) { // qbar1.reset(qhel2); // qbar1p.reset(qhel2); // Complex diag = weakVertex->evaluate(scale,q1,qbar1,off2); // lome += norm(diag); // for(unsigned int ghel=0;ghel<2;++ghel) { // gl.reset(2*ghel); // SpinorWaveFunction inter1 = // strongVertex->evaluate(Q12,5,q1p.particle(),q1p,gl); // Complex diag1 = weakVertex->evaluate(scale,inter1,qbar1p,off2); // SpinorBarWaveFunction inter2 = // strongVertex->evaluate(Q12,5,qbar1p.particle(),qbar1p,gl); // Complex diag2 = weakVertex->evaluate(scale,q1p,inter2,off2); // realme += norm(diag1+diag2); // } // } // } // } // } // double test1 = realme/lome/hwsm->alphaS(Q12)*Q12*UnitRemoval::InvE2; // cerr << "testing ratio B " << old/test1 << "\n"; // } // } // } MEPP2HiggsVBF::MEPP2HiggsVBF() : comptonWeight_(8.), BGFWeight_(30.), pTmin_(1.*GeV),initial_(10.),final_(8.), procProb_(0.5), comptonInt_(0.), bgfInt_(0.), nover_(0),maxwgt_(make_pair(0.,0.)) {} void MEPP2HiggsVBF::doinit() { gluon_ = getParticleData(ParticleID::g); // integrals of me over phase space double r5=sqrt(5.),darg((r5-1.)/(r5+1.)),ath(0.5*log((1.+1./r5)/(1.-1./r5))); comptonInt_ = 2.*(-21./20.-6./(5.*r5)*ath+sqr(Constants::pi)/3. -2.*Math::ReLi2(1.-darg)-2.*Math::ReLi2(1.-1./darg)); bgfInt_ = 121./9.-56./r5*ath; // get the vertex pointers from the SM object tcHwSMPtr hwsm= dynamic_ptr_cast(standardModel()); if(!hwsm) throw InitException() << "Wrong type of StandardModel object in " << "MEPP2HiggsVBF::doinit() the Herwig" << " version must be used" << Exception::runerror; // set the vertex setWWHVertex(hwsm->vertexWWH()); higgs(getParticleData(ParticleID::h0)); MEfftoffH::doinit(); } void MEPP2HiggsVBF::dofinish() { MEfftoffH::dofinish(); if(nover_==0) return; generator()->log() << "VBFMECorrection when applying the hard correction " << nover_ << " weights larger than one were generated of which" << " the largest was " << maxwgt_.first << " for the QCD compton" << " processes and " << maxwgt_.second << " for the BGF process\n"; } void MEPP2HiggsVBF::getDiagrams() const { // get the quark particle data objects as we'll be using them tcPDPtr q[6],qbar[6]; for ( int ix=0; ix<5; ++ix ) { q [ix] = getParticleData(ix+1); qbar[ix] = q[ix]->CC(); } // WW processes if(process()==0||process()==1) { std::vector > parentpair; parentpair.reserve(6); // don't even think of putting 'break' in here! switch(maxFlavour()) { case 5: if (minFlavour()<=4) parentpair.push_back(make_pair(getParticleData(ParticleID::b), getParticleData(ParticleID::c))); if (minFlavour()<=2) parentpair.push_back(make_pair(getParticleData(ParticleID::b), getParticleData(ParticleID::u))); [[fallthrough]]; case 4: if (minFlavour()<=3) parentpair.push_back(make_pair(getParticleData(ParticleID::s), getParticleData(ParticleID::c))); if (minFlavour()<=1) parentpair.push_back(make_pair(getParticleData(ParticleID::d), getParticleData(ParticleID::c))); [[fallthrough]]; case 3: if (minFlavour()<=2) parentpair.push_back(make_pair(getParticleData(ParticleID::s), getParticleData(ParticleID::u))); [[fallthrough]]; case 2: if (minFlavour()<=1) parentpair.push_back(make_pair(getParticleData(ParticleID::d), getParticleData(ParticleID::u))); [[fallthrough]]; default: ; } for(unsigned int ix=0;ix q1' q2' h if(parentpair[ix].first->id()id()) { add(new_ptr((Tree2toNDiagram(4), parentpair[ix].first, WMinus(), WPlus(), parentpair[iy].second, 1, parentpair[ix].second, 3, parentpair[iy].first, 2, higgs(),-1))); } else { add(new_ptr((Tree2toNDiagram(4), parentpair[iy].second, WPlus(), WMinus(), parentpair[ix].first, 1, parentpair[iy].first, 3, parentpair[ix].second, 2, higgs(),-1))); } // q1 qbar2 -> q1' qbar2' h add(new_ptr((Tree2toNDiagram(4), parentpair[ix].first, WMinus(), WPlus(), parentpair[iy].first->CC(), 1, parentpair[ix].second, 3, parentpair[iy].second->CC(), 2, higgs(),-1))); add(new_ptr((Tree2toNDiagram(4),parentpair[iy].second, WPlus(), WMinus(), parentpair[ix].second->CC(), 1, parentpair[iy].first, 3, parentpair[ix].first->CC(), 2, higgs(),-1))); // qbar1 qbar2 -> qbar1' qbar2' h if(parentpair[ix].first->id()id()) { add(new_ptr((Tree2toNDiagram(4), parentpair[ix].first->CC(), WPlus(), WMinus(), parentpair[iy].second->CC(), 1, parentpair[ix].second->CC(), 3, parentpair[iy].first->CC(), 2, higgs(),-1))); } else { add(new_ptr((Tree2toNDiagram(4), parentpair[iy].second->CC(), WMinus(), WPlus(), parentpair[ix].first->CC(), 1, parentpair[iy].first->CC(), 3, parentpair[ix].second->CC(), 2, higgs(),-1))); } } } } // ZZ processes if(process()==0||process()==2) { for(unsigned int ix=minFlavour()-1;ix q q H add(new_ptr((Tree2toNDiagram(4), q[ix], Z0(), Z0(), q[iy], 1, q[ix], 3, q[iy], 2, higgs(),-2))); // qbar qbar -> qbar qbar H add(new_ptr((Tree2toNDiagram(4), qbar[ix], Z0(), Z0(), qbar[iy], 1, qbar[ix], 3, qbar[iy], 2, higgs(),-2))); } // q qbar -> q qbar H for(unsigned int iy=minFlavour()-1;iy> initial_ >> final_ >> alpha_ >> iunit(pTmin_,GeV) >> comptonWeight_ >> BGFWeight_ >> gluon_ >> comptonInt_ >> bgfInt_ >> procProb_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigMEPP2HiggsVBF("Herwig::MEPP2HiggsVBF", "HwMEHadron.so"); void MEPP2HiggsVBF::Init() { static ClassDocumentation documentation ("The MEPP2HiggsVBF class implements Higgs production via vector-boson fusion"); static Reference interfaceShowerAlphaQCD ("ShowerAlphaQCD", "The object calculating the strong coupling constant", &MEPP2HiggsVBF::alpha_, false, false, true, false, false); static Parameter interfacepTMin ("pTMin", "The minimum pT", &MEPP2HiggsVBF::pTmin_, GeV, 1.*GeV, 0.0*GeV, 10.0*GeV, false, false, Interface::limited); static Parameter interfaceComptonWeight ("ComptonWeight", "Weight for the overestimate ofthe compton channel", &MEPP2HiggsVBF::comptonWeight_, 50.0, 0.0, 100.0, false, false, Interface::limited); static Parameter interfaceBGFWeight ("BGFWeight", "Weight for the overestimate of the BGF channel", &MEPP2HiggsVBF::BGFWeight_, 100.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfaceProcessProbability ("ProcessProbability", "The probabilty of the QCD compton process for the process selection", &MEPP2HiggsVBF::procProb_, 0.3, 0.0, 1., false, false, Interface::limited); } RealEmissionProcessPtr MEPP2HiggsVBF::generateHardest(RealEmissionProcessPtr born, ShowerInteraction inter) { - if(inter==ShowerInteraction::QED) return RealEmissionProcessPtr(); + // check if generating QCD radiation + if(inter!=ShowerInteraction::QCD && inter!=ShowerInteraction::QEDQCD && + inter!=ShowerInteraction::ALL) + return RealEmissionProcessPtr(); pair first,second; pair beams; pair hadrons; // get the incoming particles for(unsigned int ix=0;ixbornIncoming().size();++ix) { if(!first.first) { first.first = born->bornIncoming()[ix]; hadrons.first = born->hadrons()[ix]; beams.first = dynamic_ptr_cast(born->hadrons()[ix]->dataPtr()); } else { second.first = born->bornIncoming()[ix]; hadrons.second = born->hadrons()[ix]; beams.second = dynamic_ptr_cast(born->hadrons()[ix]->dataPtr()); } } // and the outgoing for(unsigned int ix=0;ixbornOutgoing().size();++ix) { if(born->bornOutgoing()[ix]->id()==ParticleID::h0) { higgs_ = born->bornOutgoing()[ix]; } else { if(abs(born->bornOutgoing()[ix]->id())>5) continue; if(born->bornOutgoing()[ix]->colourLine()&& born->bornOutgoing()[ix]->colourLine()==first.first->colourLine()) { first.second = born->bornOutgoing()[ix]; continue; } if(born->bornOutgoing()[ix]->antiColourLine()&& born->bornOutgoing()[ix]->antiColourLine()==first.first->antiColourLine()) { first.second = born->bornOutgoing()[ix]; continue; } if(born->bornOutgoing()[ix]->colourLine()&& born->bornOutgoing()[ix]->colourLine()==second.first->colourLine()) { second.second = born->bornOutgoing()[ix]; continue; } if(born->bornOutgoing()[ix]->antiColourLine()&& born->bornOutgoing()[ix]->antiColourLine()==second.first->antiColourLine()) { second.second = born->bornOutgoing()[ix]; continue; } } } // loop over the two possible emitting systems q_ [0] = first .second->momentum()-first .first->momentum(); q2_[0] = -q_[0].m2(); q_ [1] = second.second->momentum()-second.first->momentum(); q2_[1] = -q_[1].m2(); for(unsigned int ix=0;ix<2;++ix) { if(ix==1) { swap(first,second); swap(beams.first,beams.second); swap(hadrons.first,hadrons.second); } // check beam, all particles assert(beams.first && higgs_ && first .first && first.second && second.first && second.second); // beam and pdf beam_[ix] = beams.first; pdf_ [ix] = beam_[ix]->pdf(); assert(beam_[ix] && pdf_[ix] ); // Particle data objects partons_[ix][0] = first. first->dataPtr(); partons_[ix][1] = first.second->dataPtr(); partons_[ix][2] = second. first->dataPtr(); partons_[ix][3] = second.second->dataPtr(); // extract the born variables xB_[ix] = first.first->momentum().rho()/hadrons.first->momentum().rho(); Lorentz5Momentum pb = first.first->momentum(); Axis axis(q_[ix].vect().unit()); double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); rot_[ix] = LorentzRotation(); if(axis.perp2()>1e-20) { rot_[ix].setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); rot_[ix].rotateX(Constants::pi); } if(abs(1.-q_[ix].e()/q_[ix].vect().mag())>1e-6) rot_[ix].boostZ( q_[ix].e()/q_[ix].vect().mag()); pb *= rot_[ix]; if(pb.perp2()/GeV2>1e-20) { Boost trans = -1./pb.e()*pb.vect(); trans.setZ(0.); rot_[ix].boost(trans); } // momenta of the particles phiggs_ [ix] = rot_[ix]*higgs_->momentum(); pother_ [ix][0] = rot_[ix]*second. first->momentum(); pother_ [ix][1] = rot_[ix]*second.second->momentum(); psystem_[ix][0] = rot_[ix]* first. first->momentum(); psystem_[ix][1] = rot_[ix]* first.second->momentum(); q_[ix] *= rot_[ix]; pTCompton_[ix] = pTBGF_[ix] = ZERO; // generate a compton point generateCompton(ix); // generate a BGF point generateBGF(ix); } // no valid emissions, return if(pTCompton_[0]pT()[ShowerInteraction::QCD] = pTmin_; return born; } // find the maximum pT emission unsigned int system = 0; bool isCompton = false; Energy pTmax = -GeV; for(unsigned int ix=0;ix<2;++ix) { if(pTCompton_[ix]>pTmax) { pTmax = pTCompton_[ix]; isCompton = true; system = ix; } if(pTBGF_[ix]>pTmax) { pTmax = pTBGF_[ix]; isCompton = false; system = ix; } } if(system==0) { swap(first,second); swap(beams.first,beams.second); swap(hadrons.first,hadrons.second); } // the non emitting particles PPtr spectin =second.first ->dataPtr()->produceParticle(second.first ->momentum()); PPtr spectout=second.second->dataPtr()->produceParticle(second.second->momentum()); spectout->incomingColour(spectin,spectout->id()<0); PPtr higgs = higgs_->dataPtr()->produceParticle(higgs_->momentum()); rot_[system].invert(); PPtr newout,newin,emitted; bool FSR = false; bool isQuark = first.first->colourLine(); // compton hardest if(isCompton) { for(unsigned int ix=0;ixproduceParticle(ComptonMomenta_[system][1]); emitted = gluon_ ->produceParticle(ComptonMomenta_[system][2]); newin = partons_[system][0]->produceParticle(ComptonMomenta_[system][0]); FSR = !ComptonISFS_[system]; emitted->incomingColour(newin,!isQuark); emitted->colourConnect(newout,!isQuark); } // BGF hardest else { for(unsigned int ix=0;ixproduceParticle(BGFMomenta_[system][0]); emitted = partons_[system][0]->CC()->produceParticle(BGFMomenta_[system][2]); newout = partons_[system][1] ->produceParticle(BGFMomenta_[system][1]); emitted->incomingColour(newin, isQuark); newout ->incomingColour(newin,!isQuark); } pair x; pair radiators; if(born->bornIncoming()[0]!=first.first) { born->incoming().push_back(spectin); born->incoming().push_back(newin); x.first = born->bornIncoming()[0]->momentum().rho()/born->hadrons()[0]->momentum().rho(); x.second = newin ->momentum().rho()/born->hadrons()[1]->momentum().rho(); radiators.first = 1; } else { born->incoming().push_back(newin); born->incoming().push_back(spectin); x.first = newin ->momentum().rho()/born->hadrons()[0]->momentum().rho(); x.second = born->bornIncoming()[1]->momentum().rho()/born->hadrons()[1]->momentum().rho(); radiators.first = 0; } born->x(x); for(unsigned int ix=0;ixbornOutgoing().size();++ix) { if(born->bornOutgoing()[ix]==second.second) { born->outgoing().push_back(spectout); } else if(born->bornOutgoing()[ix]==first.second) { radiators.second = born->outgoing().size()+2; born->outgoing().push_back(newout); } else born->outgoing().push_back(higgs); } if(FSR) swap(radiators.first,radiators.second); born->emitter (radiators.first ); born->spectator(radiators.second); born->emitted(born->outgoing().size()+2); // radiated particle born->outgoing().push_back(emitted); born->pT()[ShowerInteraction::QCD] = isCompton ? pTCompton_[system] : pTBGF_[system]; born->interaction(ShowerInteraction::QCD); return born; } void MEPP2HiggsVBF::generateCompton(unsigned int system) { // calculate the A coefficient for the correlations acoeff_ = A(partons_[system][0],partons_[system][1], partons_[system][2],partons_[system][3]); // maximum value of the xT double xT = sqrt((1.-xB_[system])/xB_[system]); double xTMin = 2.*pTmin_/sqrt(q2_[system]); double zp; // prefactor double a = alpha_->overestimateValue()*comptonWeight_/Constants::twopi; // loop to generate kinematics double wgt(0.),xp(0.); l_ = 2.*pother_[system][0]/sqrt(q2_[system]); m_ = 2.*pother_[system][1]/sqrt(q2_[system]); vector azicoeff; do { wgt = 0.; // intergration variables dxT/xT^3 xT *= 1./sqrt(1.-2.*log(UseRandom::rnd())/a*sqr(xT)); // dz zp = UseRandom::rnd(); xp = 1./(1.+0.25*sqr(xT)/zp/(1.-zp)); // check allowed if(xp1.) continue; // phase-space piece of the weight wgt = 8.*(1.-xp)*zp/comptonWeight_; // PDF piece of the weight Energy2 mu2 = q2_[system]*((1.-xp)*(1-zp)*zp/xp+1.); double pdf = pdf_[system]->xfx(beam_[system],partons_[system][0], mu2 ,xB_[system]/xp)/ pdf_[system]->xfx(beam_[system],partons_[system][0], scale(),xB_[system] ); wgt *= max(pdf,0.); // me piece of the weight // double me = comptonME(system,xT,xp,zp,phi); double x2 = 1.-(1.-zp)/xp; azicoeff = ComptonME(xp,x2,xT,l_,m_); double me = 4./3.*alpha_->ratio(0.25*q2_[system]*sqr(xT))* (azicoeff[0]+0.5*azicoeff[2]+0.5*azicoeff[4]); wgt *= me; if(wgt>1.||wgt<-1e-8) { ostringstream wstring; wstring << "MEPP2HiggsVBF::generateCompton() " << "Weight greater than one or less than zero" << "wgt = " << wgt << "\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } while(xT>xTMin&&UseRandom::rnd()>wgt); if(xT<=xTMin) { pTCompton_[system]=-GeV; return; } // generate phi unsigned int itry(0); double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.); double phiwgt,phi; do { phi = UseRandom::rnd()*Constants::twopi; double cphi(cos(phi)),sphi(sin(phi)); phiwgt = azicoeff[0]+azicoeff[5]*sphi*cphi +azicoeff[1]*cphi+azicoeff[2]*sqr(cphi) +azicoeff[3]*sphi+azicoeff[4]*sqr(sphi); ++itry; } while (phimax*UseRandom::rnd() > phiwgt && itry<200); if(itry==200) throw Exception() << "Too many tries in MEPP2HiggsVBF" << "::generateCompton() to" << " generate phi" << Exception::eventerror; // momenta for the configuration Energy Q(sqrt(q2_[system])); double x1 = -1./xp; double x2 = 1.-(1.-zp)/xp; double x3 = 2.+x1-x2; Lorentz5Momentum p1( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi), -0.5*Q*x2, 0.5*Q*sqrt(sqr(xT)+sqr(x2))); Lorentz5Momentum p2(-0.5*Q*xT*cos(phi), -0.5*Q*xT*sin(phi), -0.5*Q*x3, 0.5*Q*sqrt(sqr(xT)+sqr(x3))); Lorentz5Momentum p0(ZERO,ZERO,-0.5*Q*x1,-0.5*Q*x1); pTCompton_[system] = 0.5*Q*xT; ComptonMomenta_[system].resize(3); ComptonMomenta_[system][0] = p0; ComptonMomenta_[system][1] = p1; ComptonMomenta_[system][2] = p2; ComptonISFS_[system] = zp>xp; } double MEPP2HiggsVBF::comptonME(unsigned int system, double xT, double xp, double zp, double phi) { // scale and prefactors double CFfact = 4./3.*alpha_->ratio(0.25*q2_[system]*sqr(xT)); Energy Q(sqrt(q2_[system])); double x1 = -1./xp; double x2 = 1.-(1.-zp)/xp; double x3 = 2.+x1-x2; //set NLO momenta Lorentz5Momentum p1( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi), -0.5*Q*x2, 0.5*Q*sqrt(sqr(xT)+sqr(x2))); Lorentz5Momentum p2(-0.5*Q*xT*cos(phi), -0.5*Q*xT*sin(phi), -0.5*Q*x3, 0.5*Q*sqrt(sqr(xT)+sqr(x3))); Lorentz5Momentum p0(ZERO,ZERO,-0.5*Q*x1,-0.5*Q*x1); Lorentz5Momentum qnlo = p2+p1-p0; // Breit frame variables Lorentz5Momentum r1 = -p0/x1; Lorentz5Momentum r2 = p1/x2; // electroweak parameters double c0L,c1L,c0R,c1R; // W if(partons_[system][0]->id()!=partons_[system][1]->id()) { c0L = sqrt(0.5); c0R = 0; c1L = sqrt(0.5); c1R = 0; } // Z else { if(abs(partons_[system][0]->id())%2==0) { c0L = generator()->standardModel()->vu()+ generator()->standardModel()->au(); c0R = generator()->standardModel()->vu()- generator()->standardModel()->au(); } else { c0L = generator()->standardModel()->vd()+ generator()->standardModel()->ad(); c0R = generator()->standardModel()->vd()- generator()->standardModel()->ad(); } if(abs(partons_[system][2]->id())%2==0) { c1L = generator()->standardModel()->vu()+ generator()->standardModel()->au(); c1R = generator()->standardModel()->vu()- generator()->standardModel()->au(); } else { c1L = generator()->standardModel()->vd()+ generator()->standardModel()->ad(); c1R = generator()->standardModel()->vd()- generator()->standardModel()->ad(); } c0L *= 0.25; c0R *= 0.25; c1L *= 0.25; c1R *= 0.25; } // Matrix element variables double G1 = sqr(c0L*c1L)+sqr(c0R*c1R); double G2 = sqr(c0L*c1R)+sqr(c0R*c1L); Energy4 term1,term2,loME; if(partons_[system][0]->id()>0) { if(partons_[system][2]->id()>0) { term1 = loMatrixElement(r1 ,pother_[system][0], qnlo+r1 ,pother_[system][1],G1,G2); term2 = loMatrixElement(r2-qnlo ,pother_[system][0], r2 ,pother_[system][1],G1,G2); loME = loMatrixElement(psystem_[system][0],pother_[system][0], psystem_[system][1],pother_[system][1],G1,G2); } else { term1 = loMatrixElement(r1 ,pother_[system][1], qnlo+r1 ,pother_[system][0],G1,G2); term2 = loMatrixElement(r2-qnlo ,pother_[system][1], r2 ,pother_[system][0],G1,G2); loME = loMatrixElement(psystem_[system][0],pother_[system][1], psystem_[system][1],pother_[system][0],G1,G2); } } else { if(partons_[system][2]->id()>0) { term1 = loMatrixElement(qnlo+r1 ,pother_[system][0], r1 ,pother_[system][1],G1,G2); term2 = loMatrixElement(r2 ,pother_[system][0], r2-qnlo ,pother_[system][1],G1,G2); loME = loMatrixElement(psystem_[system][1],pother_[system][0], psystem_[system][0],pother_[system][1],G1,G2); } else { term1 = loMatrixElement(qnlo+r1,pother_[system][1],r1 , pother_[system][0],G1,G2); term2 = loMatrixElement(r2 ,pother_[system][1],r2-qnlo, pother_[system][0],G1,G2); loME = loMatrixElement(psystem_[system][1],pother_[system][1], psystem_[system][0],pother_[system][0],G1,G2); } } double R1 = term1/loME; double R2 = sqr(x2)/(sqr(x2)+sqr(xT))*(term2/loME); // debuggingMatrixElement(false, // partons_[system][0],partons_[system][1], // partons_[system][2],partons_[system][3], // psystem_[system][0],psystem_[system][1], // pother_ [system][0],pother_ [system][1], // p0,p1,p2,phiggs_[system],q2_[system],scale(), // 8.*Constants::pi/(1.-xp)/(1.-zp)*(R1+sqr(xp)*(sqr(x2)+sqr(xT))*R2)); // cerr << "testing pieces A " << R1 << " " << sqr(xp)*(sqr(x2)+sqr(xT)) << " " << R2 << "\n"; return CFfact*(R1+sqr(xp)*(sqr(x2)+sqr(xT))*R2); } void MEPP2HiggsVBF::generateBGF(unsigned int system) { // maximum value of the xT double xT = (1.-xB_[system])/xB_[system]; double xTMin = 2.*pTmin_/sqrt(q2_[system]); double zp; // prefactor double a = alpha_->overestimateValue()*BGFWeight_/Constants::twopi; // loop to generate kinematics double wgt(0.),xp(0.); l_ = 2.*pother_[system][0]/sqrt(q2_[system]); m_ = 2.*pother_[system][1]/sqrt(q2_[system]); vector azicoeff; do { wgt = 0.; // intergration variables dxT/xT^3 xT *= 1./sqrt(1.-2.*log(UseRandom::rnd())/a*sqr(xT)); // dzp zp = UseRandom::rnd(); xp = 1./(1.+0.25*sqr(xT)/zp/(1.-zp)); // check allowed if(xp1.) continue; // phase-space piece of the weight wgt = 8.*sqr(1.-xp)*zp/BGFWeight_; // PDF piece of the weight Energy2 mu2 = q2_[system]*((1.-xp)*(1-zp)*zp/xp+1.); wgt *= pdf_[system]->xfx(beam_[system],gluon_ , mu2 ,xB_[system]/xp)/ pdf_[system]->xfx(beam_[system],partons_[system][0], scale(),xB_[system]); // me piece of the weight //double me = BGFME(system,xT,xp,zp,phi); double x1 = -1./xp; double x2 = 1.-(1.-zp)/xp; double x3 = 2.+x1-x2; azicoeff = BGFME(xp,x2,x3,xT,l_,m_); double me = 0.5*alpha_->ratio(0.25*q2_[system]*sqr(xT))* (azicoeff[0]+0.5*azicoeff[2]+0.5*azicoeff[4]); wgt *= me; if(wgt>1.||wgt<-1e-8) { ostringstream wstring; wstring << "MEPP2HiggsVBF::generateBGF() " << "Weight greater than one or less than zero" << "wgt = " << wgt << "\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } while(xT>xTMin&&UseRandom::rnd()>wgt); if(xT<=xTMin) { pTBGF_[system] = -GeV; return; } // generate phi unsigned int itry(0); double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.); double phiwgt,phi; do { phi = UseRandom::rnd()*Constants::twopi; double cphi(cos(phi)),sphi(sin(phi)); phiwgt = azicoeff[0]+azicoeff[5]*sphi*cphi +azicoeff[1]*cphi+azicoeff[2]*sqr(cphi) +azicoeff[3]*sphi+azicoeff[4]*sqr(sphi); ++itry; } while (phimax*UseRandom::rnd() > phiwgt && itry<200); if(itry==200) throw Exception() << "Too many tries in MEPP2HiggsVBF" << "::generateBGF() to" << " generate phi" << Exception::eventerror; // momenta for the configuration Energy Q(sqrt(q2_[system])); double x1 = -1./xp; double x2 = 1.-(1.-zp)/xp; double x3 = 2.+x1-x2; Lorentz5Momentum p1( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi), -0.5*Q*x2, 0.5*Q*sqrt(sqr(xT)+sqr(x2))); Lorentz5Momentum p2(-0.5*Q*xT*cos(phi), -0.5*Q*xT*sin(phi), -0.5*Q*x3, 0.5*Q*sqrt(sqr(xT)+sqr(x3))); Lorentz5Momentum p0(ZERO,ZERO,-0.5*Q*x1,-0.5*Q*x1); pTBGF_[system] = 0.5*Q*xT; BGFMomenta_[system].resize(3); BGFMomenta_[system][0] = p0; BGFMomenta_[system][1] = p1; BGFMomenta_[system][2] = p2; } double MEPP2HiggsVBF::BGFME(unsigned int system, double xT, double xp, double zp, double phi) { // scale and prefactors double TRfact = 0.5*alpha_->ratio(0.25*q2_[system]*sqr(xT)); Energy Q(sqrt(q2_[system])); double x1 = -1./xp; double x2 = 1.-(1.-zp)/xp; double x3 = 2.+x1-x2; // Set NLO momenta Lorentz5Momentum p1( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi), -0.5*Q*x2, 0.5*Q*sqrt(sqr(xT)+sqr(x2))); Lorentz5Momentum p2(-0.5*Q*xT*cos(phi), -0.5*Q*xT*sin(phi), -0.5*Q*x3, 0.5*Q*sqrt(sqr(xT)+sqr(x3))); Lorentz5Momentum p0(ZERO,ZERO,-0.5*Q*x1,-0.5*Q*x1); Lorentz5Momentum qnlo = p2+p1-p0; // Breit frame variables Lorentz5Momentum r2 = p1/x2; Lorentz5Momentum r3 = -p2/x3; // electroweak parameters double c0L,c1L,c0R,c1R; // W if(partons_[system][0]->id()!=partons_[system][1]->id()) { c0L = sqrt(0.5); c0R = 0; c1L = sqrt(0.5); c1R = 0; } // Z else { if(abs(partons_[system][0]->id())%2==0) { c0L = generator()->standardModel()->vu()+ generator()->standardModel()->au(); c0R = generator()->standardModel()->vu()- generator()->standardModel()->au(); } else { c0L = generator()->standardModel()->vd()+ generator()->standardModel()->ad(); c0R = generator()->standardModel()->vd()- generator()->standardModel()->ad(); } if(abs(partons_[system][2]->id())%2==0) { c1L = generator()->standardModel()->vu()+ generator()->standardModel()->au(); c1R = generator()->standardModel()->vu()- generator()->standardModel()->au(); } else { c1L = generator()->standardModel()->vd()+ generator()->standardModel()->ad(); c1R = generator()->standardModel()->vd()- generator()->standardModel()->ad(); } c0L *= 0.25; c0R *= 0.25; c1L *= 0.25; c1R *= 0.25; } // Matrix element variables double G1 = sqr(c0L*c1L)+sqr(c0R*c1R); double G2 = sqr(c0L*c1R)+sqr(c0R*c1L); Energy4 term2,term3,loME; if(partons_[system][0]->id()>0) { if(partons_[system][2]->id()>0) { term2 = loMatrixElement(r2-qnlo,pother_[system][0], r2 ,pother_[system][1],G1,G2); term3 = loMatrixElement(r3 ,pother_[system][0], qnlo+r3,pother_[system][1],G1,G2); loME = loMatrixElement(psystem_[system][0],pother_[system][0], psystem_[system][1],pother_[system][1],G1,G2); } else { term2 = loMatrixElement(r2-qnlo,pother_[system][1], r2 ,pother_[system][0],G1,G2); term3 = loMatrixElement(r3 ,pother_[system][1], qnlo+r3,pother_[system][0],G1,G2); loME = loMatrixElement(psystem_[system][0],pother_[system][1], psystem_[system][1],pother_[system][0],G1,G2); } } else { if(partons_[system][2]->id()>0) { term2 = loMatrixElement(r2 ,pother_[system][0], r2-qnlo,pother_[system][1],G1,G2); term3 = loMatrixElement(qnlo+r3,pother_[system][0], r3 ,pother_[system][1],G1,G2); loME = loMatrixElement(psystem_[system][1],pother_[system][0], psystem_[system][0],pother_[system][1],G1,G2); } else { term2 = loMatrixElement(r2 ,pother_[system][1], r2-qnlo,pother_[system][0],G1,G2); term3 = loMatrixElement(qnlo+r3,pother_[system][1], r3 ,pother_[system][0],G1,G2); loME = loMatrixElement(psystem_[system][1],pother_[system][1], psystem_[system][0],pother_[system][0],G1,G2); } } double R3 = sqr(x3)/(sqr(x3)+sqr(xT))*(term3/loME); double R2 = sqr(x2)/(sqr(x2)+sqr(xT))*(term2/loME); // debuggingMatrixElement(true, // partons_[system][0],partons_[system][1], // partons_[system][2],partons_[system][3], // psystem_[system][0],psystem_[system][1], // pother_ [system][0],pother_ [system][1], // p0,p1,p2,phiggs_[system],q2_[system], // 8.*Constants::pi/zp/(1.-zp)*(sqr(xp)*(sqr(x3)+sqr(xT))*R3+ // sqr(xp)*(sqr(x2)+sqr(xT))*R2)); return TRfact* (sqr(xp)*(sqr(x3)+sqr(xT))*R3+ sqr(xp)*(sqr(x2)+sqr(xT))*R2); } Energy4 MEPP2HiggsVBF::loMatrixElement(const Lorentz5Momentum &p1, const Lorentz5Momentum &p2, const Lorentz5Momentum &q1, const Lorentz5Momentum &q2, double G1, double G2) const { return G1*(p1*p2)*(q1*q2) + G2*(p1*q2)*(q1*p2); } void MEPP2HiggsVBF::initializeMECorrection(RealEmissionProcessPtr born, double & initial, double & final) { systems_.clear(); for(unsigned int ix=0;ixbornIncoming().size();++ix) { if(QuarkMatcher::Check(born->bornIncoming()[ix]->data())) { systems_.push_back(tChannelPair()); systems_.back().hadron = born->hadrons()[ix]; systems_.back().beam = dynamic_ptr_cast(systems_.back().hadron->dataPtr()); systems_.back().incoming = born->bornIncoming()[ix]; systems_.back().pdf = systems_.back().beam->pdf(); } } vector outgoing; for(unsigned int ix=0;ixbornOutgoing().size();++ix) { if(born->bornOutgoing()[ix]->id()==ParticleID::h0) higgs_ = born->bornOutgoing()[ix]; else if(QuarkMatcher::Check(born->bornOutgoing()[ix]->data())) outgoing.push_back(born->bornOutgoing()[ix]); } assert(outgoing.size()==2&&higgs_); // match up the quarks for(unsigned int ix=0;ixcolourLine()) { for(unsigned int iy=0;iycolourLine()==systems_[ix].incoming->colourLine()) { systems_[ix].outgoing=outgoing[iy]; break; } } } else { for(unsigned int iy=0;iyantiColourLine()==systems_[ix].incoming->antiColourLine()) { systems_[ix].outgoing=outgoing[iy]; break; } } } } assert(systems_[0].outgoing&&systems_[1].outgoing); assert(systems_.size()==2); initial = initial_; final = final_; } RealEmissionProcessPtr MEPP2HiggsVBF::applyHardMatrixElementCorrection(RealEmissionProcessPtr born) { static const double eps = 1e-6; // select emitting line if(UseRandom::rndbool()) swap(systems_[0],systems_[1]); // extract the born variables q_[0] = systems_[0].outgoing->momentum()-systems_[0].incoming->momentum(); q2_[0] = -q_[0].m2(); Energy Q = sqrt(q2_[0]); xB_[0] = systems_[0].incoming->momentum().rho()/systems_[0].hadron->momentum().rho(); // construct lorentz transform from lab to breit frame Lorentz5Momentum phadron = systems_[0].hadron->momentum(); phadron.setMass(0.*GeV); phadron.rescaleEnergy(); Lorentz5Momentum pcmf = phadron+0.5/xB_[0]*q_[0]; pcmf.rescaleMass(); LorentzRotation rot(-pcmf.boostVector()); Lorentz5Momentum pbeam = rot*phadron; Axis axis(pbeam.vect().unit()); double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); rot.rotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); Lorentz5Momentum pout = rot*(systems_[1].outgoing->momentum()+higgs_->momentum()); rot.rotateZ(-atan2(pout.y(),pout.x())); // calculate the A coefficient for the correlations acoeff_ = A(systems_[0].incoming->dataPtr(),systems_[0].outgoing->dataPtr(), systems_[1].incoming->dataPtr(),systems_[1].outgoing->dataPtr()); vector azicoeff; // select the type of process bool BGF = UseRandom::rnd()>procProb_; double wgt,xp,zp,x1,x2,x3,xperp; l_ = 2.*(rot*systems_[1].incoming->momentum())/Q; m_ = 2.*(rot*systems_[1].outgoing->momentum())/Q; // compton process if(!BGF) { wgt = generateComptonPoint(xp,zp); if(xpvalue(mu2)/procProb_; // PDF piece wgt *= systems_[0].pdf->xfx(systems_[0].beam, systems_[0].incoming->dataPtr(),mu2 ,xB_[0]/xp)/ systems_[0].pdf->xfx(systems_[0].beam, systems_[0].incoming->dataPtr(),scale(),xB_[0] ); // numerator factors wgt /= (1.-xp)*(1.-zp); // other bits xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp); x1 = -1./xp; x2 = 1.-(1.-zp)/xp; x3 = 2.+x1-x2; // matrix element pieces azicoeff = ComptonME(xp,x2,xperp,l_,m_); } else { wgt = generateBGFPoint(xp,zp); if(xp<1e-6) return RealEmissionProcessPtr(); // common pieces Energy2 mu2 = q2_[0]*((1.-xp)*(1-zp)*zp/xp+1); wgt *= 0.25/Constants::pi*alpha_->value(mu2)/(1.-procProb_); // PDF piece wgt *= systems_[0].pdf->xfx(systems_[0].beam, gluon_ ,mu2 ,xB_[0]/xp)/ systems_[0].pdf->xfx(systems_[0].beam, systems_[0].incoming->dataPtr(),scale(),xB_[0] ); // numerator factors wgt /= (1.-zp); // other bits xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp); x1 = -1./xp; x2 = 1.-(1.-zp)/xp; x3 = 2.+x1-x2; // matrix element pieces azicoeff = BGFME(xp,x2,x3,xperp,l_,m_); } // compute the azimuthal average of the weight wgt *= azicoeff[0]+0.5*(azicoeff[2]+azicoeff[4]); // finally factor as picked one line wgt *= 2.; // decide whether or not to accept the weight if(UseRandom::rnd()>wgt) return RealEmissionProcessPtr(); // if accepted generate generate phi unsigned int itry(0); double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.); double phiwgt,phi; do { phi = UseRandom::rnd()*Constants::twopi; double cphi(cos(phi)),sphi(sin(phi)); phiwgt = azicoeff[0]+azicoeff[5]*sphi*cphi +azicoeff[1]*cphi+azicoeff[2]*sqr(cphi) +azicoeff[3]*sphi+azicoeff[4]*sqr(sphi); ++itry; } while (phimax*UseRandom::rnd() > phiwgt && itry<200); if(itry==200) throw Exception() << "Too many tries in VBFMECorrection" << "::applyHardMatrixElementCorrection() to" << " generate phi" << Exception::eventerror; // compute the new incoming and outgoing momenta Lorentz5Momentum p1 = Lorentz5Momentum( 0.5*Q*xperp*cos(phi), 0.5*Q*xperp*sin(phi), -0.5*Q*x2,0.*GeV,0.*GeV); p1.rescaleEnergy(); Lorentz5Momentum p2 = Lorentz5Momentum(-0.5*Q*xperp*cos(phi),-0.5*Q*xperp*sin(phi), -0.5*Q*x3,0.*GeV,0.*GeV); p2.rescaleEnergy(); Lorentz5Momentum pin(0.*GeV,0.*GeV,-0.5*x1*Q,-0.5*x1*Q,0.*GeV); // debugging code to test vs helicity amplitude expression for matrix elements // double cphi(cos(phi)),sphi(sin(phi)); // double old = (azicoeff[0]+azicoeff[5]*sphi*cphi // +azicoeff[1]*cphi+azicoeff[2]*sqr(cphi) // +azicoeff[3]*sphi+azicoeff[4]*sqr(sphi)); // if(!BGF) { // old *= 8.*Constants::pi/(1.-xp)/(1.-zp); // } // else { // old *= 8.*Constants::pi/zp/(1.-zp); // } // debuggingMatrixElement(BGF, // systems_[0].incoming->dataPtr(), // systems_[0].outgoing->dataPtr(), // systems_[1].incoming->dataPtr(), // systems_[1].outgoing->dataPtr(), // rot*systems_[0].incoming->momentum(), // rot*systems_[0].outgoing->momentum(), // rot*systems_[1].incoming->momentum(), // rot*systems_[1].outgoing->momentum(), // pin,p1,p2,rot*higgs_->momentum(), // q2_[0],scale(),old); // we need inverse of the rotation, i.e back to lab from breit rot.invert(); // transform the momenta to lab frame pin *= rot; p1 *= rot; p2 *= rot; // test to ensure outgoing particles can be put on-shell if(!BGF) { if(p1.e()dataPtr()->constituentMass()) return RealEmissionProcessPtr(); if(p2.e()constituentMass()) return RealEmissionProcessPtr(); } else { if(p1.e()dataPtr() ->constituentMass()) return RealEmissionProcessPtr(); if(p2.e()dataPtr()->CC()->constituentMass()) return RealEmissionProcessPtr(); } // stats for weights > 1 if(wgt>1.) { ++nover_; if(!BGF) maxwgt_.first = max(maxwgt_.first ,wgt); else maxwgt_.second = max(maxwgt_.second,wgt); } // create the new particles and add to ShowerTree bool isQuark = systems_[0].incoming->colourLine(); bool FSR= false; PPtr newin,newout,emitted; if(!BGF) { newin = systems_[0].incoming->dataPtr()->produceParticle(pin); emitted = gluon_ ->produceParticle(p2 ); newout = systems_[0].outgoing->dataPtr()->produceParticle(p1 ); emitted->incomingColour(newin,!isQuark); emitted->colourConnect(newout,!isQuark); FSR = xp>zp; } else { newin = gluon_ ->produceParticle(pin); emitted = systems_[0].incoming->dataPtr()->CC()->produceParticle(p2 ); newout = systems_[0].outgoing->dataPtr() ->produceParticle(p1 ); emitted->incomingColour(newin, isQuark); newout ->incomingColour(newin,!isQuark); FSR = false; } pair x; pair radiators; if(born->bornIncoming()[0]!=systems_[0].incoming) { born->incoming().push_back(born->bornIncoming()[0]); born->incoming().push_back(newin); x.first = born->bornIncoming()[0]->momentum().rho()/born->hadrons()[0]->momentum().rho(); x.second = x.first = xB_[0]/xp; radiators.first = 1; } else { born->incoming().push_back(newin); born->incoming().push_back(born->bornIncoming()[1]); x.first = xB_[0]/xp; x.second = born->bornIncoming()[1]->momentum().rho()/born->hadrons()[1]->momentum().rho(); radiators.first = 0; } born->x(x); for(unsigned int ix=0;ixbornOutgoing().size();++ix) { if(born->bornOutgoing()[ix]!=systems_[0].outgoing) { born->outgoing().push_back(born->bornOutgoing()[ix]); } else { radiators.second = born->outgoing().size()+2; born->outgoing().push_back(newout); } } if(FSR) swap(radiators.first,radiators.second); born->emitter (radiators.first ); born->spectator(radiators.second); born->emitted(born->outgoing().size()+2); // radiated particle born->outgoing().push_back(emitted); born->interaction(ShowerInteraction::QCD); return born; } double MEPP2HiggsVBF::A(tcPDPtr qin1, tcPDPtr qout1, tcPDPtr qin2, tcPDPtr ) { double output; // charged current if(qin1->id()!=qout1->id()) { output = 2; } // neutral current else { double cvl,cal,cvq,caq; if(abs(qin2->id())%2==0) { cvl = generator()->standardModel()->vu(); cal = generator()->standardModel()->au(); } else { cvl = generator()->standardModel()->vd(); cal = generator()->standardModel()->ad(); } if(abs(qin1->id())%2==0) { cvq = generator()->standardModel()->vu(); caq = generator()->standardModel()->au(); } else { cvq = generator()->standardModel()->vd(); caq = generator()->standardModel()->ad(); } output = 8.*cvl*cal*cvq*caq/(sqr(cvl)+sqr(cal))/(sqr(cvq)+sqr(caq)); } if(qin1->id()<0) output *= -1.; if(qin2->id()<0) output *= -1; return output; } double MEPP2HiggsVBF::generateComptonPoint(double &xp, double & zp) { static const double maxwgt = 50.; double wgt,xperp2,x2; do { xp = UseRandom::rnd(); double zpmin = xp, zpmax = 1./(1.+xp*(1.-xp)); zp = 1.-pow((1.-zpmin)/(1.-zpmax),UseRandom::rnd())*(1.-zpmax); wgt = log((1.-zpmin)/(1.-zpmax))*(1.-zp); if(UseRandom::rndbool()) swap(xp,zp); xperp2 = 4.*(1.-xp)*(1.-zp)*zp/xp; x2 = 1.-(1.-zp)/xp; wgt *= 2.*(1.+sqr(xp)*(sqr(x2)+1.5*xperp2))/(1.-xp)/(1.-zp); if(wgt>maxwgt) if(wgt>maxwgt) { ostringstream wstring; wstring << "MEPP2HiggsVBF::generateComptonPoint() " << "Weight greater than maximum" << "wgt = " << wgt << " maxwgt = " << maxwgt << "\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } while(wgtmaxwgt) { ostringstream wstring; wstring << "DISBase::generateBGFPoint " << "Weight greater than maximum " << "wgt = " << wgt << " maxwgt = 1\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } while(wgt & ids, const double & z, const Energy & scale, const Energy & pT) { bool veto = !UseRandom::rndbool(fs ? 1./final_ : 1./initial_); // check if me correction should be applied long id[2]={progenitor->id(),parent->id()}; if(id[0]!=id[1]||id[1]==ParticleID::g) return veto; // if not from the right side if(progenitor!=systems_[0].incoming && progenitor!=systems_[0].outgoing) return veto; // check if hardest so far if(pT azicoeff = ComptonME(xp,x2,xperp,l_,m_); wgt = (azicoeff[0]+0.5*azicoeff[2]+0.5*azicoeff[4])* xp/(1.+sqr(z))/final_; if(wgt<.0||wgt>1.) { ostringstream wstring; wstring << "Soft ME correction weight too large or " << "negative for FSR in MEPP2HiggsVBF::" << "softMatrixElementVeto() soft weight " << " xp = " << xp << " zp = " << zp << " weight = " << wgt << "\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } else { double xp = 2.*z/(1.+zk+sqrt(sqr(1.+zk)-4.*z*zk)); double zp = 0.5* (1.-zk+sqrt(sqr(1.+zk)-4.*z*zk)); double xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp); double x1 = -1./xp, x2 = 1.-(1.-zp)/xp, x3 = 2.+x1-x2; // compton if(ids[0]->id()!=ParticleID::g) { vector azicoeff = ComptonME(xp,x2,xperp,l_,m_); wgt = (azicoeff[0]+0.5*azicoeff[2]+0.5*azicoeff[4])* xp*(1.-z)/(1.-xp)/(1.+sqr(z))/(1.-zp+xp-2.*xp*(1.-zp)); } // BGF else { vector azicoeff = BGFME(xp,x2,x3,xperp,l_,m_); wgt = (azicoeff[0]+0.5*azicoeff[2]+0.5*azicoeff[4])* xp/(1.-zp+xp-2.*xp*(1.-zp))/(sqr(z)+sqr(1.-z)); } wgt /=initial_; if(wgt<.0||wgt>1.) { ostringstream wstring; wstring << "Soft ME correction weight too large or " << "negative for ISR in MEPP2HiggsVBF::" << "softMatrixElementVeto() soft weight " << " xp = " << xp << " zp = " << zp << " weight = " << wgt << "\n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); } } // return whether or not vetoed return !UseRandom::rndbool(wgt); } vector MEPP2HiggsVBF::ComptonME(double xp, double x2, double xperp, LorentzVector l, LorentzVector m) { vector output(6,0.); double cos2 = x2 /sqrt(sqr(x2)+sqr(xperp)); double sin2 = xperp/sqrt(sqr(x2)+sqr(xperp)); // no phi dependence output[0] = l.t()*m.t()-l.z()*m.z()*sqr(cos2)+0.5*acoeff_*cos2*(l.t()*m.z()-l.z()*m.t()); // cos(phi) output[1] = sin2*(-l.x()*m.t()-l.t()*m.x() + 0.5*acoeff_*cos2*(l.z()*m.x()-m.z()*l.x())); // cos(phi)^2 output[2] = +sqr(sin2)*l.x()*m.x(); // sin(phi) output[3] = sin2*(-l.t()*m.y()-l.y()*m.t() + 0.5*acoeff_*cos2*(l.z()*m.y()-m.z()*l.y())); // sin(phi)^2 output[4] = +sqr(sin2)*l.y()*m.y(); // sin(phi)cos(phi) output[5] = +sqr(sin2)*(m.y()*l.x()+m.x()*l.y()); // additional factors double denom = -l.z()*m.z()+l.t()*m.t()+0.5*acoeff_*(l.t()*m.z()-l.z()*m.t()); double fact = sqr(xp)*(sqr(x2)+sqr(xperp))/denom; for(unsigned int ix=0;ix MEPP2HiggsVBF::BGFME(double xp, double x2, double x3, double xperp, LorentzVector l, LorentzVector m) { vector output(6,0.); double denom = -l.z()*m.z()+l.t()*m.t()+0.5*acoeff_*(l.t()*m.z()-l.z()*m.t()); double cos2 = x2 /sqrt(sqr(x2)+sqr(xperp)); double sin2 = xperp/sqrt(sqr(x2)+sqr(xperp)); double fact2 = sqr(xp)*(sqr(x2)+sqr(xperp))/denom; double cos3 = x3 /sqrt(sqr(x3)+sqr(xperp)); double sin3 = xperp/sqrt(sqr(x3)+sqr(xperp)); double fact3 = sqr(xp)*(sqr(x3)+sqr(xperp))/denom; // no phi dependence output[0] = fact2*(l.t()*m.t()-l.z()*m.z()*sqr(cos2) + 0.5*acoeff_*cos2*(l.t()*m.z()-l.z()*m.t())) + fact3*(l.t()*m.t()-l.z()*m.z()*sqr(cos3) - 0.5*acoeff_*cos3*(l.t()*m.z()-l.z()*m.t())); // cos(phi) output[1] = fact2*sin2*( - l.x()*m.t()-l.t()*m.x() + 0.5*acoeff_*cos2*(l.z()*m.x()-m.z()*l.x())) - fact3*sin3*( - l.x()*m.t()-l.t()*m.x() - 0.5*acoeff_*cos3*(l.z()*m.x()-m.z()*l.x())) ; // cos(phi)^2 output[2] = (fact2*sqr(sin2)+fact3*sqr(sin3))*l.x()*m.x(); // sin(phi) output[3] = fact2*sin2*( - l.t()*m.y()-l.y()*m.t() + 0.5*acoeff_*cos2*(l.z()*m.y()-m.z()*l.y())) - fact3*sin3*( - l.t()*m.y()-l.y()*m.t() - 0.5*acoeff_*cos3*(l.z()*m.y()-m.z()*l.y())); // sin(phi)^2 output[4] = (fact2*sqr(sin2)+fact3*sqr(sin3))*l.y()*m.y(); // sin(phi)cos(phi) output[5] = (fact2*sqr(sin2)+fact3*sqr(sin3))*(m.y()*l.x()+m.x()*l.y()); // return the answer return output; } diff --git a/MatrixElement/Lepton/MEee2Higgs2SM.cc b/MatrixElement/Lepton/MEee2Higgs2SM.cc --- a/MatrixElement/Lepton/MEee2Higgs2SM.cc +++ b/MatrixElement/Lepton/MEee2Higgs2SM.cc @@ -1,354 +1,422 @@ // -*- C++ -*- // // MEee2Higgs2SM.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the MEee2Higgs2SM class. // #include "MEee2Higgs2SM.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Handlers/StandardXComb.h" #include "Herwig/MatrixElement/HardVertex.h" #include "ThePEG/PDT/EnumParticles.h" using namespace Herwig; void MEee2Higgs2SM::doinit() { ME2to2Base::doinit(); h0_ = getParticleData(ThePEG::ParticleID::h0); tcHwSMPtr hwsm=ThePEG::dynamic_ptr_cast(standardModel()); // do the initialisation if(hwsm) { FFHVertex_ = hwsm->vertexFFH(); HGGVertex_ = hwsm->vertexHGG(); + HWWVertex_ = hwsm->vertexWWH(); } else { throw InitException() << "Must have Herwig StandardModel object in " << "MEee2Higgs2SM::doinit()" << Exception::runerror; } } Energy2 MEee2Higgs2SM::scale() const { return sHat(); } unsigned int MEee2Higgs2SM::orderInAlphaS() const { return 0; } unsigned int MEee2Higgs2SM::orderInAlphaEW() const { return 2; } void MEee2Higgs2SM::getDiagrams() const { // specific the diagrams tcPDPtr ep = getParticleData(ParticleID::eplus ); tcPDPtr em = getParticleData(ParticleID::eminus); // outgoing quarks for(int i=1;i<=5;++i) { if(allowed_==0 || allowed_==1 || allowed_==i+2) { tcPDPtr lm = getParticleData(i); tcPDPtr lp = lm->CC(); add(new_ptr((Tree2toNDiagram(2), em, ep, 1, h0_, 3, lm, 3, lp, -1))); } } // outgoing leptons for( int i =11;i<=16;i+=2) { if(allowed_==0 || allowed_==2 || allowed_==(i+7)/2) { tcPDPtr lm = getParticleData(i); tcPDPtr lp = lm->CC(); add(new_ptr((Tree2toNDiagram(2), em, ep, 1, h0_, 3, lm, 3, lp, -1))); } } if(allowed_==0 || allowed_==12) { tcPDPtr g = getParticleData(ParticleID::g); add(new_ptr((Tree2toNDiagram(2), em, ep, 1, h0_, 3, g, 3, g, -1))); } + if(allowed_==0 || allowed_==13) { + tcPDPtr Wp = getParticleData(ParticleID::Wplus); + add(new_ptr((Tree2toNDiagram(2), em, ep, 1, h0_, 3, Wp, 3, Wp->CC(), -1))); + } + if(allowed_==0 || allowed_==14) { + tcPDPtr Z0 = getParticleData(ParticleID::Z0); + add(new_ptr((Tree2toNDiagram(2), em, ep, 1, h0_, 3, Z0, 3, Z0, -1))); + } } double MEee2Higgs2SM::me2() const { double aver=0.; // get the order right int ielectron(0),ipositron(1),ilp(2),ilm(3); if(mePartonData()[0]->id()!=11) swap(ielectron,ipositron); if(mePartonData()[2]->id()>mePartonData()[3]->id()) swap(ilp,ilm); // the arrays for the wavefunction to be passed to the matrix element vector fin; vector ain; for(unsigned int ihel=0;ihel<2;++ihel) { fin .push_back(SpinorWaveFunction(meMomenta()[ielectron], mePartonData()[ielectron],ihel,incoming)); ain .push_back(SpinorBarWaveFunction(meMomenta()[ipositron], mePartonData()[ipositron],ihel,incoming)); } // H -> f fbar - if(mePartonData()[2]->id()!=ParticleID::g) { + if(abs(mePartonData()[2]->id())<20) { vector aout; vector fout; for(unsigned int ihel=0;ihel<2;++ihel) { fout.push_back(SpinorBarWaveFunction(meMomenta()[ilm], mePartonData()[ilm],ihel,outgoing)); aout.push_back(SpinorWaveFunction(meMomenta()[ilp], mePartonData()[ilp],ihel,outgoing)); } HelicityME(fin,ain,fout,aout,aver); if(mePartonData()[ilm]->id()<=6) aver*=3.; } - else { + else if(mePartonData()[2]->id()==21) { vector g1,g2; for(unsigned int ihel=0;ihel<2;++ihel) { g1.push_back(VectorWaveFunction(meMomenta()[2],mePartonData()[2], 2*ihel,outgoing)); g2.push_back(VectorWaveFunction(meMomenta()[3],mePartonData()[3], 2*ihel,outgoing)); } ggME(fin,ain,g1,g2,aver); aver *= 8.; } + else if(abs(mePartonData()[2]->id())==24 ||mePartonData()[2]->id()==23) { + vector g1,g2; + for(unsigned int ihel=0;ihel<3;++ihel) { + g1.push_back(VectorWaveFunction(meMomenta()[2],mePartonData()[2], + ihel,outgoing)); + g2.push_back(VectorWaveFunction(meMomenta()[3],mePartonData()[3], + ihel,outgoing)); + } + WWME(fin,ain,g1,g2,aver); + } + else { + assert(false); + } return aver; } // the helicity amplitude matrix element ProductionMatrixElement MEee2Higgs2SM::HelicityME(vector fin, vector ain, vector fout, vector aout, double & aver) const { // the particles should be in the order // for the incoming // 0 incoming fermion (u spinor) // 1 incoming antifermion (vbar spinor) // for the outgoing // 0 outgoing fermion (ubar spinor) // 1 outgoing antifermion (v spinor) // me to be returned ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half); // wavefunctions for the intermediate particles ScalarWaveFunction interh; // temporary storage of the different diagrams Complex diag; aver=0.; // sum over helicities to get the matrix element unsigned int inhel1,inhel2,outhel1,outhel2; for(inhel1=0;inhel1<2;++inhel1) { for(inhel2=0;inhel2<2;++inhel2) { interh = FFHVertex_->evaluate(sHat(),1,h0_,fin[inhel1],ain[inhel2]); for(outhel1=0;outhel1<2;++outhel1) { for(outhel2=0;outhel2<2;++outhel2) { diag = FFHVertex_->evaluate(sHat(),aout[outhel2], fout[outhel1],interh); output(inhel1,inhel2,outhel1,outhel2)=diag; aver +=real(diag*conj(diag)); } } } } return output; } Selector MEee2Higgs2SM::diagrams(const DiagramVector &) const { Selector sel;sel.insert(1.0, 0); return sel; } Selector MEee2Higgs2SM::colourGeometries(tcDiagPtr diag) const { static ColourLines neutral ( " " ); static ColourLines quarks ( "-5 4"); static ColourLines gluons ( "-5 4, 5 -4"); Selector sel; int id = abs((diag->partons()[2])->id()); if (id<=6 ) sel.insert(1.0, &quarks); else if (id==21) sel.insert(1.0, &gluons); else sel.insert(1.0, &neutral); return sel; } void MEee2Higgs2SM::persistentOutput(PersistentOStream & os) const { - os << FFHVertex_ << HGGVertex_ << h0_ << allowed_; + os << FFHVertex_ << HGGVertex_ << HWWVertex_ << h0_ << allowed_; } void MEee2Higgs2SM::persistentInput(PersistentIStream & is, int) { - is >> FFHVertex_ >> HGGVertex_ >> h0_ >> allowed_; + is >> FFHVertex_ >> HGGVertex_ >> HWWVertex_ >> h0_ >> allowed_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigMEee2Higgs2SM("Herwig::MEee2Higgs2SM", "HwMELepton.so"); void MEee2Higgs2SM::Init() { static ClassDocumentation documentation ("The MEee2Higgs2SM class implements the matrix element for e+e- to" " SM particle via Higgs exchnage and is designed to be a process to test" " things involving scalar particles. "); static Switch interfaceallowed ("Allowed", "Allowed outgoing particles", &MEee2Higgs2SM::allowed_, 0, false, false); static SwitchOption interfaceallowedAll (interfaceallowed, "All", "All SM particles allowed", 0); static SwitchOption interfaceallowed1 (interfaceallowed, "Quarks", "Only the quarks allowed", 1); static SwitchOption interfaceallowed2 (interfaceallowed, "Leptons", "Only the leptons allowed", 2); static SwitchOption interfacealloweddown (interfaceallowed, "Down", "Only d dbar allowed", 3); static SwitchOption interfaceallowedup (interfaceallowed, "Up", "Only u ubar allowed", 4); static SwitchOption interfaceallowedstrange (interfaceallowed, "Strange", "Only s sbar allowed", 5); static SwitchOption interfaceallowedcharm (interfaceallowed, "Charm", "Only c cbar allowed", 6); static SwitchOption interfaceallowedbottom (interfaceallowed, "Bottom", "Only b bbar allowed", 7); static SwitchOption interfaceallowedtop (interfaceallowed, "Top", "Only t tbar allowed", 8); static SwitchOption interfaceallowedelectron (interfaceallowed, "Electron", "Only e+e- allowed", 9); static SwitchOption interfaceallowedMuon (interfaceallowed, "Muon", "Only mu+mu- allowed", 10); static SwitchOption interfaceallowedTau (interfaceallowed, "Tau", "Only tau+tau- allowed", 11); static SwitchOption interfaceallowedGluon (interfaceallowed, "Gluon", "Only gg allowed", 12); + static SwitchOption interfaceallowedW + (interfaceallowed, + "W", + "Only W+W- allowed", + 13); + static SwitchOption interfaceallowedZ + (interfaceallowed, + "Z", + "Only ZZ allowed", + 14); } void MEee2Higgs2SM::constructVertex(tSubProPtr sub) { // extract the particles in the hard process ParticleVector hard; hard.push_back(sub->incoming().first);hard.push_back(sub->incoming().second); hard.push_back(sub->outgoing()[0]);hard.push_back(sub->outgoing()[1]); if(hard[0]->id()id()) swap(hard[0],hard[1]); if(hard[2]->id()id()) swap(hard[2],hard[3]); vector fin; vector ain; SpinorWaveFunction( fin ,hard[0],incoming,false,true); SpinorBarWaveFunction(ain ,hard[1],incoming,false,true); double me; ProductionMatrixElement prodme; - if(hard[2]->id()!=ParticleID::g) { + if(abs(hard[2]->id())<20) { vector aout; vector fout; SpinorBarWaveFunction(fout,hard[2],outgoing,true ,true); SpinorWaveFunction( aout,hard[3],outgoing,true ,true); // calculate the matrix element prodme=HelicityME(fin,ain,fout,aout,me); } - else { + else if(abs(hard[2]->id())==21) { vector g1,g2; VectorWaveFunction(g1,hard[2],outgoing,true,true); VectorWaveFunction(g2,hard[3],outgoing,true,true); g1[1]=g1[2]; g2[1]=g2[2]; prodme=ggME(fin,ain,g1,g2,me); } + else { + vector g1,g2; + VectorWaveFunction(g1,hard[2],outgoing,true,false); + VectorWaveFunction(g2,hard[3],outgoing,true,false); + prodme=WWME(fin,ain,g1,g2,me); + } // construct the vertex HardVertexPtr hardvertex=new_ptr(HardVertex()); // set the matrix element for the vertex hardvertex->ME(prodme); // set the pointers and to and from the vertex for(unsigned int ix=0;ix<4;++ix) { (hard[ix]->spinInfo())->productionVertex(hardvertex); } } void MEee2Higgs2SM::rebind(const TranslationMap & trans) { // dummy = trans.translate(dummy); FFHVertex_ = trans.translate(FFHVertex_); HGGVertex_ = trans.translate(HGGVertex_); h0_ = trans.translate(h0_); ME2to2Base::rebind(trans); } IVector MEee2Higgs2SM::getReferences() { IVector ret = ME2to2Base::getReferences(); ret.push_back(FFHVertex_); ret.push_back(HGGVertex_); ret.push_back(h0_); return ret; } // the helicity amplitude matrix element ProductionMatrixElement MEee2Higgs2SM::ggME(vector fin, vector ain, vector g1, vector g2, double & aver) const { ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1,PDT::Spin1); // wavefunctions for the intermediate particles ScalarWaveFunction interh; // temporary storage of the different diagrams Complex diag; aver=0.; // sum over helicities to get the matrix element unsigned int inhel1,inhel2,outhel1,outhel2; for(inhel1=0;inhel1<2;++inhel1) { for(inhel2=0;inhel2<2;++inhel2) { interh = FFHVertex_->evaluate(sHat(),1,h0_,fin[inhel1],ain[inhel2]); for(outhel1=0;outhel1<2;++outhel1) { for(outhel2=0;outhel2<2;++outhel2) { diag = HGGVertex_->evaluate(sHat(),g1[outhel1],g2[outhel2],interh); output(inhel1,inhel2,2*outhel1,2*outhel2)=diag; - aver +=real(diag*conj(diag)); + aver += norm(diag); } } } } return output; } + +// the helicity amplitude matrix element +ProductionMatrixElement MEee2Higgs2SM::WWME(vector fin, + vector ain, + vector g1, + vector g2, + double & aver) const { + ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half, + PDT::Spin1,PDT::Spin1); + // wavefunctions for the intermediate particles + ScalarWaveFunction interh; + // temporary storage of the different diagrams + Complex diag; + aver=0.; + // sum over helicities to get the matrix element + unsigned int inhel1,inhel2,outhel1,outhel2; + for(inhel1=0;inhel1<2;++inhel1) { + for(inhel2=0;inhel2<2;++inhel2) { + interh = FFHVertex_->evaluate(sHat(),1,h0_,fin[inhel1],ain[inhel2]); + for(outhel1=0;outhel1<3;++outhel1) { + for(outhel2=0;outhel2<3;++outhel2) { + diag = HWWVertex_->evaluate(sHat(),g1[outhel1],g2[outhel2],interh); + output(inhel1,inhel2,outhel1,outhel2)=diag; + aver += norm(diag); + } + } + } + } + return output; +} diff --git a/MatrixElement/Lepton/MEee2Higgs2SM.h b/MatrixElement/Lepton/MEee2Higgs2SM.h --- a/MatrixElement/Lepton/MEee2Higgs2SM.h +++ b/MatrixElement/Lepton/MEee2Higgs2SM.h @@ -1,236 +1,254 @@ // -*- C++ -*- // // MEee2Higgs2SM.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_MEee2Higgs2SM_H #define HERWIG_MEee2Higgs2SM_H // // This is the declaration of the MEee2Higgs2SM class. // #include "ThePEG/MatrixElement/ME2to2Base.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "Herwig/MatrixElement/ProductionMatrixElement.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" namespace Herwig { using namespace ThePEG; /** * The MEee2Higgs2SM class implements the production of an \f$s\f$-channel * Higgs in \f$e^+e^-\f$ collisions in order to allow easy tests of Higgs * decays. It should not be used for physics studies. * * @see \ref MEee2Higgs2SMInterfaces "The interfaces" * defined for MEee2Higgs2SM. */ class MEee2Higgs2SM: public ME2to2Base { public: /** * The default constructor. */ inline MEee2Higgs2SM() : allowed_(0) {} /** @name Virtual functions required by the MEBase class. */ //@{ /** * Return the order in \f$\alpha_S\f$ in which this matrix * element is given. */ virtual unsigned int orderInAlphaS() const; /** * Return the order in \f$\alpha_{EW}\f$ in which this matrix * element is given. */ virtual unsigned int orderInAlphaEW() const; /** * The matrix element for the kinematical configuration * previously provided by the last call to setKinematics(), suitably * scaled by sHat() to give a dimension-less number. * @return the matrix element scaled with sHat() to give a * dimensionless number. */ virtual double me2() const; /** * Return the scale associated with the last set phase space point. */ virtual Energy2 scale() const; /** * Add all possible diagrams with the add() function. */ virtual void getDiagrams() const; /** * Get diagram selector. With the information previously supplied with the * setKinematics method, a derived class may optionally * override this method to weight the given diagrams with their * (although certainly not physical) relative probabilities. * @param dv the diagrams to be weighted. * @return a Selector relating the given diagrams to their weights. */ virtual Selector diagrams(const DiagramVector & dv) const; /** * Return a Selector with possible colour geometries for the selected * diagram weighted by their relative probabilities. * @param diag the diagram chosen. * @return the possible colour geometries weighted by their * relative probabilities. */ virtual Selector colourGeometries(tcDiagPtr diag) const; /** * set up the spin correlations */ virtual void constructVertex(tSubProPtr sub); //@} public: /** @name Functions used by the persistent I/O system. */ //@{ /** * Function used to write out object persistently. * @param os the persistent output stream written to. */ void persistentOutput(PersistentOStream & os) const; /** * Function used to read in object persistently. * @param is the persistent input stream read from. * @param version the version number of the object when written. */ void persistentInput(PersistentIStream & is, int version); //@} /** * The standard Init function used to initialize the interfaces. * Called exactly once for each class by the class description system * before the main function starts or * when this class is dynamically loaded. */ static void Init(); protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ inline virtual IBPtr clone() const {return new_ptr(*this);} /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ inline virtual IBPtr fullclone() const {return new_ptr(*this);} //@} protected: /** @name Standard Interfaced functions. */ //@{ /** * Initialize this object after the setup phase before saving an * EventGenerator to disk. * @throws InitException if object could not be initialized properly. */ virtual void doinit(); /** * Rebind pointer to other Interfaced objects. Called in the setup phase * after all objects used in an EventGenerator has been cloned so that * the pointers will refer to the cloned objects afterwards. * @param trans a TranslationMap relating the original objects to * their respective clones. * @throws RebindException if no cloned object was found for a given * pointer. */ virtual void rebind(const TranslationMap & trans) ; /** * Return a vector of all pointers to Interfaced objects used in this * object. * @return a vector of pointers. */ virtual IVector getReferences(); //@} private: /** * The matrix element * @param fin The incoming spinor wavefunction * @param ain The incoming spinorbar wavefunction * @param fout The outgoing spinor bar wavefunction * @param aout The outgoing spinor wavefunction * @param me The spin averaged matrix element */ ProductionMatrixElement HelicityME(vector fin, vector ain, vector fout, vector aout,double& me) const; /** * \f$H\to gg\f$ matrix element * @param fin The incoming spinor wavefunction * @param ain The incoming spinorbar wavefunction * @param g1 Outgoing gluon wavefunction * @param g2 Outgoing gluon wavefunction * @param me The spin averaged matrix element */ ProductionMatrixElement ggME(vector fin, vector ain, vector g1, vector g2, double & me) const; + /** + * \f$H\to WW\f$ matrix element + * @param fin The incoming spinor wavefunction + * @param ain The incoming spinorbar wavefunction + * @param g1 Outgoing W wavefunction + * @param g2 Outgoing W wavefunction + * @param me The spin averaged matrix element + */ + ProductionMatrixElement WWME(vector fin, + vector ain, + vector g1, + vector g2, + double & me) const; private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ MEee2Higgs2SM & operator=(const MEee2Higgs2SM &) = delete; private: /** * Pointer to the Higgs fermion-antifermion vertex */ AbstractFFSVertexPtr FFHVertex_; /** * Pointer to Higgs-gluon-gluon vertex */ AbstractVVSVertexPtr HGGVertex_; /** + * Pointer to Higgs-WW vertex + */ + AbstractVVSVertexPtr HWWVertex_; + + /** * Allowed outgoing particles */ int allowed_; /** * Pointer to the Higgs ParticleData object */ PDPtr h0_; }; } #endif /* HERWIG_MEee2Higgs2SM_H */ diff --git a/MatrixElement/Lepton/MEee2ff.cc b/MatrixElement/Lepton/MEee2ff.cc new file mode 100644 --- /dev/null +++ b/MatrixElement/Lepton/MEee2ff.cc @@ -0,0 +1,776 @@ +// -*- C++ -*- +// +// MEee2ff.cc is a part of Herwig - A multi-purpose Monte Carlo event generator +// Copyright (C) 2002-2019 The Herwig Collaboration +// +// Herwig is licenced under version 3 of the GPL, see COPYING for details. +// Please respect the MCnet academic guidelines, see GUIDELINES for details. +// +// +// This is the implementation of the non-inlined, non-templated member +// functions of the MEee2ff class. +// + +#include "MEee2ff.h" +#include "ThePEG/Interface/ClassDocumentation.h" +#include "ThePEG/Interface/Switch.h" +#include "ThePEG/Interface/Parameter.h" +#include "ThePEG/Interface/Reference.h" +#include "ThePEG/Persistency/PersistentOStream.h" +#include "ThePEG/Persistency/PersistentIStream.h" +#include "ThePEG/PDT/EnumParticles.h" +#include "ThePEG/MatrixElement/Tree2toNDiagram.h" +#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" +#include "ThePEG/Handlers/StandardXComb.h" +#include "Herwig/MatrixElement/HardVertex.h" +#include "ThePEG/PDF/PolarizedBeamParticleData.h" +#include "ThePEG/Utilities/DescribeClass.h" +#include +#include "Herwig/Shower/RealEmissionProcess.h" + +using namespace Herwig; + +void MEee2ff::getDiagrams() const { + // specific the diagrams + tcPDPtr f, fbar; + if(MEee2ff::incoming_==0) { + f = getParticleData(ParticleID::eplus); + fbar = getParticleData(ParticleID::eminus); + } + else if(MEee2ff::incoming_==1) { + f = getParticleData(ParticleID::muplus); + fbar = getParticleData(ParticleID::muminus); + } + else + assert(false); + // setup the processes + for( int i =11;i<=16;++i) { + if(allowed_==0 || (allowed_==1 && i%2==1) || (allowed_==2&&i==11) + || (allowed_==3&&i==13) || (allowed_==4&&i==15)) { + tcPDPtr lm = getParticleData(i); + tcPDPtr lp = lm->CC(); + add(new_ptr((Tree2toNDiagram(2), f, fbar, 1, gamma_, 3, lm, 3, lp, -1))); + add(new_ptr((Tree2toNDiagram(2), f, fbar, 1, Z0_, 3, lm, 3, lp, -2))); + } + } +} + +Energy2 MEee2ff::scale() const { + return sHat(); +} + +unsigned int MEee2ff::orderInAlphaS() const { + return 0; +} + +unsigned int MEee2ff::orderInAlphaEW() const { + return 2; +} + +Selector +MEee2ff::diagrams(const DiagramVector & diags) const { + double lastCont(0.5),lastBW(0.5); + if ( lastXCombPtr() ) { + lastCont = meInfo()[0]; + lastBW = meInfo()[1]; + } + Selector sel; + for ( DiagramIndex i = 0; i < diags.size(); ++i ) { + if ( diags[i]->id() == -1 ) sel.insert(lastCont, i); + else if ( diags[i]->id() == -2 ) sel.insert(lastBW, i); + } + return sel; +} + +Selector +MEee2ff::colourGeometries(tcDiagPtr) const { + static ColourLines ctST(" "); + Selector sel; + sel.insert(1.0, &ctST); + return sel; +} + +void MEee2ff::persistentOutput(PersistentOStream & os) const { + os << allowed_ << FFZVertex_ << FFPVertex_ << gamma_ << Z0_ + << alphaQED_ << ounit(pTmin_,GeV) << preFactor_ + << helicity_ << incoming_; +} + +void MEee2ff::persistentInput(PersistentIStream & is, int) { + is >> allowed_ >> FFZVertex_ >> FFPVertex_ >> gamma_ >> Z0_ + >> alphaQED_ >> iunit(pTmin_,GeV) >> preFactor_ + >> helicity_ >> incoming_; +} + +// *** Attention *** The following static variable is needed for the type +// description system in ThePEG. Please check that the template arguments +// are correct (the class and its base class), and that the constructor +// arguments are correct (the class name and the name of the dynamically +// loadable library where the class implementation can be found). +DescribeClass +describeMEee2ff("Herwig::MEee2ff", "HwMELepton.so"); + +void MEee2ff::Init() { + + static ClassDocumentation documentation + ("The MEee2ff class implements the matrix element for" + "e+e- to leptons via Z and photon exchange using helicity amplitude" + "techniques"); + + static Switch interfaceallowed + ("Outgoing", + "Allowed outgoing leptons", + &MEee2ff::allowed_, 0, false, false); + static SwitchOption interfaceallowedAll + (interfaceallowed, + "All", + "Allow all leptons as outgoing particles", + 0); + static SwitchOption interfaceallowedCharged + (interfaceallowed, + "Charged", + "Only charged leptons as outgoing particles", + 1); + static SwitchOption interfaceallowedElectron + (interfaceallowed, + "Electron", + "Only the electron and positron as outgoing leptons", + 2); + static SwitchOption interfaceallowedMuon + (interfaceallowed, + "Muon", + "Only muons as outgoing particles", + 3); + static SwitchOption interfaceallowedTau + (interfaceallowed, + "Tau", + "Only taus as outgoing particles", + 4); + static SwitchOption interfaceallowedElectronNeutrino + (interfaceallowed, + "ElectronNeutrino", + "Only electron neutrino as outgoing particles", + 5); + static SwitchOption interfaceallowedMuonNeutrino + (interfaceallowed, + "MuonNeutrino", + "Only muon neutrino as outgoing particles", + 6); + static SwitchOption interfaceallowedTauNeutrino + (interfaceallowed, + "TauNeutrino", + "Only tau neutrino as outgoing particles", + 7); + + static Parameter interfacepTMin + ("pTMin", + "Minimum pT for hard radiation", + &MEee2ff::pTmin_, GeV, 1.0*GeV, 0.001*GeV, 10.0*GeV, + false, false, Interface::limited); + + static Parameter interfacePrefactor + ("Prefactor", + "Prefactor for the overestimate of the emission probability", + &MEee2ff::preFactor_, 6.0, 1.0, 100.0, + false, false, Interface::limited); + + static Reference interfaceEMCoupling + ("AlphaQED", + "Pointer to the object to calculate the EM coupling for the correction", + &MEee2ff::alphaQED_, false, false, true, false, false); + + static Switch interfacehelicity + ("Helicity", + "Helicity of the outgoing fermions", + &MEee2ff::helicity_, 0, false, false); + static SwitchOption interfacehelicityall + (interfacehelicity, + "Any", + "Allow all helicity configurations for the outgoing particles", + 0); + static SwitchOption interfacehelicityll + (interfacehelicity, + "LL", + "Allow only left-left helicity configuration for the outgoing particles", + 1); + static SwitchOption interfacehelicityrr + (interfacehelicity, + "RR", + "Allow only right-right helicity configuration for the outgoing particles", + 2); + + static Switch interfaceincoming + ("Incoming", + "Incoming fermionc beam", + &MEee2ff::incoming_, 0, false, false); + static SwitchOption interfaceincomingElectron + (interfaceincoming, + "Electron", + "Incoming elecron-positron beam", + 0); + static SwitchOption interfaceincomingMuon + (interfaceincoming, + "Muon", + "Incoming muon-antimuon beam", + 1); +} + +double MEee2ff::me2() const { + return loME(mePartonData(),rescaledMomenta(),true); +} + +double MEee2ff::loME(const vector & partons, + const vector & momenta, + bool first) const { + vector fin,aout; + vector ain,fout; + SpinorWaveFunction ein (momenta[0],partons[0],incoming); + SpinorBarWaveFunction pin (momenta[1],partons[1],incoming); + SpinorBarWaveFunction ilmout(momenta[2],partons[2],outgoing); + SpinorWaveFunction ilpout(momenta[3],partons[3],outgoing); + for(unsigned int ix=0;ix<2;++ix) { + ein.reset(ix) ;fin.push_back( ein ); + pin.reset(ix) ;ain.push_back( pin ); + ilmout.reset(ix);fout.push_back(ilmout); + ilpout.reset(ix);aout.push_back(ilpout); + } + // compute the matrix element + double me,lastCont,lastBW; + HelicityME(fin,ain,fout,aout,me,lastCont,lastBW); + // save the components + if(first) { + DVector save; + save.push_back(lastCont); + save.push_back(lastBW); + meInfo(save); + } + // return the answer + return me; +} + +ProductionMatrixElement MEee2ff::HelicityME(vector & fin, + vector & ain, + vector & fout, + vector & aout, + double & me,double & cont, + double & BW ) const { + // the particles should be in the order + // for the incoming + // 0 incoming fermion (u spinor) + // 1 incoming antifermion (vbar spinor) + // for the outgoing + // 0 outgoing fermion (ubar spinor) + // 1 outgoing antifermion (v spinor) + // me to be returned + ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half, + PDT::Spin1Half,PDT::Spin1Half); + ProductionMatrixElement gamma (PDT::Spin1Half,PDT::Spin1Half, + PDT::Spin1Half,PDT::Spin1Half); + ProductionMatrixElement Zboson(PDT::Spin1Half,PDT::Spin1Half, + PDT::Spin1Half,PDT::Spin1Half); + // // wavefunctions for the intermediate particles + VectorWaveFunction interZ,interG; + // temporary storage of the different diagrams + Complex diag1,diag2; + // sum over helicities to get the matrix element + unsigned int inhel1,inhel2,outhel1,outhel2; + double total[3]={0.,0.,0.}; + for(inhel1=0;inhel1<2;++inhel1) { + for(inhel2=0;inhel2<2;++inhel2) { + // intermediate Z + interZ = FFZVertex_->evaluate(sHat(),1,Z0_,fin[inhel1],ain[inhel2]); + // intermediate photon + interG = FFPVertex_->evaluate(sHat(),1,gamma_,fin[inhel1],ain[inhel2]); + for(outhel1=0;outhel1<2;++outhel1) { + for(outhel2=0;outhel2<2;++outhel2) { + // in case LL or RR helicity configurations are requested + if(MEee2ff::helicity_==1 && (outhel1==1 || outhel2==1)) //LL + continue; + if(MEee2ff::helicity_==2 && (outhel1==0 || outhel2==0)) //RR + continue; + // first the Z exchange diagram + diag1 = FFZVertex_->evaluate(sHat(),aout[outhel2],fout[outhel1], + interZ); + // then the photon exchange diagram + diag2 = FFPVertex_->evaluate(sHat(),aout[outhel2],fout[outhel1], + interG); + // add up squares of individual terms + total[1] += norm(diag1); + Zboson(inhel1,inhel2,outhel1,outhel2) = diag1; + total[2] += norm(diag2); + gamma (inhel1,inhel2,outhel1,outhel2) = diag2; + // the full thing including interference + diag1 += diag2; + total[0] += norm(diag1); + output(inhel1,inhel2,outhel1,outhel2) = diag1; + } + } + } + } + // results + for(int ix=0;ix<3;++ix) total[ix] *= 0.25; + tcPolarizedBeamPDPtr beam[2] = + {dynamic_ptr_cast(mePartonData()[0]), + dynamic_ptr_cast(mePartonData()[1])}; + if( beam[0] || beam[1] ) { + RhoDMatrix rho[2] = {beam[0] ? beam[0]->rhoMatrix() : RhoDMatrix(mePartonData()[0]->iSpin()), + beam[1] ? beam[1]->rhoMatrix() : RhoDMatrix(mePartonData()[1]->iSpin())}; + total[0] = output.average(rho[0],rho[1]); + total[1] = Zboson.average(rho[0],rho[1]); + total[2] = gamma .average(rho[0],rho[1]); + } + cont = total[2]; + BW = total[1]; + me = total[0]; + return output; +} + +void MEee2ff::constructVertex(tSubProPtr sub) { + // extract the particles in the hard process + ParticleVector hard; + hard.push_back(sub->incoming().first);hard.push_back(sub->incoming().second); + hard.push_back(sub->outgoing()[0]);hard.push_back(sub->outgoing()[1]); + if(hard[0]->id()id()) swap(hard[0],hard[1]); + if(hard[2]->id()id()) swap(hard[2],hard[3]); + vector fin,aout; + vector ain,fout; + SpinorWaveFunction( fin ,hard[0],incoming,false,true); + SpinorBarWaveFunction(ain ,hard[1],incoming,false,true); + SpinorBarWaveFunction(fout,hard[2],outgoing,true ,true); + SpinorWaveFunction( aout,hard[3],outgoing,true ,true); + // calculate the matrix element + double me,cont,BW; + ProductionMatrixElement prodme=HelicityME(fin,ain,fout,aout,me,cont,BW); + // construct the vertex + HardVertexPtr hardvertex=new_ptr(HardVertex()); + // set the matrix element for the vertex + hardvertex->ME(prodme); + // set the pointers and to and from the vertex + for(unsigned int ix=0;ix<4;++ix) { + tSpinPtr spin = hard[ix]->spinInfo(); + if(ix<2) { + tcPolarizedBeamPDPtr beam = + dynamic_ptr_cast(hard[ix]->dataPtr()); + if(beam) spin->rhoMatrix() = beam->rhoMatrix(); + } + spin->productionVertex(hardvertex); + } +} + +void MEee2ff::doinit() { + HwMEBase::doinit(); + // set the particle data objects + Z0_=getParticleData(ThePEG::ParticleID::Z0); + gamma_=getParticleData(ThePEG::ParticleID::gamma); + // cast the SM pointer to the Herwig SM pointer + tcHwSMPtr hwsm= dynamic_ptr_cast(standardModel()); + // do the initialisation + if(!hwsm) throw InitException() << "Wrong type of StandardModel object in " + << "MEee2ff::doinit() the Herwig" + << " version must be used" + << Exception::runerror; + FFZVertex_ = hwsm->vertexFFZ(); + FFPVertex_ = hwsm->vertexFFP(); +} + +void MEee2ff::rebind(const TranslationMap & trans) { + FFZVertex_ = trans.translate(FFZVertex_); + FFPVertex_ = trans.translate(FFPVertex_); + Z0_ = trans.translate(Z0_); + gamma_ = trans.translate(gamma_); + HwMEBase::rebind(trans); +} + +IVector MEee2ff::getReferences() { + IVector ret = HwMEBase::getReferences(); + ret.push_back(FFZVertex_); + ret.push_back(FFPVertex_); + ret.push_back(Z0_ ); + ret.push_back(gamma_ ); + return ret; +} + +RealEmissionProcessPtr MEee2ff::generateHardest(RealEmissionProcessPtr born, + ShowerInteraction inter) { + // check if QED switched on + if(inter==ShowerInteraction::QCD) return RealEmissionProcessPtr(); + // generate the momenta for the hard emission + vector emission; + unsigned int iemit,ispect; + Energy pTveto = generateHard(born,emission,iemit,ispect,false); + // check if charged + if(!partons_[2]->charged()) return RealEmissionProcessPtr(); + // maximum pT of emission + if(pTveto<=ZERO) { + born->pT()[ShowerInteraction::QED] = pTmin_; + return born; + } + else { + born->pT()[ShowerInteraction::QED] = pTveto; + } + born->interaction(ShowerInteraction::QED); + // get the quark and antiquark + ParticleVector qq; + for(unsigned int ix=0;ix<2;++ix) qq.push_back(born->bornOutgoing()[ix]); + bool order = qq[0]->id()>0; + if(!order) swap(qq[0],qq[1]); + // create the new quark, antiquark and gluon + PPtr newq = qq[0]->dataPtr()->produceParticle(emission[2]); + PPtr newa = qq[1]->dataPtr()->produceParticle(emission[3]); + PPtr newg = gamma_->produceParticle(emission[4]); + // create the output real emission process + for(unsigned int ix=0;ixbornIncoming().size();++ix) { + born->incoming().push_back(born->bornIncoming()[ix]->dataPtr()-> + produceParticle(born->bornIncoming()[ix]->momentum())); + } + if(order) { + born->outgoing().push_back(newq); + born->outgoing().push_back(newa); + } + else { + born->outgoing().push_back(newa); + born->outgoing().push_back(newq); + swap(iemit,ispect); + } + born->outgoing().push_back(newg); + // set emitter and spectator + born->emitter (iemit); + born->spectator(ispect); + born->emitted(4); + return born; +} + +double MEee2ff::meRatio(vector partons, + vector momenta, + unsigned int iemitter, bool subtract) const { + Lorentz5Momentum q = momenta[2]+momenta[3]+momenta[4]; + Energy2 Q2=q.m2(); + Energy2 lambda = sqrt((Q2-sqr(momenta[2].mass()+momenta[3].mass()))* + (Q2-sqr(momenta[2].mass()-momenta[3].mass()))); + InvEnergy2 D[2]; + double lome[2]; + for(unsigned int iemit=0;iemit<2;++iemit) { + unsigned int ispect = iemit==0 ? 1 : 0; + Energy2 pipj = momenta[4 ] * momenta[2+iemit ]; + Energy2 pipk = momenta[4 ] * momenta[2+ispect]; + Energy2 pjpk = momenta[2+iemit] * momenta[2+ispect]; + double y = pipj/(pipj+pipk+pjpk); + double z = pipk/( pipk+pjpk); + Energy mij = sqrt(2.*pipj+sqr(momenta[2+iemit].mass())); + Energy2 lamB = sqrt((Q2-sqr(mij+momenta[2+ispect].mass()))* + (Q2-sqr(mij-momenta[2+ispect].mass()))); + Energy2 Qpk = q*momenta[2+ispect]; + Lorentz5Momentum pkt = + lambda/lamB*(momenta[2+ispect]-Qpk/Q2*q) + +0.5/Q2*(Q2+sqr(momenta[2+ispect].mass())-sqr(momenta[2+ispect].mass()))*q; + Lorentz5Momentum pijt = + q-pkt; + double muj = momenta[2+iemit ].mass()/sqrt(Q2); + double muk = momenta[2+ispect].mass()/sqrt(Q2); + double vt = sqrt((1.-sqr(muj+muk))*(1.-sqr(muj-muk)))/(1.-sqr(muj)-sqr(muk)); + double v = sqrt(sqr(2.*sqr(muk)+(1.-sqr(muj)-sqr(muk))*(1.-y))-4.*sqr(muk)) + /(1.-y)/(1.-sqr(muj)-sqr(muk)); + // dipole term + D[iemit] = 0.5/pipj*(2./(1.-(1.-z)*(1.-y)) + -vt/v*(2.-z+sqr(momenta[2+iemit].mass())/pipj)); + // matrix element + vector lomom(4); + lomom[0] = momenta[0]; + lomom[1] = momenta[1]; + if(iemit==0) { + lomom[2] = pijt; + lomom[3] = pkt ; + } + else { + lomom[3] = pijt; + lomom[2] = pkt ; + } + lome[iemit] = loME(partons,lomom,false); + } + InvEnergy2 ratio = realME(partons,momenta) + *abs(D[iemitter])/(abs(D[0]*lome[0])+abs(D[1]*lome[1])); + double output = Q2*ratio; + if(subtract) output -= 2.*Q2*D[iemitter]; + return output; +} + +InvEnergy2 MEee2ff::realME(const vector & partons, + const vector & momenta) const { + // compute the spinors + vector fin,aout; + vector ain,fout; + vector gout; + SpinorWaveFunction ein (momenta[0],partons[0],incoming); + SpinorBarWaveFunction pin (momenta[1],partons[1],incoming); + SpinorBarWaveFunction qkout(momenta[2],partons[2],outgoing); + SpinorWaveFunction qbout(momenta[3],partons[3],outgoing); + VectorWaveFunction photon(momenta[4],partons[4],outgoing); + for(unsigned int ix=0;ix<2;++ix) { + ein.reset(ix) ; + fin.push_back( ein ); + pin.reset(ix) ; + ain.push_back( pin ); + qkout.reset(ix); + fout.push_back(qkout); + qbout.reset(ix); + aout.push_back(qbout); + photon.reset(2*ix); + gout.push_back(photon); + } + vector diag(4,0.); + ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half, + PDT::Spin1Half,PDT::Spin1Half, + PDT::Spin1); + double total(0.); + for(unsigned int inhel1=0;inhel1<2;++inhel1) { + for(unsigned int inhel2=0;inhel2<2;++inhel2) { + // intermediate Z + VectorWaveFunction interZ = + FFZVertex_->evaluate(scale(),1,Z0_,fin[inhel1],ain[inhel2]); + // intermediate photon + VectorWaveFunction interG = + FFPVertex_->evaluate(scale(),1,gamma_,fin[inhel1],ain[inhel2]); + for(unsigned int outhel1=0;outhel1<2;++outhel1) { + for(unsigned int outhel2=0;outhel2<2;++outhel2) { + for(unsigned int outhel3=0;outhel3<2;++outhel3) { + SpinorBarWaveFunction off1 = + FFPVertex_->evaluate(scale(),3,partons[2],fout[outhel1],gout[outhel3]); + diag[0] = FFZVertex_->evaluate(scale(),aout[outhel2],off1,interZ); + diag[1] = FFPVertex_->evaluate(scale(),aout[outhel2],off1,interG); + SpinorWaveFunction off2 = + FFPVertex_->evaluate(scale(),3,partons[3],aout[outhel2],gout[outhel3]); + diag[2] = FFZVertex_->evaluate(scale(),off2,fout[outhel1],interZ); + diag[3] = FFPVertex_->evaluate(scale(),off2,fout[outhel1],interG); + // sum of diagrams + Complex sum = std::accumulate(diag.begin(),diag.end(),Complex(0.)); + // matrix element + output(inhel1,inhel2,outhel1,outhel2,outhel3)=sum; + // me2 + total += norm(sum); + } + } + } + } + } + // spin average + total *= 0.25; + tcPolarizedBeamPDPtr beam[2] = + {dynamic_ptr_cast(partons[0]), + dynamic_ptr_cast(partons[1])}; + if( beam[0] || beam[1] ) { + RhoDMatrix rho[2] = + {beam[0] ? beam[0]->rhoMatrix() : RhoDMatrix(mePartonData()[0]->iSpin()), + beam[1] ? beam[1]->rhoMatrix() : RhoDMatrix(mePartonData()[1]->iSpin())}; + total = output.average(rho[0],rho[1]); + } + // divide out the coupling and charge + total /= norm(FFPVertex_->norm())* + sqr(double(mePartonData()[2]->iCharge())/3.); + // return the total + return total*UnitRemoval::InvE2; +} + +Energy MEee2ff::generateHard(RealEmissionProcessPtr born, + vector & emmision, + unsigned int & iemit, unsigned int & ispect, + bool applyVeto) { + // get the momenta of the incoming and outgoing particles + // incoming + tPPtr em = born->bornIncoming()[0]; + tPPtr ep = born->bornIncoming()[1]; + if(em->id()<0) swap(em,ep); + // outgoing + tPPtr qk = born->bornOutgoing()[0]; + tPPtr qb = born->bornOutgoing()[1]; + if(qk->id()<0) swap(qk,qb); + // extract the momenta + loMomenta_.clear(); + loMomenta_.push_back(em->momentum()); + loMomenta_.push_back(ep->momentum()); + loMomenta_.push_back(qk->momentum()); + loMomenta_.push_back(qb->momentum()); + // and ParticleData objects + partons_.resize(5); + partons_[0]=em->dataPtr(); + partons_[1]=ep->dataPtr(); + partons_[2]=qk->dataPtr(); + partons_[3]=qb->dataPtr(); + partons_[4]=gamma_; + // boost from lab to CMS frame with outgoing particles + // along the z axis + LorentzRotation eventFrame( ( loMomenta_[2] + loMomenta_[3] ).findBoostToCM() ); + Lorentz5Momentum spectator = eventFrame*loMomenta_[2]; + eventFrame.rotateZ( -spectator.phi() ); + eventFrame.rotateY( -spectator.theta() ); + eventFrame.invert(); + // mass of the final-state system + Energy2 M2 = (loMomenta_[2]+loMomenta_[3]).m2(); + Energy M = sqrt(M2); + double mu1 = loMomenta_[2].mass()/M; + double mu2 = loMomenta_[3].mass()/M; + double mu12 = sqr(mu1), mu22 = sqr(mu2); + double lambda = sqrt(1.+sqr(mu12)+sqr(mu22)-2.*mu12-2.*mu22-2.*mu12*mu22); + // max pT + Energy pTmax = 0.5*sqrt(M2)* + (1.-sqr(loMomenta_[2].mass()+loMomenta_[3].mass())/M2); + // max y + double ymax = acosh(pTmax/pTmin_); + double a = alphaQED_->overestimateValue()/Constants::twopi* + 2.*ymax*preFactor_*sqr(double(mePartonData()[2]->iCharge())/3.); + // variables for the emission + Energy pT[2]; + double y[2],phi[2],x3[2],x1[2][2],x2[2][2]; + double contrib[2][2]; + // storage of the real emission momenta + vector realMomenta[2][2]= + {{vector(5),vector(5)}, + {vector(5),vector(5)}}; + for(unsigned int ix=0;ix<2;++ix) + for(unsigned int iy=0;iy<2;++iy) + for(unsigned int iz=0;iz<2;++iz) + realMomenta[ix][iy][iz] = loMomenta_[iz]; + // generate the emission + for(unsigned int ix=0;ix<2;++ix) { + if(ix==1) { + swap(mu1 ,mu2 ); + swap(mu12,mu22); + } + pT[ix] = pTmax; + y [ix] = 0.; + bool reject = true; + do { + // generate pT + pT[ix] *= pow(UseRandom::rnd(),1./a); + if(pT[ix] 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]x2max) continue; + // check the z components + double z1 = sqrt(sqr(x1[ix][iy])-4.*mu12-xT2); + double z2 = -sqrt(sqr(x2[ix][iy])-4.*mu22); + double z3 = pT[ix]*sinh(y[ix])*2./M; + if(ix==1) z3 *=-1.; + if(abs(-z1+z2+z3)<1e-9) z1 *= -1.; + if(abs(z1+z2+z3)>1e-5) continue; + // if using as an ME correction the veto + if(applyVeto) { +// double xb = x1[ix][iy], xc = x2[ix][iy]; +// double b = mu12, c = mu22; +// double r = 0.5*(1.+b/(1.+c-xc)); +// double z1 = r + (xb-(2.-xc)*r)/sqrt(sqr(xc)-4.*c); +// double kt1 = (1.-b+c-xc)/z1/(1.-z1); +// r = 0.5*(1.+c/(1.+b-xb)); +// double z2 = r + (xc-(2.-xb)*r)/sqrt(sqr(xb)-4.*b); +// double kt2 = (1.-c+b-xb)/z2/(1.-z2); +// if(ix==1) { +// swap(z1 ,z2); +// swap(kt1,kt2); +// } +// // veto the shower region +// if( kt1 < d_kt1_ || kt2 < d_kt2_ ) continue; + } + // construct the momenta + realMomenta[ix][iy][4] = + Lorentz5Momentum(pT[ix]*cos(phi[ix]),pT[ix]*sin(phi[ix]), + pT[ix]*sinh(y[ix]) ,pT[ix]*cosh(y[ix]),ZERO); + if(ix==0) { + realMomenta[ix][iy][2] = + Lorentz5Momentum(-pT[ix]*cos(phi[ix]),-pT[ix]*sin(phi[ix]), + z1*0.5*M,x1[ix][iy]*0.5*M,M*mu1); + realMomenta[ix][iy][3] = + Lorentz5Momentum(ZERO,ZERO, z2*0.5*M,x2[ix][iy]*0.5*M,M*mu2); + } + else { + realMomenta[ix][iy][2] = + Lorentz5Momentum(ZERO,ZERO,-z2*0.5*M,x2[ix][iy]*0.5*M,M*mu2); + realMomenta[ix][iy][3] = + Lorentz5Momentum(-pT[ix]*cos(phi[ix]),-pT[ix]*sin(phi[ix]), + -z1*0.5*M,x1[ix][iy]*0.5*M,M*mu1); + } + // boost the momenta back to the lab + for(unsigned int iz=2;iz<5;++iz) + realMomenta[ix][iy][iz] *= eventFrame; + // jacobian and prefactors for the weight + Energy J = M/sqrt(xT2)*abs(-x1[ix][iy]*x2[ix][iy]+2.*mu22*x1[ix][iy] + +x2[ix][iy]+x2[ix][iy]*mu12+mu22*x2[ix][iy] + -sqr(x2[ix][iy])) + /pow(sqr(x2[ix][iy])-4.*mu22,1.5); + // prefactors etc + contrib[ix][iy] = 0.5*pT[ix]/J/preFactor_/lambda; + // matrix element piece + contrib[ix][iy] *= meRatio(partons_,realMomenta[ix][iy],ix,false); + // coupling piece + contrib[ix][iy] *= alphaQED_->ratio(sqr(pT[ix])); + } + if(contrib[ix][0]+contrib[ix][1]>1.) { + ostringstream s; + s << "MEee2gZ2qq::generateHardest weight for channel " << ix + << "is " << contrib[ix][0]+contrib[ix][1] + << " which is greater than 1"; + generator()->logWarning( Exception(s.str(), Exception::warning) ); + } + reject = UseRandom::rnd() > contrib[ix][0] + contrib[ix][1]; + } + while (reject); + if(pT[ix]pT[1]) { + iemit = 2; + ispect = 3; + pTemit = pT[0]; + if(UseRandom::rnd()(2,1)); + } + + /** + * Members for hard corrections to the emission of QCD radiation + */ + //@{ + /** + * Has a POWHEG style correction + */ + virtual POWHEGType hasPOWHEGCorrection() {return FSR;} + + /** + * Has an old fashioned ME correction + */ + virtual bool hasMECorrection() {return false;} + + /** + * Apply the POWHEG style correction + */ + virtual RealEmissionProcessPtr generateHardest(RealEmissionProcessPtr, + ShowerInteraction); + //@} + +public: + + /** @name Virtual functions required by the MEBase class. */ + //@{ + /** + * Return the order in \f$\alpha_S\f$ in which this matrix + * element is given. + */ + virtual unsigned int orderInAlphaS() const; + + /** + * Return the order in \f$\alpha_{EW}\f$ in which this matrix + * element is given. + */ + virtual unsigned int orderInAlphaEW() const; + + /** + * The matrix element for the kinematical configuration + * previously provided by the last call to setKinematics(), suitably + * scaled by sHat() to give a dimension-less number. + * @return the matrix element scaled with sHat() to give a + * dimensionless number. + */ + virtual double me2() const; + + /** + * Return the scale associated with the last set phase space point. + */ + virtual Energy2 scale() const; + + /** + * Add all possible diagrams with the add() function. + */ + virtual void getDiagrams() const; + + /** + * Get diagram selector. With the information previously supplied with the + * setKinematics method, a derived class may optionally + * override this method to weight the given diagrams with their + * (although certainly not physical) relative probabilities. + * @param dv the diagrams to be weighted. + * @return a Selector relating the given diagrams to their weights. + */ + virtual Selector diagrams(const DiagramVector & dv) const; + + /** + * Return a Selector with possible colour geometries for the selected + * diagram weighted by their relative probabilities. + * @param diag the diagram chosen. + * @return the possible colour geometries weighted by their + * relative probabilities. + */ + virtual Selector + colourGeometries(tcDiagPtr diag) const; + + /** + * Construct the vertex of spin correlations. + */ + virtual void constructVertex(tSubProPtr); + //@} + + +public: + + /** @name Functions used by the persistent I/O system. */ + //@{ + /** + * Function used to write out object persistently. + * @param os the persistent output stream written to. + */ + void persistentOutput(PersistentOStream & os) const; + + /** + * Function used to read in object persistently. + * @param is the persistent input stream read from. + * @param version the version number of the object when written. + */ + void persistentInput(PersistentIStream & is, int version); + //@} + + /** + * The standard Init function used to initialize the interfaces. + * Called exactly once for each class by the class description system + * before the main function starts or + * when this class is dynamically loaded. + */ + static void Init(); + +protected: + + /** @name Clone Methods. */ + //@{ + /** + * Make a simple clone of this object. + * @return a pointer to the new object. + */ + virtual IBPtr clone() const {return new_ptr(*this);} + + /** Make a clone of this object, possibly modifying the cloned object + * to make it sane. + * @return a pointer to the new object. + */ + virtual IBPtr fullclone() const {return new_ptr(*this);} + //@} + +protected: + + /** @name Standard Interfaced functions. */ + //@{ + /** + * Initialize this object after the setup phase before saving an + * EventGenerator to disk. + * @throws InitException if object could not be initialized properly. + */ + virtual void doinit(); + + /** + * Rebind pointer to other Interfaced objects. Called in the setup phase + * after all objects used in an EventGenerator has been cloned so that + * the pointers will refer to the cloned objects afterwards. + * @param trans a TranslationMap relating the original objects to + * their respective clones. + * @throws RebindException if no cloned object was found for a given + * pointer. + */ + virtual void rebind(const TranslationMap & trans) + ; + + /** + * Return a vector of all pointers to Interfaced objects used in this + * object. + * @return a vector of pointers. + */ + virtual IVector getReferences(); + //@} + +protected: + + /** + * Calculate the matrix element for \f$e^+e^-\to \ell^+ \ell^-\f$. + * @param partons The incoming and outgoing particles + * @param momenta The momenta of the incoming and outgoing particles + */ + double loME(const vector & partons, + const vector & momenta, + bool first) const; + + /** + * Member to calculate the matrix element + * @param fin Spinors for incoming fermion + * @param ain Spinors for incoming antifermion + * @param fout Spinors for outgoing fermion + * @param aout Spinors for outgong antifermion + * @param me Spin summed Matrix element + * @param cont The continuum piece of the matrix element + * @param BW The Z piece of the matrix element + */ + ProductionMatrixElement HelicityME(vector & fin, + vector & ain, + vector & fout, + vector & aout, + double & me, + double & cont, + double & BW ) const; + + /** + * The ratio of the matrix element for one additional jet over the + * leading order result. In practice + * \[\frac{\hat{s}|\overline{\mathcal{M}}|^2_2|D_{\rm emit}|}{4\pi C_F\alpha_S|\overline{\mathcal{M}}|^2_3\left(|D_{\rm emit}|+|D_{\rm spect}\right)}}\] + * is returned where \f$\|\overline{\mathcal{M}}|^2\f$ is + * the spin and colour summed/averaged matrix element. + * @param partons The incoming and outgoing particles + * @param momenta The momenta of the incoming and outgoing particles + * @param iemitter Whether the quark or antiquark is regardede as the emitter + * @param inter The type of interaction + */ + double meRatio(vector partons, + vector momenta, + unsigned int iemittor, + bool subtract=false) const; + + /** + * Calculate the matrix element for \f$e^-e^-\to q \bar q g$. + * @param partons The incoming and outgoing particles + * @param momenta The momenta of the incoming and outgoing particles + * @param inter The type of interaction + */ + InvEnergy2 realME(const vector & partons, + const vector & momenta) const; + + /** + * Generate the momenta for a hard configuration + */ + Energy generateHard(RealEmissionProcessPtr tree, + vector & emission, + unsigned int & iemit, unsigned int & ispect, + bool applyVeto); + + +protected: + + /** + * Pointer to the fermion-antifermion Z vertex + */ + AbstractFFVVertexPtr FFZVertex() const {return FFZVertex_;} + + /** + * Pointer to the fermion-antifermion photon vertex + */ + AbstractFFVVertexPtr FFPVertex() const {return FFPVertex_;} + + /** + * Pointer to the particle data object for the Z + */ + PDPtr Z0() const {return Z0_;} + + /** + * Pointer to the particle data object for the photon + */ + PDPtr gamma() const {return gamma_;} + +private: + + /** + * The assignment operator is private and must never be called. + * In fact, it should not even be implemented. + */ + MEee2ff & operator=(const MEee2ff &) = delete; + +private: + + /** + * Pointers to the vertices + */ + //@{ + /** + * Pointer to the fermion-antifermion Z vertex + */ + AbstractFFVVertexPtr FFZVertex_; + + /** + * Pointer to the fermion-antifermion photon vertex + */ + AbstractFFVVertexPtr FFPVertex_; + //@} + + /** + * Pointer to the particle data object for the Z + */ + PDPtr Z0_; + + /** + * Pointer to the particle data object for the photon + */ + PDPtr gamma_; + + /** + * The allowed outgoing + */ + int allowed_; + + /** + * The allowed helicity configuration + */ + int helicity_; + + /** + * Set the incoming lepton beam, either electron or meuon beams + */ + int incoming_; + + /** + * Pointer to the EM coupling + */ + ShowerAlphaPtr alphaQED_; + + /** + * Variables for the POWHEG style corrections + */ + //@{ + /** + * The cut off on pt, assuming massless quarks. + */ + Energy pTmin_; + + /** + * Overestimate for the prefactor + */ + double preFactor_; + + /** + * ParticleData objects for the partons + */ + vector partons_; + + /** + * Momenta of the leading-order partons + */ + vector loMomenta_; + //@} + +}; + +} + +#endif /* HERWIG_MEee2ff_H */ diff --git a/MatrixElement/Lepton/MEee2gZ2ll.cc b/MatrixElement/Lepton/MEee2gZ2ll.cc --- a/MatrixElement/Lepton/MEee2gZ2ll.cc +++ b/MatrixElement/Lepton/MEee2gZ2ll.cc @@ -1,716 +1,718 @@ // -*- C++ -*- // // MEee2gZ2ll.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the MEee2gZ2ll class. // #include "MEee2gZ2ll.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/MatrixElement/Tree2toNDiagram.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "ThePEG/Handlers/StandardXComb.h" #include "Herwig/MatrixElement/HardVertex.h" #include "ThePEG/PDF/PolarizedBeamParticleData.h" #include "ThePEG/Utilities/DescribeClass.h" #include #include "Herwig/Shower/RealEmissionProcess.h" using namespace Herwig; void MEee2gZ2ll::getDiagrams() const { // specific the diagrams tcPDPtr ep = getParticleData(ParticleID::eplus); tcPDPtr em = getParticleData(ParticleID::eminus); // setup the processes for( int i =11;i<=16;++i) { if(allowed_==0 || (allowed_==1 && i%2==1) || (allowed_==2&&i==11) || (allowed_==3&&i==13) || (allowed_==4&&i==15)) { tcPDPtr lm = getParticleData(i); tcPDPtr lp = lm->CC(); add(new_ptr((Tree2toNDiagram(2), em, ep, 1, gamma_, 3, lm, 3, lp, -1))); add(new_ptr((Tree2toNDiagram(2), em, ep, 1, Z0_, 3, lm, 3, lp, -2))); } } } Energy2 MEee2gZ2ll::scale() const { return sHat(); } unsigned int MEee2gZ2ll::orderInAlphaS() const { return 0; } unsigned int MEee2gZ2ll::orderInAlphaEW() const { return 2; } Selector MEee2gZ2ll::diagrams(const DiagramVector & diags) const { double lastCont(0.5),lastBW(0.5); if ( lastXCombPtr() ) { lastCont = meInfo()[0]; lastBW = meInfo()[1]; } Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ) { if ( diags[i]->id() == -1 ) sel.insert(lastCont, i); else if ( diags[i]->id() == -2 ) sel.insert(lastBW, i); } return sel; } Selector MEee2gZ2ll::colourGeometries(tcDiagPtr) const { static ColourLines ctST(" "); Selector sel; sel.insert(1.0, &ctST); return sel; } void MEee2gZ2ll::persistentOutput(PersistentOStream & os) const { os << allowed_ << FFZVertex_ << FFPVertex_ << gamma_ << Z0_ << alphaQED_ << ounit(pTmin_,GeV) << preFactor_; } void MEee2gZ2ll::persistentInput(PersistentIStream & is, int) { is >> allowed_ >> FFZVertex_ >> FFPVertex_ >> gamma_ >> Z0_ >> alphaQED_ >> iunit(pTmin_,GeV) >> preFactor_; } // *** Attention *** The following static variable is needed for the type // description system in ThePEG. Please check that the template arguments // are correct (the class and its base class), and that the constructor // arguments are correct (the class name and the name of the dynamically // loadable library where the class implementation can be found). DescribeClass describeMEee2gZ2ll("Herwig::MEee2gZ2ll", "HwMELepton.so"); void MEee2gZ2ll::Init() { static ClassDocumentation documentation ("The MEee2gZ2ll class implements the matrix element for" "e+e- to leptons via Z and photon exchange using helicity amplitude" "techniques"); static Switch interfaceallowed ("Allowed", "Allowed outgoing leptons", &MEee2gZ2ll::allowed_, 0, false, false); static SwitchOption interfaceallowedAll (interfaceallowed, "All", "Allow all leptons as outgoing particles", 0); static SwitchOption interfaceallowedCharged (interfaceallowed, "Charged", "Only charged leptons as outgoing particles", 1); static SwitchOption interfaceallowedElectron (interfaceallowed, "Electron", "Only the electron and positron as outgoing leptons", 2); static SwitchOption interfaceallowedMuon (interfaceallowed, "Muon", "Only muons as outgoing particles", 3); static SwitchOption interfaceallowedTau (interfaceallowed, "Tau", "Only taus as outgoing particles", 4); static Parameter interfacepTMin ("pTMin", "Minimum pT for hard radiation", &MEee2gZ2ll::pTmin_, GeV, 1.0*GeV, 0.001*GeV, 10.0*GeV, false, false, Interface::limited); static Parameter interfacePrefactor ("Prefactor", "Prefactor for the overestimate of the emission probability", &MEee2gZ2ll::preFactor_, 6.0, 1.0, 100.0, false, false, Interface::limited); static Reference interfaceEMCoupling ("AlphaQED", "Pointer to the object to calculate the EM coupling for the correction", &MEee2gZ2ll::alphaQED_, false, false, true, false, false); } double MEee2gZ2ll::me2() const { return loME(mePartonData(),rescaledMomenta(),true); } double MEee2gZ2ll::loME(const vector & partons, const vector & momenta, bool first) const { vector fin,aout; vector ain,fout; SpinorWaveFunction ein (momenta[0],partons[0],incoming); SpinorBarWaveFunction pin (momenta[1],partons[1],incoming); SpinorBarWaveFunction ilmout(momenta[2],partons[2],outgoing); SpinorWaveFunction ilpout(momenta[3],partons[3],outgoing); for(unsigned int ix=0;ix<2;++ix) { ein.reset(ix) ;fin.push_back( ein ); pin.reset(ix) ;ain.push_back( pin ); ilmout.reset(ix);fout.push_back(ilmout); ilpout.reset(ix);aout.push_back(ilpout); } // compute the matrix element double me,lastCont,lastBW; HelicityME(fin,ain,fout,aout,me,lastCont,lastBW); // save the components if(first) { DVector save; save.push_back(lastCont); save.push_back(lastBW); meInfo(save); } // return the answer return me; } ProductionMatrixElement MEee2gZ2ll::HelicityME(vector & fin, vector & ain, vector & fout, vector & aout, double & me,double & cont, double & BW ) const { // the particles should be in the order // for the incoming // 0 incoming fermion (u spinor) // 1 incoming antifermion (vbar spinor) // for the outgoing // 0 outgoing fermion (ubar spinor) // 1 outgoing antifermion (v spinor) // me to be returned ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half); ProductionMatrixElement gamma (PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half); ProductionMatrixElement Zboson(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half); // // wavefunctions for the intermediate particles VectorWaveFunction interZ,interG; // temporary storage of the different diagrams Complex diag1,diag2; // sum over helicities to get the matrix element unsigned int inhel1,inhel2,outhel1,outhel2; double total[3]={0.,0.,0.}; for(inhel1=0;inhel1<2;++inhel1) { for(inhel2=0;inhel2<2;++inhel2) { // intermediate Z interZ = FFZVertex_->evaluate(sHat(),1,Z0_,fin[inhel1],ain[inhel2]); // intermediate photon interG = FFPVertex_->evaluate(sHat(),1,gamma_,fin[inhel1],ain[inhel2]); for(outhel1=0;outhel1<2;++outhel1) { for(outhel2=0;outhel2<2;++outhel2) { // first the Z exchange diagram diag1 = FFZVertex_->evaluate(sHat(),aout[outhel2],fout[outhel1], interZ); // then the photon exchange diagram diag2 = FFPVertex_->evaluate(sHat(),aout[outhel2],fout[outhel1], interG); // add up squares of individual terms total[1] += norm(diag1); Zboson(inhel1,inhel2,outhel1,outhel2) = diag1; total[2] += norm(diag2); gamma (inhel1,inhel2,outhel1,outhel2) = diag2; // the full thing including interference diag1 += diag2; total[0] += norm(diag1); output(inhel1,inhel2,outhel1,outhel2) = diag1; } } } } // results for(int ix=0;ix<3;++ix) total[ix] *= 0.25; tcPolarizedBeamPDPtr beam[2] = {dynamic_ptr_cast(mePartonData()[0]), dynamic_ptr_cast(mePartonData()[1])}; if( beam[0] || beam[1] ) { RhoDMatrix rho[2] = {beam[0] ? beam[0]->rhoMatrix() : RhoDMatrix(mePartonData()[0]->iSpin()), beam[1] ? beam[1]->rhoMatrix() : RhoDMatrix(mePartonData()[1]->iSpin())}; total[0] = output.average(rho[0],rho[1]); total[1] = Zboson.average(rho[0],rho[1]); total[2] = gamma .average(rho[0],rho[1]); } cont = total[2]; BW = total[1]; me = total[0]; return output; } void MEee2gZ2ll::constructVertex(tSubProPtr sub) { // extract the particles in the hard process ParticleVector hard; hard.push_back(sub->incoming().first);hard.push_back(sub->incoming().second); hard.push_back(sub->outgoing()[0]);hard.push_back(sub->outgoing()[1]); if(hard[0]->id()id()) swap(hard[0],hard[1]); if(hard[2]->id()id()) swap(hard[2],hard[3]); vector fin,aout; vector ain,fout; SpinorWaveFunction( fin ,hard[0],incoming,false,true); SpinorBarWaveFunction(ain ,hard[1],incoming,false,true); SpinorBarWaveFunction(fout,hard[2],outgoing,true ,true); SpinorWaveFunction( aout,hard[3],outgoing,true ,true); // calculate the matrix element double me,cont,BW; ProductionMatrixElement prodme=HelicityME(fin,ain,fout,aout,me,cont,BW); // construct the vertex HardVertexPtr hardvertex=new_ptr(HardVertex()); // set the matrix element for the vertex hardvertex->ME(prodme); // set the pointers and to and from the vertex for(unsigned int ix=0;ix<4;++ix) { tSpinPtr spin = hard[ix]->spinInfo(); if(ix<2) { tcPolarizedBeamPDPtr beam = dynamic_ptr_cast(hard[ix]->dataPtr()); if(beam) spin->rhoMatrix() = beam->rhoMatrix(); } spin->productionVertex(hardvertex); } } void MEee2gZ2ll::doinit() { HwMEBase::doinit(); // set the particle data objects Z0_=getParticleData(ThePEG::ParticleID::Z0); gamma_=getParticleData(ThePEG::ParticleID::gamma); // cast the SM pointer to the Herwig SM pointer tcHwSMPtr hwsm= dynamic_ptr_cast(standardModel()); // do the initialisation if(!hwsm) throw InitException() << "Wrong type of StandardModel object in " << "MEee2gZ2ll::doinit() the Herwig" << " version must be used" << Exception::runerror; FFZVertex_ = hwsm->vertexFFZ(); FFPVertex_ = hwsm->vertexFFP(); } void MEee2gZ2ll::rebind(const TranslationMap & trans) { FFZVertex_ = trans.translate(FFZVertex_); FFPVertex_ = trans.translate(FFPVertex_); Z0_ = trans.translate(Z0_); gamma_ = trans.translate(gamma_); HwMEBase::rebind(trans); } IVector MEee2gZ2ll::getReferences() { IVector ret = HwMEBase::getReferences(); ret.push_back(FFZVertex_); ret.push_back(FFPVertex_); ret.push_back(Z0_ ); ret.push_back(gamma_ ); return ret; } RealEmissionProcessPtr MEee2gZ2ll::generateHardest(RealEmissionProcessPtr born, ShowerInteraction inter) { - // check if QED switched on - if(inter==ShowerInteraction::QCD) return RealEmissionProcessPtr(); + // check if generating QCD radiation + if(inter!=ShowerInteraction::QED && inter!=ShowerInteraction::QEDQCD && + inter!=ShowerInteraction::ALL) + return RealEmissionProcessPtr(); // generate the momenta for the hard emission vector emission; unsigned int iemit,ispect; Energy pTveto = generateHard(born,emission,iemit,ispect,false); // check if charged if(!partons_[2]->charged()) return RealEmissionProcessPtr(); // maximum pT of emission if(pTveto<=ZERO) { born->pT()[ShowerInteraction::QED] = pTmin_; return born; } else { born->pT()[ShowerInteraction::QED] = pTveto; } born->interaction(ShowerInteraction::QED); // get the quark and antiquark ParticleVector qq; for(unsigned int ix=0;ix<2;++ix) qq.push_back(born->bornOutgoing()[ix]); bool order = qq[0]->id()>0; if(!order) swap(qq[0],qq[1]); // create the new quark, antiquark and gluon PPtr newq = qq[0]->dataPtr()->produceParticle(emission[2]); PPtr newa = qq[1]->dataPtr()->produceParticle(emission[3]); PPtr newg = gamma_->produceParticle(emission[4]); // create the output real emission process for(unsigned int ix=0;ixbornIncoming().size();++ix) { born->incoming().push_back(born->bornIncoming()[ix]->dataPtr()-> produceParticle(born->bornIncoming()[ix]->momentum())); } if(order) { born->outgoing().push_back(newq); born->outgoing().push_back(newa); } else { born->outgoing().push_back(newa); born->outgoing().push_back(newq); swap(iemit,ispect); } born->outgoing().push_back(newg); // set emitter and spectator born->emitter (iemit); born->spectator(ispect); born->emitted(4); return born; } double MEee2gZ2ll::meRatio(vector partons, vector momenta, unsigned int iemitter, bool subtract) const { Lorentz5Momentum q = momenta[2]+momenta[3]+momenta[4]; Energy2 Q2=q.m2(); Energy2 lambda = sqrt((Q2-sqr(momenta[2].mass()+momenta[3].mass()))* (Q2-sqr(momenta[2].mass()-momenta[3].mass()))); InvEnergy2 D[2]; double lome[2]; for(unsigned int iemit=0;iemit<2;++iemit) { unsigned int ispect = iemit==0 ? 1 : 0; Energy2 pipj = momenta[4 ] * momenta[2+iemit ]; Energy2 pipk = momenta[4 ] * momenta[2+ispect]; Energy2 pjpk = momenta[2+iemit] * momenta[2+ispect]; double y = pipj/(pipj+pipk+pjpk); double z = pipk/( pipk+pjpk); Energy mij = sqrt(2.*pipj+sqr(momenta[2+iemit].mass())); Energy2 lamB = sqrt((Q2-sqr(mij+momenta[2+ispect].mass()))* (Q2-sqr(mij-momenta[2+ispect].mass()))); Energy2 Qpk = q*momenta[2+ispect]; Lorentz5Momentum pkt = lambda/lamB*(momenta[2+ispect]-Qpk/Q2*q) +0.5/Q2*(Q2+sqr(momenta[2+ispect].mass())-sqr(momenta[2+ispect].mass()))*q; Lorentz5Momentum pijt = q-pkt; double muj = momenta[2+iemit ].mass()/sqrt(Q2); double muk = momenta[2+ispect].mass()/sqrt(Q2); double vt = sqrt((1.-sqr(muj+muk))*(1.-sqr(muj-muk)))/(1.-sqr(muj)-sqr(muk)); double v = sqrt(sqr(2.*sqr(muk)+(1.-sqr(muj)-sqr(muk))*(1.-y))-4.*sqr(muk)) /(1.-y)/(1.-sqr(muj)-sqr(muk)); // dipole term D[iemit] = 0.5/pipj*(2./(1.-(1.-z)*(1.-y)) -vt/v*(2.-z+sqr(momenta[2+iemit].mass())/pipj)); // matrix element vector lomom(4); lomom[0] = momenta[0]; lomom[1] = momenta[1]; if(iemit==0) { lomom[2] = pijt; lomom[3] = pkt ; } else { lomom[3] = pijt; lomom[2] = pkt ; } lome[iemit] = loME(partons,lomom,false); } InvEnergy2 ratio = realME(partons,momenta) *abs(D[iemitter])/(abs(D[0]*lome[0])+abs(D[1]*lome[1])); double output = Q2*ratio; if(subtract) output -= 2.*Q2*D[iemitter]; return output; } InvEnergy2 MEee2gZ2ll::realME(const vector & partons, const vector & momenta) const { // compute the spinors vector fin,aout; vector ain,fout; vector gout; SpinorWaveFunction ein (momenta[0],partons[0],incoming); SpinorBarWaveFunction pin (momenta[1],partons[1],incoming); SpinorBarWaveFunction qkout(momenta[2],partons[2],outgoing); SpinorWaveFunction qbout(momenta[3],partons[3],outgoing); VectorWaveFunction photon(momenta[4],partons[4],outgoing); for(unsigned int ix=0;ix<2;++ix) { ein.reset(ix) ; fin.push_back( ein ); pin.reset(ix) ; ain.push_back( pin ); qkout.reset(ix); fout.push_back(qkout); qbout.reset(ix); aout.push_back(qbout); photon.reset(2*ix); gout.push_back(photon); } vector diag(4,0.); ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1); double total(0.); for(unsigned int inhel1=0;inhel1<2;++inhel1) { for(unsigned int inhel2=0;inhel2<2;++inhel2) { // intermediate Z VectorWaveFunction interZ = FFZVertex_->evaluate(scale(),1,Z0_,fin[inhel1],ain[inhel2]); // intermediate photon VectorWaveFunction interG = FFPVertex_->evaluate(scale(),1,gamma_,fin[inhel1],ain[inhel2]); for(unsigned int outhel1=0;outhel1<2;++outhel1) { for(unsigned int outhel2=0;outhel2<2;++outhel2) { for(unsigned int outhel3=0;outhel3<2;++outhel3) { SpinorBarWaveFunction off1 = FFPVertex_->evaluate(scale(),3,partons[2],fout[outhel1],gout[outhel3]); diag[0] = FFZVertex_->evaluate(scale(),aout[outhel2],off1,interZ); diag[1] = FFPVertex_->evaluate(scale(),aout[outhel2],off1,interG); SpinorWaveFunction off2 = FFPVertex_->evaluate(scale(),3,partons[3],aout[outhel2],gout[outhel3]); diag[2] = FFZVertex_->evaluate(scale(),off2,fout[outhel1],interZ); diag[3] = FFPVertex_->evaluate(scale(),off2,fout[outhel1],interG); // sum of diagrams Complex sum = std::accumulate(diag.begin(),diag.end(),Complex(0.)); // matrix element output(inhel1,inhel2,outhel1,outhel2,outhel3)=sum; // me2 total += norm(sum); } } } } } // spin average total *= 0.25; tcPolarizedBeamPDPtr beam[2] = {dynamic_ptr_cast(partons[0]), dynamic_ptr_cast(partons[1])}; if( beam[0] || beam[1] ) { RhoDMatrix rho[2] = {beam[0] ? beam[0]->rhoMatrix() : RhoDMatrix(mePartonData()[0]->iSpin()), beam[1] ? beam[1]->rhoMatrix() : RhoDMatrix(mePartonData()[1]->iSpin())}; total = output.average(rho[0],rho[1]); } // divide out the coupling and charge total /= norm(FFPVertex_->norm())* sqr(double(mePartonData()[2]->iCharge())/3.); // return the total return total*UnitRemoval::InvE2; } Energy MEee2gZ2ll::generateHard(RealEmissionProcessPtr born, vector & emmision, unsigned int & iemit, unsigned int & ispect, bool applyVeto) { // get the momenta of the incoming and outgoing particles // incoming tPPtr em = born->bornIncoming()[0]; tPPtr ep = born->bornIncoming()[1]; if(em->id()<0) swap(em,ep); // outgoing tPPtr qk = born->bornOutgoing()[0]; tPPtr qb = born->bornOutgoing()[1]; if(qk->id()<0) swap(qk,qb); // extract the momenta loMomenta_.clear(); loMomenta_.push_back(em->momentum()); loMomenta_.push_back(ep->momentum()); loMomenta_.push_back(qk->momentum()); loMomenta_.push_back(qb->momentum()); // and ParticleData objects partons_.resize(5); partons_[0]=em->dataPtr(); partons_[1]=ep->dataPtr(); partons_[2]=qk->dataPtr(); partons_[3]=qb->dataPtr(); partons_[4]=gamma_; // boost from lab to CMS frame with outgoing particles // along the z axis LorentzRotation eventFrame( ( loMomenta_[2] + loMomenta_[3] ).findBoostToCM() ); Lorentz5Momentum spectator = eventFrame*loMomenta_[2]; eventFrame.rotateZ( -spectator.phi() ); eventFrame.rotateY( -spectator.theta() ); eventFrame.invert(); // mass of the final-state system Energy2 M2 = (loMomenta_[2]+loMomenta_[3]).m2(); Energy M = sqrt(M2); double mu1 = loMomenta_[2].mass()/M; double mu2 = loMomenta_[3].mass()/M; double mu12 = sqr(mu1), mu22 = sqr(mu2); double lambda = sqrt(1.+sqr(mu12)+sqr(mu22)-2.*mu12-2.*mu22-2.*mu12*mu22); // max pT Energy pTmax = 0.5*sqrt(M2)* (1.-sqr(loMomenta_[2].mass()+loMomenta_[3].mass())/M2); // max y double ymax = acosh(pTmax/pTmin_); double a = alphaQED_->overestimateValue()/Constants::twopi* 2.*ymax*preFactor_*sqr(double(mePartonData()[2]->iCharge())/3.); // variables for the emission Energy pT[2]; double y[2],phi[2],x3[2],x1[2][2],x2[2][2]; double contrib[2][2]; // storage of the real emission momenta vector realMomenta[2][2]= {{vector(5),vector(5)}, {vector(5),vector(5)}}; for(unsigned int ix=0;ix<2;++ix) for(unsigned int iy=0;iy<2;++iy) for(unsigned int iz=0;iz<2;++iz) realMomenta[ix][iy][iz] = loMomenta_[iz]; // generate the emission for(unsigned int ix=0;ix<2;++ix) { if(ix==1) { swap(mu1 ,mu2 ); swap(mu12,mu22); } pT[ix] = pTmax; y [ix] = 0.; bool reject = true; do { // generate pT pT[ix] *= pow(UseRandom::rnd(),1./a); if(pT[ix] 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]x2max) continue; // check the z components double z1 = sqrt(sqr(x1[ix][iy])-4.*mu12-xT2); double z2 = -sqrt(sqr(x2[ix][iy])-4.*mu22); double z3 = pT[ix]*sinh(y[ix])*2./M; if(ix==1) z3 *=-1.; if(abs(-z1+z2+z3)<1e-9) z1 *= -1.; if(abs(z1+z2+z3)>1e-5) continue; // if using as an ME correction the veto if(applyVeto) { // double xb = x1[ix][iy], xc = x2[ix][iy]; // double b = mu12, c = mu22; // double r = 0.5*(1.+b/(1.+c-xc)); // double z1 = r + (xb-(2.-xc)*r)/sqrt(sqr(xc)-4.*c); // double kt1 = (1.-b+c-xc)/z1/(1.-z1); // r = 0.5*(1.+c/(1.+b-xb)); // double z2 = r + (xc-(2.-xb)*r)/sqrt(sqr(xb)-4.*b); // double kt2 = (1.-c+b-xb)/z2/(1.-z2); // if(ix==1) { // swap(z1 ,z2); // swap(kt1,kt2); // } // // veto the shower region // if( kt1 < d_kt1_ || kt2 < d_kt2_ ) continue; } // construct the momenta realMomenta[ix][iy][4] = Lorentz5Momentum(pT[ix]*cos(phi[ix]),pT[ix]*sin(phi[ix]), pT[ix]*sinh(y[ix]) ,pT[ix]*cosh(y[ix]),ZERO); if(ix==0) { realMomenta[ix][iy][2] = Lorentz5Momentum(-pT[ix]*cos(phi[ix]),-pT[ix]*sin(phi[ix]), z1*0.5*M,x1[ix][iy]*0.5*M,M*mu1); realMomenta[ix][iy][3] = Lorentz5Momentum(ZERO,ZERO, z2*0.5*M,x2[ix][iy]*0.5*M,M*mu2); } else { realMomenta[ix][iy][2] = Lorentz5Momentum(ZERO,ZERO,-z2*0.5*M,x2[ix][iy]*0.5*M,M*mu2); realMomenta[ix][iy][3] = Lorentz5Momentum(-pT[ix]*cos(phi[ix]),-pT[ix]*sin(phi[ix]), -z1*0.5*M,x1[ix][iy]*0.5*M,M*mu1); } // boost the momenta back to the lab for(unsigned int iz=2;iz<5;++iz) realMomenta[ix][iy][iz] *= eventFrame; // jacobian and prefactors for the weight Energy J = M/sqrt(xT2)*abs(-x1[ix][iy]*x2[ix][iy]+2.*mu22*x1[ix][iy] +x2[ix][iy]+x2[ix][iy]*mu12+mu22*x2[ix][iy] -sqr(x2[ix][iy])) /pow(sqr(x2[ix][iy])-4.*mu22,1.5); // prefactors etc contrib[ix][iy] = 0.5*pT[ix]/J/preFactor_/lambda; // matrix element piece contrib[ix][iy] *= meRatio(partons_,realMomenta[ix][iy],ix,false); // coupling piece contrib[ix][iy] *= alphaQED_->ratio(sqr(pT[ix])); } if(contrib[ix][0]+contrib[ix][1]>1.) { ostringstream s; s << "MEee2gZ2qq::generateHardest weight for channel " << ix << "is " << contrib[ix][0]+contrib[ix][1] << " which is greater than 1"; generator()->logWarning( Exception(s.str(), Exception::warning) ); } reject = UseRandom::rnd() > contrib[ix][0] + contrib[ix][1]; } while (reject); if(pT[ix]pT[1]) { iemit = 2; ispect = 3; pTemit = pT[0]; if(UseRandom::rnd() #include "ThePEG/Utilities/DescribeClass.h" #include "Herwig/Shower/RealEmissionProcess.h" using namespace Herwig; const double MEee2gZ2qq::EPS_=0.00000001; void MEee2gZ2qq::doinit() { HwMEBase::doinit(); massOption(vector(2,massopt_)); rescalingOption(3); if(minflav_>maxflav_) throw InitException() << "The minimum flavour " << minflav_ << "must be lower the than maximum flavour " << maxflav_ << " in MEee2gZ2qq::doinit() " << Exception::runerror; // set the particle data objects Z0_ = getParticleData(ParticleID::Z0); gamma_ = getParticleData(ParticleID::gamma); gluon_ = getParticleData(ParticleID::g); // cast the SM pointer to the Herwig SM pointer tcHwSMPtr hwsm= dynamic_ptr_cast(standardModel()); // do the initialisation if(!hwsm) throw InitException() << "Wrong type of StandardModel object in " << "MEee2gZ2qq::doinit() the Herwig version must be used" << Exception::runerror; FFZVertex_ = hwsm->vertexFFZ(); FFPVertex_ = hwsm->vertexFFP(); FFGVertex_ = hwsm->vertexFFG(); } void MEee2gZ2qq::getDiagrams() const { // specific the diagrams tcPDPtr ep = getParticleData(ParticleID::eplus); tcPDPtr em = getParticleData(ParticleID::eminus); tcPDPtr gamma = getParticleData(ParticleID::gamma); tcPDPtr Z0 = getParticleData(ParticleID::Z0); // setup the processes for ( int i =minflav_; i<=maxflav_; ++i ) { tcPDPtr qk = getParticleData(i); tcPDPtr qb = qk->CC(); add(new_ptr((Tree2toNDiagram(2), em, ep, 1, gamma, 3, qk, 3, qb, -1))); add(new_ptr((Tree2toNDiagram(2), em, ep, 1, Z0 , 3, qk, 3, qb, -2))); } } Energy2 MEee2gZ2qq::scale() const { return sHat(); } unsigned int MEee2gZ2qq::orderInAlphaS() const { return 0; } unsigned int MEee2gZ2qq::orderInAlphaEW() const { return 2; } Selector MEee2gZ2qq::diagrams(const DiagramVector & diags) const { double lastCont(0.5),lastBW(0.5); if ( lastXCombPtr() ) { lastCont = meInfo()[0]; lastBW = meInfo()[1]; } Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ) { if ( diags[i]->id() == -1 ) sel.insert(lastCont, i); else if ( diags[i]->id() == -2 ) sel.insert(lastBW, i); } return sel; } Selector MEee2gZ2qq::colourGeometries(tcDiagPtr ) const { static const ColourLines c("-5 4"); Selector sel; sel.insert(1.0, &c); return sel; } void MEee2gZ2qq::persistentOutput(PersistentOStream & os) const { os << FFZVertex_ << FFPVertex_ << FFGVertex_ << Z0_ << gamma_ << gluon_ << minflav_ << maxflav_ << massopt_ << alphaQCD_ << alphaQED_ << ounit(pTminQED_,GeV) << ounit(pTminQCD_,GeV) << preFactor_ << spinCorrelations_; } void MEee2gZ2qq::persistentInput(PersistentIStream & is, int) { is >> FFZVertex_ >> FFPVertex_ >> FFGVertex_ >> Z0_ >> gamma_ >> gluon_ >> minflav_ >> maxflav_ >> massopt_ >> alphaQCD_ >> alphaQED_ >> iunit(pTminQED_,GeV) >> iunit(pTminQCD_,GeV) >> preFactor_ >> spinCorrelations_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeMEee2gZ2qq("Herwig::MEee2gZ2qq", "HwMELepton.so"); void MEee2gZ2qq::Init() { static ClassDocumentation documentation ("The MEee2gZ2qq class implements the matrix element for e+e- -> q qbar"); static Parameter interfaceMinimumFlavour ("MinimumFlavour", "The PDG code of the quark with the lowest PDG code to produce.", &MEee2gZ2qq::minflav_, 1, 1, 6, false, false, Interface::limited); static Parameter interfaceMaximumFlavour ("MaximumFlavour", "The PDG code of the quark with the highest PDG code to produce", &MEee2gZ2qq::maxflav_, 5, 1, 6, false, false, Interface::limited); static Switch interfaceTopMassOption ("TopMassOption", "Option for the treatment of the top quark mass", &MEee2gZ2qq::massopt_, 1, false, false); static SwitchOption interfaceTopMassOptionOnMassShell (interfaceTopMassOption, "OnMassShell", "The top is produced on its mass shell", 1); static SwitchOption interfaceTopMassOption2 (interfaceTopMassOption, "OffShell", "The top is generated off-shell using the mass and width generator.", 2); static Parameter interfacepTMinQED ("pTMinQED", "Minimum pT for hard QED radiation", &MEee2gZ2qq::pTminQED_, GeV, 1.0*GeV, 0.001*GeV, 10.0*GeV, false, false, Interface::limited); static Parameter interfacepTMinQCD ("pTMinQCD", "Minimum pT for hard QCD radiation", &MEee2gZ2qq::pTminQCD_, GeV, 1.0*GeV, 0.001*GeV, 10.0*GeV, false, false, Interface::limited); static Parameter interfacePrefactor ("Prefactor", "Prefactor for the overestimate of the emission probability", &MEee2gZ2qq::preFactor_, 6.0, 1.0, 100.0, false, false, Interface::limited); static Reference interfaceQCDCoupling ("AlphaQCD", "Pointer to the object to calculate the strong coupling for the correction", &MEee2gZ2qq::alphaQCD_, false, false, true, false, false); static Reference interfaceEMCoupling ("AlphaQED", "Pointer to the object to calculate the EM coupling for the correction", &MEee2gZ2qq::alphaQED_, false, false, true, false, false); static Switch interfaceSpinCorrelations ("SpinCorrelations", "Switch the construction of the veretx for spin correlations on/off", &MEee2gZ2qq::spinCorrelations_, true, false, false); static SwitchOption interfaceSpinCorrelationsYes (interfaceSpinCorrelations, "Yes", "Swtich On", true); static SwitchOption interfaceSpinCorrelationsNo (interfaceSpinCorrelations, "No", "Switch off", false); } double MEee2gZ2qq::me2() const { return loME(mePartonData(),rescaledMomenta(),true); } ProductionMatrixElement MEee2gZ2qq::HelicityME(vector & fin, vector & ain, vector & fout, vector & aout, double & me, double & cont, double & BW ) const { // the particles should be in the order // for the incoming // 0 incoming fermion (u spinor) // 1 incoming antifermion (vbar spinor) // for the outgoing // 0 outgoing fermion (ubar spinor) // 1 outgoing antifermion (v spinor) // me to be returned ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half); ProductionMatrixElement gamma (PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half); ProductionMatrixElement Zboson(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half); // wavefunctions for the intermediate particles VectorWaveFunction interZ,interG; // temporary storage of the different diagrams Complex diag1,diag2; // sum over helicities to get the matrix element unsigned int inhel1,inhel2,outhel1,outhel2; double total[3]={0.,0.,0.}; for(inhel1=0;inhel1<2;++inhel1) { for(inhel2=0;inhel2<2;++inhel2) { // intermediate Z interZ = FFZVertex_->evaluate(scale(),1,Z0_,fin[inhel1],ain[inhel2]); // intermediate photon interG = FFPVertex_->evaluate(scale(),1,gamma_,fin[inhel1],ain[inhel2]); for(outhel1=0;outhel1<2;++outhel1) { for(outhel2=0;outhel2<2;++outhel2) { // first the Z exchange diagram diag1 = FFZVertex_->evaluate(scale(),aout[outhel2],fout[outhel1], interZ); // then the photon exchange diagram diag2 = FFPVertex_->evaluate(scale(),aout[outhel2],fout[outhel1], interG); // add up squares of individual terms total[1] += norm(diag1); Zboson(inhel1,inhel2,outhel1,outhel2) = diag1; total[2] += norm(diag2); gamma (inhel1,inhel2,outhel1,outhel2) = diag2; // the full thing including interference diag1 += diag2; total[0] += norm(diag1); output(inhel1,inhel2,outhel1,outhel2)=diag1; } } } } for(int ix=0;ix<3;++ix) total[ix] *= 0.25; tcPolarizedBeamPDPtr beam[2] = {dynamic_ptr_cast(mePartonData()[0]), dynamic_ptr_cast(mePartonData()[1])}; if( beam[0] || beam[1] ) { RhoDMatrix rho[2] = {beam[0] ? beam[0]->rhoMatrix() : RhoDMatrix(mePartonData()[0]->iSpin()), beam[1] ? beam[1]->rhoMatrix() : RhoDMatrix(mePartonData()[1]->iSpin())}; total[0] = output.average(rho[0],rho[1]); total[1] = Zboson.average(rho[0],rho[1]); total[2] = gamma .average(rho[0],rho[1]); } // results for(int ix=0;ix<3;++ix) total[ix]*= 3.; cont = total[2]; BW = total[1]; me = total[0]; return output; } void MEee2gZ2qq::constructVertex(tSubProPtr sub) { if(!spinCorrelations_) return; // extract the particles in the hard process ParticleVector hard; hard.push_back(sub->incoming().first); hard.push_back(sub->incoming().second); hard.push_back(sub->outgoing()[0]); hard.push_back(sub->outgoing()[1]); if(hard[0]->id()id()) swap(hard[0],hard[1]); if(hard[2]->id()id()) swap(hard[2],hard[3]); vector fin,aout; vector ain,fout; // get wave functions for off-shell momenta for later on SpinorWaveFunction( fin ,hard[0],incoming,false,true); SpinorBarWaveFunction(ain ,hard[1],incoming,false,true); SpinorBarWaveFunction(fout,hard[2],outgoing,true ,true); SpinorWaveFunction( aout,hard[3],outgoing,true ,true); // now rescale the momenta and compute the matrix element with the // rescaled momenta for correlations vector momenta; cPDVector data; for(unsigned int ix=0;ix<4;++ix) { momenta.push_back(hard[ix]->momentum()); data .push_back(hard[ix]->dataPtr()); } rescaleMomenta(momenta,data); SpinorWaveFunction ein (rescaledMomenta()[0],data[0],incoming); SpinorBarWaveFunction pin (rescaledMomenta()[1],data[1],incoming); SpinorBarWaveFunction qkout(rescaledMomenta()[2],data[2],outgoing); SpinorWaveFunction qbout(rescaledMomenta()[3],data[3],outgoing); for(unsigned int ix=0;ix<2;++ix) { ein.reset(ix) ; fin [ix] = ein ; pin.reset(ix) ; ain [ix] = pin ; qkout.reset(ix); fout[ix] = qkout; qbout.reset(ix); aout[ix] = qbout; } // calculate the matrix element double me,cont,BW; ProductionMatrixElement prodme=HelicityME(fin,ain,fout,aout,me,cont,BW); // construct the vertex HardVertexPtr hardvertex=new_ptr(HardVertex()); // set the matrix element for the vertex hardvertex->ME(prodme); // set the pointers and to and from the vertex for(unsigned int ix=0;ix<4;++ix) { tSpinPtr spin = hard[ix]->spinInfo(); if(ix<2) { tcPolarizedBeamPDPtr beam = dynamic_ptr_cast(hard[ix]->dataPtr()); if(beam) spin->rhoMatrix() = beam->rhoMatrix(); } spin->productionVertex(hardvertex); } } void MEee2gZ2qq::rebind(const TranslationMap & trans) { FFZVertex_ = trans.translate(FFZVertex_); FFPVertex_ = trans.translate(FFPVertex_); FFGVertex_ = trans.translate(FFGVertex_); Z0_ = trans.translate(Z0_); gamma_ = trans.translate(gamma_); gluon_ = trans.translate(gluon_); HwMEBase::rebind(trans); } IVector MEee2gZ2qq::getReferences() { IVector ret = HwMEBase::getReferences(); ret.push_back(FFZVertex_); ret.push_back(FFPVertex_); ret.push_back(FFGVertex_); ret.push_back(Z0_ ); ret.push_back(gamma_ ); ret.push_back(gluon_ ); return ret; } void MEee2gZ2qq::initializeMECorrection(RealEmissionProcessPtr, double & initial, double & final) { d_Q_ = sqrt(sHat()); d_m_ = 0.5*(meMomenta()[2].mass()+meMomenta()[3].mass()); // set the other parameters d_rho_ = sqr(d_m_/d_Q_); d_v_ = sqrt(1.-4.*d_rho_); // maximum evolution scale d_kt1_ = (1. + sqrt(1. - 4.*d_rho_))/2.; double num = d_rho_ * d_kt1_ + 0.25 * d_v_ *(1.+d_v_)*(1.+d_v_); double den = d_kt1_ - d_rho_; d_kt2_ = num/den; // maximums for reweighting initial = 1.; final = 1.; } RealEmissionProcessPtr MEee2gZ2qq::applyHardMatrixElementCorrection(RealEmissionProcessPtr born) { return calculateRealEmission(born,true,ShowerInteraction::QCD); } RealEmissionProcessPtr MEee2gZ2qq::calculateRealEmission(RealEmissionProcessPtr born, bool veto, ShowerInteraction inter) { vector emission; unsigned int iemit,ispect; pair output = generateHard(born,emission,iemit,ispect,veto,inter); if(emission.empty()) { if(inter!=ShowerInteraction::QCD) born->pT()[ShowerInteraction::QED] = pTminQED_; if(inter!=ShowerInteraction::QED) born->pT()[ShowerInteraction::QCD] = pTminQCD_; return born; } else { Energy pTveto = output.first; if(inter!=ShowerInteraction::QCD) born->pT()[ShowerInteraction::QED] = pTveto; if(inter!=ShowerInteraction::QED) born->pT()[ShowerInteraction::QCD] = pTveto; } // generate the momenta for the hard emission ShowerInteraction force = output.second; born->interaction(force); // get the quark and antiquark ParticleVector qq; for(unsigned int ix=0;ix<2;++ix) qq.push_back(born->bornOutgoing()[ix]); bool order = qq[0]->id()>0; if(!order) swap(qq[0],qq[1]); // perform final check to ensure energy greater than constituent mass for (int i=0; i<2; i++) { if (emission[i+2].e() < qq[i]->data().constituentMass()) return RealEmissionProcessPtr(); } if(force!=ShowerInteraction::QED && emission[4].e() < gluon_->constituentMass()) return RealEmissionProcessPtr(); // set masses for (int i=0; i<2; i++) emission[i+2].setMass(qq[i]->mass()); emission[4].setMass(ZERO); // create the new quark, antiquark and gluon PPtr newq = qq[0]->dataPtr()->produceParticle(emission[2]); PPtr newa = qq[1]->dataPtr()->produceParticle(emission[3]); PPtr newg; if(force==ShowerInteraction::QCD) newg = gluon_->produceParticle(emission[4]); else newg = gamma_->produceParticle(emission[4]); // create the output real emission process for(unsigned int ix=0;ixbornIncoming().size();++ix) { born->incoming().push_back(born->bornIncoming()[ix]->dataPtr()-> produceParticle(born->bornIncoming()[ix]->momentum())); } if(order) { born->outgoing().push_back(newq); born->outgoing().push_back(newa); } else { born->outgoing().push_back(newa); born->outgoing().push_back(newq); swap(iemit,ispect); } born->outgoing().push_back(newg); // set emitter and spectator born->emitter (iemit); born->spectator(ispect); born->emitted(4); // make colour connections if(force==ShowerInteraction::QCD) { newg->colourNeighbour(newq); newa->colourNeighbour(newg); } else { newa->colourNeighbour(newq); } return born; } bool MEee2gZ2qq::softMatrixElementVeto(PPtr parent, PPtr progenitor, const bool & , const Energy & highestpT, const vector & ids, const double & d_z, const Energy & d_qt, const Energy & ) { // check we should be applying the veto if(parent->id()!=progenitor->id()|| ids[0]->id()!=ids[1]->id()|| ids[2]->id()!=ParticleID::g) return false; // calculate pt Energy2 d_m2 = parent->momentum().m2(); Energy pPerp = (1.-d_z)*sqrt( sqr(d_z*d_qt) - d_m2); // if not hardest so far don't apply veto if(pPerpid()<0) swap(x,xb); // if exceptionally out of phase space, leave this emission, as there // is no good interpretation for the soft ME correction. if( x<0 || xb<0) return false; double xg = 2. - xb - x; // always return one in the soft gluon region if(xg < EPS_) return false; // check it is in the phase space if((1.-x)*(1.-xb)*(1.-xg) < d_rho_*xg*xg) return true; double k1 = getKfromX(x, xb); double k2 = getKfromX(xb, x); double weight = 1.; // quark emission if(parent->id() > 0 && k1 < d_kt1_) { weight = MEV(x, xb)/PS(x, xb); // is it also in the anti-quark emission zone? if(k2 < d_kt2_) weight *= 0.5; } // antiquark emission if(parent->id() < 0 && k2 < d_kt2_) { weight = MEV(x, xb)/PS(xb, x); // is it also in the quark emission zone? if(k1 < d_kt1_) weight *= 0.5; } // compute veto from weight return !UseRandom::rndbool(weight); } double MEee2gZ2qq::getKfromX(double x1, double x2) { double uval = 0.5*(1. + d_rho_/(1.-x2+d_rho_)); double num = x1 - (2. - x2)*uval; double den = sqrt(x2*x2 - 4.*d_rho_); double zval = uval + num/den; return (1.-x2)/(zval*(1.-zval)); } double MEee2gZ2qq::MEV(double x1, double x2) { // Vector part double num = (x1+2.*d_rho_)*(x1+2.*d_rho_) + (x2+2.*d_rho_)*(x2+2.*d_rho_) - 8.*d_rho_*(1.+2.*d_rho_); double den = (1.+2.*d_rho_)*(1.-x1)*(1.-x2); return (num/den - 2.*d_rho_/((1.-x1)*(1.-x1)) - 2*d_rho_/((1.-x2)*(1.-x2)))/d_v_; } double MEee2gZ2qq::PS(double x, double xbar) { double u = 0.5*(1. + d_rho_ / (1.-xbar+d_rho_)); double z = u + (x - (2.-xbar)*u)/sqrt(xbar*xbar - 4.*d_rho_); double brack = (1.+z*z)/(1.-z)- 2.*d_rho_/(1-xbar); // interesting: the splitting function without the subtraction // term. Actually gives a much worse approximation in the collinear // limit. double brack = (1.+z*z)/(1.-z); double den = (1.-xbar)*sqrt(xbar*xbar - 4.*d_rho_); return brack/den; } pair MEee2gZ2qq::generateHard(RealEmissionProcessPtr born, vector & emmision, unsigned int & iemit, unsigned int & ispect, bool applyVeto,ShowerInteraction inter) { vector interactions; - if(inter==ShowerInteraction::Both) { + if(inter==ShowerInteraction::QCD) + interactions.push_back(ShowerInteraction::QCD); + else if(inter==ShowerInteraction::QED) interactions.push_back(ShowerInteraction::QED); + else if(inter==ShowerInteraction::QEDQCD || + inter==ShowerInteraction::ALL) { interactions.push_back(ShowerInteraction::QCD); + interactions.push_back(ShowerInteraction::QED); } - else - interactions.push_back(inter); // incoming particles tPPtr em = born->bornIncoming()[0]; tPPtr ep = born->bornIncoming()[1]; if(em->id()<0) swap(em,ep); // outgoing particles tPPtr qk = born->bornOutgoing()[0]; tPPtr qb = born->bornOutgoing()[1]; if(qk->id()<0) swap(qk,qb); // extract the momenta loMomenta_.clear(); loMomenta_.push_back(em->momentum()); loMomenta_.push_back(ep->momentum()); loMomenta_.push_back(qk->momentum()); loMomenta_.push_back(qb->momentum()); // and ParticleData objects partons_.resize(5); partons_[0]=em->dataPtr(); partons_[1]=ep->dataPtr(); partons_[2]=qk->dataPtr(); partons_[3]=qb->dataPtr(); partons_[4]=cPDPtr(); // boost from lab to CMS frame with outgoing particles // along the z axis LorentzRotation eventFrame( ( loMomenta_[2] + loMomenta_[3] ).findBoostToCM() ); Lorentz5Momentum spectator = eventFrame*loMomenta_[2]; eventFrame.rotateZ( -spectator.phi() ); eventFrame.rotateY( -spectator.theta() ); eventFrame.invert(); // mass of the final-state system Energy2 M2 = (loMomenta_[2]+loMomenta_[3]).m2(); Energy M = sqrt(M2); double mu1 = loMomenta_[2].mass()/M; double mu2 = loMomenta_[3].mass()/M; double mu12 = sqr(mu1), mu22 = sqr(mu2); double lambda = sqrt(1.+sqr(mu12)+sqr(mu22)-2.*mu12-2.*mu22-2.*mu12*mu22); // max pT Energy pTmax = 0.5*sqrt(M2)* (1.-sqr(loMomenta_[2].mass()+loMomenta_[3].mass())/M2); // max y if ( pTmax < pTminQED_ && pTmax < pTminQCD_ ) return make_pair(ZERO,ShowerInteraction::QCD); vector pTemit; vector > emittedMomenta;; vector iemitter,ispectator; for(unsigned int iinter=0;iinteroverestimateValue()/Constants::twopi* 2.*ymax*preFactor_; } else { pTmin = pTminQED_; ymax = acosh(pTmax/pTmin); partons_[4] = gamma_; a = alphaQED_->overestimateValue()/Constants::twopi* 2.*ymax*preFactor_*sqr(double(mePartonData()[2]->iCharge())/3.); } // variables for the emission Energy pT[2]; double y[2],phi[2],x3[2],x1[2][2],x2[2][2]; double contrib[2][2]; // storage of the real emission momenta vector realMomenta[2][2]= {{vector(5),vector(5)}, {vector(5),vector(5)}}; for(unsigned int ix=0;ix<2;++ix) for(unsigned int iy=0;iy<2;++iy) for(unsigned int iz=0;iz<2;++iz) realMomenta[ix][iy][iz] = loMomenta_[iz]; // generate the emission for(unsigned int ix=0;ix<2;++ix) { if(ix==1) { swap(mu1 ,mu2 ); swap(mu12,mu22); } pT[ix] = pTmax; y [ix] = 0.; bool reject = true; do { // generate pT pT[ix] *= pow(UseRandom::rnd(),1./a); if(pT[ix] 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]x2max) continue; // check the z components double z1 = sqr(x1[ix][iy])-4.*mu12-xT2; if(z1<0. && z1>-1e-10) z1 = 0.; assert(z1>=0.); z1 = sqrt(z1); double z2 = sqr(x2[ix][iy])-4.*mu22; if(z2<0. && z2>-1e-12) z2 = 0.; assert(z2>=0.); z2 = -sqrt(z2); double z3 = pT[ix]*sinh(y[ix])*2./M; if(ix==1) z3 *=-1.; if(abs(-z1+z2+z3)<1e-9) z1 *= -1.; if(abs(z1+z2+z3)>1e-5) continue; // if using as an ME correction the veto if(applyVeto) { double xb = x1[ix][iy], xc = x2[ix][iy]; double b = mu12, c = mu22; double r = 0.5*(1.+b/(1.+c-xc)); double z1 = r + (xb-(2.-xc)*r)/sqrt(sqr(xc)-4.*c); double kt1 = (1.-b+c-xc)/z1/(1.-z1); r = 0.5*(1.+c/(1.+b-xb)); double z2 = r + (xc-(2.-xb)*r)/sqrt(sqr(xb)-4.*b); double kt2 = (1.-c+b-xb)/z2/(1.-z2); if(ix==1) { swap(z1 ,z2); swap(kt1,kt2); } // veto the shower region if( kt1 < d_kt1_ || kt2 < d_kt2_ ) continue; } // construct the momenta realMomenta[ix][iy][4] = Lorentz5Momentum(pT[ix]*cos(phi[ix]),pT[ix]*sin(phi[ix]), pT[ix]*sinh(y[ix]) ,pT[ix]*cosh(y[ix]),ZERO); if(ix==0) { realMomenta[ix][iy][2] = Lorentz5Momentum(-pT[ix]*cos(phi[ix]),-pT[ix]*sin(phi[ix]), z1*0.5*M,x1[ix][iy]*0.5*M,M*mu1); realMomenta[ix][iy][3] = Lorentz5Momentum(ZERO,ZERO, z2*0.5*M,x2[ix][iy]*0.5*M,M*mu2); } else { realMomenta[ix][iy][2] = Lorentz5Momentum(ZERO,ZERO,-z2*0.5*M,x2[ix][iy]*0.5*M,M*mu2); realMomenta[ix][iy][3] = Lorentz5Momentum(-pT[ix]*cos(phi[ix]),-pT[ix]*sin(phi[ix]), -z1*0.5*M,x1[ix][iy]*0.5*M,M*mu1); } // boost the momenta back to the lab for(unsigned int iz=2;iz<5;++iz) realMomenta[ix][iy][iz] *= eventFrame; // jacobian and prefactors for the weight Energy J = M/sqrt(xT2)*abs(-x1[ix][iy]*x2[ix][iy]+2.*mu22*x1[ix][iy] +x2[ix][iy]+x2[ix][iy]*mu12+mu22*x2[ix][iy] -sqr(x2[ix][iy])) /pow(sqr(x2[ix][iy])-4.*mu22,1.5); // prefactors etc contrib[ix][iy] = 0.5*pT[ix]/J/preFactor_/lambda; // matrix element piece contrib[ix][iy] *= meRatio(partons_,realMomenta[ix][iy], ix,interactions[iinter],false); // coupling piece if(interactions[iinter]==ShowerInteraction::QCD) contrib[ix][iy] *= alphaQCD_->ratio(sqr(pT[ix])); else contrib[ix][iy] *= alphaQED_->ratio(sqr(pT[ix])); } if(contrib[ix][0]+contrib[ix][1]>1.) { ostringstream s; s << "MEee2gZ2qq::generateHardest weight for channel " << ix << "is " << contrib[ix][0]+contrib[ix][1] << " which is greater than 1"; generator()->logWarning( Exception(s.str(), Exception::warning) ); } reject = UseRandom::rnd() > contrib[ix][0] + contrib[ix][1]; } while (reject); if(pT[ix]()); iemitter .push_back(0); ispectator.push_back(0); continue; } // now pick the emission with highest pT vector emission; if(pT[0]>pT[1]) { iemitter .push_back(2); ispectator.push_back(3); pTemit.push_back(pT[0]); if(UseRandom::rnd()pTmax) { iselect = ix; pTmax = pTemit[ix]; } } // no emission return if(iselect<0) { return make_pair(ZERO,ShowerInteraction::QCD); } partons_[4] = interactions[iselect]==ShowerInteraction::QCD ? gluon_ : gamma_; iemit = iemitter[iselect]; ispect = ispectator[iselect]; emmision = emittedMomenta[iselect]; // return pT of emission return make_pair(pTmax,interactions[iselect]); } RealEmissionProcessPtr MEee2gZ2qq::generateHardest(RealEmissionProcessPtr born, ShowerInteraction inter) { return calculateRealEmission(born,false,inter); } double MEee2gZ2qq::meRatio(vector partons, vector momenta, unsigned int iemitter, ShowerInteraction inter, bool subtract) const { Lorentz5Momentum q = momenta[2]+momenta[3]+momenta[4]; Energy2 Q2=q.m2(); Energy2 lambda = sqrt((Q2-sqr(momenta[2].mass()+momenta[3].mass()))* (Q2-sqr(momenta[2].mass()-momenta[3].mass()))); InvEnergy2 D[2]; double lome[2]; for(unsigned int iemit=0;iemit<2;++iemit) { unsigned int ispect = iemit==0 ? 1 : 0; Energy2 pipj = momenta[4 ] * momenta[2+iemit ]; Energy2 pipk = momenta[4 ] * momenta[2+ispect]; Energy2 pjpk = momenta[2+iemit] * momenta[2+ispect]; double y = pipj/(pipj+pipk+pjpk); double z = pipk/( pipk+pjpk); Energy mij = sqrt(2.*pipj+sqr(momenta[2+iemit].mass())); Energy2 lamB = sqrt((Q2-sqr(mij+momenta[2+ispect].mass()))* (Q2-sqr(mij-momenta[2+ispect].mass()))); Energy2 Qpk = q*momenta[2+ispect]; Lorentz5Momentum pkt = lambda/lamB*(momenta[2+ispect]-Qpk/Q2*q) +0.5/Q2*(Q2+sqr(momenta[2+ispect].mass())-sqr(momenta[2+ispect].mass()))*q; Lorentz5Momentum pijt = q-pkt; double muj = momenta[2+iemit ].mass()/sqrt(Q2); double muk = momenta[2+ispect].mass()/sqrt(Q2); double vt = sqrt((1.-sqr(muj+muk))*(1.-sqr(muj-muk)))/(1.-sqr(muj)-sqr(muk)); double v = sqr(2.*sqr(muk)+(1.-sqr(muj)-sqr(muk))*(1.-y))-4.*sqr(muk); if(v<=0.) return 0.; v = sqrt(v)/(1.-y)/(1.-sqr(muj)-sqr(muk)); // dipole term D[iemit] = 0.5/pipj*(2./(1.-(1.-z)*(1.-y)) -vt/v*(2.-z+sqr(momenta[2+iemit].mass())/pipj)); // matrix element vector lomom(4); lomom[0] = momenta[0]; lomom[1] = momenta[1]; if(iemit==0) { lomom[2] = pijt; lomom[3] = pkt ; } else { lomom[3] = pijt; lomom[2] = pkt ; } lome[iemit] = loME(partons,lomom,false)/3.; } InvEnergy2 ratio = realME(partons,momenta,inter) *abs(D[iemitter])/(abs(D[0]*lome[0])+abs(D[1]*lome[1])); double output = Q2*ratio; if(subtract) output -= 2.*Q2*D[iemitter]; return output; } double MEee2gZ2qq::loME(const vector & partons, const vector & momenta, bool first) const { // compute the spinors vector fin,aout; vector ain,fout; SpinorWaveFunction ein (momenta[0],partons[0],incoming); SpinorBarWaveFunction pin (momenta[1],partons[1],incoming); SpinorBarWaveFunction qkout(momenta[2],partons[2],outgoing); SpinorWaveFunction qbout(momenta[3],partons[3],outgoing); for(unsigned int ix=0;ix<2;++ix) { ein.reset(ix) ; fin.push_back( ein ); pin.reset(ix) ; ain.push_back( pin ); qkout.reset(ix); fout.push_back(qkout); qbout.reset(ix); aout.push_back(qbout); } // compute the matrix element double me,lastCont,lastBW; HelicityME(fin,ain,fout,aout,me,lastCont,lastBW); // save the components if(first) { DVector save; save.push_back(lastCont); save.push_back(lastBW); meInfo(save); } // return the answer return me; } InvEnergy2 MEee2gZ2qq::realME(const vector & partons, const vector & momenta, ShowerInteraction inter) const { // compute the spinors vector fin,aout; vector ain,fout; vector gout; SpinorWaveFunction ein (momenta[0],partons[0],incoming); SpinorBarWaveFunction pin (momenta[1],partons[1],incoming); SpinorBarWaveFunction qkout(momenta[2],partons[2],outgoing); SpinorWaveFunction qbout(momenta[3],partons[3],outgoing); VectorWaveFunction gluon(momenta[4],partons[4],outgoing); for(unsigned int ix=0;ix<2;++ix) { ein.reset(ix) ; fin.push_back( ein ); pin.reset(ix) ; ain.push_back( pin ); qkout.reset(ix); fout.push_back(qkout); qbout.reset(ix); aout.push_back(qbout); gluon.reset(2*ix); gout.push_back(gluon); } AbstractFFVVertexPtr vertex = inter == ShowerInteraction::QCD ? FFGVertex_ : FFPVertex_; vector diag(4,0.); ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1); double total(0.); for(unsigned int inhel1=0;inhel1<2;++inhel1) { for(unsigned int inhel2=0;inhel2<2;++inhel2) { // intermediate Z VectorWaveFunction interZ = FFZVertex_->evaluate(scale(),1,Z0_,fin[inhel1],ain[inhel2]); // intermediate photon VectorWaveFunction interG = FFPVertex_->evaluate(scale(),1,gamma_,fin[inhel1],ain[inhel2]); for(unsigned int outhel1=0;outhel1<2;++outhel1) { for(unsigned int outhel2=0;outhel2<2;++outhel2) { for(unsigned int outhel3=0;outhel3<2;++outhel3) { SpinorBarWaveFunction off1 = vertex->evaluate(scale(),3,partons[2]->CC(),fout[outhel1],gout[outhel3]); diag[0] = FFZVertex_->evaluate(scale(),aout[outhel2],off1,interZ); diag[1] = FFPVertex_->evaluate(scale(),aout[outhel2],off1,interG); SpinorWaveFunction off2 = vertex->evaluate(scale(),3,partons[3]->CC(),aout[outhel2],gout[outhel3]); diag[2] = FFZVertex_->evaluate(scale(),off2,fout[outhel1],interZ); diag[3] = FFPVertex_->evaluate(scale(),off2,fout[outhel1],interG); // sum of diagrams Complex sum = std::accumulate(diag.begin(),diag.end(),Complex(0.)); // matrix element output(inhel1,inhel2,outhel1,outhel2,outhel3)=sum; // me2 total += norm(sum); } } } } } // spin average total *= 0.25; tcPolarizedBeamPDPtr beam[2] = {dynamic_ptr_cast(partons[0]), dynamic_ptr_cast(partons[1])}; if( beam[0] || beam[1] ) { RhoDMatrix rho[2] = {beam[0] ? beam[0]->rhoMatrix() : RhoDMatrix(mePartonData()[0]->iSpin()), beam[1] ? beam[1]->rhoMatrix() : RhoDMatrix(mePartonData()[1]->iSpin())}; total = output.average(rho[0],rho[1]); } // divide out the coupling total /= norm(vertex->norm()); // and charge (if needed) if(inter==ShowerInteraction::QED) total /= sqr(double(mePartonData()[2]->iCharge())/3.); // return the total return total*UnitRemoval::InvE2; } diff --git a/MatrixElement/Lepton/Makefile.am b/MatrixElement/Lepton/Makefile.am --- a/MatrixElement/Lepton/Makefile.am +++ b/MatrixElement/Lepton/Makefile.am @@ -1,15 +1,16 @@ pkglib_LTLIBRARIES = HwMELepton.la HwMELeptonLowEnergy.la HwMELepton_la_SOURCES = \ MEee2gZ2qq.h MEee2gZ2qq.cc\ MEee2gZ2ll.h MEee2gZ2ll.cc\ MEee2ZH.h MEee2ZH.cc\ MEee2HiggsVBF.h MEee2HiggsVBF.cc \ MEee2VV.h MEee2VV.cc \ MEee2VectorMeson.h MEee2VectorMeson.cc \ -MEee2Higgs2SM.h MEee2Higgs2SM.cc +MEee2Higgs2SM.h MEee2Higgs2SM.cc \ +MEee2ff.h MEee2ff.cc HwMELepton_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 8:0:1 HwMELeptonLowEnergy_la_SOURCES = \ MEee2Mesons.h MEee2Mesons.cc HwMELeptonLowEnergy_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 1:0:0 diff --git a/MatrixElement/Makefile.am b/MatrixElement/Makefile.am --- a/MatrixElement/Makefile.am +++ b/MatrixElement/Makefile.am @@ -1,18 +1,18 @@ -SUBDIRS = General Lepton Hadron DIS Powheg Gamma Matchbox Reweighters +SUBDIRS = General Lepton Hadron DIS Powheg Gamma Matchbox Reweighters EW if WANT_LIBFASTJET SUBDIRS += FxFx endif noinst_LTLIBRARIES = libHwME.la libHwME_la_SOURCES = \ HwMEBase.h HwMEBase.fh HwMEBase.cc \ MEMultiChannel.h MEMultiChannel.cc \ MEfftoVH.h MEfftoVH.cc \ MEfftoffH.h MEfftoffH.cc \ HardVertex.fh HardVertex.h HardVertex.cc \ ProductionMatrixElement.h ProductionMatrixElement.cc \ DrellYanBase.h DrellYanBase.cc \ BlobME.h BlobME.cc \ MEMinBias.h MEMinBias.cc diff --git a/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc b/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc --- a/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc +++ b/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc @@ -1,2051 +1,2059 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the MEPP2GammaGammaPowheg class. // #include "MEPP2GammaGammaPowheg.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/MatrixElement/Tree2toNDiagram.h" #include "ThePEG/Cuts/Cuts.h" #include "ThePEG/Utilities/SimplePhaseSpace.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "Herwig/Utilities/Maths.h" #include "Herwig/Shower/RealEmissionProcess.h" #include "ThePEG/Utilities/DescribeClass.h" using namespace Herwig; // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeMEPP2GammaGammaPowheg("Herwig::MEPP2GammaGammaPowheg", "HwMEHadron.so HwPowhegMEHadron.so"); unsigned int MEPP2GammaGammaPowheg::orderInAlphaS() const { return 0; } unsigned int MEPP2GammaGammaPowheg::orderInAlphaEW() const { return 2; } IBPtr MEPP2GammaGammaPowheg::clone() const { return new_ptr(*this); } IBPtr MEPP2GammaGammaPowheg::fullclone() const { return new_ptr(*this); } MEPP2GammaGammaPowheg::MEPP2GammaGammaPowheg() : contrib_(1), power_(0.1), process_(0), threeBodyProcess_(0), maxflavour_(5), alphaS_(0.), fixedAlphaS_(false), supressionFunction_(0), supressionScale_(0), lambda_(20.*GeV), preQCDqqbarq_(5.), preQCDqqbarqbar_(0.5), preQCDqg_(50.), preQCDgqbar_(50.), preQEDqqbarq_(40.), preQEDqqbarqbar_(0.5), preQEDqgq_(1.), preQEDgqbarqbar_(1.), minpT_(2.*GeV), scaleChoice_(0), scalePreFactor_(1.) {} void MEPP2GammaGammaPowheg::getDiagrams() const { tcPDPtr gamma = getParticleData(ParticleID::gamma); tcPDPtr g = getParticleData(ParticleID::g); for(int ix=1;ix<=maxflavour_;++ix) { tcPDPtr qk = getParticleData(ix); tcPDPtr qb = qk->CC(); // gamma gamma if(process_==0 || process_ == 1) { add(new_ptr((Tree2toNDiagram(3), qk, qk, qb, 1, gamma, 2, gamma, -1))); add(new_ptr((Tree2toNDiagram(3), qk, qk, qb, 2, gamma, 1, gamma, -2))); } // gamma +jet if(process_==0 || process_ == 2) { add(new_ptr((Tree2toNDiagram(3), qk, qb, qb, 1, gamma, 2, g, -4))); add(new_ptr((Tree2toNDiagram(3), qk, qk, qb, 2, gamma, 1, g, -5))); add(new_ptr((Tree2toNDiagram(3), qk, qk, g, 1, gamma, 2, qk, -6))); add(new_ptr((Tree2toNDiagram(2), qk, g, 1, qk, 3, gamma, 3, qk, -7))); add(new_ptr((Tree2toNDiagram(3), g, qb, qb, 2, gamma, 1, qb, -8))); add(new_ptr((Tree2toNDiagram(2), g, qb, 1, qb, 3, gamma, 3, qb, -9))); } // gamma + jet + gamma if((process_==0 && contrib_==1) || process_ == 3) { // gamma + g + gamma if(threeBodyProcess_==0 || threeBodyProcess_==1) { add(new_ptr((Tree2toNDiagram(4), qk, qk, qk, qb, 1, gamma, 2, gamma, 3, g, -10))); add(new_ptr((Tree2toNDiagram(4), qk, qk, qk, qb, 3, gamma, 2, gamma, 1, g, -12))); } // Z + q + gamma if(threeBodyProcess_==0 || threeBodyProcess_==2) { add(new_ptr((Tree2toNDiagram(4),qk,qk,qk,g,1,gamma,2,gamma,3,qk, -20))); add(new_ptr((Tree2toNDiagram(4),qk,qk,qk,g,2,gamma,1,gamma,3,qk, -21))); add(new_ptr((Tree2toNDiagram(3),qk,qk,g,1,gamma,2,qk,5,gamma,5,qk,-22))); } // Z + qbar + gamma if(threeBodyProcess_==0 || threeBodyProcess_==3) { add(new_ptr((Tree2toNDiagram(4),g,qb,qb,qb,3,gamma,2,gamma,1,qb ,-30))); add(new_ptr((Tree2toNDiagram(4),g,qb,qb,qb,2,gamma,3,gamma,1,qb ,-31))); add(new_ptr((Tree2toNDiagram(3),g,qb,qb ,2,gamma,1,qb,5,gamma,5,qb,-32))); } } } } Energy2 MEPP2GammaGammaPowheg::scale() const { Energy2 scale; if(scaleChoice_==0) { Energy pt; if(meMomenta()[2].perp(meMomenta()[0].vect())>= meMomenta()[3].perp(meMomenta()[0].vect())){ pt = meMomenta()[2].perp(meMomenta()[0].vect()); } else { pt = meMomenta()[3].perp(meMomenta()[0].vect()); } scale = sqr(pt); } else if(scaleChoice_==1) { scale = sHat(); } return scalePreFactor_*scale; } int MEPP2GammaGammaPowheg::nDim() const { return HwMEBase::nDim() + ( contrib_>=1 ? 3 : 0 ); } bool MEPP2GammaGammaPowheg::generateKinematics(const double * r) { // radiative variables if(contrib_>=1) { zTilde_ = r[nDim()-1]; vTilde_ = r[nDim()-2]; phi_ = Constants::twopi*r[nDim()-3]; } // set the jacobian jacobian(1.0); // set up the momenta for ( int i = 2, N = meMomenta().size(); i < N; ++i ) meMomenta()[i] = Lorentz5Momentum(ZERO); // generate sHat Energy2 shat(sHat()); if(mePartonData().size()==5) { double eps = sqr(meMomenta()[2].mass())/shat; jacobian(jacobian()*(1.-eps)); shat *= eps+zTilde_*(1.-eps); } // momenta of the core process double ctmin = -1.0, ctmax = 1.0; Energy q = ZERO; try { q = SimplePhaseSpace:: getMagnitude(shat, meMomenta()[2].mass(), ZERO); } catch ( ImpossibleKinematics & e ) { return false; } Energy e = 0.5*sqrt(shat); Energy2 m22 = meMomenta()[2].mass2(); Energy2 e0e2 = 2.0*e*sqrt(sqr(q) + m22); Energy2 e1e2 = 2.0*e*sqrt(sqr(q) + m22); Energy2 e0e3 = 2.0*e*sqrt(sqr(q)); Energy2 e1e3 = 2.0*e*sqrt(sqr(q)); Energy2 pq = 2.0*e*q; if(mePartonData().size()==4) { Energy2 thmin = lastCuts().minTij(mePartonData()[0], mePartonData()[2]); if ( thmin > ZERO ) ctmax = min(ctmax, (e0e2 - m22 - thmin)/pq); thmin = lastCuts().minTij(mePartonData()[1], mePartonData()[2]); if ( thmin > ZERO ) ctmin = max(ctmin, (thmin + m22 - e1e2)/pq); thmin = lastCuts().minTij(mePartonData()[1], mePartonData()[3]); if ( thmin > ZERO ) ctmax = min(ctmax, (e1e3 - thmin)/pq); thmin = lastCuts().minTij(mePartonData()[0], mePartonData()[3]); if ( thmin > ZERO ) ctmin = max(ctmin, (thmin - e0e3)/pq); Energy ptmin = max(lastCuts().minKT(mePartonData()[2]), lastCuts().minKT(mePartonData()[3])); if ( ptmin > ZERO ) { double ctm = 1.0 - sqr(ptmin/q); if ( ctm <= 0.0 ) return false; ctmin = max(ctmin, -sqrt(ctm)); ctmax = min(ctmax, sqrt(ctm)); } double ymin2 = lastCuts().minYStar(mePartonData()[2]); double ymax2 = lastCuts().maxYStar(mePartonData()[2]); double ymin3 = lastCuts().minYStar(mePartonData()[3]); double ymax3 = lastCuts().maxYStar(mePartonData()[3]); double ytot = lastCuts().Y() + lastCuts().currentYHat(); if ( ymin2 + ytot > -0.9*Constants::MaxRapidity ) ctmin = max(ctmin, sqrt(sqr(q) + m22)*tanh(ymin2)/q); if ( ymax2 + ytot < 0.9*Constants::MaxRapidity ) ctmax = min(ctmax, sqrt(sqr(q) + m22)*tanh(ymax2)/q); if ( ymin3 + ytot > -0.9*Constants::MaxRapidity ) ctmax = min(ctmax, tanh(-ymin3)); if ( ymax3 + ytot < 0.9*Constants::MaxRapidity ) ctmin = max(ctmin, tanh(-ymax3)); if ( ctmin >= ctmax ) return false; } double cth = getCosTheta(ctmin, ctmax, r[0]); Energy pt = q*sqrt(1.0-sqr(cth)); phi(rnd(2.0*Constants::pi)); meMomenta()[2].setVect(Momentum3( pt*sin(phi()), pt*cos(phi()), q*cth)); meMomenta()[3].setVect(Momentum3(-pt*sin(phi()), -pt*cos(phi()), -q*cth)); meMomenta()[2].rescaleEnergy(); meMomenta()[3].rescaleEnergy(); // jacobian tHat(pq*cth + m22 - e0e2); uHat(m22 - shat - tHat()); jacobian(pq/shat*Constants::pi*jacobian()); // end for 2->2 processes if(mePartonData().size()==4) { vector out(2); out[0] = meMomenta()[2]; out[1] = meMomenta()[3]; tcPDVector tout(2); tout[0] = mePartonData()[2]; tout[1] = mePartonData()[3]; if ( !lastCuts().passCuts(tout, out, mePartonData()[0], mePartonData()[1]) ) return false; return true; } // special for 2-3 processes pair x = make_pair(lastX1(),lastX2()); // partons pair partons = make_pair(mePartonData()[0],mePartonData()[1]); // If necessary swap the particle data objects so that // first beam gives the incoming quark if(lastPartons().first ->dataPtr()!=partons.first) { swap(x.first,x.second); } // use vTilde to select the dipole for emission // gamma gamma g processes if(mePartonData()[4]->id()==ParticleID::g) { if(vTilde_<=0.5) { dipole_ = IIQCD1; vTilde_ = 4.*vTilde_; } else { dipole_ = IIQCD2; vTilde_ = 4.*(vTilde_-0.25); } jacobian(2.*jacobian()); } // gamma gamma q processes else if(mePartonData()[4]->id()>0&&mePartonData()[4]->id()<6) { if(vTilde_<=1./3.) { dipole_ = IIQCD2; vTilde_ = 3.*vTilde_; } else if(vTilde_<=2./3.) { dipole_ = IFQED1; vTilde_ = 3.*vTilde_-1.; } else { dipole_ = FIQED1; vTilde_ = 3.*vTilde_-2.; } jacobian(3.*jacobian()); } // gamma gamma qbar processes else if(mePartonData()[4]->id()<0&&mePartonData()[4]->id()>-6) { if(vTilde_<=1./3.) { dipole_ = IIQCD1; vTilde_ = 3.*vTilde_; } else if(vTilde_<=2./3.) { dipole_ = IFQED2; vTilde_ = 3.*vTilde_-1.; } else { dipole_ = FIQED2; vTilde_ = 3.*vTilde_-2.; } jacobian(3.*jacobian()); } else { assert(false); } // initial-initial dipoles if(dipole_<=4) { double z = shat/sHat(); double vt = vTilde_*(1.-z); double vJac = 1.-z; Energy pT = sqrt(shat*vt*(1.-vt-z)/z); if(pT pnew(5); pnew [0] = Lorentz5Momentum(ZERO,ZERO,0.5*rs*x.first, 0.5*rs*x.first,ZERO); pnew [1] = Lorentz5Momentum(ZERO,ZERO,-0.5*rs*x.second, 0.5*rs*x.second,ZERO) ; pnew [2] = meMomenta()[2]; pnew [3] = meMomenta()[3]; pnew [4] = Lorentz5Momentum(pT*cos(phi_),pT*sin(phi_), pT*sinh(rapidity), pT*cosh(rapidity), ZERO); pnew[4].rescaleEnergy(); Lorentz5Momentum K = pnew [0]+pnew [1]-pnew [4]; Lorentz5Momentum Kt = pcmf; Lorentz5Momentum Ksum = K+Kt; Energy2 K2 = K.m2(); Energy2 Ksum2 = Ksum.m2(); for(unsigned int ix=2;ix<4;++ix) { pnew [ix].boost(blab); pnew [ix] = pnew [ix] - 2.*Ksum*(Ksum*pnew [ix])/Ksum2 +2*K*(Kt*pnew [ix])/K2; pnew[ix].rescaleEnergy(); } pcmf = Lorentz5Momentum(ZERO,ZERO, 0.5*rs*(x.first-x.second), 0.5*rs*(x.first+x.second)); pcmf.rescaleMass(); blab = pcmf.boostVector(); for(unsigned int ix=0;ix1e-20) { rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); rot.rotateX(Constants::pi); } if(abs(1.-q.e()/q.vect().mag())>1e-6) rot.boostZ(q.e()/q.vect().mag()); pin *= rot; if(pin.perp2()/GeV2>1e-20) { Boost trans = -1./pin.e()*pin.vect(); trans.setZ(0.); rot.boost(trans); } rot.invert(); Energy Q = sqrt(-q.m2()); meMomenta()[4] = rot*Lorentz5Momentum( 0.5*Q*xT*cos(phi_), 0.5*Q*xT*sin(phi_), -0.5*Q*x2,0.5*Q*sqrt(sqr(x2)+sqr(xT))); meMomenta()[3] = rot*Lorentz5Momentum(-0.5*Q*xT*cos(phi_),-0.5*Q*xT*sin(phi_), -0.5*Q*x3,0.5*Q*sqrt(sqr(x3)+sqr(xT))); double ratio; if(dipole_<=6) { ratio = 2.*((meMomenta()[3]+meMomenta()[4])*meMomenta()[0])/sHat(); } else { ratio = 2.*((meMomenta()[3]+meMomenta()[4])*meMomenta()[1])/sHat(); } jacobian(jacobian()*ratio); } else { assert(false); } vector out(3); tcPDVector tout(3); for(unsigned int ix=0;ix<3;++ix) { out[ix] = meMomenta() [2+ix]; tout[ix] = mePartonData()[2+ix]; } return lastCuts().passCuts(tout, out, mePartonData()[0], mePartonData()[1]); } double MEPP2GammaGammaPowheg::me2() const { // Born configurations if(mePartonData().size()==4) { // gamma gamma core process if(mePartonData()[3]->id()==ParticleID::gamma) { return 2.*Constants::twopi*alphaEM_* loGammaGammaME(mePartonData(),meMomenta(),true); } // V jet core process else if(mePartonData()[3]->id()==ParticleID::g) { return 2.*Constants::twopi*alphaS_* loGammagME(mePartonData(),meMomenta(),true); } else if(mePartonData()[3]->id()>0) { return 2.*Constants::twopi*alphaS_* loGammaqME(mePartonData(),meMomenta(),true); } else if(mePartonData()[3]->id()<0) { return 2.*Constants::twopi*alphaS_* loGammaqbarME(mePartonData(),meMomenta(),true); } else { assert(false); return 0.; } } // hard emission configurations else { if(mePartonData()[4]->id()==ParticleID::g) return sHat()*realGammaGammagME (mePartonData(),meMomenta(),dipole_,Hard,true); else if(mePartonData()[4]->id()>0&&mePartonData()[4]->id()<6) return sHat()*realGammaGammaqME (mePartonData(),meMomenta(),dipole_,Hard,true); else if(mePartonData()[4]->id()<0&&mePartonData()[4]->id()>-6) return sHat()*realGammaGammaqbarME(mePartonData(),meMomenta(),dipole_,Hard,true); else { assert(false); return 0.; } } } CrossSection MEPP2GammaGammaPowheg::dSigHatDR() const { // couplings if(!fixedAlphaS_) alphaS_ = SM().alphaS(scale()); alphaEM_ = SM().alphaEM(); // cross section CrossSection preFactor = jacobian()/(16.0*sqr(Constants::pi)*sHat())*sqr(hbarc); loME_ = me2(); if( contrib_== 0 || mePartonData().size()==5 || (mePartonData().size()==4&& mePartonData()[3]->coloured())) return loME_*preFactor; else return NLOWeight()*preFactor; } Selector MEPP2GammaGammaPowheg::diagrams(const DiagramVector & diags) const { if(mePartonData().size()==4) { if(mePartonData()[3]->id()==ParticleID::gamma) { Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ){ sel.insert(meInfo()[abs(diags[i]->id())], i); } return sel; } else { Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ){ sel.insert(meInfo()[abs(diags[i]->id())%2], i); } return sel; } } else { Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ) { if(abs(diags[i]->id()) == 10 && dipole_ == IIQCD2 ) sel.insert(1., i); else if(abs(diags[i]->id()) == 12 && dipole_ == IIQCD1 ) sel.insert(1., i); else if(abs(diags[i]->id()) == 20 && dipole_ == IIQCD2 ) sel.insert(1., i); else if(abs(diags[i]->id()) == 21 && dipole_ == IFQED1 ) sel.insert(1., i); else if(abs(diags[i]->id()) == 22 && dipole_ == FIQED1 ) sel.insert(1., i); else sel.insert(0., i); } return sel; } } Selector MEPP2GammaGammaPowheg::colourGeometries(tcDiagPtr diag) const { // colour lines for V gamma static ColourLines cs("1 -2"); static ColourLines ct("1 2 -3"); // colour lines for q qbar -> V g static const ColourLines cqqbar[2]={ColourLines("1 -2 5,-3 -5"), ColourLines("1 5,-5 2 -3")}; // colour lines for q g -> V q static const ColourLines cqg [2]={ColourLines("1 2 -3,3 5"), ColourLines("1 -2,2 3 5")}; // colour lines for g qbar -> V qbar static const ColourLines cgqbar[2]={ColourLines("-3 -2 1,-1 -5"), ColourLines("-2 1,-1 -3 -5")}; // colour lines for q qbar -> V gamma g static const ColourLines cqqbarg[4]={ColourLines("1 2 3 7,-4 -7"), ColourLines("1 2 7,-4 3 -7"), ColourLines("1 7,-4 3 2 -7"), ColourLines("1 2 7,-4 3 -7")}; // colour lines for q g -> V gamma q static const ColourLines cqgq [3]={ColourLines("1 2 3 -4,4 7"), ColourLines("1 2 3 -4,4 7"), ColourLines("1 2 -3,3 5 7")}; // colour lines for gbar -> V gamma qbar static const ColourLines cqbargqbar[3]={ColourLines("1 -2 -3 -4,-1 -7"), ColourLines("1 -2 -3 -4,-1 -7"), ColourLines("1 -2 -3,-1 -5 -7")}; Selector sel; switch(abs(diag->id())) { case 1 :case 2 : sel.insert(1.0, &ct); break; case 3 : sel.insert(1.0, &cs); break; case 4 : sel.insert(1.0, &cqqbar[0]); break; case 5: sel.insert(1.0, &cqqbar[1]); break; case 6: sel.insert(1.0, &cqg[0]); break; case 7: sel.insert(1.0, &cqg[1]); break; case 8: sel.insert(1.0, &cgqbar[0]); break; case 9: sel.insert(1.0, &cgqbar[1]); break; case 10: case 11: case 12: case 13: sel.insert(1.0, &cqqbarg[abs(diag->id())-10]); break; case 20: case 21: case 22: sel.insert(1.0, &cqgq[abs(diag->id())-20]); break; case 30: case 31: case 32: sel.insert(1.0, &cqbargqbar[abs(diag->id())-30]); break; default: assert(false); } return sel; } void MEPP2GammaGammaPowheg::persistentOutput(PersistentOStream & os) const { os << FFPvertex_ << FFGvertex_ << contrib_ << power_ << gluon_ << prefactor_ << process_ << threeBodyProcess_<< maxflavour_ << alphaS_ << fixedAlphaS_ << supressionFunction_ << supressionScale_ << ounit(lambda_,GeV) << alphaQCD_ << alphaQED_ << ounit(minpT_,GeV) << preQCDqqbarq_ << preQCDqqbarqbar_ << preQCDqg_ << preQCDgqbar_ << preQEDqqbarq_ << preQEDqqbarqbar_ << preQEDqgq_ << preQEDgqbarqbar_ << scaleChoice_ << scalePreFactor_; } void MEPP2GammaGammaPowheg::persistentInput(PersistentIStream & is, int) { is >> FFPvertex_ >> FFGvertex_ >> contrib_ >> power_ >> gluon_ >> prefactor_ >> process_ >> threeBodyProcess_ >> maxflavour_ >> alphaS_ >> fixedAlphaS_ >> supressionFunction_ >> supressionScale_ >> iunit(lambda_,GeV) >> alphaQCD_ >> alphaQED_ >> iunit(minpT_,GeV) >> preQCDqqbarq_ >> preQCDqqbarqbar_ >> preQCDqg_ >> preQCDgqbar_ >> preQEDqqbarq_ >> preQEDqqbarqbar_ >> preQEDqgq_ >> preQEDgqbarqbar_ >> scaleChoice_ >> scalePreFactor_; } void MEPP2GammaGammaPowheg::Init() { static ClassDocumentation documentation ("TheMEPP2GammaGammaPowheg class implements gamma gamma production at NLO"); static Switch interfaceProcess ("Process", "Which processes to include", &MEPP2GammaGammaPowheg::process_, 0, false, false); static SwitchOption interfaceProcessAll (interfaceProcess, "All", "Include all the processes", 0); static SwitchOption interfaceProcessGammaGamma (interfaceProcess, "GammaGamma", "Only include gamma gamma", 1); static SwitchOption interfaceProcessVJet (interfaceProcess, "VJet", "Only include gamma + jet", 2); static SwitchOption interfaceProcessHard (interfaceProcess, "Hard", "Only include hard radiation contributions", 3); static Switch interfaceThreeBodyProcess ("ThreeBodyProcess", "The possible three body processes to include", &MEPP2GammaGammaPowheg::threeBodyProcess_, 0, false, false); static SwitchOption interfaceThreeBodyProcessAll (interfaceThreeBodyProcess, "All", "Include all processes", 0); static SwitchOption interfaceThreeBodyProcessqqbar (interfaceThreeBodyProcess, "qqbar", "Only include q qbar -> gamma gamma g processes", 1); static SwitchOption interfaceThreeBodyProcessqg (interfaceThreeBodyProcess, "qg", "Only include q g -> gamma gamma q processes", 2); static SwitchOption interfaceThreeBodyProcessgqbar (interfaceThreeBodyProcess, "gqbar", "Only include g qbar -> gamma gamma qbar processes", 3); static Switch interfaceContribution ("Contribution", "Which contributions to the cross section to include", &MEPP2GammaGammaPowheg::contrib_, 1, false, false); static SwitchOption interfaceContributionLeadingOrder (interfaceContribution, "LeadingOrder", "Just generate the leading order cross section", 0); static SwitchOption interfaceContributionPositiveNLO (interfaceContribution, "PositiveNLO", "Generate the positive contribution to the full NLO cross section", 1); static SwitchOption interfaceContributionNegativeNLO (interfaceContribution, "NegativeNLO", "Generate the negative contribution to the full NLO cross section", 2); static Parameter interfaceMaximumFlavour ("MaximumFlavour", "The maximum flavour allowed for the incoming quarks", &MEPP2GammaGammaPowheg::maxflavour_, 5, 1, 5, false, false, Interface::limited); static Parameter interfaceAlphaS ("AlphaS", "The value of alphaS to use if using a fixed alphaS", &MEPP2GammaGammaPowheg::alphaS_, 0.118, 0.0, 0.2, false, false, Interface::limited); static Switch interfaceFixedAlphaS ("FixedAlphaS", "Use a fixed value of alphaS", &MEPP2GammaGammaPowheg::fixedAlphaS_, false, false, false); static SwitchOption interfaceFixedAlphaSYes (interfaceFixedAlphaS, "Yes", "Use a fixed alphaS", true); static SwitchOption interfaceFixedAlphaSNo (interfaceFixedAlphaS, "No", "Use a running alphaS", false); static Switch interfaceSupressionFunction ("SupressionFunction", "Choice of the supression function", &MEPP2GammaGammaPowheg::supressionFunction_, 0, false, false); static SwitchOption interfaceSupressionFunctionNone (interfaceSupressionFunction, "None", "Default POWHEG approach", 0); static SwitchOption interfaceSupressionFunctionThetaFunction (interfaceSupressionFunction, "ThetaFunction", "Use theta functions at scale Lambda", 1); static SwitchOption interfaceSupressionFunctionSmooth (interfaceSupressionFunction, "Smooth", "Supress high pT by pt^2/(pt^2+lambda^2)", 2); static Parameter interfaceSupressionScale ("SupressionScale", "The square of the scale for the supression function", &MEPP2GammaGammaPowheg::lambda_, GeV, 20.0*GeV, 0.0*GeV, 0*GeV, false, false, Interface::lowerlim); static Switch interfaceSupressionScaleChoice ("SupressionScaleChoice", "Choice of the supression scale", &MEPP2GammaGammaPowheg::supressionScale_, 0, false, false); static SwitchOption interfaceSupressionScaleChoiceFixed (interfaceSupressionScaleChoice, "Fixed", "Use a fixed scale", 0); static SwitchOption interfaceSupressionScaleChoiceVariable (interfaceSupressionScaleChoice, "Variable", "Use the pT of the hard process as the scale", 1); static Reference interfaceShowerAlphaQCD ("ShowerAlphaQCD", "Reference to the object calculating the QCD coupling for the shower", &MEPP2GammaGammaPowheg::alphaQCD_, false, false, true, false, false); static Reference interfaceShowerAlphaQED ("ShowerAlphaQED", "Reference to the object calculating the QED coupling for the shower", &MEPP2GammaGammaPowheg::alphaQED_, false, false, true, false, false); static Parameter interfacepreQCDqqbarq ("preQCDqqbarq", "The constant for the Sudakov overestimate for the " "q qbar -> V Gamma +g with emission from the q", &MEPP2GammaGammaPowheg::preQCDqqbarq_, 23.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacepreQCDqqbarqbar ("preQCDqqbarqbar", "The constant for the Sudakov overestimate for the " "q qbar -> V Gamma +g with emission from the qbar", &MEPP2GammaGammaPowheg::preQCDqqbarqbar_, 23.0, 0.0, 1000.0, false, false, Interface::limited); static Switch interfaceScaleChoice ("ScaleChoice", "The scale choice to use", &MEPP2GammaGammaPowheg::scaleChoice_, 0, false, false); static SwitchOption interfaceScaleChoicepT (interfaceScaleChoice, "pT", "Use the pT of the photons", 0); static SwitchOption interfaceScaleChoiceMGammaGamma (interfaceScaleChoice, "MGammaGamma", "Use the mass of the photon pair", 1); static Parameter interfaceScalePreFactor ("ScalePreFactor", "Prefactor to change factorization/renormalisation scale", &MEPP2GammaGammaPowheg::scalePreFactor_, 1.0, 0.1, 10.0, false, false, Interface::limited); // prefactor_.push_back(preQCDqg_); // prefactor_.push_back(preQCDgqbar_); // prefactor_.push_back(preQEDqqbarq_); // prefactor_.push_back(preQEDqqbarqbar_); // prefactor_.push_back(preQEDqgq_); // prefactor_.push_back(preQEDgqbarqbar_); } double MEPP2GammaGammaPowheg::NLOWeight() const { // if leading-order return if(contrib_==0) return loME_; // prefactors CFfact_ = 4./3.*alphaS_/Constants::twopi; TRfact_ = 1./2.*alphaS_/Constants::twopi; // scale Energy2 mu2 = scale(); // virtual pieces double virt = CFfact_*subtractedVirtual(); // extract the partons and stuff for the real emission // and collinear counter terms // hadrons pair hadrons= make_pair(dynamic_ptr_cast(lastParticles().first->dataPtr() ), dynamic_ptr_cast(lastParticles().second->dataPtr())); // momentum fractions pair x = make_pair(lastX1(),lastX2()); // partons pair partons = make_pair(mePartonData()[0],mePartonData()[1]); // If necessary swap the particle data objects so that // first beam gives the incoming quark if(lastPartons().first ->dataPtr()!=partons.first) { swap(x.first,x.second); swap(hadrons.first,hadrons.second); } // convert the values of z tilde to z pair z; pair zJac; double rhomax(pow(1.-x.first,1.-power_)); double rho = zTilde_*rhomax; z.first = 1.-pow(rho,1./(1.-power_)); zJac.first = rhomax*pow(1.-z.first,power_)/(1.-power_); rhomax = pow(1.-x.second,1.-power_); rho = zTilde_*rhomax; z.second = 1.-pow(rho,1./(1.-power_)); zJac.second = rhomax*pow(1.-z.second,power_)/(1.-power_); // calculate the PDFs pair oldqPDF = make_pair(hadrons.first ->pdf()->xfx(hadrons.first ,partons.first ,scale(), x.first )/x.first , hadrons.second->pdf()->xfx(hadrons.second,partons.second,scale(), x.second)/x.second); // real/coll q/qbar pair newqPDF = make_pair(hadrons.first ->pdf()->xfx(hadrons.first ,partons.first ,scale(), x.first /z.first )*z.first /x.first , hadrons.second->pdf()->xfx(hadrons.second,partons.second,scale(), x.second/z.second)*z.second/x.second); // real/coll gluon pair newgPDF = make_pair(hadrons.first ->pdf()->xfx(hadrons.first ,gluon_,scale(), x.first /z.first )*z.first /x.first , hadrons.second->pdf()->xfx(hadrons.second,gluon_,scale(), x.second/z.second)*z.second/x.second); // coll terms // g -> q double collGQ = collinearGluon(mu2,zJac.first,z.first, oldqPDF.first,newgPDF.first); // g -> qbar double collGQbar = collinearGluon(mu2,zJac.second,z.second, oldqPDF.second,newgPDF.second); // q -> q double collQQ = collinearQuark(x.first ,mu2,zJac.first ,z.first , oldqPDF.first ,newqPDF.first ); // qbar -> qbar double collQbarQbar = collinearQuark(x.second,mu2,zJac.second,z.second, oldqPDF.second,newqPDF.second); // collinear remnants double coll = collQQ+collQbarQbar+collGQ+collGQbar; // real emission contribution double real1 = subtractedReal(x,z. first,zJac. first,oldqPDF. first, newqPDF. first,newgPDF. first, true); double real2 = subtractedReal(x,z.second,zJac.second,oldqPDF.second, newqPDF.second,newgPDF.second,false); // the total weight double wgt = loME_ + loME_*virt + loME_*coll + real1 + real2; return contrib_ == 1 ? max(0.,wgt) : max(0.,-wgt); } double MEPP2GammaGammaPowheg::loGammaGammaME(const cPDVector & particles, const vector & momenta, bool first) const { double output(0.); // analytic formula for speed if(!first) { Energy2 th = (momenta[0]-momenta[2]).m2(); Energy2 uh = (momenta[0]-momenta[3]).m2(); output = 4./3.*Constants::pi*SM().alphaEM(ZERO)*(th/uh+uh/th)* pow(double(particles[0]->iCharge())/3.,4); } // HE code result else { // wavefunctions for the incoming fermions SpinorWaveFunction em_in( momenta[0],particles[0],incoming); SpinorBarWaveFunction ep_in( momenta[1],particles[1],incoming); // wavefunctions for the outgoing bosons VectorWaveFunction v1_out(momenta[2],particles[2],outgoing); VectorWaveFunction v2_out(momenta[3],particles[3],outgoing); vector f1; vector a1; vector v1,v2; // calculate the wavefunctions for(unsigned int ix=0;ix<2;++ix) { em_in.reset(ix); f1.push_back(em_in); ep_in.reset(ix); a1.push_back(ep_in); v1_out.reset(2*ix); v1.push_back(v1_out); v2_out.reset(2*ix); v2.push_back(v2_out); } vector me(4,0.0); me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1,PDT::Spin1)); vector diag(2,0.0); SpinorWaveFunction inter; for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { for(unsigned int ohel1=0;ohel1<2;++ohel1) { for(unsigned int ohel2=0;ohel2<2;++ohel2) { inter = FFPvertex_->evaluate(ZERO,5,f1[ihel1].particle()->CC(), f1[ihel1],v1[ohel1]); diag[0] = FFPvertex_->evaluate(ZERO,inter,a1[ihel2],v2[ohel2]); inter = FFPvertex_->evaluate(ZERO,5,f1[ihel1].particle()->CC(), f1[ihel1] ,v2[ohel2]); diag[1] = FFPvertex_->evaluate(ZERO,inter,a1[ihel2],v1[ohel1]); // individual diagrams for (size_t ii=0; ii<2; ++ii) me[ii] += std::norm(diag[ii]); // full matrix element diag[0] += diag[1]; output += std::norm(diag[0]); // storage of the matrix element for spin correlations me_(ihel1,ihel2,2*ohel1,2*ohel2) = diag[0]; } } } } // store diagram info, etc. DVector save(3); for (size_t i = 0; i < 3; ++i) save[i] = 0.25 * me[i]; meInfo(save); // spin and colour factors output *= 0.125/3./norm(FFPvertex_->norm()); } return output; } double MEPP2GammaGammaPowheg::loGammaqME(const cPDVector & particles, const vector & momenta, bool first) const { double output(0.); // analytic formula for speed if(!first) { Energy2 sh = (momenta[0]+momenta[1]).m2(); Energy2 th = (momenta[0]-momenta[2]).m2(); Energy2 uh = (momenta[0]-momenta[3]).m2(); output = -1./3./sh/th*(sh*sh+th*th+2.*uh*(sh+th+uh))* 4.*Constants::pi*SM().alphaEM(ZERO)* sqr(particles[0]->iCharge()/3.); } // HE result else { vector fin; vector gin; vector fout; vector vout; SpinorWaveFunction qin (momenta[0],particles[0],incoming); VectorWaveFunction glin(momenta[1],particles[1],incoming); VectorWaveFunction wout(momenta[2],particles[2],outgoing); SpinorBarWaveFunction qout(momenta[3],particles[3],outgoing); // polarization states for the particles for(unsigned int ix=0;ix<2;++ix) { qin.reset(ix) ; fin.push_back(qin); qout.reset(ix); fout.push_back(qout); glin.reset(2*ix); gin.push_back(glin); wout.reset(2*ix); vout.push_back(wout); } me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1, PDT::Spin1,PDT::Spin1Half)); // compute the matrix elements double me[3]={0.,0.,0.}; Complex diag[2]; SpinorWaveFunction inters; SpinorBarWaveFunction interb; for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { for(unsigned int ohel1=0;ohel1<2;++ohel1) { // intermediates for the diagrams interb= FFGvertex_->evaluate(scale(),5,particles[3]->CC(), fout[ohel1],gin[ihel2]); inters= FFGvertex_->evaluate(scale(),5,particles[0], fin[ihel1],gin[ihel2]); for(unsigned int vhel=0;vhel<2;++vhel) { diag[0] = FFPvertex_->evaluate(ZERO,fin[ihel1],interb,vout[vhel]); diag[1] = FFPvertex_->evaluate(ZERO,inters,fout[ohel1],vout[vhel]); // diagram contributions me[1] += norm(diag[0]); me[2] += norm(diag[1]); // total diag[0] += diag[1]; me[0] += norm(diag[0]); me_(ihel1,2*ihel2,2*vhel,ohel1) = diag[0]; } } } } // results // initial state spin and colour average double colspin = 1./24./4.; // and C_F N_c from matrix element colspin *= 4.; DVector save; for(unsigned int ix=0;ix<3;++ix) { me[ix] *= colspin; if(ix>0) save.push_back(me[ix]); } meInfo(save); output = me[0]/norm(FFGvertex_->norm()); } return output; } double MEPP2GammaGammaPowheg::loGammaqbarME(const cPDVector & particles, const vector & momenta, bool first) const { double output(0.); // analytic formula for speed if(!first) { Energy2 sh = (momenta[0]+momenta[1]).m2(); Energy2 uh = (momenta[0]-momenta[2]).m2(); Energy2 th = (momenta[0]-momenta[3]).m2(); output = -1./3./sh/th*(sh*sh+th*th+2.*uh*(sh+th+uh))* 4.*Constants::pi*SM().alphaEM()* sqr(particles[1]->iCharge()/3.); } // HE result else { vector ain; vector gin; vector aout; vector vout; VectorWaveFunction glin (momenta[0],particles[0],incoming); SpinorBarWaveFunction qbin (momenta[1],particles[1],incoming); VectorWaveFunction wout (momenta[2],particles[2],outgoing); SpinorWaveFunction qbout(momenta[3],particles[3],outgoing); // polarization states for the particles for(unsigned int ix=0;ix<2;++ix) { qbin .reset(ix ); ain .push_back(qbin ); qbout.reset(ix ); aout.push_back(qbout); glin.reset(2*ix); gin.push_back(glin); wout.reset(2*ix); vout.push_back(wout); } // if calculation spin corrections construct the me me_.reset(ProductionMatrixElement(PDT::Spin1,PDT::Spin1Half, PDT::Spin1,PDT::Spin1Half)); // compute the matrix elements double me[3]={0.,0.,0.}; Complex diag[2]; SpinorWaveFunction inters; SpinorBarWaveFunction interb; for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { for(unsigned int ohel1=0;ohel1<2;++ohel1) { // intermediates for the diagrams inters= FFGvertex_->evaluate(scale(),5,particles[3]->CC(), aout[ohel1],gin[ihel1]); interb= FFGvertex_->evaluate(scale(),5,particles[1], ain[ihel2],gin[ihel1]); for(unsigned int vhel=0;vhel<2;++vhel) { diag[0]= FFPvertex_->evaluate(ZERO,inters,ain[ihel2],vout[vhel]); diag[1]= FFPvertex_->evaluate(ZERO,aout[ohel1],interb,vout[vhel]); // diagram contributions me[1] += norm(diag[0]); me[2] += norm(diag[1]); // total diag[0] += diag[1]; me[0] += norm(diag[0]); me_(2*ihel1,ihel2,2*vhel,ohel1) = diag[0]; } } } } // results // initial state spin and colour average double colspin = 1./24./4.; // and C_F N_c from matrix element colspin *= 4.; DVector save; for(unsigned int ix=0;ix<3;++ix) { me[ix] *= colspin; if(ix>0) save.push_back(me[ix]); } meInfo(save); output = me[0]/norm(FFGvertex_->norm()); } return output; } double MEPP2GammaGammaPowheg::loGammagME(const cPDVector & particles, const vector & momenta, bool first) const { double output(0.); // analytic formula for speed if(!first) { Energy2 uh = (momenta[0]-momenta[2]).m2(); Energy2 th = (momenta[0]-momenta[3]).m2(); output = 8./9.*double((th*th+uh*uh)/uh/th)* 4.*Constants::pi*SM().alphaEM(ZERO)* sqr(particles[0]->iCharge()/3.); } else { vector fin; vector ain; vector gout; vector vout; SpinorWaveFunction qin (momenta[0],particles[0],incoming); SpinorBarWaveFunction qbin(momenta[1],particles[1],incoming); VectorWaveFunction wout(momenta[2],particles[2],outgoing); VectorWaveFunction glout(momenta[3],particles[3],outgoing); // polarization states for the particles for(unsigned int ix=0;ix<2;++ix) { qin.reset(ix) ; fin.push_back(qin); qbin.reset(ix) ; ain.push_back(qbin); glout.reset(2*ix); gout.push_back(glout); wout.reset(2*ix); vout.push_back(wout); } // if calculation spin corrections construct the me if(first) me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1,PDT::Spin1)); // compute the matrix elements double me[3]={0.,0.,0.}; Complex diag[2]; SpinorWaveFunction inters; SpinorBarWaveFunction interb; for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { for(unsigned int ohel1=0;ohel1<2;++ohel1) { // intermediates for the diagrams inters= FFGvertex_->evaluate(scale(),5,particles[0], fin[ihel1],gout[ohel1]); interb= FFGvertex_->evaluate(scale(),5,particles[1], ain[ihel2],gout[ohel1]); for(unsigned int vhel=0;vhel<2;++vhel) { diag[0]= FFPvertex_->evaluate(ZERO,fin[ihel1],interb,vout[vhel]); diag[1]= FFPvertex_->evaluate(ZERO,inters,ain[ihel2],vout[vhel]); // diagram contributions me[1] += norm(diag[0]); me[2] += norm(diag[1]); // total diag[0] += diag[1]; me[0] += norm(diag[0]); if(first) me_(ihel1,ihel2,vhel,2*ohel1) = diag[0]; } } } } // results // initial state spin and colour average double colspin = 1./9./4.; // and C_F N_c from matrix element colspin *= 4.; DVector save; for(unsigned int ix=0;ix<3;++ix) { me[ix] *= colspin; if(ix>0) save.push_back(me[ix]); } meInfo(save); output = me[0]/norm(FFGvertex_->norm()); } return output; } InvEnergy2 MEPP2GammaGammaPowheg:: realGammaGammagME(const cPDVector & particles, const vector & momenta, DipoleType dipole, RadiationType rad, bool ) const { // matrix element double sum = realME(particles,momenta); // loop over the QCD and QCD dipoles InvEnergy2 dipoles[2]; pair supress[2]; // compute the two dipole terms unsigned int iemit = 4, ihard = 3; double x = (momenta[0]*momenta[1]-momenta[iemit]*momenta[1]- momenta[iemit]*momenta[0])/(momenta[0]*momenta[1]); Lorentz5Momentum Kt = momenta[0]+momenta[1]-momenta[iemit]; vector pa(4),pb(4); // momenta for q -> q g/gamma emission pa[0] = x*momenta[0]; pa[1] = momenta[1]; Lorentz5Momentum K = pa[0]+pa[1]; Lorentz5Momentum Ksum = K+Kt; Energy2 K2 = K.m2(); Energy2 Ksum2 = Ksum.m2(); pa[2] = momenta[2]-2.*Ksum*(Ksum*momenta[2])/Ksum2+2*K*(Kt*momenta[2])/K2; pa[2].setMass(momenta[2].mass()); pa[3] = momenta[ihard] -2.*Ksum*(Ksum*momenta[ihard])/Ksum2+2*K*(Kt*momenta[ihard])/K2; pa[3].setMass(ZERO); cPDVector part(particles.begin(),--particles.end()); part[3] = particles[ihard]; // first leading-order matrix element double lo1 = loGammaGammaME(part,pa); // first dipole dipoles[0] = 1./(momenta[0]*momenta[iemit])/x*(2./(1.-x)-(1.+x))*lo1; supress[0] = supressionFunction(momenta[iemit].perp(),pa[3].perp()); // momenta for qbar -> qbar g/gamma emission pb[0] = momenta[0]; pb[1] = x*momenta[1]; K = pb[0]+pb[1]; Ksum = K+Kt; K2 = K.m2(); Ksum2 = Ksum.m2(); pb[2] = momenta[2]-2.*Ksum*(Ksum*momenta[2])/Ksum2+2*K*(Kt*momenta[2])/K2; pb[2].setMass(momenta[2].mass()); pb[3] = momenta[ihard] -2.*Ksum*(Ksum*momenta[ihard])/Ksum2+2*K*(Kt*momenta[ihard])/K2; pb[3].setMass(ZERO); // second LO matrix element double lo2 = loGammaGammaME(part,pb); // second dipole dipoles[1] = 1./(momenta[1]*momenta[iemit])/x*(2./(1.-x)-(1.+x))*lo2; supress[1] = supressionFunction(momenta[iemit].perp(),pb[3].perp()); for(unsigned int ix=0;ix<2;++ix) dipoles[ix] *= 4./3.; // denominator for the matrix element InvEnergy2 denom = abs(dipoles[0]) + abs(dipoles[1]); // contribution if( denom==ZERO || dipoles[(dipole-1)/2]==ZERO ) return ZERO; sum *= abs(dipoles[(dipole-1)/2])/denom; // final coupling factors InvEnergy2 output; if(rad==Subtraction) { output = alphaS_*alphaEM_* (sum*UnitRemoval::InvE2*supress[(dipole-1)/2].first - dipoles[(dipole-1)/2]); } else { output = alphaS_*alphaEM_*sum*UnitRemoval::InvE2; if(rad==Hard) output *=supress[(dipole-1)/2].second; else if(rad==Shower) output *=supress[(dipole-1)/2].first ; } return output; } InvEnergy2 MEPP2GammaGammaPowheg::realGammaGammaqME(const cPDVector & particles, const vector & momenta, DipoleType dipole, RadiationType rad, bool ) const { double sum = realME(particles,momenta); // initial-state QCD dipole double x = (momenta[0]*momenta[1]-momenta[4]*momenta[1]- momenta[4]*momenta[0])/(momenta[0]*momenta[1]); Lorentz5Momentum Kt = momenta[0]+momenta[1]-momenta[4]; vector pa(4); pa[0] = momenta[0]; pa[1] = x*momenta[1]; Lorentz5Momentum K = pa[0]+pa[1]; Lorentz5Momentum Ksum = K+Kt; Energy2 K2 = K.m2(); Energy2 Ksum2 = Ksum.m2(); pa[2] = momenta[2]-2.*Ksum*(Ksum*momenta[2])/Ksum2+2*K*(Kt*momenta[2])/K2; pa[2].setMass(momenta[2].mass()); pa[3] = momenta[3] -2.*Ksum*(Ksum*momenta[3])/Ksum2+2*K*(Kt*momenta[3])/K2; pa[3].setMass(ZERO); cPDVector part(particles.begin(),--particles.end()); part[1] = particles[4]->CC(); double lo1 = loGammaGammaME(part,pa); InvEnergy2 D1 = 0.5/(momenta[1]*momenta[4])/x*(1.-2.*x*(1.-x))*lo1; // initial-final QED dipole vector pb(4); x = 1.-(momenta[3]*momenta[4])/(momenta[4]*momenta[0]+momenta[0]*momenta[3]); pb[3] = momenta[4]+momenta[3]-(1.-x)*momenta[0]; pb[0] = x*momenta[0]; pb[1] = momenta[1]; pb[2] = momenta[2]; double z = momenta[0]*momenta[3]/(momenta[0]*momenta[3]+momenta[0]*momenta[4]); part[1] = particles[1]; part[3] = particles[4]; double lo2 = loGammaqME(part,pb); Energy pT = sqrt(-(pb[0]-pb[3]).m2()*(1.-x)*(1.-z)*z/x); InvEnergy2 DF = 1./(momenta[4]*momenta[3])/x*(1./(1.-x+z)-2.+z)*lo2; InvEnergy2 DI = 1./(momenta[0]*momenta[3])/x*(1./(1.-x+z)-1.-x)*lo2; DI *= sqr(double(particles[0]->iCharge())/3.); DF *= sqr(double(particles[0]->iCharge())/3.); InvEnergy2 denom = abs(D1)+abs(DI)+abs(DF); pair supress; InvEnergy2 term; if ( dipole == IFQED1 ) { term = DI; supress = supressionFunction(pT,pb[3].perp()); } else if( dipole == FIQED1 ) { term = DF; supress = supressionFunction(pT,pb[3].perp()); } else { term = D1; supress = supressionFunction(momenta[4].perp(),pa[3].perp()); } if( denom==ZERO || term == ZERO ) return ZERO; sum *= abs(term)/denom; // final coupling factors InvEnergy2 output; if(rad==Subtraction) { output = alphaS_*alphaEM_* (sum*UnitRemoval::InvE2*supress.first - term); } else { output = alphaS_*alphaEM_*sum*UnitRemoval::InvE2; if(rad==Hard) output *= supress.second; else if(rad==Shower) output *= supress.first ; } // final coupling factors return output; } InvEnergy2 MEPP2GammaGammaPowheg:: realGammaGammaqbarME(const cPDVector & particles, const vector & momenta, DipoleType dipole, RadiationType rad, bool) const { double sum = realME(particles,momenta); // initial-state QCD dipole double x = (momenta[0]*momenta[1]-momenta[4]*momenta[1]-momenta[4]*momenta[0])/ (momenta[0]*momenta[1]); Lorentz5Momentum Kt = momenta[0]+momenta[1]-momenta[4]; vector pa(4); pa[0] = x*momenta[0]; pa[1] = momenta[1]; Lorentz5Momentum K = pa[0]+pa[1]; Lorentz5Momentum Ksum = K+Kt; Energy2 K2 = K.m2(); Energy2 Ksum2 = Ksum.m2(); pa[2] = momenta[2]-2.*Ksum*(Ksum*momenta[2])/Ksum2+2*K*(Kt*momenta[2])/K2; pa[2].setMass(momenta[2].mass()); pa[3] = momenta[3] -2.*Ksum*(Ksum*momenta[3])/Ksum2+2*K*(Kt*momenta[3])/K2; pa[3].setMass(ZERO); cPDVector part(particles.begin(),--particles.end()); part[0] = particles[4]->CC(); double lo1 = loGammaGammaME(part,pa); InvEnergy2 D1 = 0.5/(momenta[0]*momenta[4])/x*(1.-2.*x*(1.-x))*lo1; // initial-final QED dipole vector pb(4); x = 1.-(momenta[3]*momenta[4])/(momenta[4]*momenta[1]+momenta[1]*momenta[3]); pb[3] = momenta[4]+momenta[3]-(1.-x)*momenta[1]; pb[0] = momenta[0]; pb[1] = x*momenta[1]; pb[2] = momenta[2]; double z = momenta[1]*momenta[3]/(momenta[1]*momenta[3]+momenta[1]*momenta[4]); part[0] = particles[0]; part[3] = particles[4]; double lo2 = loGammaqbarME(part,pb); Energy pT = sqrt(-(pb[1]-pb[3]).m2()*(1.-x)*(1.-z)*z/x); InvEnergy2 DF = 1./(momenta[4]*momenta[3])/x*(2./(1.-x+z)-2.+z)*lo2; InvEnergy2 DI = 1./(momenta[0]*momenta[3])/x*(2./(1.-x+z)-1.-x)*lo2; InvEnergy2 term; DI *= sqr(double(particles[1]->iCharge())/3.); DF *= sqr(double(particles[1]->iCharge())/3.); InvEnergy2 denom = abs(D1)+abs(DI)+abs(DF); pair supress; if ( dipole == IFQED2 ) { term = DI; supress = supressionFunction(pT,pb[3].perp()); } else if( dipole == FIQED2 ) { term = DF; supress = supressionFunction(pT,pb[3].perp()); } else { term = D1; supress = supressionFunction(momenta[4].perp(),pa[3].perp()); } if( denom==ZERO || dipole==ZERO ) return ZERO; sum *= abs(term)/denom; // final coupling factors InvEnergy2 output; if(rad==Subtraction) { output = alphaS_*alphaEM_* (sum*UnitRemoval::InvE2*supress.first - term); } else { output = alphaS_*alphaEM_*sum*UnitRemoval::InvE2; if(rad==Hard) output *= supress.second; else if(rad==Shower) output *= supress.first ; } // final coupling factors return output; } double MEPP2GammaGammaPowheg:: realME(const cPDVector & particles, const vector & momenta) const { vector qin; vector qbarin; vector wout,pout,gout; SpinorWaveFunction q_in; SpinorBarWaveFunction qbar_in; VectorWaveFunction g_out; VectorWaveFunction v_out (momenta[2],particles[2],outgoing); VectorWaveFunction p_out (momenta[3],particles[3],outgoing); // q qbar -> gamma gamma g if(particles[4]->id()==ParticleID::g) { q_in = SpinorWaveFunction (momenta[0],particles[0],incoming); qbar_in = SpinorBarWaveFunction (momenta[1],particles[1],incoming); g_out = VectorWaveFunction (momenta[4],particles[4],outgoing); } // q g -> gamma gamma q else if(particles[4]->id()>0) { q_in = SpinorWaveFunction (momenta[0],particles[0],incoming); qbar_in = SpinorBarWaveFunction (momenta[4],particles[4],outgoing); g_out = VectorWaveFunction (momenta[1],particles[1],incoming); } else if(particles[4]->id()<0) { q_in = SpinorWaveFunction (momenta[4],particles[4],outgoing); qbar_in = SpinorBarWaveFunction (momenta[1],particles[1],incoming); g_out = VectorWaveFunction (momenta[0],particles[0],incoming); } else assert(false); for(unsigned int ix=0;ix<2;++ix) { q_in.reset(ix); qin.push_back(q_in); qbar_in.reset(ix); qbarin.push_back(qbar_in); g_out.reset(2*ix); gout.push_back(g_out); p_out.reset(2*ix); pout.push_back(p_out); v_out.reset(2*ix); wout.push_back(v_out); } vector diag(6 , 0.); Energy2 mu2 = scale(); double sum(0.); for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { for(unsigned int whel=0;whel<2;++whel) { for(unsigned int phel=0;phel<2;++phel) { for(unsigned int ghel=0;ghel<2;++ghel) { // first diagram SpinorWaveFunction inters1 = FFPvertex_->evaluate(ZERO,5,qin[ihel1].particle()->CC(),qin[ihel1],pout[phel]); SpinorBarWaveFunction inters2 = FFPvertex_->evaluate(ZERO,5,qin[ihel1].particle(), qbarin[ihel2],wout[whel]); diag[0] = FFGvertex_->evaluate(mu2,inters1,inters2,gout[ghel]); // second diagram SpinorWaveFunction inters3 = FFGvertex_->evaluate(mu2,5,qin[ihel1].particle()->CC(),qin[ihel1],gout[ghel]); SpinorBarWaveFunction inters4 = FFPvertex_->evaluate(ZERO,5,qbarin[ihel2].particle()->CC(), qbarin[ihel2],pout[phel]); diag[1] = FFPvertex_->evaluate(ZERO,inters3,inters4,wout[whel]); // fourth diagram diag[2] = FFPvertex_->evaluate(ZERO,inters3,inters2,pout[phel]); // fifth diagram SpinorBarWaveFunction inters5 = FFGvertex_->evaluate(mu2,5,qbarin[ihel2].particle()->CC(), qbarin[ihel2],gout[ghel]); diag[3] = FFPvertex_->evaluate(ZERO,inters1,inters5,wout[whel]); // sixth diagram SpinorWaveFunction inters6 = FFPvertex_->evaluate(ZERO,5,qbarin[ihel2].particle(), qin[ihel1],wout[whel]); diag[4] = FFGvertex_->evaluate(mu2,inters6,inters4,gout[ghel]); // eighth diagram diag[5] = FFPvertex_->evaluate(ZERO,inters6,inters5,pout[phel]); // sum Complex dsum = std::accumulate(diag.begin(),diag.end(),Complex(0.)); sum += norm(dsum); } } } } } // divide out the em and strong couplings sum /= norm(FFGvertex_->norm()*FFPvertex_->norm()); // final spin and colour factors spin = 1/4 colour = 4/9 if(particles[4]->id()==ParticleID::g) sum /= 9.; // final spin and colour factors spin = 1/4 colour = 4/(3*8) else sum /= 24.; // finally identical particle factor return 0.5*sum; } double MEPP2GammaGammaPowheg::subtractedVirtual() const { double v = 1+tHat()/sHat(); double born = (1-v)/v+v/(1-v); double finite_term = born* (2./3.*sqr(Constants::pi)-3.+sqr(log(v))+sqr(log(1-v))+3.*log(1-v))+ 2.+2.*log(v)+2.*log(1-v)+3.*(1-v)/v*(log(v)-log(1-v))+ (2.+v/(1-v))*sqr(log(v))+(2.+(1-v)/v)*sqr(log(1-v)); double virt = ((6.-(2./3.)*sqr(Constants::pi))* born-2.+finite_term); return virt/born; } double MEPP2GammaGammaPowheg::subtractedReal(pair x, double z, double zJac, double oldqPDF, double newqPDF, double newgPDF,bool order) const { double vt = vTilde_*(1.-z); double vJac = 1.-z; Energy pT = sqrt(sHat()*vt*(1.-vt-z)/z); // rapidities double rapidity; if(order) { rapidity = -log(x.second*sqrt(lastS())/pT*vt); } else { rapidity = log(x.first *sqrt(lastS())/pT*vt); } // CMS system Energy rs=sqrt(lastS()); Lorentz5Momentum pcmf = Lorentz5Momentum(ZERO,ZERO,0.5*rs*(x.first-x.second), 0.5*rs*(x.first+x.second)); pcmf.rescaleMass(); Boost blab(pcmf.boostVector()); // emission from the quark radiation vector pnew(5); if(order) { pnew [0] = Lorentz5Momentum(ZERO,ZERO,0.5*rs*x.first/z, 0.5*rs*x.first/z,ZERO); pnew [1] = Lorentz5Momentum(ZERO,ZERO,-0.5*rs*x.second, 0.5*rs*x.second,ZERO) ; } else { pnew[0] = Lorentz5Momentum(ZERO,ZERO,0.5*rs*x.first, 0.5*rs*x.first,ZERO); pnew[1] = Lorentz5Momentum(ZERO,ZERO,-0.5*rs*x.second/z, 0.5*rs*x.second/z,ZERO) ; } pnew [2] = meMomenta()[2]; pnew [3] = meMomenta()[3]; pnew [4] = Lorentz5Momentum(pT*cos(phi_),pT*sin(phi_), pT*sinh(rapidity), pT*cosh(rapidity), ZERO); Lorentz5Momentum K = pnew [0]+pnew [1]-pnew [4]; Lorentz5Momentum Kt = pcmf; Lorentz5Momentum Ksum = K+Kt; Energy2 K2 = K.m2(); Energy2 Ksum2 = Ksum.m2(); for(unsigned int ix=2;ix<4;++ix) { pnew [ix].boost(blab); pnew [ix] = pnew [ix] - 2.*Ksum*(Ksum*pnew [ix])/Ksum2 +2*K*(Kt*pnew [ix])/K2; } // phase-space prefactors double phase = zJac*vJac/z; // real emission q qbar vector output(4,0.); double realQQ(0.),realGQ(0.); if(!(zTilde_<1e-7 || vt<1e-7 || 1.-z-vt < 1e-7 )) { cPDVector particles(mePartonData()); particles.push_back(gluon_); // calculate the full 2->3 matrix element realQQ = sHat()*phase*newqPDF/oldqPDF* realGammaGammagME(particles,pnew,order ? IIQCD1 : IIQCD2,Subtraction,false); if(order) { particles[0] = gluon_; particles[4] = mePartonData()[0]->CC(); realGQ = sHat()*phase*newgPDF/oldqPDF* realGammaGammaqbarME(particles,pnew,IIQCD2,Subtraction,false); } else { particles[1] = gluon_; particles[4] = mePartonData()[1]->CC(); realGQ = sHat()*phase*newgPDF/oldqPDF* realGammaGammaqME (particles,pnew,IIQCD1,Subtraction,false); } } // return the answer return realQQ+realGQ; } double MEPP2GammaGammaPowheg::collinearQuark(double x, Energy2 mu2, double jac, double z, double oldPDF, double newPDF) const { if(1.-z < 1.e-8) return 0.; return CFfact_*( // this bit is multiplied by LO PDF sqr(Constants::pi)/3.-5.+2.*sqr(log(1.-x )) +(1.5+2.*log(1.-x ))*log(sHat()/mu2) // NLO PDF bit +jac /z * newPDF /oldPDF * (1.-z -(1.+z )*log(sqr(1.-z )/z ) -(1.+z )*log(sHat()/mu2)-2.*log(z )/(1.-z )) // + function bit +jac /z *(newPDF /oldPDF -z )* 2./(1.-z )*log(sHat()*sqr(1.-z )/mu2)); } double MEPP2GammaGammaPowheg::collinearGluon(Energy2 mu2, double jac, double z, double oldPDF, double newPDF) const { if(1.-z < 1.e-8) return 0.; return TRfact_*jac/z*newPDF/oldPDF* ((sqr(z)+sqr(1.-z))*log(sqr(1.-z)*sHat()/z/mu2) +2.*z*(1.-z)); } void MEPP2GammaGammaPowheg::doinit() { HwMEBase::doinit(); vector mopt(2,1); massOption(mopt); // get the vertices we need // get a pointer to the standard model object in the run static const tcHwSMPtr hwsm = dynamic_ptr_cast(standardModel()); if (!hwsm) throw InitException() << "hwsm pointer is null in" << " MEPP2GammaGamma::doinit()" << Exception::abortnow; // get pointers to all required Vertex objects FFPvertex_ = hwsm->vertexFFP(); FFGvertex_ = hwsm->vertexFFG(); gluon_ = getParticleData(ParticleID::g); // sampling factors prefactor_.push_back(preQCDqqbarq_); prefactor_.push_back(preQCDqqbarqbar_); prefactor_.push_back(preQCDqg_); prefactor_.push_back(preQCDgqbar_); prefactor_.push_back(preQEDqqbarq_); prefactor_.push_back(preQEDqqbarqbar_); prefactor_.push_back(preQEDqgq_); prefactor_.push_back(preQEDgqbarqbar_); } RealEmissionProcessPtr MEPP2GammaGammaPowheg:: generateHardest(RealEmissionProcessPtr born, ShowerInteraction inter) { beams_.clear(); partons_.clear(); - bool QCDAllowed = inter !=ShowerInteraction::QED; - bool QEDAllowed = inter !=ShowerInteraction::QCD; + bool QCDAllowed(false),QEDAllowed(false); + if(inter==ShowerInteraction::QCD) + QCDAllowed = true; + else if(inter==ShowerInteraction::QED) + QEDAllowed = true; + else if(inter==ShowerInteraction::QEDQCD || + inter==ShowerInteraction::ALL) { + QEDAllowed = true; + QCDAllowed = true; + } // find the incoming particles // and get the particles to be showered ParticleVector incoming,particlesToShower; pair x; for(unsigned int ix=0;ixbornIncoming().size();++ix) { incoming.push_back( born->bornIncoming()[ix] ); beams_.push_back(dynamic_ptr_cast(born->hadrons()[ix]->dataPtr())); partons_.push_back( born->bornIncoming()[ix]->dataPtr() ); particlesToShower.push_back( born->bornIncoming()[ix] ); if(ix==0) x.first = incoming.back()->momentum().rho()/born->hadrons()[ix]->momentum().rho(); else x.second = incoming.back()->momentum().rho()/born->hadrons()[ix]->momentum().rho(); } // find the parton which should be first if( ( particlesToShower[1]->id() > 0 && particlesToShower[0]->id() < 0 ) || ( particlesToShower[0]->id() == ParticleID::g && particlesToShower[1]->id() < 6 && particlesToShower[1]->id() > 0 ) ) { swap(particlesToShower[0],particlesToShower[1]); swap(partons_[0],partons_[1]); swap(beams_ [0],beams_ [1]); swap(x.first ,x.second ); } // check that quark is along +ve z direction quarkplus_ = particlesToShower[0]->momentum().z() > ZERO; // outgoing partons for(unsigned int ix=0;ixbornOutgoing().size();++ix) { particlesToShower.push_back( born->bornOutgoing()[ix] ); } if(particlesToShower.size()!=4) return RealEmissionProcessPtr(); if(particlesToShower[2]->id()!=ParticleID::gamma) swap(particlesToShower[2],particlesToShower[3]); if(particlesToShower[3]->id()==ParticleID::gamma) { if(QCDAllowed) return hardQCDEmission(born,particlesToShower,x); } else { if(QEDAllowed) return hardQEDEmission(born,particlesToShower,x); } return born; } RealEmissionProcessPtr MEPP2GammaGammaPowheg:: hardQCDEmission(RealEmissionProcessPtr born, ParticleVector particlesToShower, pair x) { Energy rootS = sqrt(lastS()); // limits on the rapidity of the jet double minyj = -8.0,maxyj = 8.0; // generate the hard emission vector pT; Energy pTmax(-GeV); cPDVector selectedParticles; vector selectedMomenta; int iemit(-1); for(unsigned int ix=0;ix<4;++ix) { pT.push_back(0.5*generator()->maximumCMEnergy()); double a = alphaQCD_->overestimateValue()/Constants::twopi* prefactor_[ix]*(maxyj-minyj); cPDVector particles; for(unsigned int iy=0;iydataPtr()); if(ix<2) particles.push_back(gluon_); else if(ix==2) { particles.push_back(particles[0]->CC()); particles[0] = gluon_; } else { particles.push_back(particles[1]->CC()); particles[1] = gluon_; } vector momenta(5); do { pT[ix] *= pow(UseRandom::rnd(),1./a); double y = UseRandom::rnd()*(maxyj-minyj)+ minyj; double vt,z; if(ix%2==0) { vt = pT[ix]*exp(-y)/rootS/x.second; z = (1.-pT[ix]*exp(-y)/rootS/x.second)/(1.+pT[ix]*exp( y)/rootS/x.first ); if(z>1.||z1.||z1.-z || vt<0.) continue; if(ix%2==0) { momenta[0] = particlesToShower[0]->momentum()/z; momenta[1] = particlesToShower[1]->momentum(); } else { momenta[0] = particlesToShower[0]->momentum(); momenta[1] = particlesToShower[1]->momentum()/z; } double phi = Constants::twopi*UseRandom::rnd(); momenta[2] = particlesToShower[2]->momentum(); momenta[3] = particlesToShower[3]->momentum(); if(!quarkplus_) y *= -1.; momenta[4] = Lorentz5Momentum(pT[ix]*cos(phi),pT[ix]*sin(phi), pT[ix]*sinh(y),pT[ix]*cosh(y), ZERO); Lorentz5Momentum K = momenta[0] + momenta[1] - momenta[4]; Lorentz5Momentum Kt = momenta[2]+momenta[3]; Lorentz5Momentum Ksum = K+Kt; Energy2 K2 = K.m2(), Ksum2 = Ksum.m2(); for(unsigned int iy=2;iy<4;++iy) { momenta [iy] = momenta [iy] - 2.*Ksum*(Ksum*momenta [iy])/Ksum2 +2*K*(Kt*momenta [iy])/K2; } // matrix element piece double wgt = alphaQCD_->ratio(sqr(pT[ix]))*z/(1.-vt)/prefactor_[ix]/loME_; if(ix==0) wgt *= sqr(pT[ix])*realGammaGammagME(particles,momenta,IIQCD1,Shower,false); else if(ix==1) wgt *= sqr(pT[ix])*realGammaGammagME(particles,momenta,IIQCD2,Shower,false); else if(ix==2) wgt *= sqr(pT[ix])*realGammaGammaqbarME(particles,momenta,IIQCD1,Shower,false); else if(ix==3) wgt *= sqr(pT[ix])*realGammaGammaqME(particles,momenta,IIQCD2,Shower,false); wgt *= 4.*Constants::pi/alphaS_; // pdf piece double pdf[2]; if(ix%2==0) { pdf[0] = beams_[0]->pdf()->xfx(beams_[0],partons_ [0], scale(), x.first ) /x.first; pdf[1] = beams_[0]->pdf()->xfx(beams_[0],particles[0], scale()+sqr(pT[ix]),x.first /z)*z/x.first; } else { pdf[0] = beams_[1]->pdf()->xfx(beams_[1],partons_ [1], scale() ,x.second ) /x.second; pdf[1] = beams_[1]->pdf()->xfx(beams_[1],particles[1], scale()+sqr(pT[ix]),x.second/z)*z/x.second; } if(pdf[0]<=0.||pdf[1]<=0.) continue; wgt *= pdf[1]/pdf[0]; if(wgt>1.) generator()->log() << "Weight greater than one in " << "MEPP2GammaGammaPowheg::hardQCDEmission() " << "for channel " << ix << " Weight = " << wgt << "\n"; if(UseRandom::rnd()minpT_); if(pT[ix]>minpT_ && pT[ix]>pTmax) { pTmax = pT[ix]; selectedParticles = particles; selectedMomenta = momenta; iemit=ix; } } // if no emission if(pTmaxpT()[ShowerInteraction::QCD] = minpT_; return born; } // construct the HardTree object needed to perform the showers // create the partons ParticleVector newparticles; newparticles.push_back(selectedParticles[0]->produceParticle(selectedMomenta[0])); newparticles.push_back(selectedParticles[1]->produceParticle(selectedMomenta[1])); for(unsigned int ix=2;ixdataPtr()-> produceParticle(selectedMomenta[ix])); } newparticles.push_back(selectedParticles[4]->produceParticle(selectedMomenta[4])); // identify the type of process // gluon emission if(newparticles.back()->id()==ParticleID::g) { newparticles[4]->incomingColour(newparticles[0]); newparticles[4]->incomingColour(newparticles[1],true); } // quark else if(newparticles.back()->id()>0) { iemit=1; newparticles[4]->incomingColour(newparticles[1]); newparticles[1]-> colourConnect(newparticles[0]); } // antiquark else { iemit=0; newparticles[4]->incomingColour(newparticles[0],true); newparticles[1]-> colourConnect(newparticles[0]); } // add incoming int ispect = iemit==0 ? 1 : 0; if(particlesToShower[0]==born->bornIncoming()[0]) { born->incoming().push_back(newparticles[0]); born->incoming().push_back(newparticles[1]); } else { born->incoming().push_back(newparticles[1]); born->incoming().push_back(newparticles[0]); swap(iemit,ispect); } // add the outgoing for(unsigned int ix=2;ixoutgoing().push_back(newparticles[ix]); // emitter spectator etc born->emitter (iemit ); born->spectator(ispect); born->emitted(4); // x values pair xnew; for(unsigned int ix=0;ix<2;++ix) { double x = born->incoming()[ix]->momentum().rho()/born->hadrons()[ix]->momentum().rho(); if(ix==0) xnew.first = x; else xnew.second = x; } born->x(xnew); // max pT born->pT()[ShowerInteraction::QCD] = pTmax; born->interaction(ShowerInteraction::QCD); // return the process return born; } RealEmissionProcessPtr MEPP2GammaGammaPowheg:: hardQEDEmission(RealEmissionProcessPtr born, ParticleVector particlesToShower, pair x) { // return if not emission from quark if(particlesToShower[0]->id()!=ParticleID::g && particlesToShower[1]->id()!=ParticleID::g ) return RealEmissionProcessPtr(); // generate the hard emission vector pT; Energy pTmax(-GeV); cPDVector selectedParticles; vector selectedMomenta; int iemit(-1); pair mewgt(make_pair(0.,0.)); for(unsigned int ix=0;ixdataPtr()); selectedMomenta.push_back(particlesToShower[ix]->momentum()); } selectedParticles.push_back(getParticleData(ParticleID::gamma)); swap(selectedParticles[3],selectedParticles[4]); selectedMomenta.push_back(Lorentz5Momentum()); swap(selectedMomenta[3],selectedMomenta[4]); Lorentz5Momentum pin,pout; double xB; unsigned int iloc; if(particlesToShower[0]->dataPtr()->charged()) { pin = particlesToShower[0]->momentum(); xB = x.first; iloc = 6; } else { pin = particlesToShower[1]->momentum(); xB = x.second; iloc = 7; } pout = particlesToShower[3]->momentum(); Lorentz5Momentum q = pout-pin; Axis axis(q.vect().unit()); LorentzRotation rot; double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); rot = LorentzRotation(); if(axis.perp2()>1e-20) { rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); rot.rotateX(Constants::pi); } if(abs(1.-q.e()/q.vect().mag())>1e-6) rot.boostZ(q.e()/q.vect().mag()); Lorentz5Momentum ptemp = rot*pin; if(ptemp.perp2()/GeV2>1e-20) { Boost trans = -1./ptemp.e()*ptemp.vect(); trans.setZ(0.); rot.boost(trans); } rot.invert(); Energy Q = sqrt(-q.m2()); double xT = sqrt((1.-xB)/xB); double xTMin = 2.*minpT_/Q; double wgt(0.); double a = alphaQED_->overestimateValue()*prefactor_[iloc]/Constants::twopi; Lorentz5Momentum p1,p2,p3; do { wgt = 0.; // intergration variables dxT/xT^3 xT *= 1./sqrt(1.-2.*log(UseRandom::rnd())/a*sqr(xT)); // dz double zp = UseRandom::rnd(); double xp = 1./(1.+0.25*sqr(xT)/zp/(1.-zp)); if(xT1.) continue; // phase-space piece of the weight wgt = 4.*sqr(1.-xp)*(1.-zp)*zp/prefactor_[iloc]/loME_; // coupling Energy2 pT2 = 0.25*sqr(Q*xT); wgt *= alphaQED_->ratio(pT2); // matrix element wgt *= 4.*Constants::pi/alphaEM_; // PDF double pdf[2]; if(iloc==6) { pdf[0] = beams_[0]->pdf()-> xfx(beams_[0],partons_[0],scale() ,x.first ); pdf[1] = beams_[0]->pdf()-> xfx(beams_[0],partons_[0],scale()+pT2,x.first /xp); } else { pdf[0] = beams_[1]->pdf()-> xfx(beams_[1],partons_[1],scale() ,x.second ); pdf[1] = beams_[1]->pdf()-> xfx(beams_[1],partons_[1],scale()+pT2,x.second/xp); } if(pdf[0]<=0.||pdf[1]<=0.) { wgt = 0.; continue; } wgt *= pdf[1]/pdf[0]; // matrix element piece double phi = Constants::twopi*UseRandom::rnd(); double x2 = 1.-(1.-zp)/xp; double x3 = 2.-1./xp-x2; p1=Lorentz5Momentum(ZERO,ZERO,0.5*Q/xp,0.5*Q/xp,ZERO); p2=Lorentz5Momentum( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi), -0.5*Q*x2,0.5*Q*sqrt(sqr(xT)+sqr(x2))); p3=Lorentz5Momentum(-0.5*Q*xT*cos(phi),-0.5*Q*xT*sin(phi), -0.5*Q*x3,0.5*Q*sqrt(sqr(xT)+sqr(x3))); selectedMomenta[iloc-6] = rot*p1; selectedMomenta[3] = rot*p3; selectedMomenta[4] = rot*p2; if(iloc==6) { mewgt.first = sqr(Q)*realGammaGammaqME(selectedParticles,selectedMomenta,IFQED1,Shower,false); mewgt.second = sqr(Q)*realGammaGammaqME(selectedParticles,selectedMomenta,FIQED1,Shower,false); wgt *= mewgt.first+mewgt.second; } else { mewgt.first = sqr(Q)*realGammaGammaqbarME(selectedParticles,selectedMomenta,IFQED2,Shower,false); mewgt.second = sqr(Q)*realGammaGammaqbarME(selectedParticles,selectedMomenta,FIQED2,Shower,false); wgt *= mewgt.first+mewgt.second; } if(wgt>1.) generator()->log() << "Weight greater than one in " << "MEPP2GammaGammaPowheg::hardQEDEmission() " << "for IF channel " << " Weight = " << wgt << "\n"; } while(xT>xTMin&&UseRandom::rnd()>wgt); // if no emission if(xTpT()[ShowerInteraction::QED] = minpT_; return born; } pTmax = 0.5*xT*Q; iemit = mewgt.first>mewgt.second ? 2 : 3; // construct the object needed to perform the showers // create the partons ParticleVector newparticles; newparticles.push_back(selectedParticles[0]->produceParticle(selectedMomenta[0])); newparticles.push_back(selectedParticles[1]->produceParticle(selectedMomenta[1])); for(unsigned int ix=2;ix dataPtr()->produceParticle(selectedMomenta[ix==2 ? 2 : 4 ])); } newparticles.push_back(selectedParticles[3]->produceParticle(selectedMomenta[3])); // make the colour connections bool col = newparticles[3]->id()<0; if(particlesToShower[0]->dataPtr()->charged()) { newparticles[3]->incomingColour(newparticles[1],col); newparticles[1]->colourConnect (newparticles[0],col); } else { newparticles[3]->incomingColour(newparticles[0],col); newparticles[0]->colourConnect (newparticles[1],col); } bool FSR = iemit==3; // add incoming particles if(particlesToShower[0]==born->bornIncoming()[0]) { born->incoming().push_back(newparticles[0]); born->incoming().push_back(newparticles[1]); } else { born->incoming().push_back(newparticles[1]); born->incoming().push_back(newparticles[0]); } // IS radiatng particle unsigned int iemitter = born->incoming()[0]->dataPtr()->charged() ? 0 : 1; // add outgoing particles if(particlesToShower[2]==born->bornOutgoing()[0]) { born->outgoing().push_back(newparticles[2]); born->outgoing().push_back(newparticles[3]); } else { born->outgoing().push_back(newparticles[3]); born->outgoing().push_back(newparticles[2]); } born->outgoing().push_back(newparticles[4]); // outgoing radiating particle unsigned int ispectator = born->outgoing()[0]->dataPtr()->charged() ? 2 : 3; // get emitter and spectator right if(FSR) swap(iemitter,ispectator); born->emitter (iemitter ); born->spectator(ispectator); born->emitted(4); // x values pair xnew; for(unsigned int ix=0;ix<2;++ix) { double x = born->incoming()[ix]->momentum().rho()/born->hadrons()[ix]->momentum().rho(); if(ix==0) xnew.first = x; else xnew.second = x; } born->x(xnew); // max pT born->pT()[ShowerInteraction::QED] = pTmax; // return the process born->interaction(ShowerInteraction::QED); return born; } diff --git a/MatrixElement/Powheg/MEPP2VVPowheg.cc b/MatrixElement/Powheg/MEPP2VVPowheg.cc --- a/MatrixElement/Powheg/MEPP2VVPowheg.cc +++ b/MatrixElement/Powheg/MEPP2VVPowheg.cc @@ -1,5281 +1,5284 @@ // -*- C++ -*- // // MEPP2VVPowheg.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the MEPP2VVPowheg class. // #include "MEPP2VVPowheg.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/MatrixElement/Tree2toNDiagram.h" #include "ThePEG/Handlers/StandardXComb.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "Herwig/MatrixElement/HardVertex.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include "Herwig/Shower/RealEmissionProcess.h" using namespace Herwig; MEPP2VVPowheg::MEPP2VVPowheg() : tiny(1.e-10), CF_(4./3.), TR_(0.5), NC_(3.), contrib_(1), channels_(0), nlo_alphaS_opt_(0) , fixed_alphaS_(0.1180346226), removebr_(1), scaleopt_(1), mu_F_(100.*GeV), mu_UV_(100.*GeV), ckm_(3,vector(3,0.0)), helicityConservation_(true), realMESpinCorrelations_(true), power_(2.0), preqqbar_(3.7),preqg_(16.0),pregqbar_(11.0), b0_((11.-2./3.*5.)/4./Constants::pi), LambdaQCD_(91.118*GeV*exp(-1./2./((11.-2./3.*5.)/4./Constants::pi)/0.118)), min_pT_(2.*GeV){ massOption(vector(2,1)); } void MEPP2VVPowheg::persistentOutput(PersistentOStream & os) const { os << contrib_ << channels_ << nlo_alphaS_opt_ << fixed_alphaS_ << removebr_ << scaleopt_ << ounit(mu_F_,GeV) << ounit(mu_UV_,GeV) << ckm_ << helicityConservation_ << FFPvertex_ << FFWvertex_ << FFZvertex_ << WWWvertex_ << FFGvertex_ << realMESpinCorrelations_ << showerAlphaS_ << power_ << preqqbar_ << preqg_ << pregqbar_ << prefactor_ << b0_ << ounit(LambdaQCD_,GeV) << ounit( min_pT_,GeV ); } void MEPP2VVPowheg::persistentInput(PersistentIStream & is, int) { is >> contrib_ >> channels_ >> nlo_alphaS_opt_ >> fixed_alphaS_ >> removebr_ >> scaleopt_ >> iunit(mu_F_,GeV) >> iunit(mu_UV_,GeV) >> ckm_ >> helicityConservation_ >> FFPvertex_ >> FFWvertex_ >> FFZvertex_ >> WWWvertex_ >> FFGvertex_ >> realMESpinCorrelations_ >> showerAlphaS_ >> power_ >> preqqbar_ >> preqg_ >> pregqbar_ >> prefactor_ >> b0_ >> iunit(LambdaQCD_,GeV) >> iunit( min_pT_, GeV ); } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigMEPP2VVPowheg("Herwig::MEPP2VVPowheg", "HwMEHadron.so HwPowhegMEHadron.so"); void MEPP2VVPowheg::Init() { static ClassDocumentation documentation ("The MEPP2VVPowheg class implements the NLO matrix elements for the production of" "pairs of electroweak vector bosons.", "The calcultaion of $W^+W^-$, $W^\\pm Z^0$ and $Z^0Z^0$ production" " in hadron collisions at next-to-leading order in the POWHEG scheme" " is described in \\cite{Hamilton:2010mb}.", "\\bibitem{Hamilton:2010mb}\n" " K.~Hamilton,\n" "%``A positive-weight next-to-leading order simulation of weak boson pair\n" "%production,''\n" "JHEP {\bf 1101} (2011) 009\n" "[arXiv:1009.5391 [hep-ph]].\n" "%%CITATION = JHEPA,1101,009;%%\n"); static Switch interfaceContribution ("Contribution", "Which contributions to the cross section to include", &MEPP2VVPowheg::contrib_, 1, false, false); static SwitchOption interfaceContributionLeadingOrder (interfaceContribution, "LeadingOrder", "Just generate the leading order cross section", 0); static SwitchOption interfaceContributionPositiveNLO (interfaceContribution, "PositiveNLO", "Generate the positive contribution to the full NLO cross section", 1); static SwitchOption interfaceContributionNegativeNLO (interfaceContribution, "NegativeNLO", "Generate the negative contribution to the full NLO cross section", 2); static Switch interfaceChannels ("Channels", "Which channels to include in the cross section", &MEPP2VVPowheg::channels_, 0, false, false); static SwitchOption interfaceChannelsAll (interfaceChannels, "All", "All channels required for the full NLO cross section: qqb, qg, gqb", 0); static SwitchOption interfaceChannelsAnnihilation (interfaceChannels, "Annihilation", "Only include the qqb annihilation channel, omitting qg and gqb channels", 1); static SwitchOption interfaceChannelsCompton (interfaceChannels, "Compton", "Only include the qg and gqb compton channels, omitting all qqb processes", 2); static Switch interfaceNLOalphaSopt ("NLOalphaSopt", "An option allowing you to supply a fixed value of alpha_S " "through the FixedNLOAlphaS interface.", &MEPP2VVPowheg::nlo_alphaS_opt_, 0, false, false); static SwitchOption interfaceNLOalphaSoptRunningAlphaS (interfaceNLOalphaSopt, "RunningAlphaS", "Use the usual running QCD coupling evaluated at scale mu_UV2()", 0); static SwitchOption interfaceNLOalphaSoptFixedAlphaS (interfaceNLOalphaSopt, "FixedAlphaS", "Use a constant QCD coupling for comparison/debugging purposes", 1); static Parameter interfaceFixedNLOalphaS ("FixedNLOalphaS", "The value of alphaS to use for the nlo weight if nlo_alphaS_opt_=1", &MEPP2VVPowheg::fixed_alphaS_, 0.1180346226, 0., 1.0, false, false, Interface::limited); static Switch interfaceremovebr ("removebr", "Whether to multiply the event weights by the MCFM branching ratios", &MEPP2VVPowheg::removebr_, 1, false, false); static SwitchOption interfaceProductionCrossSection (interfaceremovebr, "Yes", "Do not multiply in the branching ratios (default running)", 1); static SwitchOption interfaceIncludeBRs (interfaceremovebr, "No", "Multiply by MCFM branching ratios for comparison/debugging purposes", 0); static Switch interfaceScaleOption ("ScaleOption", "Option for running / fixing EW and QCD factorization & renormalization scales", &MEPP2VVPowheg::scaleopt_, 1, false, false); static SwitchOption interfaceDynamic (interfaceScaleOption, "Dynamic", "QCD factorization & renormalization scales are sqr(pV1+pV2). " "EW scale is (mV1^2+mV2^2)/2 (similar to MCatNLO)", 1); static SwitchOption interfaceFixed (interfaceScaleOption, "Fixed", "QCD factorization fixed to value by FactorizationScaleValue." "EW and QCD renormalization scales fixed by RenormalizationScaleValue.", 2); static Parameter interfaceFactorizationScaleValue ("FactorizationScaleValue", "Value to use for the QCD factorization scale if fixed scales" "have been requested with the ScaleOption interface.", &MEPP2VVPowheg::mu_F_, GeV, 100.0*GeV, 50.0*GeV, 500.0*GeV, true, false, Interface::limited); static Parameter interfaceRenormalizationScaleValue ("RenormalizationScaleValue", "Value to use for the EW and QCD renormalization scales if fixed " "scales have been requested with the ScaleOption interface.", &MEPP2VVPowheg::mu_UV_, GeV, 100.0*GeV, 50.0*GeV, 500.0*GeV, true, false, Interface::limited); static Switch interfaceSpinCorrelations ("SpinCorrelations", "Flag to select leading order spin correlations or a " "calculation taking into account the real NLO effects", &MEPP2VVPowheg::realMESpinCorrelations_, 1, false, false); static SwitchOption interfaceSpinCorrelationsLeadingOrder (interfaceSpinCorrelations, "LeadingOrder", "Decay bosons using a leading order 2->2 calculation of the " "production spin density matrix", 0); static SwitchOption interfaceSpinCorrelationsRealNLO (interfaceSpinCorrelations, "RealNLO", "Decay bosons using a production spin density matrix which " "takes into account the effects of real radiation", 1); static Reference interfaceCoupling ("Coupling", "The object calculating the strong coupling constant", &MEPP2VVPowheg::showerAlphaS_, false, false, true, false, false); static Parameter interfacePower ("Power", "The power for the sampling of the matrix elements", &MEPP2VVPowheg::power_, 2.0, 1.0, 10.0, false, false, Interface::limited); static Parameter interfacePrefactorqqbar ("Prefactorqqbar", "The prefactor for the sampling of the q qbar channel", &MEPP2VVPowheg::preqqbar_, 5.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacePrefactorqg ("Prefactorqg", "The prefactor for the sampling of the q g channel", &MEPP2VVPowheg::preqg_, 3.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacePrefactorgqbar ("Prefactorgqbar", "The prefactor for the sampling of the g qbar channel", &MEPP2VVPowheg::pregqbar_, 3.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacepTMin ("minPt", "The pT cut on hardest emision generation" "2*(1-Beta)*exp(-sqr(intrinsicpT/RMS))/sqr(RMS)", &MEPP2VVPowheg::min_pT_, GeV, 2.*GeV, ZERO, 100000.0*GeV, false, false, Interface::limited); } Energy2 MEPP2VVPowheg::scale() const { // N.B. This scale is the electroweak scale! // It is used in the evaluation of the LO code // in the MEPP2VV base class. This means it // should appear in the denominator of the // NLOweight here and all other LO parts like // the function for the lumi ratio (Lhat). It // should also be used for evaluating any EW // parameters / vertices in the numerator. // The scaleopt_ == 1 "running" option is // chosen to be like the MC@NLO one (it ought // to be more like sHat instead?). return scaleopt_ == 1 ? // 0.5*(meMomenta()[2].m2()+meMomenta()[3].m2()) : sqr(mu_UV_); sHat() : sqr(mu_UV_); } Energy2 MEPP2VVPowheg::mu_F2() const { return scaleopt_ == 1 ? // ((H_.k1r()).m2()+k1r_perp2_lab_+(H_.k2r()).m2()+k2r_perp2_lab_)/2. : sqr(mu_F_); sHat() : sqr(mu_F_); } Energy2 MEPP2VVPowheg::mu_UV2() const { return scaleopt_ == 1 ? // ((H_.k1r()).m2()+k1r_perp2_lab_+(H_.k2r()).m2()+k2r_perp2_lab_)/2. : sqr(mu_UV_); sHat() : sqr(mu_UV_); } void MEPP2VVPowheg::doinit() { MEPP2VV::doinit(); // get the vertices we need // get a pointer to the standard model object in the run static const tcHwSMPtr hwsm = dynamic_ptr_cast(standardModel()); if (!hwsm) throw InitException() << "missing hwsm pointer in MEPP2VVPowheg::doinit()" << Exception::abortnow; // get pointers to all required Vertex objects FFPvertex_ = hwsm->vertexFFP(); FFZvertex_ = hwsm->vertexFFZ(); WWWvertex_ = hwsm->vertexWWW(); FFWvertex_ = hwsm->vertexFFW(); FFGvertex_ = hwsm->vertexFFG(); // get the ckm object Ptr::pointer theCKM=dynamic_ptr_cast::pointer>(SM().CKM()); if(!theCKM) throw InitException() << "MEPP2VVPowheg::doinit() " << "the CKM object must be the Herwig one" << Exception::runerror; unsigned int ix,iy; // get the CKM matrix (unsquared for interference) vector< vector > CKM(theCKM->getUnsquaredMatrix(SM().families())); for(ix=0;ix<3;++ix){for(iy=0;iy<3;++iy){ckm_[ix][iy]=CKM[ix][iy];}} // insert the different prefactors in the vector for easy look up prefactor_.push_back(preqqbar_); prefactor_.push_back(preqg_); prefactor_.push_back(pregqbar_); } int MEPP2VVPowheg::nDim() const { int output = MEPP2VV::nDim(); // See related comment in MEPP2VVPowheg::generateKinematics! if(contrib_>0) output += 2; return output; } bool MEPP2VVPowheg::generateKinematics(const double * r) { // N.B. A fix was made to make theta2 a radiative // variable in r4532. Originally theta2 was take to // be the azimuthal angle coming from the generation // of the Born kinematics inherited from MEPP2VV i.e. // before the change theta2 was a random number between // 0 and 2pi. On changing theta2 was set to be // theta2 = (*(r+3)) * 2.*Constants::pi; // and nDim returned if(contrib_>0) output += 3; // In the months following it was noticed that agreement // with MCFM was per mille at Tevatron energies but got // close to 1 percent for LHC energies (for all VV // processes). After searching back up the svn branch // running 2M events each time, the change was spotted // to occur on r4532. Changing: // if(contrib_>0) output += 3; // in ::nDim() and also, // xt = (*(r +nDim() -3)); // y = (*(r +nDim() -2)) * 2. - 1.; // theta2 = (*(r +nDim() -1)) * 2.*Constants::pi; // did not fix the problem. The following code gives the // same good level of agreement at LHC and TVT: double xt( -999.); double y( -999.); double theta2( -999.); if(contrib_>0) { // Generate the radiative integration variables: xt = (*(r +nDim() -2)); y = (*(r +nDim() -1)) * 2. - 1.; // KH 19th August - next line changed for phi in 0->pi not 0->2pi // theta2 = UseRandom::rnd() * 2.*Constants::pi; theta2 = UseRandom::rnd() *Constants::pi; } // Continue with lo matrix element code: bool output(MEPP2VV::generateKinematics(r)); // Work out the kinematics for the leading order / virtual process // and also get the leading order luminosity function: getKinematics(xt,y,theta2); return output; } double MEPP2VVPowheg::me2() const { double output(0.0); useMe(); output = MEPP2VV::me2(); double mcfm_brs(1.); if(!removebr_) { switch(MEPP2VV::process()) { case 1: // W+(->e+,nu_e) W-(->e-,nu_ebar) (MCFM: 61 [nproc]) mcfm_brs *= 0.109338816; mcfm_brs *= 0.109338816; break; case 2: // W+/-(mu+,nu_mu / mu-,nu_mubar) Z(nu_e,nu_ebar) // (MCFM: 72+77 [nproc]) mcfm_brs *= 0.109338816; mcfm_brs *= 0.06839002; break; case 3: // Z(mu-,mu+) Z(e-,e+) (MCFM: 86 [nproc]) mcfm_brs *= 0.034616433; mcfm_brs *= 0.034616433; mcfm_brs *= 2.; // as identical particle factor 1/2 is now obsolete. break; case 4: // W+(mu+,nu_mu) Z(nu_e,nu_ebar) (MCFM: 72 [nproc]) mcfm_brs *= 0.109338816; mcfm_brs *= 0.06839002; break; case 5: // W-(mu-,nu_mubar) Z(nu_e,nu_ebar) (MCFM: 77 [nproc]) mcfm_brs *= 0.109338816; mcfm_brs *= 0.06839002; break; } } // Store the value of the leading order squared matrix element: lo_me2_ = output; output *= NLOweight(); output *= mcfm_brs; return output; } void MEPP2VVPowheg::getKinematics(double xt, double y, double theta2) { // In this member we want to get the lo_lumi_ as this is a // common denominator in the NLO weight. We want also the // bornVVKinematics object and all of the realVVKinematics // objects needed for the NLO weight. // Check if the W- is first in W+W- production. Already confirmed // mePartonData()[0] is a quark, and mePartonData()[1] is an antiquark. // We assume mePartonData[2] and mePartonData[3] are, respectively, // W+/- Z, W+/- W-/+, or Z Z. bool wminus_first(false); if((mePartonData()[2]->id()==-24)&&(mePartonData()[3]->id()==24)) wminus_first=true; // Now get all data on the LO process needed for the NLO computation: // The +z hadron in the lab: hadron_A_=dynamic_ptr_cast::transient_const_pointer> (lastParticles().first->dataPtr()); // The -z hadron in the lab: hadron_B_=dynamic_ptr_cast::transient_const_pointer> (lastParticles().second->dataPtr()); // Leading order momentum fractions: double xa(lastX1()); // The +z momentum fraction in the lab. double xb(lastX2()); // The -z momentum fraction in the lab. // Particle data for incoming +z & -z QCD particles respectively: ab_ = lastPartons().first ->dataPtr(); // The +z momentum parton in the lab. bb_ = lastPartons().second->dataPtr(); // The -z momentum parton in the lab. // We checked TVT & LHC for all VV channels with 10K events: // lastParticles().first ->momentum().z() is always positive // lastParticles().second->momentum().z() is always negative // lastParticles().first ->momentum().z()*xa=lastPartons().first ->momentum().z() 1 in 10^6 // lastParticles().second->momentum().z()*xb=lastPartons().second->momentum().z() 1 in 10^6 // Set the quark and antiquark data pointers. quark_ = mePartonData()[0]; antiquark_ = mePartonData()[1]; if(quark_->id()<0) swap(quark_,antiquark_); // Now in _our_ calculation we basically define the +z axis as being // given by the direction of the incoming quark for q+qb & q+g processes // and the incoming gluon for g+qbar processes. So now we might need to // flip the values of hadron_A_, hadron_B_, ab_, bb_, xa, xb accordingly: if(ab_->id()!=quark_->id()) { swap(hadron_A_,hadron_B_); swap(ab_,bb_); swap(xa,xb); } // So hadron_A_ is the thing containing a quark (ab_) with momentum frac xa, // hadron_B_ is the thing containing an antiquark (bb_) with momentum frac xb. // Now get the partonic flux for the Born process: lo_lumi_ = hadron_A_->pdf()->xfx(hadron_A_,ab_,scale(),xa)/xa * hadron_B_->pdf()->xfx(hadron_B_,bb_,scale(),xb)/xb; // For W+W- events make sure k1 corresponds to the W+ momentum: if(MEPP2VV::process()==1&&wminus_first) swap(meMomenta()[2],meMomenta()[3]); // Create the object containing all 2->2 __kinematic__ information: B_ = bornVVKinematics(meMomenta(),xa,xb); // We checked that meMomenta()[0] (quark) is in the +z direction and meMomenta()[1] // is in the -z direction (antiquark). // Revert momentum swap in case meMomenta and mePartonData correlation // needs preserving for other things. if(MEPP2VV::process()==1&&wminus_first) swap(meMomenta()[2],meMomenta()[3]); // Check the Born kinematics objects is internally consistent: // B_.sanityCheck(); // If we are going beyond leading order then lets calculate all of // the necessary real emission kinematics. if(contrib_>0) { // Soft limit of the 2->3 real emission kinematics: S_ = realVVKinematics(B_, 1., y, theta2); // Soft-collinear limit of the 2->3 kinematics (emission in +z direction): SCp_ = realVVKinematics(B_, 1., 1., theta2); // Soft-collinear limit of the 2->3 kinematics (emission in -z direction): SCm_ = realVVKinematics(B_, 1.,-1., theta2); // Collinear limit of the 2->3 kinematics (emission in +z direction): Cp_ = realVVKinematics(B_, xt, 1., theta2); // Collinear limit of the 2->3 kinematics (emission in -z direction): Cm_ = realVVKinematics(B_, xt,-1., theta2); // The resolved 2->3 real emission kinematics: H_ = realVVKinematics(B_, xt, y, theta2); // Borrowed from VVhardGenerator (lab momenta of k1,k2): Energy pT(sqrt(H_.pT2_in_lab())); LorentzRotation yzRotation; yzRotation.setRotateX(-atan2(pT/GeV,sqrt(B_.sb())/GeV)); LorentzRotation boostFrompTisZero; boostFrompTisZero.setBoostY(-pT/sqrt(B_.sb()+pT*pT)); LorentzRotation boostFromYisZero; boostFromYisZero.setBoostZ(tanh(B_.Yb())); k1r_perp2_lab_ = (boostFromYisZero*boostFrompTisZero*yzRotation*(H_.k1r())).perp2(); k2r_perp2_lab_ = (boostFromYisZero*boostFrompTisZero*yzRotation*(H_.k2r())).perp2(); // Check all the real kinematics objects are internally consistent: // S_.sanityCheck(); // SCp_.sanityCheck(); // SCm_.sanityCheck(); // Cp_.sanityCheck(); // Cm_.sanityCheck(); // H_.sanityCheck(); } return; } double MEPP2VVPowheg::NLOweight() const { // If only leading order is required return 1: if(contrib_==0) return lo_me()/lo_me2_; // Calculate alpha_S and alpha_S/(2*pi). alphaS_ = nlo_alphaS_opt_==1 ? fixed_alphaS_ : SM().alphaS(mu_UV2()); double alsOn2pi(alphaS_/2./pi); // Particle data objects for the new plus and minus colliding partons. tcPDPtr gluon; gluon = getParticleData(ParticleID::g); // Get the all couplings. gW_ = sqrt(4.0*pi*SM().alphaEM(scale())/SM().sin2ThetaW()); sin2ThetaW_ = SM().sin2ThetaW(); double cosThetaW(sqrt(1.-sin2ThetaW_)); guL_ = gW_/2./cosThetaW*( 1.-4./3.*sin2ThetaW_); gdL_ = gW_/2./cosThetaW*(-1.+2./3.*sin2ThetaW_); guR_ = gW_/2./cosThetaW*( -4./3.*sin2ThetaW_); gdR_ = gW_/2./cosThetaW*( +2./3.*sin2ThetaW_); eZ_ = gW_*cosThetaW; eZ2_ = sqr(eZ_); // MCFM has gwsq = 0.4389585130009 -> gw = 0.662539442600115 // Here we have gW_ = 0.662888 // MCFM has xw = 0.22224653300000 -> sqrt(xw) = 0.471430306 // Here we have 0.222247 // MCFM has esq = 0.097557007645279 -> e = 0.31234117187024679 // Here we have 4.0*pi*SM().alphaEM(sqr(100.*GeV)) = 0.0976596 // If the process is W-Z instead of W+Z we must transform these // couplings as follows, according to NPB 383(1992)3-44 Eq.3.23 if(mePartonData()[2]->id()==-24&&mePartonData()[3]->id()==23) { swap(guL_,gdL_); eZ_ *= -1.; } // Get the CKM entry. Note that this code was debugged // considerably; the call to CKM(particle,particle) // did not appear to work, so we extract the elements // as follows below. The right numbers now appear to // to be associated with the right quarks. double Kij(-999.); // W+Z / W-Z if(abs(mePartonData()[2]->id())==24&&mePartonData()[3]->id()==23) { int up_id(-999),dn_id(-999); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==1) { up_id = abs(quark_->id()); dn_id = abs(antiquark_->id()); } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==0) { up_id = abs(antiquark_->id()); dn_id = abs(quark_->id()); } else { cout << "MEPP2VVPowheg:" << endl; cout << "WZ needs an up and a down type quark as incoming!" << endl; } up_id /= 2; up_id -= 1; dn_id -= 1; dn_id /= 2; Kij = sqrt(SM().CKM(up_id,dn_id)); } // W+W- else if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { int up_ida(abs(quark_->id())/2-1); int up_idb(abs(antiquark_->id())/2-1); Kij = sqrt(std::norm( CKM(up_ida,0)*CKM(up_idb,0) + CKM(up_ida,1)*CKM(up_idb,1) + CKM(up_ida,2)*CKM(up_idb,2))); } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { int dn_ida((abs(quark_->id())-1)/2); int dn_idb((abs(antiquark_->id())-1)/2); Kij = sqrt(std::norm( CKM(0,dn_ida)*CKM(0,dn_idb) + CKM(1,dn_ida)*CKM(1,dn_idb) + CKM(2,dn_ida)*CKM(2,dn_idb))); } else { cout << "MEPP2VVPowheg:" << endl; cout << "WW needs 2 down-type / 2 up-type!" << endl; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { Kij = 2.*sqrt(2.)/gW_; } else { cout << "MEPP2VVPowheg: incompatible final state particles!" << endl; } Fij2_ = sqr(gW_/2./sqrt(2.)*Kij); // Get the leading order matrix element (this is necessary!) M_Born_ = M_Born_WZ(B_); // // Get the regular part of the virtual correction (only needed for sanityCheck()!) // M_V_regular_ = M_V_regular(S_); // // Get the q + qbar real emission matrix element (only needed for sanityCheck()!) // t_u_M_R_qqb_ = t_u_M_R_qqb(H_); // Calculate the integrand double wgt(0.); double wqqb(0.); double wgqb(0.); double wqg(0.); double wqqbvirt(0.); double wqqbcollin(0.); double wqqbreal(0.); double wqgcollin(0.); double wqgreal(0.); double wgqbcollin(0.); double wgqbreal(0.); if(channels_==0||channels_==1) { // q+qb wqqbvirt = Vtilde_universal(S_) + M_V_regular(S_)/lo_me2_; wqqbcollin = alsOn2pi*( Ctilde_Ltilde_qq_on_x(quark_,antiquark_,Cp_) + Ctilde_Ltilde_qq_on_x(quark_,antiquark_,Cm_) ); wqqbreal = alsOn2pi*Rtilde_Ltilde_qqb_on_x(quark_,antiquark_); wqqb = wqqbvirt + wqqbcollin + wqqbreal; } if(channels_==0||channels_==2) { // q+g wqgcollin = alsOn2pi*Ctilde_Ltilde_gq_on_x(quark_,gluon,Cm_); wqgreal = alsOn2pi*Rtilde_Ltilde_qg_on_x(quark_,gluon); wqg = wqgreal + wqgcollin; // g+qb wgqbcollin = alsOn2pi*Ctilde_Ltilde_gq_on_x(gluon,antiquark_,Cp_); wgqbreal = alsOn2pi*Rtilde_Ltilde_gqb_on_x(gluon,antiquark_); wgqb = wgqbreal+wgqbcollin; } // total contribution wgt = 1.+(wqqb+wgqb+wqg); // If restricting to qg, gqb channels then subtract the LO contribution: if(channels_==2) wgt -= 1.; if(!isfinite(wgt)) { cout << "MEPP2VVPowheg:: NLO weight " << "is bad: wgt = " << wgt << endl; cout << "MEPP2VVPowheg sanityCheck invoked!" << endl; cout << ab_->PDGName() << ", " << bb_->PDGName() << ", " << mePartonData()[2]->PDGName() << ", " << mePartonData()[3]->PDGName() << endl; cout << "lo_me2_ - M_Born_ (rel) = " << lo_me2_-M_Born_ << " (" << (lo_me2_-M_Born_)/M_Born_ << ")\n"; cout << "lo_me2_, M_Born_ " << lo_me2_ << ", " << M_Born_ << endl; cout << "xr = " << H_.xr() << " 1-xr = " << 1.-H_.xr() << " y = " << H_.y() << endl; cout << "tkr = " << H_.tkr()/GeV2 << " ukr = " << H_.ukr()/GeV2 << endl; cout << "root(sb) = " << sqrt(B_.sb())/GeV << endl; cout << "sb+tb+ub = " << B_.sb()/GeV2 << " + " << B_.tb()/GeV2 << " + " << B_.ub()/GeV2 << endl; cout << "sqrt(k12) " << sqrt(H_.k12r())/GeV << endl; cout << "sqrt(k22) " << sqrt(H_.k22r())/GeV << endl; cout << "sqr(Kij) " << Kij*Kij << endl; cout << "wqqbvirt " << wqqbvirt << endl; cout << "wqqbcollin " << wqqbcollin << endl; cout << "wqqbreal " << wqqbreal << endl; cout << "wqqb " << wqqb << endl; cout << "wqgcollin " << wqgcollin << endl; cout << "wqgreal " << wqgreal << endl; cout << "wqg " << wqg << endl; cout << "wgqbcollin " << wgqbcollin << endl; cout << "wgqbreal " << wgqbreal << endl; cout << "wgqb " << wgqb << endl; cout << "wgt " << wgt << endl; throw Exception() << "MEPP2VVPowheg:: NLO weight " << "is bad: " << wgt << Exception::eventerror; } return contrib_==1 ? max(0.,wgt) : max(0.,-wgt); } double MEPP2VVPowheg::Lhat_ab(tcPDPtr a, tcPDPtr b, realVVKinematics Kinematics) const { if(!(abs(a->id())<=6||a->id()==21)||!(abs(b->id())<=6||b->id()==21)) cout << "MEPP2VVPowheg::Lhat_ab: Error," << "particle a = " << a->PDGName() << ", " << "particle b = " << b->PDGName() << endl; double nlo_lumi(-999.); double x1(Kinematics.x1r()),x2(Kinematics.x2r()); nlo_lumi = (hadron_A_->pdf()->xfx(hadron_A_,a,mu_F2(),x1)/x1) * (hadron_B_->pdf()->xfx(hadron_B_,b,mu_F2(),x2)/x2); return nlo_lumi / lo_lumi_; } double MEPP2VVPowheg::Vtilde_universal(realVVKinematics S) const { double xbar_y = S.xbar(); double y = S.y(); double eta1b(S.bornVariables().eta1b()); double eta2b(S.bornVariables().eta2b()); Energy2 sb(S.s2r()); return alphaS_/2./pi*CF_ * ( log(sb/mu_F2()) * (3. + 4.*log(eta1b)+4.*log(eta2b)) + 8.*sqr(log(eta1b)) +8.*sqr(log(eta2b)) - 2.*sqr(pi)/3. ) + alphaS_/2./pi*CF_ * ( 8./(1.+y)*log(sqrt(1.-xbar_y)/eta2b) + 8./(1.-y)*log(sqrt(1.-xbar_y)/eta1b) ); } double MEPP2VVPowheg::Ctilde_Ltilde_qq_on_x(tcPDPtr a, tcPDPtr b, realVVKinematics C) const { if(C.y()!= 1.&&C.y()!=-1.) cout << "\nCtilde_qq::y value not allowed."; if(C.y()== 1.&&!(abs(a->id())>0&&abs(a->id())<7)) cout << "\nCtilde_qq::for Cqq^plus a must be a quark! id = " << a->id() << "\n"; if(C.y()==-1.&&!(abs(b->id())>0&&abs(b->id())<7)) cout << "\nCtilde_qq::for Cqq^minus b must be a quark! id = " << b->id() << "\n"; double xt = C.xt(); double x = C.xr(); double etab = C.y() == 1. ? C.bornVariables().eta1b() : C.bornVariables().eta2b() ; Energy2 sb(C.s2r()); if(fabs(1.-xt)<=tiny||fabs(1.-H_.xr())<=tiny) return 0.; return ( ( (1./(1.-xt))*log(sb/mu_F2()/x)+4.*log(etab)/(1.-xt) + 2.*log(1.-xt)/(1.-xt) )*CF_*(1.+sqr(x)) + sqr(etab)*CF_*(1.-x) )*Lhat_ab(a,b,C) / x - ( ( (1./(1.-xt))*log(sb/mu_F2() )+4.*log(etab)/(1.-xt) + 2.*log(1.-xt)/(1.-xt) )*CF_*2. )*Lhat_ab(a,b,S_); } double MEPP2VVPowheg::Ctilde_Ltilde_gq_on_x(tcPDPtr a, tcPDPtr b, realVVKinematics C) const { if(C.y()!= 1.&&C.y()!=-1.) cout << "\nCtilde_gq::y value not allowed."; if(C.y()== 1.&&a->id()!=21) cout << "\nCtilde_gq::for Cgq^plus a must be a gluon! id = " << a->id() << "\n"; if(C.y()==-1.&&b->id()!=21) cout << "\nCtilde_gq::for Cgq^minus b must be a gluon! id = " << b->id() << "\n"; double xt = C.xt(); double x = C.xr(); double etab = C.y() == 1. ? C.bornVariables().eta1b() : C.bornVariables().eta2b() ; Energy2 sb(C.s2r()); return ( ( (1./(1.-xt))*log(sb/mu_F2()/x)+4.*log(etab)/(1.-xt) + 2.*log(1.-xt)/(1.-xt) )*(1.-x)*TR_*(sqr(x)+sqr(1.-x)) + sqr(etab)*TR_*2.*x*(1.-x) )*Lhat_ab(a,b,C) / x; } double MEPP2VVPowheg::Rtilde_Ltilde_qqb_on_x(tcPDPtr a , tcPDPtr b) const { if(!(abs(a->id())<=6||a->id()==21)||!(abs(b->id())<=6||b->id()==21)) cout << "MEPP2VVPowheg::Rtilde_Ltilde_qqb_on_x: Error," << "particle a = " << a->PDGName() << ", " << "particle b = " << b->PDGName() << endl; double xt(H_.xt()); double y(H_.y()); Energy2 s(H_.sr()); Energy2 sCp(Cp_.sr()); Energy2 sCm(Cm_.sr()); Energy2 t_u_M_R_qqb_H (t_u_M_R_qqb(H_ )); Energy2 t_u_M_R_qqb_Cp(t_u_M_R_qqb(Cp_)); Energy2 t_u_M_R_qqb_Cm(t_u_M_R_qqb(Cm_)); // Energy2 t_u_M_R_qqb_H (t_u_M_R_qqb_hel_amp(H_)); // Energy2 t_u_M_R_qqb_Cp(8.*pi*alphaS_*Cp_.sr()/Cp_.xr() // *CF_*(1.+sqr(Cp_.xr()))*lo_me2_); // Energy2 t_u_M_R_qqb_Cm(8.*pi*alphaS_*Cm_.sr()/Cm_.xr() // *CF_*(1.+sqr(Cm_.xr()))*lo_me2_); int config(0); if(fabs(1.-xt)<=tiny||fabs(1.-H_.xr())<=tiny) return 0.; if(fabs(1.-y )<=tiny) { t_u_M_R_qqb_H = t_u_M_R_qqb_Cp ; config = 1; } if(fabs(1.+y )<=tiny) { t_u_M_R_qqb_H = t_u_M_R_qqb_Cm ; config = -1; } if(fabs(H_.tkr()/s)<=tiny) { t_u_M_R_qqb_H = t_u_M_R_qqb_Cp ; config = 1; } if(fabs(H_.ukr()/s)<=tiny) { t_u_M_R_qqb_H = t_u_M_R_qqb_Cm ; config = -1; } if(config== 0) return ( ( (t_u_M_R_qqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qqb_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) + ( (t_u_M_R_qqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qqb_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) ) / lo_me2_ / 8. / pi / alphaS_; else if(config== 1) return ( (t_u_M_R_qqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qqb_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else if(config==-1) return ( (t_u_M_R_qqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qqb_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else throw Exception() << "MEPP2VVPowheg::Rtilde_Ltilde_qqb_on_x\n" << "The configuration is not identified as hard / soft / fwd collinear or bwd collinear." << "config = " << config << "\n" << "xt = " << xt << " 1.-xt = " << 1.-xt << "\n" << "y = " << y << " 1.-y = " << 1.-y << "\n" << Exception::eventerror; } double MEPP2VVPowheg::Rtilde_Ltilde_gqb_on_x(tcPDPtr a , tcPDPtr b) const { if(!(abs(a->id())<=6||a->id()==21)||!(abs(b->id())<=6||b->id()==21)) cout << "MEPP2VVPowheg::Rtilde_Ltilde_gqb_on_x: Error," << "particle a = " << a->PDGName() << ", " << "particle b = " << b->PDGName() << endl; double xt(H_.xt()); double y(H_.y()); Energy2 s(H_.sr()); Energy2 sCp(Cp_.sr()); Energy2 sCm(Cm_.sr()); Energy2 t_u_M_R_gqb_H (t_u_M_R_gqb(H_ )); Energy2 t_u_M_R_gqb_Cp(t_u_M_R_gqb(Cp_)); Energy2 t_u_M_R_gqb_Cm(t_u_M_R_gqb(Cm_)); // Energy2 t_u_M_R_gqb_H (t_u_M_R_gqb_hel_amp(H_)); // Energy2 t_u_M_R_gqb_Cp(8.*pi*alphaS_*Cp_.sr()/Cp_.xr()*(1.-Cp_.xr()) // *TR_*(sqr(Cp_.xr())+sqr(1.-Cp_.xr()))*lo_me2_); // Energy2 t_u_M_R_gqb_Cm(t_u_M_R_gqb(Cm_)); // // Energy2 t_u_M_R_gqb_Cm(t_u_M_R_gqb_hel_amp(Cm_)); int config(0); if(fabs(1.-xt)<=tiny||fabs(1.-H_.xr())<=tiny) return 0.; if(fabs(1.-y )<=tiny) { t_u_M_R_gqb_H = t_u_M_R_gqb_Cp ; config = 1; } if(fabs(1.+y )<=tiny) { t_u_M_R_gqb_H = t_u_M_R_gqb_Cm ; config = -1; } if(fabs(H_.tkr()/s)<=tiny) { t_u_M_R_gqb_H = t_u_M_R_gqb_Cp ; config = 1; } if(fabs(H_.ukr()/s)<=tiny) { t_u_M_R_gqb_H = t_u_M_R_gqb_Cm ; config = -1; } if(config== 0) return ( ( (t_u_M_R_gqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_gqb_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) + ( (t_u_M_R_gqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_gqb_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) ) / lo_me2_ / 8. / pi / alphaS_; else if(config== 1) return ( (t_u_M_R_gqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_gqb_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else if(config==-1) return ( (t_u_M_R_gqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_gqb_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else throw Exception() << "MEPP2VVPowheg::Rtilde_Ltilde_gqb_on_x\n" << "The configuration is not identified as hard / soft / fwd collinear or bwd collinear." << "config = " << config << "\n" << "xt = " << xt << " 1.-xt = " << 1.-xt << "\n" << "y = " << y << " 1.-y = " << 1.-y << "\n" << Exception::eventerror; } double MEPP2VVPowheg::Rtilde_Ltilde_qg_on_x(tcPDPtr a , tcPDPtr b) const { if(!(abs(a->id())<=6||a->id()==21)||!(abs(b->id())<=6||b->id()==21)) cout << "MEPP2VVPowheg::Rtilde_Ltilde_qg_on_x: Error," << "particle a = " << a->PDGName() << ", " << "particle b = " << b->PDGName() << endl; double xt(H_.xt()); double y(H_.y()); Energy2 s(H_.sr()); Energy2 sCp(Cp_.sr()); Energy2 sCm(Cm_.sr()); Energy2 t_u_M_R_qg_H (t_u_M_R_qg(H_ )); Energy2 t_u_M_R_qg_Cp(t_u_M_R_qg(Cp_)); Energy2 t_u_M_R_qg_Cm(t_u_M_R_qg(Cm_)); // Energy2 t_u_M_R_qg_H (t_u_M_R_qg_hel_amp(H_)); // Energy2 t_u_M_R_qg_Cp(t_u_M_R_qg(Cp_)); // // Energy2 t_u_M_R_qg_Cp(t_u_M_R_qg_hel_amp(Cp_)); // Energy2 t_u_M_R_qg_Cm(8.*pi*alphaS_*Cm_.sr()/Cm_.xr()*(1.-Cm_.xr()) // *TR_*(sqr(Cm_.xr())+sqr(1.-Cm_.xr()))*lo_me2_); int config(0); if(fabs(1.-xt)<=tiny||fabs(1.-H_.xr())<=tiny) return 0.; if(fabs(1.-y )<=tiny) { t_u_M_R_qg_H = t_u_M_R_qg_Cp ; config = 1; } if(fabs(1.+y )<=tiny) { t_u_M_R_qg_H = t_u_M_R_qg_Cm ; config = -1; } if(fabs(H_.tkr()/s)<=tiny) { t_u_M_R_qg_H = t_u_M_R_qg_Cp ; config = 1; } if(fabs(H_.ukr()/s)<=tiny) { t_u_M_R_qg_H = t_u_M_R_qg_Cm ; config = -1; } if(config== 0) return ( ( (t_u_M_R_qg_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qg_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) + ( (t_u_M_R_qg_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qg_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) ) / lo_me2_ / 8. / pi / alphaS_; else if(config== 1) return ( (t_u_M_R_qg_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qg_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else if(config==-1) return ( (t_u_M_R_qg_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qg_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else throw Exception() << "MEPP2VVPowheg::Rtilde_Ltilde_qg_on_x\n" << "The configuration is not identified as hard / soft / fwd collinear or bwd collinear." << "config = " << config << "\n" << "xt = " << xt << " 1.-xt = " << 1.-xt << "\n" << "y = " << y << " 1.-y = " << 1.-y << "\n" << Exception::eventerror; } /***************************************************************************/ // The following three functions are identically \tilde{I}_{4,t}, // \tilde{I}_{3,WZ} and \tilde{I}_{3,W} given in Eqs. B.8,B.9,B.10 // of NPB 383(1992)3-44, respectively. They are related to / derived // from the loop integrals in Eqs. A.3, A.5 and A.8 of the same paper. InvEnergy4 TildeI4t(Energy2 s, Energy2 t, Energy2 mW2, Energy2 mZ2); InvEnergy2 TildeI3WZ(Energy2 s, Energy2 mW2, Energy2 mZ2, double beta); InvEnergy2 TildeI3W(Energy2 s, Energy2 t, Energy2 mW2); /***************************************************************************/ // The following six functions are identically I_{dd}^{(1)}, I_{ud}^{(1)}, // I_{uu}^{(1)}, F_{u}^{(1)}, F_{d}^{(1)}, H^{(1)} from Eqs. B.4, B.5, B.3, // B.3, B.6, B.7 of NPB 383(1992)3-44, respectively. They make up the // one-loop matrix element. Ixx functions correspond to the graphs // with no TGC, Fx functions are due to non-TGC graphs interfering // with TGC graphs, while the H function is due purely to TGC graphs. double Idd1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta); double Iud1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta); double Iuu1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta); Energy2 Fu1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta); Energy2 Fd1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta); Energy4 H1 (Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); /***************************************************************************/ // M_V_Regular is the regular part of the one-loop matrix element // exactly as defined in Eqs. B.1 and B.2 of of NPB 383(1992)3-44. double MEPP2VVPowheg::M_V_regular(realVVKinematics S) const { Energy2 s(S.bornVariables().sb()); Energy2 t(S.bornVariables().tb()); Energy2 u(S.bornVariables().ub()); Energy2 mW2(S.k12r()); // N.B. the diboson masses are preserved in getting Energy2 mZ2(S.k22r()); // the 2->2 from the 2->3 kinematics. double beta(S.betaxr()); // N.B. for x=1 \beta_x=\beta in NPB 383(1992)3-44. double cosThetaW(sqrt(1.-sin2ThetaW_)); double eZ2(eZ2_); double eZ(eZ_); double gdL(gdL_); double guL(guL_); double gdR(gdR_); double guR(guR_); // W+W- if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { double e2(sqr(gW_)*sin2ThetaW_); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s-mW2)/Fij2_ * (e2*e2/s/s*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s/(s-mW2/sqr(cosThetaW))) +sqr( eZ*(guL-guR)/2./e2*s/(s-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s-mW2) * (gW_*gW_*e2/4./s *( 2./3.+2.*eZ*guL/2./e2*s/(s-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } gdL = gW_/sqrt(2.); guL = 0.; } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s-mW2)/Fij2_ * (e2*e2/s/s*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s/(s-mW2/sqr(cosThetaW))) +sqr( eZ*(gdL-gdR)/2./e2*s/(s-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s-mW2) * (gW_*gW_*e2/4./s *(-1./3.+2.*eZ*gdL/2./e2*s/(s-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } guL = gW_/sqrt(2.); gdL = 0.; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { eZ = 0.; eZ2 = 0.; double gV2,gA2; gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL; else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL; else { cout << "MEPP2VVPowheg:" << endl; cout << "ZZ needs 2 down-type / 2 up-type!" << endl; } } return 4.*pi*alphaS_*Fij2_*CF_*(1./sqr(4.*pi))/NC_ * ( gdL*gdL*Idd1(s,t,u,mW2,mZ2,beta) + gdL*guL*Iud1(s,t,u,mW2,mZ2,beta) + guL*guL*Iuu1(s,t,u,mW2,mZ2,beta) - eZ/(s-mW2) * ( gdL*Fd1(s,t,u,mW2,mZ2,beta) - guL*Fu1(s,t,u,mW2,mZ2,beta) ) + eZ2/sqr(s-mW2) * H1(s,t,u,mW2,mZ2) ); } /***************************************************************************/ InvEnergy4 TildeI4t(Energy2 s, Energy2 t, Energy2 mW2, Energy2 mZ2) { double sqrBrackets; sqrBrackets = ( sqr(log(-t/mW2))/2.+log(-t/mW2)*log(-t/mZ2)/2. - 2.*log(-t/mW2)*log((mW2-t)/mW2)-2.*ReLi2(t/mW2) ); swap(mW2,mZ2); sqrBrackets+= ( sqr(log(-t/mW2))/2.+log(-t/mW2)*log(-t/mZ2)/2. - 2.*log(-t/mW2)*log((mW2-t)/mW2)-2.*ReLi2(t/mW2) ); swap(mW2,mZ2); return sqrBrackets/s/t; } InvEnergy2 TildeI3WZ(Energy2 s, Energy2 mW2, Energy2 mZ2, double beta) { Energy2 sig(mZ2+mW2); Energy2 del(mZ2-mW2); double sqrBrackets ; sqrBrackets = ( ReLi2(2.*mW2/(sig-del*(del/s+beta))) + ReLi2((1.-del/s+beta)/2.) + sqr(log((1.-del/s+beta)/2.))/2. + log((1.-del/s-beta)/2.)*log((1.+del/s-beta)/2.) ); beta *= -1; sqrBrackets -= ( ReLi2(2.*mW2/(sig-del*(del/s+beta))) + ReLi2((1.-del/s+beta)/2.) + sqr(log((1.-del/s+beta)/2.))/2. + log((1.-del/s-beta)/2.)*log((1.+del/s-beta)/2.) ); beta *= -1; swap(mW2,mZ2); del *= -1.; sqrBrackets += ( ReLi2(2.*mW2/(sig-del*(del/s+beta))) + ReLi2((1.-del/s+beta)/2.) + sqr(log((1.-del/s+beta)/2.))/2. + log((1.-del/s-beta)/2.)*log((1.+del/s-beta)/2.) ); swap(mW2,mZ2); del *= -1.; beta *= -1; swap(mW2,mZ2); del *= -1.; sqrBrackets -= ( ReLi2(2.*mW2/(sig-del*(del/s+beta))) + ReLi2((1.-del/s+beta)/2.) + sqr(log((1.-del/s+beta)/2.))/2. + log((1.-del/s-beta)/2.)*log((1.+del/s-beta)/2.) ); beta *= -1; swap(mW2,mZ2); del *= -1.; return sqrBrackets/s/beta; } InvEnergy2 TildeI3W(Energy2 s, Energy2 t, Energy2 mW2) { return 1./(mW2-t)*(sqr(log(mW2/s))/2.-sqr(log(-t/s))/2.-sqr(pi)/2.); } /***************************************************************************/ double Idd1(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) { Energy2 sig(mZ2+mW2); Energy2 del(mZ2-mW2); double Val(0.); Val += 2.*(22.*t*t+t*(19.*s-18.*sig)+18.*mW2*mZ2)/t/t - 8.*(u*t+2*s*sig)/mW2/mZ2 - 2.*sqr(t-u)/t/s/sqr(beta); Val += +( 2.*(8.*t*t+4.*t*(s-3.*sig)+4*sqr(sig)-5.*s*sig+s*s)/t/s/sqr(beta) + 4.*(t*(3.*u+s)-3.*mW2*mZ2)/t/t + 6.*(t+u)*sqr(t-u)/t/s/s/sqr(sqr(beta)) )*log(-t/s); Val += +( ( 8.*t*t*(-2.*s+del)+8.*t*(-s*s+3.*s*sig-2.*del*sig) - 2.*(s-sig)*(s*s-4.*s*sig+3.*del*sig) )/t/s/s/beta/beta + 16.*s*(t-mZ2)/(t*(u+s)-mW2*mZ2) + 2.*(4.*t*t+t*(10.*s-3.*mZ2-9.*mW2)+12.*mW2*mZ2)/t/t -6.*(s-del)*(t+u)*sqr(t-u)/t/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( - ( 4.*t*t*(2.*sig-3.*s) - 4.*t*(s-sig)*(2.*s-3.*sig) - 2.*(s-2.*sig)*sqr(s-sig) )/t/s/beta/beta + ( 4.*sig*t-3.*s*s+4.*s*sig - 4.*(mW2*mW2+mZ2*mZ2) )/t - 3.*sqr(t*t-u*u)/t/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += +( 4.*(t*u+2.*s*sig)/3./mW2/mZ2 - 4.*(t-2.*u)/3./t )*pi*pi; Val += -( 4.*s*(t*u-2.*mW2*mZ2)/t )*TildeI4t(s,t,mW2,mZ2); Val += ( 8.*(t-mW2)*(u*t-2.*mW2*mZ2)/t/t )*TildeI3W(s,t,mW2); swap(mW2,mZ2); del *= -1; Val += 2.*(22.*t*t+t*(19.*s-18.*sig)+18.*mW2*mZ2)/t/t - 8.*(u*t+2*s*sig)/mW2/mZ2 - 2.*sqr(t-u)/t/s/sqr(beta); Val += +( 2.*(8.*t*t+4.*t*(s-3.*sig)+4*sqr(sig)-5.*s*sig+s*s)/t/s/sqr(beta) + 4.*(t*(3.*u+s)-3.*mW2*mZ2)/t/t + 6.*(t+u)*sqr(t-u)/t/s/s/sqr(sqr(beta)) )*log(-t/s); Val += +( ( 8.*t*t*(-2.*s+del)+8.*t*(-s*s+3.*s*sig-2.*del*sig) - 2.*(s-sig)*(s*s-4.*s*sig+3.*del*sig) )/t/s/s/beta/beta + 16.*s*(t-mZ2)/(t*(u+s)-mW2*mZ2) + 2.*(4.*t*t+t*(10.*s-3.*mZ2-9.*mW2)+12.*mW2*mZ2)/t/t -6.*(s-del)*(t+u)*sqr(t-u)/t/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( - ( 4.*t*t*(2.*sig-3.*s) - 4.*t*(s-sig)*(2.*s-3.*sig) - 2.*(s-2.*sig)*sqr(s-sig) )/t/s/beta/beta + ( 4.*sig*t-3.*s*s+4.*s*sig - 4.*(mW2*mW2+mZ2*mZ2) )/t - 3.*sqr(t*t-u*u)/t/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += +( 4.*(t*u+2.*s*sig)/3./mW2/mZ2 - 4.*(t-2.*u)/3./t )*pi*pi; Val += -( 4.*s*(t*u-2.*mW2*mZ2)/t )*TildeI4t(s,t,mW2,mZ2); Val += ( 8.*(t-mW2)*(u*t-2.*mW2*mZ2)/t/t )*TildeI3W(s,t,mW2); swap(mW2,mZ2); del *= -1; return Val; } /***************************************************************************/ double Iud1(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) { Energy2 sig(mZ2+mW2); Energy2 del(mZ2-mW2); double Val(0.); Val += 2.*(4.*t*t+t*(9.*s-4.*sig)-18.*s*sig)/t/u + 8.*(t*u+2.*s*sig)/mW2/mZ2 + 4.*s*s*(2.*t-sig)/u/(mW2*mZ2-t*(u+s)) - 2.*sqr(t-u)/u/s/sqr(beta); Val += ( 2.*(8.*t*t-4.*t*(s+3.*sig)-(s-sig)*(3.*s+4.*sig))/u/s/sqr(beta) + 6.*(t+u)*sqr(t-u)/u/s/s/sqr(sqr(beta)) - 12.*s*(t-sig)/t/u )*log(-t/s); Val += ( (2./u/s/s/sqr(beta))*( 4.*t*t*(-2.*s+del) + 4.*t*(s*s+s*(mZ2+5.*mW2)-2.*sig*del) + (s-sig)*(3.*s*s+8.*mW2*s-3.*sig*del) ) + (2.*t*(18.*s+3.*mW2+mZ2)-24.*s*sig)/t/u - 8.*s*(2.*t*t-t*(3.*s+4.*mZ2+2.*mW2)+2.*mZ2*(s+sig)) /u/(mW2*mZ2-t*(u+s)) - 8.*s*s*t*(2.*t-sig)*(t-mZ2)/u/sqr(mW2*mZ2-t*(u+s)) + 6.*(s-del)*(s-sig)*sqr(t-u)/u/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( -2.*(2.*t*t*(2.*sig-3.*s)+6.*sig*t*(s-sig)+sqr(s-sig)*(s+2.*sig)) /u/s/sqr(beta) +3.*s*(4.*t-4.*sig-s)/u -3.*sqr(s-sig)*sqr(t-u)/u/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += ( 4.*(u+4.*s)/3./u - 4.*(u*t+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += -( 16.*s*(t-sig)*(t-mW2)/t/u )*TildeI3W(s,t,mW2); Val += ( 8.*s*s*(t-sig)/u )*TildeI4t(s,t,mW2,mZ2); swap(t,u); Val += 2.*(4.*t*t+t*(9.*s-4.*sig)-18.*s*sig)/t/u + 8.*(t*u+2.*s*sig)/mW2/mZ2 + 4.*s*s*(2.*t-sig)/u/(mW2*mZ2-t*(u+s)) - 2.*sqr(t-u)/u/s/sqr(beta); Val += ( 2.*(8.*t*t-4.*t*(s+3.*sig)-(s-sig)*(3.*s+4.*sig))/u/s/sqr(beta) + 6.*(t+u)*sqr(t-u)/u/s/s/sqr(sqr(beta)) - 12.*s*(t-sig)/t/u )*log(-t/s); Val += ( (2./u/s/s/sqr(beta))*( 4.*t*t*(-2.*s+del) + 4.*t*(s*s+s*(mZ2+5.*mW2)-2.*sig*del) + (s-sig)*(3.*s*s+8.*mW2*s-3.*sig*del) ) + (2.*t*(18.*s+3.*mW2+mZ2)-24.*s*sig)/t/u - 8.*s*(2.*t*t-t*(3.*s+4.*mZ2+2.*mW2)+2.*mZ2*(s+sig)) /u/(mW2*mZ2-t*(u+s)) - 8.*s*s*t*(2.*t-sig)*(t-mZ2)/u/sqr(mW2*mZ2-t*(u+s)) + 6.*(s-del)*(s-sig)*sqr(t-u)/u/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( -2.*(2.*t*t*(2.*sig-3.*s)+6.*sig*t*(s-sig)+sqr(s-sig)*(s+2.*sig)) /u/s/sqr(beta) +3.*s*(4.*t-4.*sig-s)/u -3.*sqr(s-sig)*sqr(t-u)/u/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += ( 4.*(u+4.*s)/3./u - 4.*(u*t+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += -( 16.*s*(t-sig)*(t-mW2)/t/u )*TildeI3W(s,t,mW2); Val += ( 8.*s*s*(t-sig)/u )*TildeI4t(s,t,mW2,mZ2); swap(t,u); swap(mW2,mZ2); del *= -1; Val += 2.*(4.*t*t+t*(9.*s-4.*sig)-18.*s*sig)/t/u + 8.*(t*u+2.*s*sig)/mW2/mZ2 + 4.*s*s*(2.*t-sig)/u/(mW2*mZ2-t*(u+s)) - 2.*sqr(t-u)/u/s/sqr(beta); Val += ( 2.*(8.*t*t-4.*t*(s+3.*sig)-(s-sig)*(3.*s+4.*sig))/u/s/sqr(beta) + 6.*(t+u)*sqr(t-u)/u/s/s/sqr(sqr(beta)) - 12.*s*(t-sig)/t/u )*log(-t/s); Val += ( (2./u/s/s/sqr(beta))*( 4.*t*t*(-2.*s+del) + 4.*t*(s*s+s*(mZ2+5.*mW2)-2.*sig*del) + (s-sig)*(3.*s*s+8.*mW2*s-3.*sig*del) ) + (2.*t*(18.*s+3.*mW2+mZ2)-24.*s*sig)/t/u - 8.*s*(2.*t*t-t*(3.*s+4.*mZ2+2.*mW2)+2.*mZ2*(s+sig)) /u/(mW2*mZ2-t*(u+s)) - 8.*s*s*t*(2.*t-sig)*(t-mZ2)/u/sqr(mW2*mZ2-t*(u+s)) + 6.*(s-del)*(s-sig)*sqr(t-u)/u/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( -2.*(2.*t*t*(2.*sig-3.*s)+6.*sig*t*(s-sig)+sqr(s-sig)*(s+2.*sig)) /u/s/sqr(beta) +3.*s*(4.*t-4.*sig-s)/u -3.*sqr(s-sig)*sqr(t-u)/u/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += ( 4.*(u+4.*s)/3./u - 4.*(u*t+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += -( 16.*s*(t-sig)*(t-mW2)/t/u )*TildeI3W(s,t,mW2); Val += ( 8.*s*s*(t-sig)/u )*TildeI4t(s,t,mW2,mZ2); swap(mW2,mZ2); del *= -1; swap(t,u); swap(mW2,mZ2); del *= -1; Val += 2.*(4.*t*t+t*(9.*s-4.*sig)-18.*s*sig)/t/u + 8.*(t*u+2.*s*sig)/mW2/mZ2 + 4.*s*s*(2.*t-sig)/u/(mW2*mZ2-t*(u+s)) - 2.*sqr(t-u)/u/s/sqr(beta); Val += ( 2.*(8.*t*t-4.*t*(s+3.*sig)-(s-sig)*(3.*s+4.*sig))/u/s/sqr(beta) + 6.*(t+u)*sqr(t-u)/u/s/s/sqr(sqr(beta)) - 12.*s*(t-sig)/t/u )*log(-t/s); Val += ( (2./u/s/s/sqr(beta))*( 4.*t*t*(-2.*s+del) + 4.*t*(s*s+s*(mZ2+5.*mW2)-2.*sig*del) + (s-sig)*(3.*s*s+8.*mW2*s-3.*sig*del) ) + (2.*t*(18.*s+3.*mW2+mZ2)-24.*s*sig)/t/u - 8.*s*(2.*t*t-t*(3.*s+4.*mZ2+2.*mW2)+2.*mZ2*(s+sig)) /u/(mW2*mZ2-t*(u+s)) - 8.*s*s*t*(2.*t-sig)*(t-mZ2)/u/sqr(mW2*mZ2-t*(u+s)) + 6.*(s-del)*(s-sig)*sqr(t-u)/u/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( -2.*(2.*t*t*(2.*sig-3.*s)+6.*sig*t*(s-sig)+sqr(s-sig)*(s+2.*sig)) /u/s/sqr(beta) +3.*s*(4.*t-4.*sig-s)/u -3.*sqr(s-sig)*sqr(t-u)/u/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += ( 4.*(u+4.*s)/3./u - 4.*(u*t+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += -( 16.*s*(t-sig)*(t-mW2)/t/u )*TildeI3W(s,t,mW2); Val += ( 8.*s*s*(t-sig)/u )*TildeI4t(s,t,mW2,mZ2); swap(t,u); swap(mW2,mZ2); del *= -1; return Val; } /***************************************************************************/ double Iuu1(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) { double Val(Idd1(s,u,t,mW2,mZ2,beta)); return Val; } /***************************************************************************/ Energy2 Fd1 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) { Energy2 sig(mZ2+mW2); Energy2 del(mZ2-mW2); Energy2 Val(0.*GeV2); Val += 4.*(17.*t*t+t*(11.*s-13.*sig)+17.*(s*sig+mW2*mZ2))/t + 16.*(s-sig)*(t*u+2.*s*sig)/mW2/mZ2 + 4*s*s*(2.*t-sig)/(t*(u+s)-mW2*mZ2); Val += ( 8.*(t-u)/sqr(beta) - 4.*(3.*t*t-t*(s+3.*sig)+3.*(s*sig+mW2*mZ2))/t )*log(-t/s); Val += ( 8.*(t*t-t*(2.*s+3.*mW2+mZ2)+3.*(s*sig+mW2*mZ2))/t + 8.*s*(t*(3.*s+2.*sig)-2.*mZ2*(s+sig))/(t*(u+s)-mW2*mZ2) + 8.*s*s*t*(2.*t-sig)*(t-mZ2)/sqr(t*(u+s)-mW2*mZ2) - 8.*(s-del)*(t-u)/s/sqr(beta) )*log(-t/mW2); Val += ( 4.*(s-sig)*(t-u)/sqr(beta) + 4.*(sig-3.*s)*t + 4.*(4.*s*sig-mZ2*mZ2-mW2*mW2) )*TildeI3WZ(s,mW2,mZ2,beta); Val += -( 8.*(3.*t*t+2.*t*(2.*s-sig)+2.*(s*sig+mW2*mZ2))/3./t + 8.*(s-sig)*(t*u+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += ( 4.*(s*t*t-s*(s+sig)*t+2.*s*(s*sig+mW2*mZ2)) )*TildeI4t(s,t,mW2,mZ2); Val += -( 8.*(t-mW2)*(t*t-t*(s+sig)+2.*(s*sig+mW2*mZ2))/t )*TildeI3W(s,t,mW2); swap(mW2,mZ2); del *= -1; Val += 4.*(17.*t*t+t*(11.*s-13.*sig)+17.*(s*sig+mW2*mZ2))/t + 16.*(s-sig)*(t*u+2.*s*sig)/mW2/mZ2 + 4*s*s*(2.*t-sig)/(t*(u+s)-mW2*mZ2); Val += ( 8.*(t-u)/sqr(beta) - 4.*(3.*t*t-t*(s+3.*sig)+3.*(s*sig+mW2*mZ2))/t )*log(-t/s); Val += ( 8.*(t*t-t*(2.*s+3.*mW2+mZ2)+3.*(s*sig+mW2*mZ2))/t + 8.*s*(t*(3.*s+2.*sig)-2.*mZ2*(s+sig))/(t*(u+s)-mW2*mZ2) + 8.*s*s*t*(2.*t-sig)*(t-mZ2)/sqr(t*(u+s)-mW2*mZ2) - 8.*(s-del)*(t-u)/s/sqr(beta) )*log(-t/mW2); Val += ( 4.*(s-sig)*(t-u)/sqr(beta) + 4.*(sig-3.*s)*t + 4.*(4.*s*sig-mZ2*mZ2-mW2*mW2) )*TildeI3WZ(s,mW2,mZ2,beta); Val += -( 8.*(3.*t*t+2.*t*(2.*s-sig)+2.*(s*sig+mW2*mZ2))/3./t + 8.*(s-sig)*(t*u+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += ( 4.*(s*t*t-s*(s+sig)*t+2.*s*(s*sig+mW2*mZ2)) )*TildeI4t(s,t,mW2,mZ2); Val += -( 8.*(t-mW2)*(t*t-t*(s+sig)+2.*(s*sig+mW2*mZ2))/t )*TildeI3W(s,t,mW2); swap(mW2,mZ2); del *= -1; return Val; } /***************************************************************************/ Energy2 Fu1 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) { Energy2 Val(Fd1(s,u,t,mW2,mZ2,beta)); return Val; } /***************************************************************************/ Energy4 H1 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { Energy2 sig(mZ2+mW2); Energy4 Val(0.*GeV2*GeV2); Val = 8.*t*t+8.*t*(s-sig)+s*s+6.*s*sig+mZ2*mZ2+10.*mW2*mZ2+mW2*mW2 - sqr(s-sig)*(t*u+2.*s*sig)/mW2/mZ2; Val *= ( 16.-8.*pi*pi/3.); return Val; } Energy2 t_u_Rdd(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1 , Energy2 q2, Energy2 mW2, Energy2 mZ2); Energy2 t_u_Rud(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1 , Energy2 q2, Energy2 q1h, Energy2 q2h, Energy2 mW2, Energy2 mZ2); Energy2 t_u_Ruu(Energy2 s , Energy2 tk , Energy2 uk, Energy2 q1h, Energy2 q2h, Energy2 mW2, Energy2 mZ2); Energy4 t_u_RZds(Energy2 s ,Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2,Energy2 mW2, Energy2 mZ2); Energy4 t_u_RZda(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2); Energy4 t_u_RZd(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1 , Energy2 q2 , Energy2 s2 , Energy2 mW2, Energy2 mZ2); Energy4 t_u_RZu(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1h, Energy2 q2h, Energy2 s2 , Energy2 mW2, Energy2 mZ2); Energy6 t_u_RZs(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2); Energy6 t_u_RZa(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2); Energy6 t_u_RZ(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2 , Energy2 mW2, Energy2 mZ2); /***************************************************************************/ // t_u_M_R_qqb is the real emission q + qb -> n + g matrix element // exactly as defined in Eqs. C.1 of NPB 383(1992)3-44, multiplied by // tk * uk! Energy2 MEPP2VVPowheg::t_u_M_R_qqb(realVVKinematics R) const { // First the Born variables: Energy2 s2(R.s2r()); Energy2 mW2(R.k12r()); Energy2 mZ2(R.k22r()); // Then the rest: Energy2 s(R.sr()); Energy2 tk(R.tkr()); Energy2 uk(R.ukr()); Energy2 q1(R.q1r()); Energy2 q2(R.q2r()); Energy2 q1h(R.q1hatr()); Energy2 q2h(R.q2hatr()); double cosThetaW(sqrt(1.-sin2ThetaW_)); double eZ2(eZ2_); double eZ(eZ_); double gdL(gdL_); double guL(guL_); double gdR(gdR_); double guR(guR_); // W+W- if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { double e2(sqr(gW_)*sin2ThetaW_); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(guL-guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *( 2./3.+2.*eZ*guL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } gdL = gW_/sqrt(2.); guL = 0.; } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(gdL-gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *(-1./3.+2.*eZ*gdL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } guL = gW_/sqrt(2.); gdL = 0.; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { eZ = 0.; eZ2 = 0.; double gV2,gA2; gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL; else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL; else { cout << "MEPP2VVPowheg:" << endl; cout << "ZZ needs 2 down-type / 2 up-type!" << endl; } } return -2.*pi*alphaS_*Fij2_*CF_/NC_ * ( gdL*gdL*t_u_Rdd(s,tk,uk,q1,q2,mW2,mZ2) + 2.*gdL*guL*t_u_Rud(s,tk,uk,q1,q2,q1h,q2h,mW2,mZ2) + guL*guL*t_u_Ruu(s,tk,uk,q1h,q2h,mW2,mZ2) - 2.*eZ/(s2-mW2) * ( gdL * t_u_RZd(s,tk,uk,q1 ,q2 ,s2,mW2,mZ2) - guL * t_u_RZu(s,tk,uk,q1h,q2h,s2,mW2,mZ2) ) + eZ2/sqr(s2-mW2) *t_u_RZ(s,tk,uk,q1,q2,s2,mW2,mZ2) ); } Energy2 t_u_Rdd(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1,Energy2 q2, Energy2 mW2, Energy2 mZ2) { Energy2 Val(0.*GeV2); Val += 4.*(q2*(uk+2.*s+q2)+q1*(s+q1))/mW2/mZ2*uk + 16.*(uk+s)/q2*uk - 4.*(2.*uk+4.*s+q2)/mW2*uk - 4.*(2.*uk+5.*s+q2+2.*q1-mW2)/mZ2*uk + 4.*q1*s*(s+q1)/mW2/mZ2 + 16.*s*(s+q2-mZ2-mW2)/q1 - 4.*s*(4.*s+q2+q1)/mW2 + 16.*mW2*mZ2*s/q1/q2 + 4.*s + 16.*mZ2*(tk-2.*mW2)/q1/q2/q2*tk*uk + 16.*(2.*mZ2+mW2-tk)/q1/q2*tk*uk + 16.*mW2*(s-mZ2-mW2)/q1/q2*uk + 16.*mZ2*(q1-2.*mW2)/q2/q2*uk + 32.*mW2*mW2*mZ2/q1/q2/q2*uk + 16.*mW2/q1*uk + 4.*uk + 8./q2*tk*uk + 4.*q1/mW2/mZ2*tk*uk - 24./q1*tk*uk - 4./mW2*tk*uk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); Val += 4.*(q2*(uk+2.*s+q2)+q1*(s+q1))/mW2/mZ2*uk + 16.*(uk+s)/q2*uk - 4.*(2.*uk+4.*s+q2)/mW2*uk - 4.*(2.*uk+5.*s+q2+2.*q1-mW2)/mZ2*uk + 4.*q1*s*(s+q1)/mW2/mZ2 + 16.*s*(s+q2-mZ2-mW2)/q1 - 4.*s*(4.*s+q2+q1)/mW2 + 16.*mW2*mZ2*s/q1/q2 + 4.*s + 16.*mZ2*(tk-2.*mW2)/q1/q2/q2*tk*uk + 16.*(2.*mZ2+mW2-tk)/q1/q2*tk*uk + 16.*mW2*(s-mZ2-mW2)/q1/q2*uk + 16.*mZ2*(q1-2.*mW2)/q2/q2*uk + 32.*mW2*mW2*mZ2/q1/q2/q2*uk + 16.*mW2/q1*uk + 4.*uk + 8./q2*tk*uk + 4.*q1/mW2/mZ2*tk*uk - 24./q1*tk*uk - 4./mW2*tk*uk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); return Val; } Energy2 t_u_Rud(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1,Energy2 q2, Energy2 q1h,Energy2 q2h,Energy2 mW2, Energy2 mZ2) { Energy2 Val(0.*GeV2); Val += (uk*s*(uk+3.*s+q1h)+s*s*(s+mZ2)-(s+uk)*(2.*mZ2*s+3.*mW2*s+mW2*q1h) ) * 8./q1/q2h/q2*uk - (uk*(uk+3.*s+q1h-mW2)-(q2+s)*(q2-s)+s*(q2-mW2)+q1h*(q2-mW2)+mW2*q2 ) * 4.*s/mZ2/q1/q2h*uk - 4.*((s+uk+q2h-2.*mZ2)*(s+q1h-mZ2)-mZ2*q1)/mW2/q2*uk + 4.*(2.*s*uk+2.*mW2*uk+5.*s*s+2.*q1h*s-2.*mZ2*s)/q1/q2h*uk + 4.*(2.*s*uk-s*s-2.*q1h*s+2.*mW2*s+2.*mW2*q1h)/q1/q2h/q2*tk*uk + ((2.*uk+s)*(s+q1h)+s*(q2+q2h)+2.*q2*(s+q2h)-q1*s+q1*q2+q1h*q2h ) /mW2/mZ2*uk + 8.*s*(uk-q1h+mZ2)/q1/q2*uk + 4.*s*(-uk+s-q2+q1+q1h)/mZ2/q2h*uk + 4.*s*(-uk-q2+q1h)/mZ2/q1*uk + 8.*(mZ2*uk-s*s+mW2*s-2.*mZ2*q1-2.*mZ2*q1h)/q2h/q2*uk + 2.*(-uk-9.*s-4.*q2-5.*q2h-3.*q1-4.*q1h+8.*mZ2)/mW2*uk + 2.*(-4.*uk+3.*s+5.*q1+4.*q1h)/q2h*uk + 2.*(s*tk+q2*tk+s*s-q2*q2+q1h*q2)/mW2/mZ2*tk - 8.*s*(tk+s+q1h)/mW2/q2*tk + 2.*(-tk+3.*s+q2-q1h)/mW2*tk - 8.*s*s*s/q1h/q2 - 2.*s*q2*(s+q2)/mW2/mZ2 + 2.*s*(2.*s+q2)/mZ2 + 2.*s*(2.*s+q2)/mW2 - 16.*s*s/q1h - 2.*s - 16.*s*s/q1h/q2*tk - 8.*s/q2*tk - 16.*s/q1h*tk + 6.*s/mZ2*tk + 4.*s/q1*uk + 4.*s/mZ2*uk + 12.*uk + 4.*s*(tk+q1h-mW2)/mZ2/q1/q2h*tk*uk + 2.*(s+4.*q1+5.*q1h-4.*mZ2)/q2*uk - 4.*s*s*s/q1h/q1/q2h/q2*tk*uk - 4.*s*s/q1h/q2h/q2*tk*uk - 4.*s*s/q1h/q1/q2*tk*uk + 8.*s*s/mW2/q1h/q2*tk*uk - 4.*s*s/q1h/q1/q2h*tk*uk + 4.*(s+mZ2)/mW2/q2*tk*uk - 4.*s/q1h/q2h*tk*uk - 4.*s/q1h/q1*tk*uk + 12.*s/mW2/q1h*tk*uk - (s+4.*q2)/mW2/mZ2*tk*uk - 4.*(s+2.*mZ2)/q2h/q2*tk*uk - 4.*(3.*s+2.*q1h)/q1/q2*tk*uk - 8.*mW2/q1/q2h*tk*uk + 8./q2h*tk*uk + 8./q1*tk*uk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); swap(q1h,q2h); // Note this swap is done in accordance with MC@NLO. // It is not in NPB 383(1992)3-44 Eq.C.4! Val += (uk*s*(uk+3.*s+q1h)+s*s*(s+mZ2)-(s+uk)*(2.*mZ2*s+3.*mW2*s+mW2*q1h) ) * 8./q1/q2h/q2*uk - (uk*(uk+3.*s+q1h-mW2)-(q2+s)*(q2-s)+s*(q2-mW2)+q1h*(q2-mW2)+mW2*q2 ) * 4.*s/mZ2/q1/q2h*uk - 4.*((s+uk+q2h-2.*mZ2)*(s+q1h-mZ2)-mZ2*q1)/mW2/q2*uk + 4.*(2.*s*uk+2.*mW2*uk+5.*s*s+2.*q1h*s-2.*mZ2*s)/q1/q2h*uk + 4.*(2.*s*uk-s*s-2.*q1h*s+2.*mW2*s+2.*mW2*q1h)/q1/q2h/q2*tk*uk + ((2.*uk+s)*(s+q1h)+s*(q2+q2h)+2.*q2*(s+q2h)-q1*s+q1*q2+q1h*q2h ) /mW2/mZ2*uk + 8.*s*(uk-q1h+mZ2)/q1/q2*uk + 4.*s*(-uk+s-q2+q1+q1h)/mZ2/q2h*uk + 4.*s*(-uk-q2+q1h)/mZ2/q1*uk + 8.*(mZ2*uk-s*s+mW2*s-2.*mZ2*q1-2.*mZ2*q1h)/q2h/q2*uk + 2.*(-uk-9.*s-4.*q2-5.*q2h-3.*q1-4.*q1h+8.*mZ2)/mW2*uk + 2.*(-4.*uk+3.*s+5.*q1+4.*q1h)/q2h*uk + 2.*(s*tk+q2*tk+s*s-q2*q2+q1h*q2)/mW2/mZ2*tk - 8.*s*(tk+s+q1h)/mW2/q2*tk + 2.*(-tk+3.*s+q2-q1h)/mW2*tk - 8.*s*s*s/q1h/q2 - 2.*s*q2*(s+q2)/mW2/mZ2 + 2.*s*(2.*s+q2)/mZ2 + 2.*s*(2.*s+q2)/mW2 - 16.*s*s/q1h - 2.*s - 16.*s*s/q1h/q2*tk - 8.*s/q2*tk - 16.*s/q1h*tk + 6.*s/mZ2*tk + 4.*s/q1*uk + 4.*s/mZ2*uk + 12.*uk + 4.*s*(tk+q1h-mW2)/mZ2/q1/q2h*tk*uk + 2.*(s+4.*q1+5.*q1h-4.*mZ2)/q2*uk - 4.*s*s*s/q1h/q1/q2h/q2*tk*uk - 4.*s*s/q1h/q2h/q2*tk*uk - 4.*s*s/q1h/q1/q2*tk*uk + 8.*s*s/mW2/q1h/q2*tk*uk - 4.*s*s/q1h/q1/q2h*tk*uk + 4.*(s+mZ2)/mW2/q2*tk*uk - 4.*s/q1h/q2h*tk*uk - 4.*s/q1h/q1*tk*uk + 12.*s/mW2/q1h*tk*uk - (s+4.*q2)/mW2/mZ2*tk*uk - 4.*(s+2.*mZ2)/q2h/q2*tk*uk - 4.*(3.*s+2.*q1h)/q1/q2*tk*uk - 8.*mW2/q1/q2h*tk*uk + 8./q2h*tk*uk + 8./q1*tk*uk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); swap(q1h,q2h); // Note this swap is done in accordance with MC@NLO. // It is not in NPB 383(1992)3-44 Eq.C.4! swap(tk,uk); swap(q1,q2h); swap(q2,q1h); Val += (uk*s*(uk+3.*s+q1h)+s*s*(s+mZ2)-(s+uk)*(2.*mZ2*s+3.*mW2*s+mW2*q1h) ) * 8./q1/q2h/q2*uk - (uk*(uk+3.*s+q1h-mW2)-(q2+s)*(q2-s)+s*(q2-mW2)+q1h*(q2-mW2)+mW2*q2 ) * 4.*s/mZ2/q1/q2h*uk - 4.*((s+uk+q2h-2.*mZ2)*(s+q1h-mZ2)-mZ2*q1)/mW2/q2*uk + 4.*(2.*s*uk+2.*mW2*uk+5.*s*s+2.*q1h*s-2.*mZ2*s)/q1/q2h*uk + 4.*(2.*s*uk-s*s-2.*q1h*s+2.*mW2*s+2.*mW2*q1h)/q1/q2h/q2*tk*uk + ((2.*uk+s)*(s+q1h)+s*(q2+q2h)+2.*q2*(s+q2h)-q1*s+q1*q2+q1h*q2h ) /mW2/mZ2*uk + 8.*s*(uk-q1h+mZ2)/q1/q2*uk + 4.*s*(-uk+s-q2+q1+q1h)/mZ2/q2h*uk + 4.*s*(-uk-q2+q1h)/mZ2/q1*uk + 8.*(mZ2*uk-s*s+mW2*s-2.*mZ2*q1-2.*mZ2*q1h)/q2h/q2*uk + 2.*(-uk-9.*s-4.*q2-5.*q2h-3.*q1-4.*q1h+8.*mZ2)/mW2*uk + 2.*(-4.*uk+3.*s+5.*q1+4.*q1h)/q2h*uk + 2.*(s*tk+q2*tk+s*s-q2*q2+q1h*q2)/mW2/mZ2*tk - 8.*s*(tk+s+q1h)/mW2/q2*tk + 2.*(-tk+3.*s+q2-q1h)/mW2*tk - 8.*s*s*s/q1h/q2 - 2.*s*q2*(s+q2)/mW2/mZ2 + 2.*s*(2.*s+q2)/mZ2 + 2.*s*(2.*s+q2)/mW2 - 16.*s*s/q1h - 2.*s - 16.*s*s/q1h/q2*tk - 8.*s/q2*tk - 16.*s/q1h*tk + 6.*s/mZ2*tk + 4.*s/q1*uk + 4.*s/mZ2*uk + 12.*uk + 4.*s*(tk+q1h-mW2)/mZ2/q1/q2h*tk*uk + 2.*(s+4.*q1+5.*q1h-4.*mZ2)/q2*uk - 4.*s*s*s/q1h/q1/q2h/q2*tk*uk - 4.*s*s/q1h/q2h/q2*tk*uk - 4.*s*s/q1h/q1/q2*tk*uk + 8.*s*s/mW2/q1h/q2*tk*uk - 4.*s*s/q1h/q1/q2h*tk*uk + 4.*(s+mZ2)/mW2/q2*tk*uk - 4.*s/q1h/q2h*tk*uk - 4.*s/q1h/q1*tk*uk + 12.*s/mW2/q1h*tk*uk - (s+4.*q2)/mW2/mZ2*tk*uk - 4.*(s+2.*mZ2)/q2h/q2*tk*uk - 4.*(3.*s+2.*q1h)/q1/q2*tk*uk - 8.*mW2/q1/q2h*tk*uk + 8./q2h*tk*uk + 8./q1*tk*uk; swap(tk,uk); swap(q1,q2h); swap(q2,q1h); swap(mW2,mZ2); swap(q1,q1h); swap(q2,q2h); Val += (uk*s*(uk+3.*s+q1h)+s*s*(s+mZ2)-(s+uk)*(2.*mZ2*s+3.*mW2*s+mW2*q1h) ) * 8./q1/q2h/q2*uk - (uk*(uk+3.*s+q1h-mW2)-(q2+s)*(q2-s)+s*(q2-mW2)+q1h*(q2-mW2)+mW2*q2 ) * 4.*s/mZ2/q1/q2h*uk - 4.*((s+uk+q2h-2.*mZ2)*(s+q1h-mZ2)-mZ2*q1)/mW2/q2*uk + 4.*(2.*s*uk+2.*mW2*uk+5.*s*s+2.*q1h*s-2.*mZ2*s)/q1/q2h*uk + 4.*(2.*s*uk-s*s-2.*q1h*s+2.*mW2*s+2.*mW2*q1h)/q1/q2h/q2*tk*uk + ((2.*uk+s)*(s+q1h)+s*(q2+q2h)+2.*q2*(s+q2h)-q1*s+q1*q2+q1h*q2h ) /mW2/mZ2*uk + 8.*s*(uk-q1h+mZ2)/q1/q2*uk + 4.*s*(-uk+s-q2+q1+q1h)/mZ2/q2h*uk + 4.*s*(-uk-q2+q1h)/mZ2/q1*uk + 8.*(mZ2*uk-s*s+mW2*s-2.*mZ2*q1-2.*mZ2*q1h)/q2h/q2*uk + 2.*(-uk-9.*s-4.*q2-5.*q2h-3.*q1-4.*q1h+8.*mZ2)/mW2*uk + 2.*(-4.*uk+3.*s+5.*q1+4.*q1h)/q2h*uk + 2.*(s*tk+q2*tk+s*s-q2*q2+q1h*q2)/mW2/mZ2*tk - 8.*s*(tk+s+q1h)/mW2/q2*tk + 2.*(-tk+3.*s+q2-q1h)/mW2*tk - 8.*s*s*s/q1h/q2 - 2.*s*q2*(s+q2)/mW2/mZ2 + 2.*s*(2.*s+q2)/mZ2 + 2.*s*(2.*s+q2)/mW2 - 16.*s*s/q1h - 2.*s - 16.*s*s/q1h/q2*tk - 8.*s/q2*tk - 16.*s/q1h*tk + 6.*s/mZ2*tk + 4.*s/q1*uk + 4.*s/mZ2*uk + 12.*uk + 4.*s*(tk+q1h-mW2)/mZ2/q1/q2h*tk*uk + 2.*(s+4.*q1+5.*q1h-4.*mZ2)/q2*uk - 4.*s*s*s/q1h/q1/q2h/q2*tk*uk - 4.*s*s/q1h/q2h/q2*tk*uk - 4.*s*s/q1h/q1/q2*tk*uk + 8.*s*s/mW2/q1h/q2*tk*uk - 4.*s*s/q1h/q1/q2h*tk*uk + 4.*(s+mZ2)/mW2/q2*tk*uk - 4.*s/q1h/q2h*tk*uk - 4.*s/q1h/q1*tk*uk + 12.*s/mW2/q1h*tk*uk - (s+4.*q2)/mW2/mZ2*tk*uk - 4.*(s+2.*mZ2)/q2h/q2*tk*uk - 4.*(3.*s+2.*q1h)/q1/q2*tk*uk - 8.*mW2/q1/q2h*tk*uk + 8./q2h*tk*uk + 8./q1*tk*uk; swap(mW2,mZ2); swap(q1,q1h); swap(q2,q2h); return Val; } Energy2 t_u_Ruu(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1h,Energy2 q2h, Energy2 mW2, Energy2 mZ2) { return t_u_Rdd(s,tk,uk,q1h,q2h,mZ2,mW2); } Energy4 t_u_RZds(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1,Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2) { Energy4 Val(0.*GeV2*GeV2); Energy2 sig(mZ2+mW2); Val += ( q1*q2*(5./2.*s*s+5.*s*tk+3.*tk*tk)+(tk*uk*uk+q1*q1*q2)*(tk+s) + q1*(tk*tk*uk+s*uk*uk-s*s*tk+s*s*uk)+q1*q1*q1*(uk+s)-q1*q1*s*s2 ) * 8./q1/q2 - ( tk*tk*(4.*uk+s+q1-2.*q2)+tk*(sqr(q1+q2)-q1*s-3.*q2*s-2.*q1*q1) - q1*s*(4.*s-2.*q1-q2)+tk*uk*(q1+3.*s) ) * 4.*sig/q1/q2 - 4.*sig*sig*(s*(2.*s+q1)+tk*(uk+5./2.*tk+5.*s+q1+q2) )/mW2/mZ2 + 2.*sig*s2*(4.*sqr(s+tk)+tk*(uk+s+4.*q1+2.*q2)+2.*q1*(2.*s+q1) )/mW2/mZ2 + 4.*sig*sig*(s2+s-q1+q2)/q1/q2*tk - 16.*mW2*mZ2*(tk*uk/2.+q2*tk-q1*s)/q1/q2 - 4.*s2*s2*q1*(tk+s+q1)/mW2/mZ2 + sig*sig*sig*(uk+tk)/mW2/mZ2 + 4.*mW2*mZ2*sig*(uk+tk)/q1/q2; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); Val += ( q1*q2*(5./2.*s*s+5.*s*tk+3.*tk*tk)+(tk*uk*uk+q1*q1*q2)*(tk+s) + q1*(tk*tk*uk+s*uk*uk-s*s*tk+s*s*uk)+q1*q1*q1*(uk+s)-q1*q1*s*s2 ) * 8./q1/q2 - ( tk*tk*(4.*uk+s+q1-2.*q2)+tk*(sqr(q1+q2)-q1*s-3.*q2*s-2.*q1*q1) - q1*s*(4.*s-2.*q1-q2)+tk*uk*(q1+3.*s) ) * 4.*sig/q1/q2 - 4.*sig*sig*(s*(2.*s+q1)+tk*(uk+5./2.*tk+5.*s+q1+q2) )/mW2/mZ2 + 2.*sig*s2*(4.*sqr(s+tk)+tk*(uk+s+4.*q1+2.*q2)+2.*q1*(2.*s+q1) )/mW2/mZ2 + 4.*sig*sig*(s2+s-q1+q2)/q1/q2*tk - 16.*mW2*mZ2*(tk*uk/2.+q2*tk-q1*s)/q1/q2 - 4.*s2*s2*q1*(tk+s+q1)/mW2/mZ2 + sig*sig*sig*(uk+tk)/mW2/mZ2 + 4.*mW2*mZ2*sig*(uk+tk)/q1/q2; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); return Val; } Energy4 t_u_RZda(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1,Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2) { Energy4 Val(0.*GeV2*GeV2); Val += 4.*mZ2*(2.*uk*uk-s*tk+q1*(uk-tk-s+q1+0.5*q2)+q2*(s-3.*q2) ) /q1/q2*tk - 4.*mZ2*mZ2*(q1-tk-2.*s-q2)/q1/q2*tk - 2.*mZ2*(tk+2.*s+2.*q2)/mW2*tk - 2.*s2*(s+2.*q2)/mZ2*tk + 8.*mW2*mZ2*mZ2/q1/q2*tk + 2.*mZ2*mZ2/mW2*tk; swap(mW2,mZ2); // N.B. Here we subtract! Val -= 4.*mZ2*(2.*uk*uk-s*tk+q1*(uk-tk-s+q1+0.5*q2)+q2*(s-3.*q2) ) /q1/q2*tk - 4.*mZ2*mZ2*(q1-tk-2.*s-q2)/q1/q2*tk - 2.*mZ2*(tk+2.*s+2.*q2)/mW2*tk - 2.*s2*(s+2.*q2)/mZ2*tk + 8.*mW2*mZ2*mZ2/q1/q2*tk + 2.*mZ2*mZ2/mW2*tk; swap(mW2,mZ2); swap(q1,q2); // N.B. Here we subtract! swap(tk,uk); Val -= 4.*mZ2*(2.*uk*uk-s*tk+q1*(uk-tk-s+q1+0.5*q2)+q2*(s-3.*q2) ) /q1/q2*tk - 4.*mZ2*mZ2*(q1-tk-2.*s-q2)/q1/q2*tk - 2.*mZ2*(tk+2.*s+2.*q2)/mW2*tk - 2.*s2*(s+2.*q2)/mZ2*tk + 8.*mW2*mZ2*mZ2/q1/q2*tk + 2.*mZ2*mZ2/mW2*tk; swap(q1,q2); swap(tk,uk); swap(mW2,mZ2); // N.B. Here we add! swap(q1,q2); swap(tk,uk); Val += 4.*mZ2*(2.*uk*uk-s*tk+q1*(uk-tk-s+q1+0.5*q2)+q2*(s-3.*q2) ) /q1/q2*tk - 4.*mZ2*mZ2*(q1-tk-2.*s-q2)/q1/q2*tk - 2.*mZ2*(tk+2.*s+2.*q2)/mW2*tk - 2.*s2*(s+2.*q2)/mZ2*tk + 8.*mW2*mZ2*mZ2/q1/q2*tk + 2.*mZ2*mZ2/mW2*tk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); return Val; } Energy4 t_u_RZd(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1 , Energy2 q2 , Energy2 s2, Energy2 mW2, Energy2 mZ2) { Energy4 Val(0.*GeV2*GeV2); Val = t_u_RZds(s,tk,uk,q1,q2,s2,mW2,mZ2) + t_u_RZda(s,tk,uk,q1,q2,s2,mW2,mZ2); return Val; } Energy4 t_u_RZu(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1h, Energy2 q2h, Energy2 s2, Energy2 mW2, Energy2 mZ2) { Energy4 Val(0.*GeV2*GeV2); Val = t_u_RZd(s,tk,uk,q1h,q2h,s2,mZ2,mW2); return Val; } Energy6 t_u_RZs(Energy2 s,Energy2 tk,Energy2 uk,Energy2 q1,Energy2 q2, Energy2 s2,Energy2 mW2,Energy2 mZ2) { Energy6 Val(0.*GeV2*GeV2*GeV2); Energy2 sig(mZ2+mW2); Val += 2.*sig*sig*s2*( tk*(3.*uk+9.*tk+19.*s+6.*q1+4.*q2)+8.*s*s+6.*q1*s + 2.*q1*q1 )/mW2/mZ2 - 2.*sig*sig*sig*(tk*(3.*uk+6.*tk+11.*s+2.*q1+2.*q2)+2.*s*(2.*s+q1)) / mW2/mZ2 - 2.*sig*s2*s2*(tk*(uk+4.*tk+9.*s+6.*q1+2.*q2)+4.*sqr(s+q1)-2.*q1*s) /mW2/mZ2 - 16.*sig*(2.*tk*(uk/2.-tk-s+q1+q2)-s*(3.*s/2.-2.*q1)) + 8.*s2*(s*(s/2.+tk)+4.*q1*(tk+s+q1)) + 4.*s2*s2*s2*q1*(tk+s+q1)/mW2/mZ2 + 8.*sig*sig*(2.*tk+s/2.) + 2.*sig*sig*sig*sig*tk/mW2/mZ2 + 32.*mW2*mZ2*s; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); Val += 2.*sig*sig*s2*( tk*(3.*uk+9.*tk+19.*s+6.*q1+4.*q2)+8.*s*s+6.*q1*s + 2.*q1*q1 )/mW2/mZ2 - 2.*sig*sig*sig*(tk*(3.*uk+6.*tk+11.*s+2.*q1+2.*q2)+2.*s*(2.*s+q1)) / mW2/mZ2 - 2.*sig*s2*s2*(tk*(uk+4.*tk+9.*s+6.*q1+2.*q2)+4.*sqr(s+q1)-2.*q1*s) /mW2/mZ2 - 16.*sig*(2.*tk*(uk/2.-tk-s+q1+q2)-s*(3.*s/2.-2.*q1)) + 8.*s2*(s*(s/2.+tk)+4.*q1*(tk+s+q1)) + 4.*s2*s2*s2*q1*(tk+s+q1)/mW2/mZ2 + 8.*sig*sig*(2.*tk+s/2.) + 2.*sig*sig*sig*sig*tk/mW2/mZ2 + 32.*mW2*mZ2*s; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); return Val; } Energy6 t_u_RZa(Energy2 s,Energy2 tk,Energy2 uk,Energy2 q1,Energy2 q2, Energy2 s2,Energy2 mW2,Energy2 mZ2) { Energy6 Val(0.*GeV2*GeV2*GeV2); Val += - 2.*mZ2*(2.*tk+11.*s+18.*q2)*tk - 2.*mZ2*mZ2*(2.*tk+3.*s+2.*q2)/mW2*tk + 2.*mZ2*s2*(tk+3.*s+4.*q2)/mW2*tk - 2.*s2*s2*(s+2.*q2)/mW2*tk + 2.*mZ2*mZ2*mZ2/mW2*tk + 20.*mZ2*mZ2*tk; swap(mW2,mZ2); Val -= - 2.*mZ2*(2.*tk+11.*s+18.*q2)*tk - 2.*mZ2*mZ2*(2.*tk+3.*s+2.*q2)/mW2*tk + 2.*mZ2*s2*(tk+3.*s+4.*q2)/mW2*tk - 2.*s2*s2*(s+2.*q2)/mW2*tk + 2.*mZ2*mZ2*mZ2/mW2*tk + 20.*mZ2*mZ2*tk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); Val -= - 2.*mZ2*(2.*tk+11.*s+18.*q2)*tk - 2.*mZ2*mZ2*(2.*tk+3.*s+2.*q2)/mW2*tk + 2.*mZ2*s2*(tk+3.*s+4.*q2)/mW2*tk - 2.*s2*s2*(s+2.*q2)/mW2*tk + 2.*mZ2*mZ2*mZ2/mW2*tk + 20.*mZ2*mZ2*tk; swap(q1,q2); swap(tk,uk); swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); Val += - 2.*mZ2*(2.*tk+11.*s+18.*q2)*tk - 2.*mZ2*mZ2*(2.*tk+3.*s+2.*q2)/mW2*tk + 2.*mZ2*s2*(tk+3.*s+4.*q2)/mW2*tk - 2.*s2*s2*(s+2.*q2)/mW2*tk + 2.*mZ2*mZ2*mZ2/mW2*tk + 20.*mZ2*mZ2*tk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); return Val; } Energy6 t_u_RZ(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2) { Energy6 Val(0.*GeV2*GeV2*GeV2); Val = t_u_RZs(s,tk,uk,q1,q2,s2,mW2,mZ2) + t_u_RZa(s,tk,uk,q1,q2,s2,mW2,mZ2); return Val; } /***************************************************************************/ // t_u_M_R_qg is the real emission q + qb -> n + g matrix element // exactly as defined in Eqs. C.9 of NPB 383(1992)3-44, multiplied by // tk * uk! Energy2 MEPP2VVPowheg::t_u_M_R_qg(realVVKinematics R) const { // First the Born variables: Energy2 s2(R.s2r()); Energy2 mW2(R.k12r()); Energy2 mZ2(R.k22r()); // Then the rest: Energy2 s(R.sr()); Energy2 tk(R.tkr()); Energy2 uk(R.ukr()); Energy2 q1(R.q1r()); Energy2 q2(R.q2r()); Energy2 q1h(R.q1hatr()); Energy2 q2h(R.q2hatr()); Energy2 w1(R.w1r()); Energy2 w2(R.w2r()); double cosThetaW(sqrt(1.-sin2ThetaW_)); double eZ2(eZ2_); double eZ(eZ_); double gdL(gdL_); double guL(guL_); double gdR(gdR_); double guR(guR_); // W+W- if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { double e2(sqr(gW_)*sin2ThetaW_); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(guL-guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *( 2./3.+2.*eZ*guL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } gdL = gW_/sqrt(2.); guL = 0.; } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(gdL-gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *(-1./3.+2.*eZ*gdL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } guL = gW_/sqrt(2.); gdL = 0.; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { eZ = 0.; eZ2 = 0.; double gV2,gA2; gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL; else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL; else { cout << "MEPP2VVPowheg:" << endl; cout << "ZZ needs 2 down-type / 2 up-type!" << endl; } } Energy2 Val(0.*GeV2); swap(s,tk); swap(q2,w2); swap(q2h,w1); Val = -2.*pi*alphaS_*Fij2_*CF_/NC_ * ( gdL*gdL*t_u_Rdd(s,tk,uk,q1,q2,mW2,mZ2) + 2.*gdL*guL*t_u_Rud(s,tk,uk,q1,q2,q1h,q2h,mW2,mZ2) + guL*guL*t_u_Ruu(s,tk,uk,q1h,q2h,mW2,mZ2) - 2.*eZ/(s2-mW2) * ( gdL * t_u_RZd(s,tk,uk,q1 ,q2 ,s2,mW2,mZ2) - guL * t_u_RZu(s,tk,uk,q1h,q2h,s2,mW2,mZ2) ) + eZ2/sqr(s2-mW2) *t_u_RZ(s,tk,uk,q1,q2,s2,mW2,mZ2) ); swap(s,tk); swap(q2,w2); swap(q2h,w1); Val *= -tk/s * TR_/CF_; return Val; } /***************************************************************************/ // t_u_M_R_gqb is the real emission g + qb -> n + q matrix element // exactly as defined in Eqs. C.9 of NPB 383(1992)3-44, multiplied by // tk * uk! Energy2 MEPP2VVPowheg::t_u_M_R_gqb(realVVKinematics R) const { // First the Born variables: Energy2 s2(R.s2r()); Energy2 mW2(R.k12r()); Energy2 mZ2(R.k22r()); // Then the rest: Energy2 s(R.sr()); Energy2 tk(R.tkr()); Energy2 uk(R.ukr()); Energy2 q1(R.q1r()); Energy2 q2(R.q2r()); Energy2 q1h(R.q1hatr()); Energy2 q2h(R.q2hatr()); Energy2 w1(R.w1r()); Energy2 w2(R.w2r()); double cosThetaW(sqrt(1.-sin2ThetaW_)); double eZ2(eZ2_); double eZ(eZ_); double gdL(gdL_); double guL(guL_); double gdR(gdR_); double guR(guR_); // W+W- if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { double e2(sqr(gW_)*sin2ThetaW_); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(guL-guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *( 2./3.+2.*eZ*guL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } gdL = gW_/sqrt(2.); guL = 0.; } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(gdL-gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *(-1./3.+2.*eZ*gdL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } guL = gW_/sqrt(2.); gdL = 0.; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { eZ = 0.; eZ2 = 0.; double gV2,gA2; gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL; else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL; else { cout << "MEPP2VVPowheg:" << endl; cout << "ZZ needs 2 down-type / 2 up-type!" << endl; } } Energy2 Val(0.*GeV2); swap(s,uk); swap(q1,w1); swap(q1h,w2); Val = -2.*pi*alphaS_*Fij2_*CF_/NC_ * ( gdL*gdL*t_u_Rdd(s,tk,uk,q1,q2,mW2,mZ2) + 2.*gdL*guL*t_u_Rud(s,tk,uk,q1,q2,q1h,q2h,mW2,mZ2) + guL*guL*t_u_Ruu(s,tk,uk,q1h,q2h,mW2,mZ2) - 2.*eZ/(s2-mW2) * ( gdL * t_u_RZd(s,tk,uk,q1 ,q2 ,s2,mW2,mZ2) - guL * t_u_RZu(s,tk,uk,q1h,q2h,s2,mW2,mZ2) ) + eZ2/sqr(s2-mW2) *t_u_RZ(s,tk,uk,q1,q2,s2,mW2,mZ2) ); swap(s,uk); swap(q1,w1); swap(q1h,w2); Val *= -uk/s * TR_/CF_; return Val; } /***************************************************************************/ // The following six functions are I_{dd}^{(0)}, I_{ud}^{(0)}, // I_{uu}^{(0)}, F_{u}^{(0)}, F_{d}^{(0)}, H^{(0)} from Eqs. 3.9 - 3.14 // They make up the Born matrix element. Ixx functions correspond to the // graphs with no TGC, Fx functions are due to non-TGC graphs interfering // with TGC graphs, while the H function is due purely to TGC graphs. double Idd0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); double Iud0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); double Iuu0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); Energy2 Fu0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); Energy2 Fd0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); Energy4 H0 (Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); /***************************************************************************/ // M_Born_WZ is the Born matrix element exactly as defined in Eqs. 3.3-3.14 // of of NPB 383(1992)3-44 (with a spin*colour averaging factor 1./4./NC_/NC_). double MEPP2VVPowheg::M_Born_WZ(bornVVKinematics B) const { Energy2 s(B.sb()); Energy2 t(B.tb()); Energy2 u(B.ub()); Energy2 mW2(B.k12b()); // N.B. the diboson masses are preserved in getting Energy2 mZ2(B.k22b()); // the 2->2 from the 2->3 kinematics. double cosThetaW(sqrt(1.-sin2ThetaW_)); double eZ2(eZ2_); double eZ(eZ_); double gdL(gdL_); double guL(guL_); double gdR(gdR_); double guR(guR_); // W+W- if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { double e2(sqr(gW_)*sin2ThetaW_); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s-mW2)/Fij2_ * (e2*e2/s/s*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s/(s-mW2/sqr(cosThetaW))) +sqr( eZ*(guL-guR)/2./e2*s/(s-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s-mW2) * (gW_*gW_*e2/4./s *( 2./3.+2.*eZ*guL/2./e2*s/(s-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } gdL = gW_/sqrt(2.); guL = 0.; } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s-mW2)/Fij2_ * (e2*e2/s/s*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s/(s-mW2/sqr(cosThetaW))) +sqr( eZ*(gdL-gdR)/2./e2*s/(s-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s-mW2) * (gW_*gW_*e2/4./s *(-1./3.+2.*eZ*gdL/2./e2*s/(s-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } guL = gW_/sqrt(2.); gdL = 0.; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { eZ = 0.; eZ2 = 0.; double gV2,gA2; gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL; else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL; else { cout << "MEPP2VVPowheg:" << endl; cout << "ZZ needs 2 down-type / 2 up-type!" << endl; } } return Fij2_/2./NC_ * ( gdL*gdL*Idd0(s,t,u,mW2,mZ2) + 2.*gdL*guL*Iud0(s,t,u,mW2,mZ2) + guL*guL*Iuu0(s,t,u,mW2,mZ2) - 2.*eZ/(s-mW2) * ( gdL*Fd0(s,t,u,mW2,mZ2) - guL*Fu0(s,t,u,mW2,mZ2) ) + eZ2/sqr(s-mW2) * H0(s,t,u,mW2,mZ2) ); } /***************************************************************************/ double Idd0(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return 8.*((u*t/mW2/mZ2-1.)/4.+s/2.*(mW2+mZ2)/mW2/mZ2) + 8.*(u/t-mW2*mZ2/t/t); } /***************************************************************************/ double Iud0(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return - 8.*((u*t/mW2/mZ2-1.)/4.+s/2.*(mW2+mZ2)/mW2/mZ2) + 8.*s/t/u*(mW2+mZ2); } /***************************************************************************/ double Iuu0(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return Idd0(s,u,t,mW2,mZ2); } /***************************************************************************/ Energy2 Fd0 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return - 8.*s*( (u*t/mW2/mZ2-1.)*(1.-(mW2+mZ2)/s-4.*mW2*mZ2/s/t)/4. + (mW2+mZ2)/2./mW2/mZ2*(s-mW2-mZ2+2.*mW2*mZ2/t) ); } /***************************************************************************/ Energy2 Fu0 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return Fd0(s,u,t,mW2,mZ2); } /***************************************************************************/ Energy4 H0 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return 8.*s*s*(u*t/mW2/mZ2-1.)*( 1./4.-(mW2+mZ2)/2./s + (sqr(mW2+mZ2)+8.*mW2*mZ2)/4./s/s ) + 8.*s*s*(mW2+mZ2)/mW2/mZ2*(s/2.-mW2-mZ2+sqr(mW2-mZ2)/2./s); } /***************************************************************************/ bool MEPP2VVPowheg::sanityCheck() const { bool alarm(false); Energy2 prefacs(8.*pi*alphaS_*S_.sr() /S_.xr() ); Energy2 prefacsp(8.*pi*alphaS_*SCp_.sr() /SCp_.xr() ); Energy2 prefacsm(8.*pi*alphaS_*SCm_.sr() /SCm_.xr() ); Energy2 prefacp(8.*pi*alphaS_*Cp_.sr()/Cp_.xr()); Energy2 prefacm(8.*pi*alphaS_*Cm_.sr()/Cm_.xr()); double xp(Cp_.xr()); double xm(Cm_.xr()); double M_B_WW(M_Born_WW(B_)); double M_B_ZZ(M_Born_ZZ(B_)); double M_V_reg_WW(M_V_regular_WW(S_)); double M_V_reg_ZZ(M_V_regular_ZZ(S_)); Energy2 t_u_qqb_WW(t_u_M_R_qqb_WW(H_)); Energy2 t_u_qqb_ZZ(t_u_M_R_qqb_ZZ(H_)); // Check that the native leading order Herwig matrix // element is equivalent to the WZ leading order matrix // element in NPB 383 (1992) 3-44, with the relevant WZ->WW // WZ->ZZ transformation applied (M_Born_). // if(fabs((lo_me2_ - M_Born_)/M_Born_)>1.e-2) { // alarm=true; // cout << "lo_me2_ - M_Born_ (%) = " // << lo_me2_ - M_Born_ << " (" // << (lo_me2_ - M_Born_)/M_Born_*100. << ")\n"; // } // Check that the transformation from NPB 383 (1992) 3-44 WZ // matrix elements to WW matrix elements actually works, by // comparing them to the explicit WW matrix elements in // NPB 410 (1993) 280-324. if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { if(fabs((M_Born_ -M_B_WW )/M_B_WW )>1.e-6) { alarm=true; cout << "WZ->WW transformation error!\n"; cout << "M_Born_ - M_B_WW (rel) = " << M_Born_ - M_B_WW << " (" << (M_Born_ - M_B_WW)/M_B_WW << ")\n"; cout << "M_Born_ = " << M_Born_ << endl; cout << "M_B_WW = " << M_B_WW << endl; } if(fabs((M_V_regular_-M_V_reg_WW)/M_V_reg_WW)>1.e-6) { alarm=true; cout << "WZ->WW transformation error!\n"; cout << "M_V_regular_ - M_V_reg_WW (rel) = " << M_V_regular_ - M_V_reg_WW << " (" << (M_V_regular_ - M_V_reg_WW)/M_V_reg_WW << ")\n"; cout << "M_V_regular_ = " << M_V_regular_ << endl; cout << "M_V_reg_WW = " << M_V_reg_WW << endl; } if(fabs((t_u_M_R_qqb_-t_u_qqb_WW)/t_u_qqb_WW)>1.e-6) { alarm=true; cout << "WZ->WW transformation error!\n"; cout << "t_u_M_R_qqb_ - t_u_qqb_WW (rel) = " << (t_u_M_R_qqb_ - t_u_qqb_WW)/GeV2 << " (" << (t_u_M_R_qqb_ - t_u_qqb_WW)/t_u_qqb_WW << ")\n"; cout << "t_u_M_R_qqb_ = " << t_u_M_R_qqb_/GeV2 << endl; cout << "t_u_qqb_WW = " << t_u_qqb_WW /GeV2 << endl; } } // Check that the transformation from NPB 383 (1992) 3-44 WZ // matrix elements to ZZ matrix elements actually works, by // comparing them to the explicit ZZ matrix elements in // NPB 357 (1991) 409-438. if(abs(mePartonData()[2]->id())==23&&abs(mePartonData()[3]->id())==23) { if(fabs((M_Born_ -M_B_ZZ )/M_B_ZZ )>1.e-6) { alarm=true; cout << "WZ->ZZ transformation error!\n"; cout << "M_Born_ - M_B_ZZ (rel) = " << M_Born_ - M_B_ZZ << " (" << (M_Born_ - M_B_ZZ)/M_B_ZZ << ")\n"; cout << "M_Born_ = " << M_Born_ << endl; cout << "M_B_ZZ = " << M_B_ZZ << endl; } if(fabs((M_V_regular_-M_V_reg_ZZ)/M_V_reg_ZZ)>1.e-6) { alarm=true; cout << "WZ->ZZ transformation error!\n"; cout << "M_V_regular_ - M_V_reg_ZZ (rel) = " << M_V_regular_ - M_V_reg_ZZ << " (" << (M_V_regular_ - M_V_reg_ZZ)/M_V_reg_ZZ << ")\n"; cout << "M_V_regular_ = " << M_V_regular_ << endl; cout << "M_V_reg_ZZ = " << M_V_reg_ZZ << endl; } if(fabs((t_u_M_R_qqb_-t_u_qqb_ZZ)/t_u_qqb_ZZ)>1.e-6) { alarm=true; cout << "WZ->ZZ transformation error!\n"; cout << "t_u_M_R_qqb_ - t_u_qqb_ZZ (rel) = " << (t_u_M_R_qqb_ - t_u_qqb_ZZ)/GeV2 << " (" << (t_u_M_R_qqb_ - t_u_qqb_ZZ)/t_u_qqb_ZZ << ")\n"; cout << "t_u_M_R_qqb_ = " << t_u_M_R_qqb_/GeV2 << endl; cout << "t_u_qqb_ZZ = " << t_u_qqb_ZZ /GeV2 << endl; } } // Check the soft limit of the q + qbar matrix element. Energy2 absDiff_qqbs = t_u_M_R_qqb(S_) - prefacs*2.*CF_*M_Born_; double relDiff_qqbs = absDiff_qqbs / t_u_M_R_qqb(S_); if(fabs(relDiff_qqbs)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qqb(S_) " << t_u_M_R_qqb(S_) /GeV2 << endl; cout << "t_u_M_R_qqb(S_)-8*pi*alphaS*sHat/x*2*Cab*M_Born_ (rel):\n" << absDiff_qqbs / GeV2 << " (" << relDiff_qqbs << ")\n"; } // Check the positive soft-collinearlimit of the q + qbar matrix element. Energy2 absDiff_qqbsp = t_u_M_R_qqb(SCp_) - prefacsp*2.*CF_*M_Born_; double relDiff_qqbsp = absDiff_qqbsp / t_u_M_R_qqb(SCp_); if(fabs(relDiff_qqbsp)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qqb(SCp_) " << t_u_M_R_qqb(SCp_)/GeV2 << endl; cout << "t_u_M_R_qqb(SCp_)-8*pi*alphaS*sHat/x*2*Cab*M_Born_ (rel):\n" << absDiff_qqbsp / GeV2 << " (" << relDiff_qqbsp << ")\n"; } // Check the negative soft-collinearlimit of the q + qbar matrix element. Energy2 absDiff_qqbsm = t_u_M_R_qqb(SCm_) - prefacsm*2.*CF_*M_Born_; double relDiff_qqbsm = absDiff_qqbsm / t_u_M_R_qqb(SCm_); if(fabs(relDiff_qqbsm)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qqb(SCm_) " << t_u_M_R_qqb(SCm_)/GeV2 << endl; cout << "t_u_M_R_qqb(SCm_)-8*pi*alphaS*sHat/x*2*Cab*M_Born_ (rel):\n" << absDiff_qqbsm / GeV2 << " (" << relDiff_qqbsm << ")\n"; } // Check the positive collinearlimit of the q + qbar matrix element. Energy2 absDiff_qqbp = t_u_M_R_qqb(Cp_) - prefacp*CF_*(1.+xp*xp)*M_Born_; double relDiff_qqbp = absDiff_qqbp / t_u_M_R_qqb(Cp_); if(fabs(relDiff_qqbp)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qqb(Cp_) " << t_u_M_R_qqb(Cp_) /GeV2 << endl; cout << "t_u_M_R_qqb(Cp_)-8*pi*alphaS*sHat/x*(1-x)*Pqq*M_Born_ (rel):\n" << absDiff_qqbp / GeV2 << " (" << relDiff_qqbp << ")\n"; } // Check the negative collinearlimit of the q + qbar matrix element. Energy2 absDiff_qqbm = t_u_M_R_qqb(Cm_) - prefacm*CF_*(1.+xm*xm)*M_Born_; double relDiff_qqbm = absDiff_qqbm / t_u_M_R_qqb(Cm_); if(fabs(relDiff_qqbm)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qqb(Cm_) " << t_u_M_R_qqb(Cm_) /GeV2 << endl; cout << "t_u_M_R_qqb(Cm_)-8*pi*alphaS*sHat/x*(1-x)*Pqq*M_Born_ (rel):\n" << absDiff_qqbm / GeV2 << " (" << relDiff_qqbm << ")\n"; } // Check the positive collinear limit of the g + qbar matrix element. Energy2 absDiff_gqbp = t_u_M_R_gqb(Cp_) - prefacp*(1.-xp)*TR_*(xp*xp+sqr(1.-xp))*M_Born_; double relDiff_gqbp = absDiff_gqbp/ t_u_M_R_gqb(Cp_); if(fabs(relDiff_gqbp)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_gqb(Cp_) " << t_u_M_R_gqb(Cp_) /GeV2 << endl; cout << "t_u_M_R_gqb(Cp_)-8*pi*alphaS*sHat/x*(1-x)*Pgq*M_Born_ (rel):\n" << absDiff_gqbp / GeV2 << " (" << relDiff_gqbp << ")\n"; } // Check the negative collinear limit of the q + g matrix element. Energy2 absDiff_qgm = t_u_M_R_qg(Cm_) - prefacm*(1.-xm)*TR_*(xm*xm+sqr(1.-xm))*M_Born_; double relDiff_qgm = absDiff_qgm / t_u_M_R_qg(Cm_); if(fabs(relDiff_qgm)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qg(Cm_) " << t_u_M_R_qg(Cm_) /GeV2 << endl; cout << "t_u_M_R_qg(Cm_)-8*pi*alphaS*sHat/x*(1-x)*Pgq*M_Born_ (rel):\n" << absDiff_qgm / GeV2 << " (" << relDiff_qgm << ")\n"; } return alarm; } /***************************************************************************/ // M_Born_ZZ is the Born matrix element exactly as defined in Eqs. 2.18-2.19 // of of NPB 357(1991)409-438. double MEPP2VVPowheg::M_Born_ZZ(bornVVKinematics B) const { Energy2 s(B.sb()); Energy2 t(B.tb()); Energy2 u(B.ub()); Energy2 mZ2(B.k22b()); // the 2->2 from the 2->3 kinematics. double cosThetaW(sqrt(1.-sin2ThetaW_)); double gV2,gA2,gX,gY,gZ; gV2 = sqr(guL_/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL_/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); gX = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL_/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL_/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gY = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gZ = gX; if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) gZ = gY; return 1./NC_*sqr(gZ*2.)*(t/u+u/t+4.*mZ2*s/t/u-mZ2*mZ2*(1./t/t+1./u/u)); } /***************************************************************************/ // M_V_regular_ZZ is the one-loop ZZ matrix element exactly as defined in // Eqs. B.1 & B.2 of NPB 357(1991)409-438. double MEPP2VVPowheg::M_V_regular_ZZ(realVVKinematics S) const { Energy2 s(S.bornVariables().sb()); Energy2 t(S.bornVariables().tb()); Energy2 u(S.bornVariables().ub()); Energy2 mZ2(S.k22r()); // the 2->2 from the 2->3 kinematics. double beta(S.betaxr()); // N.B. for x=1 \beta_x=\beta in NPB 383(1992)3-44. double cosThetaW(sqrt(1.-sin2ThetaW_)); double gV2,gA2,gX,gY,gZ; gV2 = sqr(guL_/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL_/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); gX = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL_/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL_/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gY = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gZ = gX; if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) gZ = gY; double M_V_reg(0.); M_V_reg = 2.*s*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/sqr(4.*pi)/2. *( 2.*sqr(t+mZ2)/sqr(beta)/s/t/u + 4.*s/(t-mZ2)/u - ( 16.*t*t*t+(28.*s-68.*mZ2)*t*t+(18.*s*s-36.*mZ2*s+88.*mZ2*mZ2)*t + 18.*mZ2*mZ2*s-36.*mZ2*mZ2*mZ2 )/t/t/s/u + ( 12.*s/(t-mZ2)/u-4.*mZ2*s/sqr(t-mZ2)/u+2.*(t+4.*s)/s/u - 6.*(s*s+mZ2*mZ2)/s/t/u+6.*mZ2*mZ2*(2.*mZ2-s)/t/t/s/u )*log(-t/mZ2) + ( - ( 5.*t*t*t+(8.*s-18.*mZ2)*t*t+(6.*s*s+25.*mZ2*mZ2)*t + 6.*mZ2*mZ2*s-12.*mZ2*mZ2*mZ2 )/t/t/s/u - 12.*mZ2*sqr(t+mZ2)/sqr(sqr(beta))/s/s/t/u + ( 3.*t*t-26.*mZ2*t-25.*mZ2*mZ2)/sqr(beta)/s/t/u )*log(s/mZ2) + ( (-2.*t*t+8.*mZ2*t-2.*s*s-12.*mZ2*mZ2)/u + 4.*mZ2*mZ2*(2.*mZ2-s)/t/u) / (s*t) * ( 2.*sqr(log(-t/mZ2))-4.*log(-t/mZ2)*log((mZ2-t)/mZ2)-4.*ReLi2(t/mZ2)) + ( 4.*(t*t-5.*mZ2*t+s*s+10.*mZ2*mZ2)/s/u + 4.*mZ2*(-s*s+2.*mZ2*s-10.*mZ2*mZ2)/s/t/u + 8.*mZ2*mZ2*mZ2*(2.*mZ2-s)/t/t/s/u ) / (t-mZ2) * (pi*pi/2.+log(-t/mZ2)*log(-t/s)-1./2.*sqr(log(-t/mZ2))) + ( ( (2.*s-3.*mZ2)*t*t+(6.*mZ2*mZ2-8.*mZ2*s)*t+2.*s*s*s-4.*mZ2*s*s + 12.*mZ2*mZ2*s-3.*mZ2*mZ2*mZ2 ) /s/t/u + 12.*mZ2*mZ2*sqr(t+mZ2)/sqr(sqr(beta))/s/s/t/u - (mZ2*t*t-30.*mZ2*mZ2*t-27.*mZ2*mZ2*mZ2)/beta/beta/s/t/u ) / (beta*s) * (pi*pi/3.+sqr(log((1.-beta)/(1.+beta)))+4.*ReLi2(-(1.-beta)/(1.+beta))) + (4.*(t+4.*s-4.*mZ2)/3./s/u+4.*sqr(s-2.*mZ2)/3./s/t/u)*pi*pi ); swap(t,u); M_V_reg += 2.*s*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/sqr(4.*pi)/2. *( 2.*sqr(t+mZ2)/sqr(beta)/s/t/u + 4.*s/(t-mZ2)/u - ( 16.*t*t*t+(28.*s-68.*mZ2)*t*t+(18.*s*s-36.*mZ2*s+88.*mZ2*mZ2)*t + 18.*mZ2*mZ2*s-36.*mZ2*mZ2*mZ2 )/t/t/s/u + ( 12.*s/(t-mZ2)/u-4.*mZ2*s/sqr(t-mZ2)/u+2.*(t+4.*s)/s/u - 6.*(s*s+mZ2*mZ2)/s/t/u+6.*mZ2*mZ2*(2.*mZ2-s)/t/t/s/u )*log(-t/mZ2) + ( - ( 5.*t*t*t+(8.*s-18.*mZ2)*t*t+(6.*s*s+25.*mZ2*mZ2)*t + 6.*mZ2*mZ2*s-12.*mZ2*mZ2*mZ2 )/t/t/s/u - 12.*mZ2*sqr(t+mZ2)/sqr(sqr(beta))/s/s/t/u + ( 3.*t*t-26.*mZ2*t-25.*mZ2*mZ2)/sqr(beta)/s/t/u )*log(s/mZ2) + ( (-2.*t*t+8.*mZ2*t-2.*s*s-12.*mZ2*mZ2)/u + 4.*mZ2*mZ2*(2.*mZ2-s)/t/u) / (s*t) * ( 2.*sqr(log(-t/mZ2))-4.*log(-t/mZ2)*log((mZ2-t)/mZ2)-4.*ReLi2(t/mZ2)) + ( 4.*(t*t-5.*mZ2*t+s*s+10.*mZ2*mZ2)/s/u + 4.*mZ2*(-s*s+2.*mZ2*s-10.*mZ2*mZ2)/s/t/u + 8.*mZ2*mZ2*mZ2*(2.*mZ2-s)/t/t/s/u ) / (t-mZ2) * (pi*pi/2.+log(-t/mZ2)*log(-t/s)-1./2.*sqr(log(-t/mZ2))) + ( ( (2.*s-3.*mZ2)*t*t+(6.*mZ2*mZ2-8.*mZ2*s)*t+2.*s*s*s-4.*mZ2*s*s + 12.*mZ2*mZ2*s-3.*mZ2*mZ2*mZ2 ) /s/t/u + 12.*mZ2*mZ2*sqr(t+mZ2)/sqr(sqr(beta))/s/s/t/u - (mZ2*t*t-30.*mZ2*mZ2*t-27.*mZ2*mZ2*mZ2)/beta/beta/s/t/u ) / (beta*s) * (pi*pi/3.+sqr(log((1.-beta)/(1.+beta)))+4.*ReLi2(-(1.-beta)/(1.+beta))) + (4.*(t+4.*s-4.*mZ2)/3./s/u+4.*sqr(s-2.*mZ2)/3./s/t/u)*pi*pi ); return M_V_reg; } /***************************************************************************/ // t_u_M_R_qqb_ZZ is the real emission q + qb -> n + g matrix element // exactly as defined in Eqs. C.1 of NPB 357(1991)409-438, multiplied by // tk * uk! Energy2 MEPP2VVPowheg::t_u_M_R_qqb_ZZ(realVVKinematics R) const { // First the Born variables: Energy2 mZ2(R.k22r()); // Then the rest: Energy2 s(R.sr()); Energy2 tk(R.tkr()); Energy2 uk(R.ukr()); Energy2 q1(R.q1r()); Energy2 q2(R.q2r()); Energy2 q1h(R.q1hatr()); Energy2 q2h(R.q2hatr()); double cosThetaW(sqrt(1.-sin2ThetaW_)); double gV2,gA2,gX,gY,gZ; gV2 = sqr(guL_/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL_/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); gX = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL_/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL_/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gY = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gZ = gX; if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) gZ = gY; Energy2 t_u_qqb(0.*GeV2); t_u_qqb = (2.*s)*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/2. * ( - ( tk*uk*uk+2.*s*uk*uk-tk*tk*uk - 2.*s*tk*uk+mZ2*(tk*tk-uk*uk+2.*s*uk-2.*s*tk-2.*s*s) )/q1h/q1/q2h/s*tk + 2.*(tk*uk*uk-mZ2*uk*(s+3.*tk)+mZ2*mZ2*(2.*uk-s))/q1/q2/s + ( tk*uk*(uk+s)-mZ2*(uk*uk+3.*tk*uk+3.*s*uk+s*tk) + 2.*mZ2*mZ2*(uk+tk+2.*s) )/q1h/q1/q2/s*tk + ( tk*(uk*uk+tk*uk-s*s)+mZ2*(4.*s*uk-3.*tk*uk-tk*tk+4.*s*s) )/q1h/q2/s - ( tk*uk+s*uk-s*tk-s*s+2.*mZ2*(s-tk) ) /q1h/q1/s*tk + q2*(tk*uk-s*uk-2.*s*tk-2.*s*s)/q1/q2h/s + 2.*(tk*uk-tk*tk-s*tk-s*s+mZ2*(2.*s-uk))/q1/s - 2.*mZ2*(uk*uk-2.*mZ2*uk+2.*mZ2*mZ2)/q1/q1/q2/s*tk + (2.*s*uk+tk*tk+3.*s*tk+2*s*s)/q1h/s + q1*(uk+s)*(uk+tk)/q1h/q2h/s + (tk*uk+s*uk+3.*s*tk+2.*s*s-mZ2*(uk+tk+2.*s))/q1h/q2h/s*uk + (uk-tk)/2./q1h/q2h/s*(q1*(uk+s)/q2/tk-q2*(tk+s)/q1/uk)*tk*uk + (tk-2.*mZ2)*(uk-2.*mZ2)/q1h/q1/q2h/q2*tk*uk - (q1*q1+q2*q2)/q1/q2 - 2.*mZ2*(q2-2.*mZ2)/q1/q1/s*tk ); swap(tk ,uk ); swap(q1 ,q2 ); swap(q1h,q2h); t_u_qqb += (2.*s)*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/2. * ( - ( tk*uk*uk+2.*s*uk*uk-tk*tk*uk - 2.*s*tk*uk+mZ2*(tk*tk-uk*uk+2.*s*uk-2.*s*tk-2.*s*s) )/q1h/q1/q2h/s*tk + 2.*(tk*uk*uk-mZ2*uk*(s+3.*tk)+mZ2*mZ2*(2.*uk-s))/q1/q2/s + ( tk*uk*(uk+s)-mZ2*(uk*uk+3.*tk*uk+3.*s*uk+s*tk) + 2.*mZ2*mZ2*(uk+tk+2.*s) )/q1h/q1/q2/s*tk + ( tk*(uk*uk+tk*uk-s*s)+mZ2*(4.*s*uk-3.*tk*uk-tk*tk+4.*s*s) )/q1h/q2/s - ( tk*uk+s*uk-s*tk-s*s+2.*mZ2*(s-tk) ) /q1h/q1/s*tk + q2*(tk*uk-s*uk-2.*s*tk-2.*s*s)/q1/q2h/s + 2.*(tk*uk-tk*tk-s*tk-s*s+mZ2*(2.*s-uk))/q1/s - 2.*mZ2*(uk*uk-2.*mZ2*uk+2.*mZ2*mZ2)/q1/q1/q2/s*tk + (2.*s*uk+tk*tk+3.*s*tk+2*s*s)/q1h/s + q1*(uk+s)*(uk+tk)/q1h/q2h/s + (tk*uk+s*uk+3.*s*tk+2.*s*s-mZ2*(uk+tk+2.*s))/q1h/q2h/s*uk + (uk-tk)/2./q1h/q2h/s*(q1*(uk+s)/q2/tk-q2*(tk+s)/q1/uk)*tk*uk + (tk-2.*mZ2)*(uk-2.*mZ2)/q1h/q1/q2h/q2*tk*uk - (q1*q1+q2*q2)/q1/q2 - 2.*mZ2*(q2-2.*mZ2)/q1/q1/s*tk ); swap(tk ,uk ); swap(q1 ,q2 ); swap(q1h,q2h); swap(q1 ,q1h); swap(q2 ,q2h); t_u_qqb += (2.*s)*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/2. * ( - ( tk*uk*uk+2.*s*uk*uk-tk*tk*uk - 2.*s*tk*uk+mZ2*(tk*tk-uk*uk+2.*s*uk-2.*s*tk-2.*s*s) )/q1h/q1/q2h/s*tk + 2.*(tk*uk*uk-mZ2*uk*(s+3.*tk)+mZ2*mZ2*(2.*uk-s))/q1/q2/s + ( tk*uk*(uk+s)-mZ2*(uk*uk+3.*tk*uk+3.*s*uk+s*tk) + 2.*mZ2*mZ2*(uk+tk+2.*s) )/q1h/q1/q2/s*tk + ( tk*(uk*uk+tk*uk-s*s)+mZ2*(4.*s*uk-3.*tk*uk-tk*tk+4.*s*s) )/q1h/q2/s - ( tk*uk+s*uk-s*tk-s*s+2.*mZ2*(s-tk) ) /q1h/q1/s*tk + q2*(tk*uk-s*uk-2.*s*tk-2.*s*s)/q1/q2h/s + 2.*(tk*uk-tk*tk-s*tk-s*s+mZ2*(2.*s-uk))/q1/s - 2.*mZ2*(uk*uk-2.*mZ2*uk+2.*mZ2*mZ2)/q1/q1/q2/s*tk + (2.*s*uk+tk*tk+3.*s*tk+2*s*s)/q1h/s + q1*(uk+s)*(uk+tk)/q1h/q2h/s + (tk*uk+s*uk+3.*s*tk+2.*s*s-mZ2*(uk+tk+2.*s))/q1h/q2h/s*uk + (uk-tk)/2./q1h/q2h/s*(q1*(uk+s)/q2/tk-q2*(tk+s)/q1/uk)*tk*uk + (tk-2.*mZ2)*(uk-2.*mZ2)/q1h/q1/q2h/q2*tk*uk - (q1*q1+q2*q2)/q1/q2 - 2.*mZ2*(q2-2.*mZ2)/q1/q1/s*tk ); swap(q1 ,q1h); swap(q2 ,q2h); swap(tk ,uk ); swap(q1 ,q2h); swap(q2 ,q1h); t_u_qqb += (2.*s)*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/2. * ( - ( tk*uk*uk+2.*s*uk*uk-tk*tk*uk - 2.*s*tk*uk+mZ2*(tk*tk-uk*uk+2.*s*uk-2.*s*tk-2.*s*s) )/q1h/q1/q2h/s*tk + 2.*(tk*uk*uk-mZ2*uk*(s+3.*tk)+mZ2*mZ2*(2.*uk-s))/q1/q2/s + ( tk*uk*(uk+s)-mZ2*(uk*uk+3.*tk*uk+3.*s*uk+s*tk) + 2.*mZ2*mZ2*(uk+tk+2.*s) )/q1h/q1/q2/s*tk + ( tk*(uk*uk+tk*uk-s*s)+mZ2*(4.*s*uk-3.*tk*uk-tk*tk+4.*s*s) )/q1h/q2/s - ( tk*uk+s*uk-s*tk-s*s+2.*mZ2*(s-tk) ) /q1h/q1/s*tk + q2*(tk*uk-s*uk-2.*s*tk-2.*s*s)/q1/q2h/s + 2.*(tk*uk-tk*tk-s*tk-s*s+mZ2*(2.*s-uk))/q1/s - 2.*mZ2*(uk*uk-2.*mZ2*uk+2.*mZ2*mZ2)/q1/q1/q2/s*tk + (2.*s*uk+tk*tk+3.*s*tk+2*s*s)/q1h/s + q1*(uk+s)*(uk+tk)/q1h/q2h/s + (tk*uk+s*uk+3.*s*tk+2.*s*s-mZ2*(uk+tk+2.*s))/q1h/q2h/s*uk + (uk-tk)/2./q1h/q2h/s*(q1*(uk+s)/q2/tk-q2*(tk+s)/q1/uk)*tk*uk + (tk-2.*mZ2)*(uk-2.*mZ2)/q1h/q1/q2h/q2*tk*uk - (q1*q1+q2*q2)/q1/q2 - 2.*mZ2*(q2-2.*mZ2)/q1/q1/s*tk ); swap(tk ,uk ); swap(q1 ,q2h); swap(q2 ,q1h); return t_u_qqb; } /***************************************************************************/ // M_B_WW is the Born matrix element exactly as defined in Eqs. 3.2-3.8 // of of NPB 410(1993)280-384. double MEPP2VVPowheg::M_Born_WW(bornVVKinematics B) const { Energy2 s(B.sb()); Energy2 t(B.tb()); Energy2 u(B.ub()); Energy2 mW2(B.k12b()); // N.B. the diboson masses are preserved in getting bool up_type = abs(quark_->id())%2==0 ? true : false; double Qi = up_type ? 2./3. : -1./3. ; double giL = up_type ? guL_/2. : gdL_/2.; double giR = up_type ? guR_/2. : gdR_/2.; double e2 = sqr(gW_)*sin2ThetaW_; double cos2ThetaW(1.-sin2ThetaW_); double ctt_i(gW_*gW_*gW_*gW_/16.); InvEnergy2 cts_i(gW_*gW_*e2/4./s *(Qi+2.*eZ_*giL/e2*s/(s-mW2/cos2ThetaW))); InvEnergy4 css_i(e2*e2/s/s*(sqr(Qi+eZ_*(giL+giR)/e2*s/(s-mW2/cos2ThetaW)) +sqr( eZ_*(giL-giR)/e2*s/(s-mW2/cos2ThetaW))) ); ctt_i *= 8.*Fij2_/gW_/gW_; cts_i *= sqrt(8.*Fij2_/gW_/gW_); if(quark_->id()!=-antiquark_->id()) { cts_i = 0./GeV2; css_i = 0./GeV2/GeV2; } if(!up_type) swap(t,u); double signf = up_type ? 1. : -1.; return 1./4./NC_ * ( ctt_i*( 16.*(u*t/mW2/mW2-1.)*(1./4.+mW2*mW2/t/t)+16.*s/mW2) - cts_i*( 16.*(u*t/mW2/mW2-1.)*(s/4.-mW2/2.-mW2*mW2/t) + 16.*s*(s/mW2-2.+2.*mW2/t) ) *signf + css_i*( 8.*(u*t/mW2/mW2-1.)*(s*s/4.-s*mW2+3.*mW2*mW2) + 8.*s*s*(s/mW2-4.) ) ); } /***************************************************************************/ // M_V_regular_WW is the regular part of the one-loop WW matrix element // exactly as defined in Eqs. C.1 - C.7 of of NPB 410(1993)280-324 *** // modulo a factor 1/(2s) ***, which is a flux factor that those authors // absorb in the matrix element. double MEPP2VVPowheg::M_V_regular_WW(realVVKinematics S) const { Energy2 s(S.bornVariables().sb()); Energy2 t(S.bornVariables().tb()); Energy2 u(S.bornVariables().ub()); Energy2 mW2(S.k12r()); // N.B. the diboson masses are preserved in getting double beta(S.betaxr()); // N.B. for x=1 \beta_x=\beta in NPB 383(1992)3-44. bool up_type = abs(quark_->id())%2==0 ? true : false; double Qi = up_type ? 2./3. : -1./3.; double giL = up_type ? guL_/2. : gdL_/2.; double giR = up_type ? guR_/2. : gdR_/2.; double e2 = sqr(gW_)*sin2ThetaW_; double cos2ThetaW(1.-sin2ThetaW_); double ctt_i(gW_*gW_*gW_*gW_/16.); InvEnergy2 cts_i(gW_*gW_*e2/4./s *(Qi+2.*eZ_*giL/e2*s/(s-mW2/cos2ThetaW))); InvEnergy4 css_i(e2*e2/s/s*(sqr(Qi+eZ_*(giL+giR)/e2*s/(s-mW2/cos2ThetaW)) +sqr( eZ_*(giL-giR)/e2*s/(s-mW2/cos2ThetaW))) ); ctt_i *= 8.*Fij2_/gW_/gW_; cts_i *= sqrt(8.*Fij2_/gW_/gW_); if(quark_->id()!=-antiquark_->id()) { cts_i = 0./GeV2; css_i = 0./GeV2/GeV2; } if(!up_type) swap(t,u); double signf = up_type ? 1. : -1.; InvEnergy4 TildeI4 = ( 2.*sqr(log(-t/mW2))-4.*log((mW2-t)/mW2)*log(-t/mW2) - 4.*ReLi2(t/mW2) )/s/t; InvEnergy2 TildeI3t = 1./(mW2-t) *(sqr(log(mW2/s))/2.-sqr(log(-t/s))/2.-pi*pi/2.); InvEnergy2 TildeI3l = 1./s/beta*( 4.*ReLi2((beta-1.)/(beta+1.)) + sqr(log((1.-beta)/(1.+beta))) + pi*pi/3.); double Fup1_st(0.); Fup1_st = 4.*(80.*t*t+73.*s*t-140.*mW2*t+72.*mW2*mW2)/t/t - 4.*sqr(4.*t+s)/s/beta/beta/t - 128.*(t+2.*s)/mW2 + 64.*t*(t+s)/mW2/mW2 - (32.*(t*t-3.*s*t-3.*mW2*mW2)/t/t+128.*s/(t-mW2))*log(-t/mW2) + ( 8.*(6.*t*t+8.*s*t-19.*mW2*t+12.*mW2*mW2)/t/t - (32.*t*t-128.*s*t-26.*s*s)/s/beta/beta/t + 6.*sqr(4.*t+s)/s/sqr(sqr(beta))/t )*log(s/mW2) + 32.*s*(2.*mW2*mW2/t-u)*TildeI4 - 64.*(t-mW2)*(2.*mW2*mW2/t/t-u/t)*TildeI3t + ( (16.*t*(4.*mW2-u)-49.*s*s+72.*mW2*s-48.*mW2*mW2)/2./t + 2.*(8.*t*t-14.*s*t-3.*s*s)/beta/beta/t - 3.*sqr(4.*t+s)/2./sqr(sqr(beta))/t )*TildeI3l + 32./3.*( 2.*(t+2.*s)/mW2 - (3.*t+2.*s-4.*mW2)/t - t*(t+s)/mW2/mW2 )*pi*pi; Energy2 Jup1_st(0.*GeV2); Jup1_st = -128.*(t*t+2.*s*t+2.*s*s)/mW2 - 16.*(t*t-21.*s*t-26.*mW2*t+34.*mW2*s+17.*mW2*mW2)/t + 64.*s*t*(t+s)/mW2/mW2 +32.*s*s/(t-mW2) + ( 16.*(t-5.*s+2.*mW2)-48.*mW2*(2.*s+mW2)/t + 64.*s*(2.*t+s)/(t-mW2) - 32.*s*s*t/sqr(t-mW2) )*log(-t/mW2) + ( 16.*(4.*t+s)/beta/beta - 16.*(3.*t-2.*s) + 48.*mW2*(2.*t-2.*s-mW2)/t )*log(s/mW2) + 16.*s*(t*(2.*s+u)-2.*mW2*(2.*s+mW2))*TildeI4 + 32.*(t-mW2)*(2.*mW2*(2.*s+mW2)/t-2.*s-u)*TildeI3t + ( 32.*s*t-12.*s*s+32.*mW2*mW2 - 16.*mW2*(2.*t+7.*s)-4.*s*(4.*t+s)/beta/beta )*TildeI3l + 32./3.*( 2.*(t*t+2.*s*t+2.*s*s)/mW2 - s*t*(t+s)/mW2/mW2-2.*mW2*(2.*t-2.*s-mW2)/t-t-4.*s )*pi*pi; Energy4 Kup1_st(0.*GeV2*GeV2); Kup1_st = 16.*( 12.*t*t+20.*s*t-24.*mW2*t+17.*s*s-4.*mW2*s+12.*mW2*mW2 + s*s*t*(t+s)/mW2/mW2-2.*s*(2.*t*t+3.*s*t+2.*s*s)/mW2) *(2.-pi*pi/3.); return pi*alphaS_*CF_/NC_/(sqr(4.*pi)) * ( ctt_i*Fup1_st - cts_i*Jup1_st*signf + css_i*Kup1_st ); } /***************************************************************************/ // t_u_M_R_qqb is the real emission q + qb -> n + g matrix element // exactly as defined in Eqs. C.1 of NPB 383(1992)3-44, multiplied by // tk * uk! Energy2 MEPP2VVPowheg::t_u_M_R_qqb_WW(realVVKinematics R) const { // First the Born variables: Energy2 s2(R.s2r()); Energy2 mW2(R.k12r()); // Then the rest: Energy2 s(R.sr()); Energy2 tk(R.tkr()); Energy2 uk(R.ukr()); Energy2 q1(R.q1r()); Energy2 q2(R.q2r()); Energy2 q1h(R.q1hatr()); Energy2 q2h(R.q2hatr()); bool up_type = abs(quark_->id())%2==0 ? true : false; double Qi = up_type ? 2./3. : -1./3.; double giL = up_type ? guL_/2. : gdL_/2.; double giR = up_type ? guR_/2. : gdR_/2.; double e2 = sqr(gW_)*sin2ThetaW_; double cos2ThetaW(1.-sin2ThetaW_); double ctt_i(gW_*gW_*gW_*gW_/16.); InvEnergy2 cts_i(gW_*gW_*e2/4./s2*(Qi+2.*eZ_*giL/e2*s2/(s2-mW2/cos2ThetaW))); InvEnergy4 css_i(e2*e2/s2/s2*(sqr(Qi+eZ_*(giL+giR)/e2*s2/(s2-mW2/cos2ThetaW)) +sqr( eZ_*(giL-giR)/e2*s2/(s2-mW2/cos2ThetaW))) ); ctt_i *= 8.*Fij2_/gW_/gW_; cts_i *= sqrt(8.*Fij2_/gW_/gW_); if(quark_->id()!=-antiquark_->id()) { cts_i = 0./GeV2; css_i = 0./GeV2/GeV2; } if(!up_type) { swap(q1,q1h); swap(q2,q2h); } double signf = up_type ? 1. : -1.; Energy2 t_u_Xup(0.*GeV2); Energy4 t_u_Yup(0.*GeV2*GeV2); Energy6 t_u_Zup(0.*GeV2*GeV2*GeV2); t_u_Xup = 32.*mW2*(tk*uk+3.*q2*uk+q2*s+q1*q2)/q1/q2/q2*tk + 32.*mW2*q1/q2/q2*uk - 64.*mW2*s/q2 - 32.*tk*(uk-q2)/q1/q2*tk + 64.*mW2*mW2*mW2/q1/q1/q2*tk - 16.*(2.*tk-2.*s-q2)/q2*uk + 16.*s*(2.*s+2.*q1+q2/2.)/q2 - 8.*(4.*tk+uk+9.*s+2.*q2+2.*q1)/mW2*tk - 16.*s*(2.*s+q1)/mW2 - 64.*mW2*mW2*(tk*uk+q2*tk+q1*uk-q2*s/2.)/q1/q2/q2 + 8.*s2*q1*(tk+s+q1)/mW2/mW2; swap(tk,uk); swap(q1,q2); t_u_Xup += 32.*mW2*(tk*uk+3.*q2*uk+q2*s+q1*q2)/q1/q2/q2*tk + 32.*mW2*q1/q2/q2*uk - 64.*mW2*s/q2 - 32.*tk*(uk-q2)/q1/q2*tk + 64.*mW2*mW2*mW2/q1/q1/q2*tk - 16.*(2.*tk-2.*s-q2)/q2*uk + 16.*s*(2.*s+2.*q1+q2/2.)/q2 - 8.*(4.*tk+uk+9.*s+2.*q2+2.*q1)/mW2*tk - 16.*s*(2.*s+q1)/mW2 - 64.*mW2*mW2*(tk*uk+q2*tk+q1*uk-q2*s/2.)/q1/q2/q2 + 8.*s2*q1*(tk+s+q1)/mW2/mW2; swap(tk,uk); swap(q1,q2); t_u_Yup = - 16.*tk*(uk*(uk+s+q1)+q2*(s-2.*q1))/q1/q2*tk - 32.*mW2*mW2*s/q2 - 32.*mW2*mW2*mW2/q1/q2*tk + 16.*(2.*q2*uk+s*s+q1*s+5.*q2*s+q1*q2+2.*q2*q2)/q2*tk - 16.*(q2*q2+s*s-q2*s)/q1*tk + 16.*s*(q1*s+3./2.*q2*s+q1*q2-q1*q1)/q2 + 16.*mW2*tk*(4.*uk+s+q1-2.*q2)/q1/q2*tk + 16.*mW2*(3.*s*uk+q1*uk-q1*s-3.*q2*s-q1*q1+q2*q2)/q1/q2*tk + 16.*mW2*s*(q2-4.*s+2.*q1)/q2 - 8.*s2*(4.*tk+uk+9.*s+4.*q1+2.*q2)/mW2*tk - 16.*s2*(2.*s*s+2.*q1*s+q1*q1)/mW2 - 32.*mW2*mW2*(tk+uk/2.+2.*s-q1)/q1/q2*tk + 8.*s2*s2*q1*(tk+s+q1)/mW2/mW2; swap(tk,uk); swap(q1,q2); t_u_Yup += - 16.*tk*(uk*(uk+s+q1)+q2*(s-2.*q1))/q1/q2*tk - 32.*mW2*mW2*s/q2 - 32.*mW2*mW2*mW2/q1/q2*tk + 16.*(2.*q2*uk+s*s+q1*s+5.*q2*s+q1*q2+2.*q2*q2)/q2*tk - 16.*(q2*q2+s*s-q2*s)/q1*tk + 16.*s*(q1*s+3./2.*q2*s+q1*q2-q1*q1)/q2 + 16.*mW2*tk*(4.*uk+s+q1-2.*q2)/q1/q2*tk + 16.*mW2*(3.*s*uk+q1*uk-q1*s-3.*q2*s-q1*q1+q2*q2)/q1/q2*tk + 16.*mW2*s*(q2-4.*s+2.*q1)/q2 - 8.*s2*(4.*tk+uk+9.*s+4.*q1+2.*q2)/mW2*tk - 16.*s2*(2.*s*s+2.*q1*s+q1*q1)/mW2 - 32.*mW2*mW2*(tk+uk/2.+2.*s-q1)/q1/q2*tk + 8.*s2*s2*q1*(tk+s+q1)/mW2/mW2; swap(tk,uk); swap(q1,q2); t_u_Zup = 8.*s2*(9.*tk+3.*uk+20.*s+10.*q1+4.*q2)*tk + 8.*s2*(17./2.*s*s+10.*q1*s+6.*q1*q1) - 4.*s2*s2*(4.*tk+uk+9.*s+6.*q1+2.*q2)/mW2*tk - 8.*s2*s2*(2.*s*s+3.*q1*s+2.*q1*q1)/mW2 - 16.*mW2*(2.*tk+5.*uk+7.*s+6.*q1+6.*q2)*tk - 16.*mW2*s*(s+6.*q1) + 4.*s2*s2*s2*q1*(tk+s+q1)/mW2/mW2 + 48.*mW2*mW2*s2; swap(tk,uk); swap(q1,q2); t_u_Zup += 8.*s2*(9.*tk+3.*uk+20.*s+10.*q1+4.*q2)*tk + 8.*s2*(17./2.*s*s+10.*q1*s+6.*q1*q1) - 4.*s2*s2*(4.*tk+uk+9.*s+6.*q1+2.*q2)/mW2*tk - 8.*s2*s2*(2.*s*s+3.*q1*s+2.*q1*q1)/mW2 - 16.*mW2*(2.*tk+5.*uk+7.*s+6.*q1+6.*q2)*tk - 16.*mW2*s*(s+6.*q1) + 4.*s2*s2*s2*q1*(tk+s+q1)/mW2/mW2 + 48.*mW2*mW2*s2; swap(tk,uk); swap(q1,q2); return -pi*alphaS_*CF_/NC_ * ( ctt_i*t_u_Xup - cts_i*t_u_Yup*signf + css_i*t_u_Zup ); } /***************************************************************************/ // The game here is to get this helicity amplitude squared to return all the // same values as t_u_M_R_qqb above, TIMES a further factor tk*uk! Energy2 MEPP2VVPowheg::t_u_M_R_qqb_hel_amp(realVVKinematics R) const { using namespace ThePEG::Helicity; // qqb_hel_amps_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half, // PDT::Spin1,PDT::Spin1, // PDT::Spin1)); double sum_hel_amps_sqr(0.); tcPDPtr p1data(quark_); tcPDPtr p2data(antiquark_); tcPDPtr k1data(mePartonData()[2]); tcPDPtr k2data(mePartonData()[3]); tcPDPtr kdata(getParticleData(ParticleID::g)); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorWaveFunction qSpinor(R.p1r(),p1data,incoming); SpinorBarWaveFunction qbSpinor(R.p2r(),p2data,incoming); vector q; vector qb; for(unsigned int ix=0;ix<2;ix++) { qSpinor.reset(ix); qbSpinor.reset(ix); q.push_back(qSpinor); qb.push_back(qbSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.kr(),kdata,outgoing); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(p2data); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorWaveFunction p1_k = ffg->evaluate(mu_UV2(),5,p1data,q[p1hel],g[khel]); SpinorBarWaveFunction p2_k = ffg->evaluate(mu_UV2(),5,p2data,qb[p2hel],g[khel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p1hel=p2hel // but if the production ME is required first fill it with (0.,0.). if((p1hel==p2hel)&&helicityConservation_) { // if(getMatrix) { // if(khel==0) // qqb_hel_amps_(p1hel,p2hel,k1hel,k2hel,0) = Complex(0.,0.); // else // qqb_hel_amps_(p1hel,p2hel,k1hel,k2hel,2) = Complex(0.,0.); // } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_t; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? p2data : tc[ix]; SpinorWaveFunction p1_v1 = ffv1->evaluate(scale(),5,intermediate_t,q[p1hel],v1[k1hel]); SpinorBarWaveFunction p2_v2 = ffv2->evaluate(scale(),5,intermediate_t,qb[p2hel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 t-channel diagrams // q+qb->g+v1+v2, q+qb->v1+g+v2, q+qb->v1+v2+g if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) { diagrams.push_back(ffv1->evaluate(scale(),p1_k,p2_v2,v1[k1hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),p1_v1,p2_v2,g[khel])); diagrams.push_back(ffv2->evaluate(scale(),p1_v1,p2_k,v2[k2hel])); } intermediate_t = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(scale(),5,intermediate_t,q[p1hel],v2[k2hel]); SpinorBarWaveFunction p2_v1 = ffv1->evaluate(scale(),5,intermediate_t,qb[p2hel],v1[k1hel]); // q+qb->g+v2+v1, q+qb->v2+g+v1, q+qb->v2+v1+g if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) { diagrams.push_back(ffv2->evaluate(scale(),p1_k,p2_v1,v2[k2hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),p1_v2,p2_v1,g[khel])); diagrams.push_back(ffv1->evaluate(scale(),p1_v2,p2_k,v1[k1hel])); } } // Note: choosing 3 as the second argument in WWWvertex_->evaluate() // sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which // means the propagator does not contain a width factor (which is // good re. gauge invariance). // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(scale(),3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(scale(),p1_k,qb[p2hel],k1_k2)); diagrams.push_back(ffv1->evaluate(scale(),q[p1hel],p2_k,k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==-p2data->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(scale(),3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(scale(),p1_k,qb[p2hel],k1_k2)); diagrams.push_back(FFZvertex_->evaluate(scale(),q[p1hel],p2_k,k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(scale(),3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(scale(),p1_k,qb[p2hel],k1_k2)); diagrams.push_back(FFPvertex_->evaluate(scale(),q[p1hel],p2_k,k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } /***************************************************************************/ // The game here is to get this helicity amplitude squared to return all the // same values as t_u_M_R_qg above, TIMES a further factor tk*uk! Energy2 MEPP2VVPowheg::t_u_M_R_qg_hel_amp(realVVKinematics R) const { using namespace ThePEG::Helicity; // qg_hel_amps_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1, // PDT::Spin1,PDT::Spin1, // PDT::Spin1Half)); double sum_hel_amps_sqr(0.); tcPDPtr p1data(quark_); tcPDPtr p2data(getParticleData(ParticleID::g)); tcPDPtr k1data(mePartonData()[2]); tcPDPtr k2data(mePartonData()[3]); tcPDPtr kdata (antiquark_->CC()); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorWaveFunction qinSpinor(R.p1r(),p1data,incoming); SpinorBarWaveFunction qoutSpinor(R.kr(),kdata,outgoing); vector qin; vector qout; for(unsigned int ix=0;ix<2;ix++) { qinSpinor.reset(ix); qoutSpinor.reset(ix); qin.push_back(qinSpinor); qout.push_back(qoutSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.p2r(),p2data,incoming); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(kdata->CC()); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorWaveFunction p1_p2 = ffg->evaluate(mu_UV2(),5,p1data,qin[p1hel],g[p2hel]); SpinorBarWaveFunction p2_k = ffg->evaluate(mu_UV2(),5,kdata->CC(),qout[khel],g[p2hel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p1hel!=khel // but if the production ME is required first fill it with (0.,0.). if((p1hel!=khel)&&helicityConservation_) { // if(getMatrix) { // if(p2hel==0) // qg_hel_amps_(p1hel,0,k1hel,k2hel,khel) = Complex(0.,0.); // else // qg_hel_amps_(p1hel,2,k1hel,k2hel,khel) = Complex(0.,0.); // } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_q; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? antiquark_ : tc[ix]; SpinorWaveFunction p1_v1 = ffv1->evaluate(scale(),5,intermediate_q,qin[p1hel],v1[k1hel]); SpinorBarWaveFunction k_v2 = ffv2->evaluate(scale(),5,intermediate_q,qout[khel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 abelian diagrams // q+g->v1+v2+q with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) { diagrams.push_back(ffv2->evaluate(scale(),p1_v1,p2_k,v2[k2hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),p1_v1,k_v2,g[p2hel])); diagrams.push_back(ffv1->evaluate(scale(),p1_p2,k_v2,v1[k1hel])); } intermediate_q = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(scale(),5,intermediate_q,qin[p1hel],v2[k2hel]); SpinorBarWaveFunction k_v1 = ffv1->evaluate(scale(),5,intermediate_q,qout[khel],v1[k1hel]); // q+g->v2+v1+q, with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) { diagrams.push_back(ffv1->evaluate(scale(),p1_v2,p2_k,v1[k1hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),p1_v2,k_v1,g[p2hel])); diagrams.push_back(ffv2->evaluate(scale(),p1_p2,k_v1,v2[k2hel])); } } // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(scale(),3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(scale(),p1_p2,qout[khel],k1_k2)); diagrams.push_back(ffv1->evaluate(scale(),qin[p1hel],p2_k,k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==kdata->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(scale(),3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(scale(),p1_p2,qout[khel],k1_k2)); diagrams.push_back(FFZvertex_->evaluate(scale(),qin[p1hel],p2_k,k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(scale(),3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(scale(),p1_p2,qout[khel],k1_k2)); diagrams.push_back(FFPvertex_->evaluate(scale(),qin[p1hel],p2_k,k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } /***************************************************************************/ // The game here is to get this helicity amplitude squared to return all the // same values as t_u_M_R_gqb above, TIMES a further factor tk*uk! Energy2 MEPP2VVPowheg::t_u_M_R_gqb_hel_amp(realVVKinematics R) const { using namespace ThePEG::Helicity; // gqb_hel_amps_.reset(ProductionMatrixElement(PDT::Spin1,PDT::Spin1Half, // PDT::Spin1,PDT::Spin1, // PDT::Spin1Half)); double sum_hel_amps_sqr(0.); tcPDPtr p1data(getParticleData(ParticleID::g)); tcPDPtr p2data(antiquark_); tcPDPtr k1data(mePartonData()[2]); tcPDPtr k2data(mePartonData()[3]); tcPDPtr kdata (quark_->CC()); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorBarWaveFunction qbinSpinor(R.p2r(),p2data,incoming); SpinorWaveFunction qboutSpinor(R.kr(),kdata,outgoing); vector qbin; vector qbout; for(unsigned int ix=0;ix<2;ix++) { qbinSpinor.reset(ix); qboutSpinor.reset(ix); qbin.push_back(qbinSpinor); qbout.push_back(qboutSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.p1r(),p1data,incoming); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p2data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p2data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(kdata->CC()); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorBarWaveFunction p1_p2 = ffg->evaluate(mu_UV2(),5,p2data,qbin[p2hel],g[p1hel]); SpinorWaveFunction p1_k = ffg->evaluate(mu_UV2(),5,kdata->CC(),qbout[khel],g[p1hel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p2hel!=khel // but if the production ME is required first fill it with (0.,0.). if((p2hel!=khel)&&helicityConservation_) { // if(getMatrix) { // if(p1hel==0) // gqb_hel_amps_(0,p2hel,k1hel,k2hel,khel) = Complex(0.,0.); // else // gqb_hel_amps_(2,p2hel,k1hel,k2hel,khel) = Complex(0.,0.); // } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_q; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? quark_ : tc[ix]; SpinorBarWaveFunction p2_v1 = ffv1->evaluate(scale(),5,intermediate_q,qbin[p2hel],v1[k1hel]); SpinorWaveFunction k_v2 = ffv2->evaluate(scale(),5,intermediate_q,qbout[khel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 abelian diagrams q+g->v1+v2+q // with 2 t-channel propagators, 1 s- and 1 t-channel // and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p2data->id())%2==0))) { diagrams.push_back(ffv2->evaluate(scale(),p1_k,p2_v1,v2[k2hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),k_v2,p2_v1,g[p1hel])); diagrams.push_back(ffv1->evaluate(scale(),k_v2,p1_p2,v1[k1hel])); } intermediate_q = (!(k1data->id()==24&&k2data->id()==-24)) ? p2data : tc[ix]; SpinorBarWaveFunction p2_v2 = ffv2->evaluate(scale(),5,intermediate_q,qbin[p2hel],v2[k2hel]); SpinorWaveFunction k_v1 = ffv1->evaluate(scale(),5,intermediate_q,qbout[khel],v1[k1hel]); // q+g->v2+v1+q, with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p2data->id())%2==1))) { diagrams.push_back(ffv1->evaluate(scale(),p1_k,p2_v2,v1[k1hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),k_v1,p2_v2,g[p1hel])); diagrams.push_back(ffv2->evaluate(scale(),k_v1,p1_p2,v2[k2hel])); } } // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(scale(),3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(scale(),qbout[khel],p1_p2,k1_k2)); diagrams.push_back(ffv1->evaluate(scale(),p1_k,qbin[p2hel],k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p2data->id()==kdata->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(scale(),3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(scale(),qbout[khel],p1_p2,k1_k2)); diagrams.push_back(FFZvertex_->evaluate(scale(),p1_k,qbin[p2hel],k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(scale(),3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(scale(),qbout[khel],p1_p2,k1_k2)); diagrams.push_back(FFPvertex_->evaluate(scale(),p1_k,qbin[p2hel],k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } double MEPP2VVPowheg::lo_me() const { using namespace ThePEG::Helicity; double sum_hel_amps_sqr(0.); tcPDPtr p1data(quark_); tcPDPtr p2data(antiquark_); tcPDPtr k1data(mePartonData()[2]); tcPDPtr k2data(mePartonData()[3]); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); // Should never actually occur. SpinorWaveFunction qSpinor(B_.p1b(),p1data,incoming); SpinorBarWaveFunction qbSpinor(B_.p2b(),p2data,incoming); vector q; vector qb; for(unsigned int ix=0;ix<2;ix++) { qSpinor.reset(ix); qbSpinor.reset(ix); q.push_back(qSpinor); qb.push_back(qbSpinor); } VectorWaveFunction v1Polarization(B_.k1b(),k1data,outgoing); VectorWaveFunction v2Polarization(B_.k2b(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(p2data); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { if((p1hel==p2hel)&&helicityConservation_) continue; for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_t; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? p2data : tc[ix]; SpinorWaveFunction p1_v1 = ffv1->evaluate(scale(),5,intermediate_t,q[p1hel],v1[k1hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 t-channel diagrams // q+qb->v1+v2 if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) diagrams.push_back(ffv2->evaluate(scale(),p1_v1,qb[p2hel],v2[k2hel])); intermediate_t = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(scale(),5,intermediate_t,q[p1hel],v2[k2hel]); // q+qb->v2+v1 if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) diagrams.push_back(ffv1->evaluate(scale(),p1_v2,qb[p2hel],v1[k1hel])); } // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(scale(),3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->v1*->v1+v2 diagrams.push_back(ffv1->evaluate(scale(),q[p1hel],qb[p2hel],k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==-p2data->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->Z0*->v1+v2 tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(scale(),3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(scale(),q[p1hel],qb[p2hel],k1_k2)); // q+qb->gamma*->v1+v2 tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(scale(),3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(scale(),q[p1hel],qb[p2hel],k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr; } RealEmissionProcessPtr MEPP2VVPowheg::generateHardest(RealEmissionProcessPtr born, ShowerInteraction inter) { - if(inter==ShowerInteraction::QED) return RealEmissionProcessPtr(); + // check if generating QCD radiation + if(inter!=ShowerInteraction::QCD && inter!=ShowerInteraction::QEDQCD && + inter!=ShowerInteraction::ALL) + return RealEmissionProcessPtr(); // Now we want to set these data vectors according to the particles we've // received from the current 2->2 hard collision: vector particlesToShower; for(unsigned int ix=0;ixbornIncoming().size();++ix) particlesToShower.push_back(born->bornIncoming()[ix]); qProgenitor_ = particlesToShower[0]; qbProgenitor_ = particlesToShower[1]; showerQuark_ = particlesToShower[0]; showerAntiquark_ = particlesToShower[1]; qHadron_ = dynamic_ptr_cast(born->hadrons()[0]->dataPtr()); qbHadron_ = dynamic_ptr_cast(born->hadrons()[1]->dataPtr()); if(showerQuark_->id()<0) { swap(qProgenitor_,qbProgenitor_); swap(showerQuark_,showerAntiquark_); swap(qHadron_,qbHadron_); } // In _our_ calculation we basically define the +z axis as being given // by the direction of the incoming quark for q+qb & q+g processes and // the incoming gluon for g+qbar processes. So now we might need to flip // the beams, bjorken x values, colliding partons accordingly: flipped_ = showerQuark_->momentum().z() cmap; // undecayed gauge bosons if(born->bornOutgoing().size()==2) { for(unsigned int ix=0;ixbornOutgoing().size();++ix) { particlesToShower.push_back(born->bornOutgoing()[ix]); } V1_ = particlesToShower[2]; V2_ = particlesToShower[3]; } else if(born->bornOutgoing().size()==4) { // If the vector bosons have decayed already then we may want to // to get the children_ (and any associated photons) to correct // spin correlations: children_.clear(); map clines; for(unsigned int ix=0;ixbornOutgoing().size();++ix) { tPPtr original = born->bornOutgoing()[ix]; PPtr copy = original->dataPtr()->produceParticle(original->momentum()); children_.push_back(copy); cmap.push_back(ix); // sort out colour if(original->colourLine()) { map::iterator cit = clines.find(original->colourLine()); if(cit!=clines.end()) { cit->second->addColoured(copy); } else { ColinePtr newline = new_ptr(ColourLine()); clines[original->colourLine()] = newline; newline->addColoured(copy); } } // and anticolour else if(original->antiColourLine()) { map::iterator cit = clines.find(original->antiColourLine()); if(cit!=clines.end()) { cit->second->addAntiColoured(copy); } else { ColinePtr newline = new_ptr(ColourLine()); clines[original->antiColourLine()] = newline; newline->addAntiColoured(copy); } } } assert(children_.size()==4); PPtr V[2]; for(unsigned int ix=0;ix<2;++ix) { int charge = children_[0+2*ix]->dataPtr()->iCharge()+ children_[1+2*ix]->dataPtr()->iCharge(); Lorentz5Momentum psum =children_[0+2*ix]->momentum()+ children_[1+2*ix]->momentum(); psum.rescaleMass(); if(charge==-3) V[ix] = getParticleData(ParticleID::Wminus)->produceParticle(psum); else if(charge==0) V[ix] = getParticleData(ParticleID::Z0)->produceParticle(psum); else if(charge==3) V[ix] = getParticleData(ParticleID::Wplus)->produceParticle(psum); else assert(false); } V1_ = V[0]; V2_ = V[1]; if(children_[0]->id()<0) { swap(children_[0],children_[1]); swap(cmap[0],cmap[1]); } if(children_[2]->id()<0) { swap(children_[2],children_[3]); swap(cmap[2],cmap[3]); } } else assert(false); gluon_ = getParticleData(ParticleID::g)->produceParticle(); // Abort the run if V1_ and V2_ are not just pointers to different gauge bosons if(!V1_||!V2_) throw Exception() << "MEPP2VVPowheg::generateHardest()\n" << "one or both of the gauge boson pointers is null." << Exception::abortnow; if(!(abs(V1_->id())==24||V1_->id()==23)||!(abs(V2_->id())==24||V2_->id()==23)) throw Exception() << "MEPP2VVPowheg::generateHardest()\nmisidentified gauge bosons" << "V1_ = " << V1_->PDGName() << "\n" << "V2_ = " << V2_->PDGName() << "\n" << Exception::abortnow; // Order the gauge bosons in the same way as in the NLO calculation // (the same way as in the NLO matrix element): // W+(->e+,nu_e) W-(->e-,nu_ebar) (MCFM: 61 [nproc]) bool order = false; if((V1_->id()==-24&&V2_->id()== 24) || // W+/-(mu+,nu_mu / mu-,nu_mubar) Z(nu_e,nu_ebar) (MCFM: 72+77 [nproc]) (V1_->id()== 23&&abs(V2_->id())== 24) ) { swap(V1_,V2_); order = true; if(born->bornOutgoing().size()==4) { swap(cmap[0],cmap[2]); swap(cmap[1],cmap[3]); swap(children_[0],children_[2]); swap(children_[1],children_[3]); } } // *** N.B. *** // We should not have to do a swap in the ZZ case, even if the different // (off-shell) masses of the Z's are taken into account by generating // the Born variables using the WZ LO/NLO matrix element(s), because // those transformed matrix elements are, according to mathematica, // symmetric in the momenta (and therefore also the masses) of the 2 Z's. // Now we want to construct a bornVVKinematics object. The // constructor for that needs all 4 momenta, q, qbar, V1_, V2_ // in that order, as well as the Bjorken xq and xqbar. // Get the momenta first: vector theBornMomenta; theBornMomenta.push_back(showerQuark_->momentum()); theBornMomenta.push_back(showerAntiquark_->momentum()); theBornMomenta.push_back(V1_->momentum()); theBornMomenta.push_back(V2_->momentum()); // N.B. if the showerQuark_ travels in the -z direction the born kinematics object // will detect this and rotate all particles by pi about the y axis! // Leading order momentum fractions: tcPPtr qHadron = generator()->currentEvent()->primaryCollision()->incoming().first; tcPPtr qbHadron = generator()->currentEvent()->primaryCollision()->incoming().second; assert(qHadron->children().size()>0&&qbHadron->children().size()>0); if(qHadron->children()[0]->id()<0) swap(qHadron,qbHadron); // quark and antiquark momentum fractions respectively double xa = showerQuark_ ->momentum().z()/qHadron ->momentum().z(); double xb = showerAntiquark_->momentum().z()/qbHadron->momentum().z(); // Create the object containing all 2->2 __kinematic__ information: B_ = bornVVKinematics(theBornMomenta,xa,xb); // lo_me_ is the colour & spin averaged n-body matrix element squared: lo_me_ = lo_me(true); // Attempt to generate some radiative variables and their kinematics: vector theRealMomenta; channel_ = 999; if(!getEvent(theRealMomenta,channel_)) { born->pT()[ShowerInteraction::QCD] = min_pT_; return born; } // Set the maximum pT for subsequent emissions: born->pT()[ShowerInteraction::QCD] = pT_ < min_pT_ ? min_pT_ : pT_; // Determine whether the quark or antiquark emitted: fermionNumberOfMother_=0; if((channel_==0&&theRealMomenta[0].z()/theRealMomenta[4].z()>=ZERO)|| channel_==2) fermionNumberOfMother_ = 1; else if((channel_==0&&theRealMomenta[0].z()/theRealMomenta[4].z()0.1*GeV||inMinusOut.x()>0.1*GeV|| inMinusOut.y()>0.1*GeV||inMinusOut.z()>0.1*GeV) cout << "MEPP2VVPowheg::generateHardest\n" << "Momentum imbalance in V1 V2 rest frame\n" << "P_in minus P_out = " << inMinusOut/GeV << endl; // From the radiative kinematics we now have to form ShowerParticle objects: PPtr p1,p2,k; PPtr k1 = V1_->dataPtr()->produceParticle(theRealMomenta[2]); PPtr k2 = V2_->dataPtr()->produceParticle(theRealMomenta[3]); // q+qbar -> V1+V2+g if(channel_==0) { p1 = showerQuark_ ->dataPtr()->produceParticle(theRealMomenta[0]); p2 = showerAntiquark_->dataPtr()->produceParticle(theRealMomenta[1]); k = gluon_ ->dataPtr()->produceParticle(theRealMomenta[4]); k->incomingColour(p1); k->incomingColour(p2,true); } // q+g -> V1+V2+q else if(channel_==1) { p1 = showerQuark_ ->dataPtr() ->produceParticle(theRealMomenta[0]); p2 = gluon_ ->dataPtr() ->produceParticle(theRealMomenta[1]); k = showerAntiquark_->dataPtr()->CC()->produceParticle(theRealMomenta[4]); k->incomingColour(p2); p2->colourConnect(p1); } // g+qbar -> V1+V2+qbar else { p1 = gluon_ ->dataPtr() ->produceParticle(theRealMomenta[0]); p2 = showerAntiquark_->dataPtr() ->produceParticle(theRealMomenta[1]); k = showerQuark_ ->dataPtr()->CC()->produceParticle(theRealMomenta[4]); k->incomingColour(p1,true); p1->colourConnect(p2,true); } Lorentz5Momentum pmother,pspect; if(fermionNumberOfMother_==1) { pmother = theRealMomenta[0]-theRealMomenta[4]; pspect = theRealMomenta[1]; } else { pmother = theRealMomenta[1]-theRealMomenta[4]; pspect = theRealMomenta[0]; } unsigned int iemit = fermionNumberOfMother_==1 ? 0 : 1; unsigned int ispect = fermionNumberOfMother_==1 ? 1 : 0; // fill the output if(showerQuark_ !=born->bornIncoming()[0]) { born->incoming().push_back(p2); born->incoming().push_back(p1); swap(iemit,ispect); } else { born->incoming().push_back(p1); born->incoming().push_back(p2); } born->emitter (iemit); born->spectator(ispect); pair xnew; for(unsigned int ix=0;ixincoming().size();++ix) { double x = born->incoming()[ix]->momentum().rho()/born->hadrons()[ix]->momentum().rho(); if(ix==0) xnew.first = x; else if (ix==1) xnew.second = x; } born->x(xnew); born->interaction(ShowerInteraction::QCD); // if gauge bosons not decayed, we're done if(born->bornOutgoing().size()==2) { born->emitted(4); if(!order) { born->outgoing().push_back(k1); born->outgoing().push_back(k2); } else { born->outgoing().push_back(k2); born->outgoing().push_back(k1); } born->outgoing().push_back(k); return born; } // Recalculate the hard vertex for this event: // For spin correlations, if an emission occurs go calculate the relevant // combination of amplitudes for the ProductionMatrixElement. if(realMESpinCorrelations_) { // Here we reset the realVVKinematics n+1 momenta to be those // of the lab frame in order to calculate the spin correlations. // Note that these momenta are not used for anything else after // this. R_.p1r(theRealMomenta[0]); R_.p2r(theRealMomenta[1]); R_.k1r(theRealMomenta[2]); R_.k2r(theRealMomenta[3]); R_.kr (theRealMomenta[4]); if(channel_==0) t_u_M_R_qqb_hel_amp(R_,true); else if(channel_==1) t_u_M_R_qg_hel_amp (R_,true); else if(channel_==2) t_u_M_R_gqb_hel_amp(R_,true); recalculateVertex(); } born->emitted(6); for(unsigned int ix=0;ixoutgoing().push_back(children_[cmap[ix]]); born->outgoing().push_back(k); // return the result return born; } double MEPP2VVPowheg::getResult(int channel, realVVKinematics R, Energy pT) { // This routine should return the integrand of the exact Sudakov form factor, // defined precisely as // KH 19th August - next 2 lines changed for phi in 0->pi not 0->2pi // \Delta(pT) = exp[ - \int_{pT}^{pTmax} dpT dYk d\phi/pi * getResult(...) ] // (Where phi is in 0->pi NOT 0->2*pi !) // Get pi for the prefactor: using Constants::pi; // Get the VV invariant mass^2: Energy2 p2 = B_.sb(); // Get the momentum fractions for the n+1 body event: double x1 = R.x1r(); double x2 = R.x2r(); // Reject the event if the x1 and x2 values are outside the phase space: if(x1<0.||x1>1.||x2<0.||x2>1.||x1*x2maximumCMEnergy())) return 0.; // Get the momentum fractions for the n body event: double x1b = B_.x1b(); double x2b = B_.x2b(); // Get the mandelstam variables needed to calculate the n+1 body matrix element: Energy2 s = R.sr() ; Energy2 t_u_MR_o_MB; double lo_lumi, nlo_lumi; // The luminosity function for the leading order n-body process: lo_lumi = qHadron_ ->pdf()->xfx(qHadron_ ,showerQuark_ ->dataPtr(),PDFScale_,x1b)* qbHadron_->pdf()->xfx(qbHadron_,showerAntiquark_->dataPtr(),PDFScale_,x2b); // Now we calculate the luminosity functions (product of the two pdfs) for the // real emission process(es) and also their matrix elements: // q + qbar -> V + V + g if(channel==0) { nlo_lumi = qHadron_ ->pdf()->xfx(qHadron_ ,showerQuark_ ->dataPtr() ,PDFScale_,x1) * qbHadron_->pdf()->xfx(qbHadron_,showerAntiquark_->dataPtr() ,PDFScale_,x2); t_u_MR_o_MB = t_u_M_R_qqb_hel_amp(R,false)/lo_me_; } // q + g -> V + V + q else if(channel==1) { nlo_lumi = qHadron_ ->pdf()->xfx(qHadron_ ,showerQuark_->dataPtr() ,PDFScale_,x1) * qbHadron_->pdf()->xfx(qbHadron_,getParticleData(ParticleID::g),PDFScale_,x2); t_u_MR_o_MB = t_u_M_R_qg_hel_amp(R,false)/lo_me_; } // g + qbar -> V + V + qbar else { nlo_lumi = qHadron_ ->pdf()->xfx(qHadron_ ,getParticleData(ParticleID::g),PDFScale_,x1) * qbHadron_->pdf()->xfx(qbHadron_,showerAntiquark_->dataPtr() ,PDFScale_,x2); t_u_MR_o_MB = t_u_M_R_gqb_hel_amp(R,false)/lo_me_; } // Multiply ratio of the real emission matrix elements to the Born matrix element // by the ratio of the pdfs for the real emission and born processes to get theWeight if(lo_lumi<=0.||nlo_lumi<=0.) return 0.; else return t_u_MR_o_MB * ( nlo_lumi/lo_lumi * p2/s ) * sqr(p2/s)/8./pi/pi / pT / p2 * GeV; } bool MEPP2VVPowheg::getEvent(vector & theRealMomenta, unsigned int & channel) { // Invariant mass of the colliding hadrons: Energy2 S = sqr(generator()->maximumCMEnergy()); // Born variables which are preserved (mass and rapidity of the diboson system): Energy2 p2 = B_.sb(); double Yb = B_.Yb(); // Born variables which are not preserved but are needed (the momentum fractions): double x1b(B_.x1b()), x2b(B_.x2b()); double x12b(x1b*x1b), x22b(x2b*x2b); // Maximum jet pT (half of the hadronic C.O.M. energy. N.B. this is overestimated a lot): Energy starting_pT = sqrt(S)/2.; // Initialize the pT_ *integration limit* i.e. the pT of the generated emission: pT_ = ZERO; // The pT *integration variable*: Energy pT; // The x_1 & x_2 momentum fractions corresponding to incoming momenta p1 & p2: double x1_(-999.), x2_(-999.); double x1 (-999.), x2 (-999.); // The jet rapidity *integration variable* and its limits: double Yk, minYk(-8.0), maxYk(8.0); // The theta2 integration variable (the azimuthal angle of the gluon w.r.t // V1 in the V1 & V2 rest frame: double theta2; // The realVVKinematics object corresponding to the current integration // set of integration variables: realVVKinematics R; // The veto algorithm rejection weight and a corresponding flag: double rejectionWeight; bool rejectEmission ; // Initialize the flag indicating the selected radiation channel: channel=999; // Some product of constants used for the crude distribution: double a(0.); for(int j=0;j<3;j++) { pT=starting_pT; a =(maxYk-minYk)*prefactor_[j]/2./b0_; do { // Generate next pT according to exp[- \int^{pTold}_{pT} dpT a*(power-1)/(pT^power)] // pT = GeV/pow( pow(GeV/pT,power_-1.) - log(UseRandom::rnd())/a // , 1./(power_-1.) ); // Generate next pT according to exp[- \int^{pTold}_{pT} dpT alpha1loop*prefactor/pT ] pT = LambdaQCD_*exp( 0.5*exp( log(log(sqr(pT/LambdaQCD_)))+log(UseRandom::rnd())/a ) ); // Generate rapidity of the jet: Yk = minYk + UseRandom::rnd()*(maxYk - minYk); // Generate the theta2 radiative variable: // KH 19th August - next line changed for phi in 0->pi not 0->2pi // theta2 = UseRandom::rnd() * 2.*Constants::pi; theta2 = UseRandom::rnd() * Constants::pi; // eT of the diboson system: Energy eT = sqrt(pT*pT+p2); // Calculate the eT and then solve for x_{\oplus} & x_{\ominus}: x1 = (pT*exp( Yk)+eT*exp( Yb))/sqrt(S); x2 = (pT*exp(-Yk)+eT*exp(-Yb))/sqrt(S); // Calculate the xr radiative variable: double xr(p2/(x1*x2*S)); // Then use this to calculate the y radiative variable: double y(-((xr+1.)/(xr-1.))*(xr*sqr(x1/x1b)-1.)/(xr*sqr(x1/x1b)+1.)); // The y value above should equal the one commented out below this line: // double y( ((xr+1.)/(xr-1.))*(xr*sqr(x2/x2b)-1.)/(xr*sqr(x2/x2b)+1.)); // Now we get the lower limit on the x integration, xbar: double omy(1.-y), opy(1.+y); double xbar1 = 2.*opy*x12b/(sqrt(sqr(1.+x12b)*sqr(omy)+16.*y*x12b)+omy*(1.-x1b)*(1.+x1b)); double xbar2 = 2.*omy*x22b/(sqrt(sqr(1.+x22b)*sqr(opy)-16.*y*x22b)+opy*(1.-x2b)*(1.+x2b)); double xbar = max(xbar1,xbar2); // Now we can calculate xtilde: double xt = (xr-xbar)/(1.-xbar); // Finally we can make the realVVKinematics object: R = realVVKinematics(B_,xt,y,theta2); // The next thing we have to do is set the QCD, EW and PDF scales using R: setTheScales(pT); // ... and so calculate rejection weight: rejectionWeight = getResult(j,R,pT); // If generating according to exp[- \int^{pTold}_{pT} dpT a*(power-1)/(pT^power)] // rejectionWeight/= showerAlphaS_->overestimateValue()*prefactor_[j]*pow(GeV/pT,power_); // If generating according to exp[- \int^{pTold}_{pT} dpT alpha1loop*prefactor/pT ] rejectionWeight/= 1./b0_/log(sqr(pT/LambdaQCD_))*prefactor_[j]*GeV/pT; rejectEmission = UseRandom::rnd()>rejectionWeight; // The event is a no-emission event if pT goes past min_pT_ - basically set to // outside the histogram bounds (hopefully histogram objects just ignore it then). if(pT1.) { ostringstream stream; stream << "MEPP2VVPowheg::getEvent weight for channel " << j << " is greater than one: " << rejectionWeight << endl; generator()->logWarning( Exception(stream.str(), Exception::warning) ); } } while(rejectEmission); // set pT of emission etc if(pT>pT_) { channel = j; pT_ = pT; Yk_ = Yk; R_ = R ; x1_ = x1; x2_ = x2; } } // Was this an (overall) no emission event? if(pT_3) throw Exception() << "MEPP2VVPowheg::getEvent() channel = " << channel << " pT = " << pT/GeV << " pT_ = " << pT_/GeV << Exception::abortnow; // Work out the momenta in the lab frame, reserving the mass and rapidity // of the VV system: LorentzRotation yzRotation; yzRotation.setRotateX(-atan2(pT_/GeV,sqrt(p2)/GeV)); LorentzRotation boostFrompTisZero; boostFrompTisZero.setBoostY(-pT_/sqrt(p2+pT_*pT_)); LorentzRotation boostFromYisZero; boostFromYisZero.setBoostZ(tanh(Yb)); theRealMomenta.resize(5); theRealMomenta[0] = Lorentz5Momentum(ZERO,ZERO, x1_*sqrt(S)/2., x1_*sqrt(S)/2.,ZERO); theRealMomenta[1] = Lorentz5Momentum(ZERO,ZERO,-x2_*sqrt(S)/2., x2_*sqrt(S)/2.,ZERO); theRealMomenta[2] = boostFromYisZero*boostFrompTisZero*yzRotation*(R_.k1r()); theRealMomenta[3] = boostFromYisZero*boostFrompTisZero*yzRotation*(R_.k2r()); theRealMomenta[4] = Lorentz5Momentum(ZERO, pT_, pT_*sinh(Yk_), pT_*cosh(Yk_),ZERO); return true; } void MEPP2VVPowheg::setTheScales(Energy pT) { // Work out the scales we want to use in the matrix elements and the pdfs: // Scale for alpha_S: pT^2 of the diboson system. QCDScale_ = max(pT*pT,sqr(min_pT_)); // Scale for real emission PDF: // pT^2+mVV^2 - as mcfm does in the case of a single W/Z boson). // Energy2 PDFScale_ = max(R.pT2_in_lab(),sqr(min_pT_))+R.s2r(); // pT^2 - as advocated by Nason & Ridolfi for ZZ production & Alioli et al for gg->h: PDFScale_ = max(pT*pT,sqr(min_pT_)); // Scale of electroweak vertices: mVV^2 the invariant mass of the diboson system. // EWScale_ = B_.sb(); // ... And this choice is more like what can be seen in mcatnlo_vbmain.f (weird). EWScale_ = 0.5*(B_.k12b()+B_.k22b()); return; } /***************************************************************************/ // This is identical to the code in the Powheg matrix element. It should // equal t_u_M_R_qqb in there, which is supposed to be the real emission ME // times tk*uk. Energy2 MEPP2VVPowheg::t_u_M_R_qqb_hel_amp(realVVKinematics R, bool getMatrix) const { using namespace ThePEG::Helicity; ProductionMatrixElement qqb_hel_amps(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1 ,PDT::Spin1 , PDT::Spin1); double sum_hel_amps_sqr(0.); tcPDPtr p1data(showerQuark_->dataPtr()); tcPDPtr p2data(showerAntiquark_->dataPtr()); tcPDPtr k1data(V1_->dataPtr()); tcPDPtr k2data(V2_->dataPtr()); tcPDPtr kdata(getParticleData(ParticleID::g)); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorWaveFunction qSpinor(R.p1r(),p1data,incoming); SpinorBarWaveFunction qbSpinor(R.p2r(),p2data,incoming); vector q; vector qb; for(unsigned int ix=0;ix<2;ix++) { qSpinor.reset(ix); qbSpinor.reset(ix); q.push_back(qSpinor); qb.push_back(qbSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.kr(),kdata,outgoing); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(p2data); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorWaveFunction p1_k = ffg->evaluate(QCDScale_,5,p1data,q[p1hel],g[khel]); SpinorBarWaveFunction p2_k = ffg->evaluate(QCDScale_,5,p2data,qb[p2hel],g[khel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p1hel=p2hel // but if the production ME is required first fill it with (0.,0.). if((p1hel==p2hel)&&helicityConservation_) { if(getMatrix) { if(khel==0) qqb_hel_amps(p1hel,p2hel,k1hel,k2hel,0) = Complex(0.,0.); else qqb_hel_amps(p1hel,p2hel,k1hel,k2hel,2) = Complex(0.,0.); } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_t; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? p2data : tc[ix]; // Note: choosing 5 as the second argument ffvX_->evaluate() sets // option 5 in thepeg/Helicity/Vertex/VertexBase.cc, which makes // the (fermion) propagator denominator massless: 1/p^2. // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams SpinorWaveFunction p1_v1 = ffv1->evaluate(EWScale_,5,intermediate_t,q[p1hel],v1[k1hel]); SpinorBarWaveFunction p2_v2 = ffv2->evaluate(EWScale_,5,intermediate_t->CC(),qb[p2hel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 t-channel diagrams // q+qb->g+v1+v2, q+qb->v1+g+v2, q+qb->v1+v2+g if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) { diagrams.push_back(ffv1->evaluate(EWScale_,p1_k,p2_v2,v1[k1hel])); diagrams.push_back(ffg->evaluate(QCDScale_,p1_v1,p2_v2,g[khel])); diagrams.push_back(ffv2->evaluate(EWScale_,p1_v1,p2_k,v2[k2hel])); } intermediate_t = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(EWScale_,5,intermediate_t,q[p1hel],v2[k2hel]); SpinorBarWaveFunction p2_v1 = ffv1->evaluate(EWScale_,5,intermediate_t->CC(),qb[p2hel],v1[k1hel]); // q+qb->g+v2+v1, q+qb->v2+g+v1, q+qb->v2+v1+g if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) { diagrams.push_back(ffv2->evaluate(EWScale_,p1_k,p2_v1,v2[k2hel])); diagrams.push_back(ffg->evaluate(QCDScale_,p1_v2,p2_v1,g[khel])); diagrams.push_back(ffv1->evaluate(EWScale_,p1_v2,p2_k,v1[k1hel])); } } // Note: choosing 3 as the second argument in WWWvertex_->evaluate() // sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which // means the propagator does not contain a width factor (which is // good re. gauge invariance). // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(EWScale_,3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(EWScale_,p1_k,qb[p2hel],k1_k2)); diagrams.push_back(ffv1->evaluate(EWScale_,q[p1hel],p2_k,k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==-p2data->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(EWScale_,3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(EWScale_,p1_k,qb[p2hel],k1_k2)); diagrams.push_back(FFZvertex_->evaluate(EWScale_,q[p1hel],p2_k,k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(EWScale_,3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(EWScale_,p1_k,qb[p2hel],k1_k2)); diagrams.push_back(FFPvertex_->evaluate(EWScale_,q[p1hel],p2_k,k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } /***************************************************************************/ // This is identical to the code in the Powheg matrix element. It should // equal t_u_M_R_qg in there, which is supposed to be the real emission ME // times tk*uk. Energy2 MEPP2VVPowheg::t_u_M_R_qg_hel_amp(realVVKinematics R, bool getMatrix) const { using namespace ThePEG::Helicity; ProductionMatrixElement qg_hel_amps(PDT::Spin1Half,PDT::Spin1, PDT::Spin1,PDT::Spin1, PDT::Spin1Half); double sum_hel_amps_sqr(0.); tcPDPtr p1data(showerQuark_->dataPtr()); tcPDPtr p2data(getParticleData(ParticleID::g)); tcPDPtr k1data(V1_->dataPtr()); tcPDPtr k2data(V2_->dataPtr()); tcPDPtr kdata (showerAntiquark_->dataPtr()->CC()); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorWaveFunction qinSpinor(R.p1r(),p1data,incoming); SpinorBarWaveFunction qoutSpinor(R.kr(),kdata,outgoing); vector qin; vector qout; for(unsigned int ix=0;ix<2;ix++) { qinSpinor.reset(ix); qoutSpinor.reset(ix); qin.push_back(qinSpinor); qout.push_back(qoutSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.p2r(),p2data,incoming); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(kdata->CC()); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorWaveFunction p1_p2 = ffg->evaluate(QCDScale_,5,p1data,qin[p1hel],g[p2hel]); SpinorBarWaveFunction p2_k = ffg->evaluate(QCDScale_,5,kdata->CC(),qout[khel],g[p2hel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p1hel!=khel // but if the production ME is required first fill it with (0.,0.). if((p1hel!=khel)&&helicityConservation_) { if(getMatrix) { if(p2hel==0) qg_hel_amps(p1hel,0,k1hel,k2hel,khel) = Complex(0.,0.); else qg_hel_amps(p1hel,2,k1hel,k2hel,khel) = Complex(0.,0.); } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_q; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? showerAntiquark_->dataPtr() : tc[ix]; SpinorWaveFunction p1_v1 = ffv1->evaluate(EWScale_,5,intermediate_q,qin[p1hel],v1[k1hel]); SpinorBarWaveFunction k_v2 = ffv2->evaluate(EWScale_,5,intermediate_q->CC(),qout[khel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 abelian diagrams // q+g->v1+v2+q with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) { diagrams.push_back(ffv2->evaluate(EWScale_,p1_v1,p2_k,v2[k2hel])); diagrams.push_back(ffg->evaluate(QCDScale_,p1_v1,k_v2,g[p2hel])); diagrams.push_back(ffv1->evaluate(EWScale_,p1_p2,k_v2,v1[k1hel])); } intermediate_q = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(EWScale_,5,intermediate_q,qin[p1hel],v2[k2hel]); SpinorBarWaveFunction k_v1 = ffv1->evaluate(EWScale_,5,intermediate_q->CC(),qout[khel],v1[k1hel]); // q+g->v2+v1+q, with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) { diagrams.push_back(ffv1->evaluate(EWScale_,p1_v2,p2_k,v1[k1hel])); diagrams.push_back(ffg->evaluate(QCDScale_,p1_v2,k_v1,g[p2hel])); diagrams.push_back(ffv2->evaluate(EWScale_,p1_p2,k_v1,v2[k2hel])); } } // Note: choosing 3 as the second argument in WWWvertex_->evaluate() // sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which // means the propagator does not contain a width factor (which is // good re. gauge invariance). // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(EWScale_,3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(EWScale_,p1_p2,qout[khel],k1_k2)); diagrams.push_back(ffv1->evaluate(EWScale_,qin[p1hel],p2_k,k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==kdata->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(EWScale_,3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(EWScale_,p1_p2,qout[khel],k1_k2)); diagrams.push_back(FFZvertex_->evaluate(EWScale_,qin[p1hel],p2_k,k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(EWScale_,3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(EWScale_,p1_p2,qout[khel],k1_k2)); diagrams.push_back(FFPvertex_->evaluate(EWScale_,qin[p1hel],p2_k,k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } /***************************************************************************/ // This is identical to the code in the Powheg matrix element. It should // equal t_u_M_R_gqb in there, which is supposed to be the real emission ME // times tk*uk. Energy2 MEPP2VVPowheg::t_u_M_R_gqb_hel_amp(realVVKinematics R, bool getMatrix) const { using namespace ThePEG::Helicity; ProductionMatrixElement gqb_hel_amps(PDT::Spin1,PDT::Spin1Half, PDT::Spin1,PDT::Spin1, PDT::Spin1Half); double sum_hel_amps_sqr(0.); tcPDPtr p1data(getParticleData(ParticleID::g)); tcPDPtr p2data(showerAntiquark_->dataPtr()); tcPDPtr k1data(V1_->dataPtr()); tcPDPtr k2data(V2_->dataPtr()); tcPDPtr kdata (showerQuark_->dataPtr()->CC()); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorBarWaveFunction qbinSpinor(R.p2r(),p2data,incoming); SpinorWaveFunction qboutSpinor(R.kr(),kdata,outgoing); vector qbin; vector qbout; for(unsigned int ix=0;ix<2;ix++) { qbinSpinor.reset(ix); qboutSpinor.reset(ix); qbin.push_back(qbinSpinor); qbout.push_back(qboutSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.p1r(),p1data,incoming); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p2data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p2data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(kdata->CC()); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorBarWaveFunction p1_p2 = ffg->evaluate(QCDScale_,5,p2data,qbin[p2hel],g[p1hel]); SpinorWaveFunction p1_k = ffg->evaluate(QCDScale_,5,kdata->CC(),qbout[khel],g[p1hel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p2hel!=khel // but if the production ME is required first fill it with (0.,0.). if((p2hel!=khel)&&helicityConservation_) { if(getMatrix) { if(p1hel==0) gqb_hel_amps(0,p2hel,k1hel,k2hel,khel) = Complex(0.,0.); else gqb_hel_amps(2,p2hel,k1hel,k2hel,khel) = Complex(0.,0.); } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_q; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? showerQuark_->dataPtr() : tc[ix]; SpinorBarWaveFunction p2_v1 = ffv1->evaluate(EWScale_,5,intermediate_q->CC(),qbin[p2hel],v1[k1hel]); SpinorWaveFunction k_v2 = ffv2->evaluate(EWScale_,5,intermediate_q,qbout[khel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 abelian diagrams q+g->v1+v2+q // with 2 t-channel propagators, 1 s- and 1 t-channel // and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p2data->id())%2==0))) { diagrams.push_back(ffv2->evaluate(EWScale_,p1_k,p2_v1,v2[k2hel])); diagrams.push_back(ffg->evaluate(QCDScale_,k_v2,p2_v1,g[p1hel])); diagrams.push_back(ffv1->evaluate(EWScale_,k_v2,p1_p2,v1[k1hel])); } intermediate_q = (!(k1data->id()==24&&k2data->id()==-24)) ? p2data : tc[ix]; SpinorBarWaveFunction p2_v2 = ffv2->evaluate(EWScale_,5,intermediate_q->CC(),qbin[p2hel],v2[k2hel]); SpinorWaveFunction k_v1 = ffv1->evaluate(EWScale_,5,intermediate_q,qbout[khel],v1[k1hel]); // q+g->v2+v1+q, with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p2data->id())%2==1))) { diagrams.push_back(ffv1->evaluate(EWScale_,p1_k,p2_v2,v1[k1hel])); diagrams.push_back(ffg->evaluate(QCDScale_,k_v1,p2_v2,g[p1hel])); diagrams.push_back(ffv2->evaluate(EWScale_,k_v1,p1_p2,v2[k2hel])); } } // Note: choosing 3 as the second argument in WWWvertex_->evaluate() // sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which // means the propagator does not contain a width factor (which is // good re. gauge invariance). // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(EWScale_,3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(EWScale_,qbout[khel],p1_p2,k1_k2)); diagrams.push_back(ffv1->evaluate(EWScale_,p1_k,qbin[p2hel],k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p2data->id()==kdata->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(EWScale_,3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(EWScale_,qbout[khel],p1_p2,k1_k2)); diagrams.push_back(FFZvertex_->evaluate(EWScale_,p1_k,qbin[p2hel],k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(EWScale_,3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(EWScale_,qbout[khel],p1_p2,k1_k2)); diagrams.push_back(FFPvertex_->evaluate(EWScale_,p1_k,qbin[p2hel],k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } /***************************************************************************/ // This returns exactly the same value as lo_me2_ when you put it in MEPP2VVPowheg.cc double MEPP2VVPowheg::lo_me(bool getMatrix) const { using namespace ThePEG::Helicity; ProductionMatrixElement lo_hel_amps(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1 ,PDT::Spin1); double sum_hel_amps_sqr(0.); tcPDPtr p1data(showerQuark_->dataPtr()); tcPDPtr p2data(showerAntiquark_->dataPtr()); tcPDPtr k1data(V1_->dataPtr()); tcPDPtr k2data(V2_->dataPtr()); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); // Should never actually occur. // If you want to reproduce the spin correlations of MEPP2VV // you should evaluate this ME using the lab frame momenta // instead of the bornVVKinematics ones (partonic C.O.M. frame). SpinorWaveFunction qSpinor; SpinorBarWaveFunction qbSpinor; if(!getMatrix) { qSpinor=SpinorWaveFunction(B_.p1b(),p1data,incoming); qbSpinor=SpinorBarWaveFunction(B_.p2b(),p2data,incoming); } else { qSpinor=SpinorWaveFunction(showerQuark_->momentum(),p1data,incoming); qbSpinor=SpinorBarWaveFunction(showerAntiquark_->momentum(),p2data,incoming); } vector q; vector qb; for(unsigned int ix=0;ix<2;ix++) { qSpinor.reset(ix); qbSpinor.reset(ix); q.push_back(qSpinor); qb.push_back(qbSpinor); } // If you want to reproduce the spin correlations of MEPP2VV // you should evaluate this ME using the lab frame momenta // instead of the bornVVKinematics ones (partonic C.O.M. frame). VectorWaveFunction v1Polarization; VectorWaveFunction v2Polarization; if(!getMatrix) { v1Polarization=VectorWaveFunction(B_.k1b(),k1data,outgoing); v2Polarization=VectorWaveFunction(B_.k2b(),k2data,outgoing); } else { v1Polarization=VectorWaveFunction(V1_->momentum(),k1data,outgoing); v2Polarization=VectorWaveFunction(V2_->momentum(),k2data,outgoing); } vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(p2data); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { if((p1hel==p2hel)&&helicityConservation_) { lo_hel_amps(p1hel,p2hel,k1hel,k2hel) = Complex(0.,0.); continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_t; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? p2data : tc[ix]; SpinorWaveFunction p1_v1 = ffv1->evaluate(EWScale_,5,intermediate_t,q[p1hel],v1[k1hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 t-channel diagrams // q+qb->v1+v2 if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) diagrams.push_back(ffv2->evaluate(EWScale_,p1_v1,qb[p2hel],v2[k2hel])); intermediate_t = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(EWScale_,5,intermediate_t,q[p1hel],v2[k2hel]); // q+qb->v2+v1 if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) diagrams.push_back(ffv1->evaluate(EWScale_,p1_v2,qb[p2hel],v1[k1hel])); } // Note: choosing 3 as the second argument in WWWvertex_->evaluate() // sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which // means the propagator does not contain a width factor (which is // good re. gauge invariance). // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(EWScale_,3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->v1*->v1+v2 diagrams.push_back(ffv1->evaluate(EWScale_,q[p1hel],qb[p2hel],k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==-p2data->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->Z0*->v1+v2 tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(EWScale_,3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(EWScale_,q[p1hel],qb[p2hel],k1_k2)); // q+qb->gamma*->v1+v2 tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(EWScale_,3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(EWScale_,q[p1hel],qb[p2hel],k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr; } /***************************************************************************/ // This member selects a [2-body] decay mode and assigns children to the // vector bosons with momenta which are isotropic in their rest frames. bool MEPP2VVPowheg::isotropicDecayer() { using namespace ThePEG::Helicity; // Generate the children's momenta isotropically in // the rest frames of V1 and V2: double cth,phi; // First V1's children: cth = UseRandom::rnd()*2.-1.; phi = UseRandom::rnd()*2.*Constants::pi; Energy m1(V1_->momentum().m()); Energy m3(children_[0]->data().constituentMass()); Energy m4(children_[1]->data().constituentMass()); Energy p34(triangleFn(sqr(m1),sqr(m3),sqr(m4)) /2./m1); if(std::isnan(double(p34/MeV))||cth>1.||cth<-1.) return false; Energy pT34(p34*sqrt(1.-cth)*sqrt(1.+cth)); Lorentz5Momentum k3(pT34*sin(phi),pT34*cos(phi),p34 *cth, sqrt(p34*p34+sqr(m3)),m3); Lorentz5Momentum k4(-k3); k4.setE(sqrt(p34*p34+sqr(m4))); k4.setTau(m4); Boost boostToV1RF(R_.k1r().boostVector()); k3.boost(boostToV1RF); k3.rescaleRho(); k4.boost(boostToV1RF); k4.rescaleRho(); // Second V2's children: cth = UseRandom::rnd()*2.-1.; phi = UseRandom::rnd()*2.*Constants::pi; Energy m2(V2_->momentum().m()); Energy m5(children_[2]->data().constituentMass()); Energy m6(children_[3]->data().constituentMass()); Energy p56(triangleFn(sqr(m2),sqr(m5),sqr(m6)) /2./m2); if(std::isnan(double(p56/MeV))||cth>1.||cth<-1.) return false; Energy pT56(p56*sqrt(1.-cth)*sqrt(1.+cth)); Lorentz5Momentum k5(pT56*sin(phi),pT56*cos(phi),p56*cth, sqrt(p56*p56+sqr(m5)),m5); Lorentz5Momentum k6(-k5); k6.setE(sqrt(p56*p56+sqr(m6))); k6.setTau(m6); Boost boostToV2RF(R_.k2r().boostVector()); k5.boost(boostToV2RF); k5.rescaleRho(); k6.boost(boostToV2RF); k6.rescaleRho(); // Assign the momenta to the children: children_[0]->set5Momentum(k3); children_[1]->set5Momentum(k4); children_[2]->set5Momentum(k5); children_[3]->set5Momentum(k6); return true; } // Override 2->2 production matrix here: void MEPP2VVPowheg::recalculateVertex() { // Zero the squared amplitude; this equals sum_hel_amps_sqr if all // is working as it should: Complex productionMatrix2(0.,0.); for(unsigned int k1hel=0;k1hel<3;++k1hel) for(unsigned int k2hel=0;k2hel<3;++k2hel) productionMatrix2 += productionMatrix_[k1hel][k1hel][k2hel][k2hel]; // Get the vector wavefunctions: VectorWaveFunction v1Polarization; VectorWaveFunction v2Polarization; v1Polarization=VectorWaveFunction(R_.k1r(),V1_->dataPtr(),outgoing); v2Polarization=VectorWaveFunction(R_.k2r(),V2_->dataPtr(),outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } AbstractFFVVertexPtr ffv1 = V1_->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = V2_->id()==23 ? FFZvertex_ : FFWvertex_; bool vetoed(true); while(vetoed) { // Decay the bosons isotropically in their rest frames: isotropicDecayer(); // Get the spinor wavefunctions: SpinorWaveFunction k3Spinor(children_[0]->momentum(),children_[0]->dataPtr(),outgoing); SpinorBarWaveFunction k4Spinor(children_[1]->momentum(),children_[1]->dataPtr(),outgoing); SpinorWaveFunction k5Spinor(children_[2]->momentum(),children_[2]->dataPtr(),outgoing); SpinorBarWaveFunction k6Spinor(children_[3]->momentum(),children_[3]->dataPtr(),outgoing); vector k3,k5; vector k4,k6; for(unsigned int ix=0;ix<2;ix++) { k3Spinor.reset(ix); k4Spinor.reset(ix); k3.push_back(k3Spinor); k4.push_back(k4Spinor); k5Spinor.reset(ix); k6Spinor.reset(ix); k5.push_back(k5Spinor); k6.push_back(k6Spinor); } DecayMEPtr decayAmps(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1Half,PDT::Spin1Half))); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k3hel=0;k3hel<2;++k3hel) { for(unsigned int k4hel=0;k4hel<2;++k4hel) { (*decayAmps)(k1hel,k3hel,k4hel) = ffv1->evaluate(EWScale_,k3[k3hel],k4[k4hel],v1[k1hel]); } } } Complex V1decayMatrix[3][3]; for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k1helpr=0;k1helpr<3;++k1helpr) { Complex theElement(0.,0.); for(unsigned int k3hel=0;k3hel<2;++k3hel) { for(unsigned int k4hel=0;k4hel<2;++k4hel) { theElement += (*decayAmps)(k1hel,k3hel,k4hel) *conj((*decayAmps)(k1helpr,k3hel,k4hel)); } } V1decayMatrix[k1hel][k1helpr] = theElement; } } Complex V1decayMatrix2(0.,0.); for(unsigned int k1hel=0;k1hel<3;++k1hel) V1decayMatrix2 += V1decayMatrix[k1hel][k1hel]; for(unsigned int k2hel=0;k2hel<3;++k2hel) { for(unsigned int k5hel=0;k5hel<2;++k5hel) { for(unsigned int k6hel=0;k6hel<2;++k6hel) { (*decayAmps)(k2hel,k5hel,k6hel) = ffv2->evaluate(EWScale_,k5[k5hel],k6[k6hel],v2[k2hel]); } } } Complex V2decayMatrix[3][3]; for(unsigned int k2hel=0;k2hel<3;++k2hel) { for(unsigned int k2helpr=0;k2helpr<3;++k2helpr) { Complex theElement(0.,0.); for(unsigned int k5hel=0;k5hel<2;++k5hel) { for(unsigned int k6hel=0;k6hel<2;++k6hel) { theElement += (*decayAmps)(k2hel,k5hel,k6hel) *conj((*decayAmps)(k2helpr,k5hel,k6hel)); } } V2decayMatrix[k2hel][k2helpr] = theElement; } } Complex V2decayMatrix2(0.,0.); for(unsigned int k2hel=0;k2hel<3;++k2hel) V2decayMatrix2 += V2decayMatrix[k2hel][k2hel]; // Contract the production matrix and the decay matrices: Complex meTimesV1V2denominators(0.,0.); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k1helpr=0;k1helpr<3;++k1helpr) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { for(unsigned int k2helpr=0;k2helpr<3;++k2helpr) { meTimesV1V2denominators += productionMatrix_[k1hel][k1helpr][k2hel][k2helpr] *V1decayMatrix[k1hel][k1helpr] *V2decayMatrix[k2hel][k2helpr]; } } } } if(imag(meTimesV1V2denominators)/real(meTimesV1V2denominators)>1.e-7) cout << "MEPP2VVPowheg warning\n" << "the matrix element's imaginary part is large " << meTimesV1V2denominators << endl; if(imag(productionMatrix2)/real(productionMatrix2)>1.e-7) cout << "MEPP2VVPowheg warning\n" << "the production matrix element's imaginary part is large " << productionMatrix2 << endl; if(imag(V1decayMatrix2)/real(V1decayMatrix2)>1.e-7) cout << "MEPP2VVPowheg warning\n" << "the V1 decay matrix element's imaginary part is large " << V1decayMatrix2 << endl; if(imag(V2decayMatrix2)/real(V2decayMatrix2)>1.e-7) cout << "MEPP2VVPowheg warning\n" << "the V2 decay matrix element's imaginary part is large " << V2decayMatrix2 << endl; // Need branching ratio at least in here I would think ---> double decayWeight( real(meTimesV1V2denominators) / real(productionMatrix2*V1decayMatrix2*V2decayMatrix2)); if(decayWeight>1.) cout << "MEPP2VVPowheg::recalculateVertex decayWeight > 1., decayWeight = " << decayWeight << endl; if(decayWeight<0.) cout << "MEPP2VVPowheg::recalculateVertex decayWeight < 0., decayWeight = " << decayWeight << endl; if(UseRandom::rnd()=ZERO) { return sqrt(lambda2); } else { generator()->log() << "MEPP2VVPowheg::triangleFn " << "kinematic instability, imaginary triangle function\n"; return -999999.*GeV2; } } diff --git a/Models/General/TwoBodyDecayConstructor.cc b/Models/General/TwoBodyDecayConstructor.cc --- a/Models/General/TwoBodyDecayConstructor.cc +++ b/Models/General/TwoBodyDecayConstructor.cc @@ -1,446 +1,446 @@ // -*- C++ -*- // // TwoBodyDecayConstructor.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the TwoBodyDecayConstructor class. // #include "TwoBodyDecayConstructor.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/Switch.h" #include "Herwig/Decay/General/GeneralTwoBodyDecayer.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "ThePEG/PDT/EnumParticles.h" #include "DecayConstructor.h" #include "ThePEG/Utilities/Throw.h" #include "ThePEG/Utilities/EnumIO.h" #include "ThePEG/Helicity/Vertex/AbstractFFVVertex.fh" #include "ThePEG/Helicity/Vertex/AbstractFFSVertex.fh" #include "ThePEG/Helicity/Vertex/AbstractVVSVertex.fh" #include "ThePEG/Helicity/Vertex/AbstractVSSVertex.fh" #include "ThePEG/Helicity/Vertex/AbstractVVTVertex.fh" #include "ThePEG/Helicity/Vertex/AbstractFFTVertex.fh" #include "ThePEG/Helicity/Vertex/AbstractSSTVertex.fh" #include "ThePEG/Helicity/Vertex/AbstractSSSVertex.fh" #include "ThePEG/Helicity/Vertex/AbstractVVVVertex.fh" #include "ThePEG/Helicity/Vertex/AbstractRFSVertex.fh" #include "ThePEG/Helicity/Vertex/AbstractRFVVertex.fh" #include "VectorCurrentDecayConstructor.h" using namespace Herwig; using ThePEG::Helicity::VertexBasePtr; IBPtr TwoBodyDecayConstructor::clone() const { return new_ptr(*this); } IBPtr TwoBodyDecayConstructor::fullclone() const { return new_ptr(*this); } void TwoBodyDecayConstructor::persistentOutput(PersistentOStream & os) const { os << alphaQCD_ << alphaQED_ << oenum(inter_); } void TwoBodyDecayConstructor::persistentInput(PersistentIStream & is, int) { is >> alphaQCD_ >> alphaQED_>> ienum(inter_); } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigTwoBodyDecayConstructor("Herwig::TwoBodyDecayConstructor", "Herwig.so"); void TwoBodyDecayConstructor::Init() { static ClassDocumentation documentation ("The TwoBodyDecayConstructor implements to creation of 2 body decaymodes " "and decayers that do not already exist for the given set of vertices."); static Reference interfaceShowerAlphaQCD ("AlphaQCD", "The coupling for QCD corrections", &TwoBodyDecayConstructor::alphaQCD_, false, false, true, false, false); static Reference interfaceShowerAlphaQED ("AlphaQED", "The coupling for QED corrections", &TwoBodyDecayConstructor::alphaQED_, false, false, true, false, false); static Switch interfaceInteractions ("Interactions", "which interactions to include for the hard corrections", &TwoBodyDecayConstructor::inter_, ShowerInteraction::QCD, false, false); static SwitchOption interfaceInteractionsQCD (interfaceInteractions, "QCD", "QCD Only", ShowerInteraction::QCD); static SwitchOption interfaceInteractionsQED (interfaceInteractions, "QED", "QED only", ShowerInteraction::QED); static SwitchOption interfaceInteractionsQCDandQED (interfaceInteractions, "QCDandQED", "Both QCD and QED", - ShowerInteraction::Both); + ShowerInteraction::QEDQCD); } void TwoBodyDecayConstructor::DecayList(const set & particles) { // special for weak decays for(unsigned int ix=0;ixdecayConstructors().size();++ix) { Ptr::pointer weak = dynamic_ptr_cast::pointer > (decayConstructor()->decayConstructors()[ix]); if(!weak) continue; weakMassCut_ = max(weakMassCut_,weak->massCut()); } if( particles.empty() ) return; tHwSMPtr model = dynamic_ptr_cast(generator()->standardModel()); unsigned int nv(model->numberOfVertices()); for(set::const_iterator ip=particles.begin(); ip!=particles.end();++ip) { tPDPtr parent = *ip; if ( Debug::level > 0 ) Repository::cout() << "Constructing 2-body decays for " << parent->PDGName() << '\n'; multiset decays; for(unsigned int iv = 0; iv < nv; ++iv) { if(excluded(model->vertex(iv)) || model->vertex(iv)->getNpoint()>3) continue; for(unsigned int il = 0; il < 3; ++il) createModes(parent, model->vertex(iv), il,decays); } if( !decays.empty() ) createDecayMode(decays); } } void TwoBodyDecayConstructor:: createModes(tPDPtr inpart, VertexBasePtr vertex, unsigned int list, multiset & modes) { if( !vertex->isIncoming(inpart) || vertex->getNpoint() != 3 ) return; Energy m1(inpart->mass()); tPDPtr ccpart = inpart->CC() ? inpart->CC() : inpart; long id = ccpart->id(); tPDVector decaylist = vertex->search(list, ccpart); tPDVector::size_type nd = decaylist.size(); for( tPDVector::size_type i = 0; i < nd; i += 3 ) { tPDPtr pa(decaylist[i]), pb(decaylist[i + 1]), pc(decaylist[i + 2]); if( pb->id() == id ) swap(pa, pb); if( pc->id() == id ) swap(pa, pc); //allowed on-shell decay? if( m1 <= pb->mass() + pc->mass() ) continue; // double counting with current decays? if(inpart->iSpin()==PDT::Spin1 && inpart->iCharge()==0 && pb->id()==-pc->id() && abs(pb->id())<=3 && inpart->mass() <= weakMassCut_ ) { continue; } //vertices are defined with all particles incoming modes.insert( TwoBodyDecay(inpart,pb, pc, vertex) ); } } GeneralTwoBodyDecayerPtr TwoBodyDecayConstructor::createDecayer(TwoBodyDecay decay, vector vertices) { string name; using namespace Helicity::VertexType; PDT::Spin in = decay.parent_->iSpin(); // PDT::Spin out1 = decay.children_.first ->iSpin(); PDT::Spin out2 = decay.children_.second->iSpin(); switch(decay.vertex_->getName()) { case FFV : if(in == PDT::Spin1Half) { name = "FFVDecayer"; if(out2==PDT::Spin1Half) swap(decay.children_.first,decay.children_.second); } else { name = "VFFDecayer"; } break; case FFS : if(in == PDT::Spin1Half) { name = "FFSDecayer"; if(out2==PDT::Spin1Half) swap(decay.children_.first,decay.children_.second); } else { name = "SFFDecayer"; } break; case VVS : if(in == PDT::Spin1) { name = "VVSDecayer"; if(out2==PDT::Spin1) swap(decay.children_.first,decay.children_.second); } else { name = "SVVDecayer"; } break; case VSS : if(in == PDT::Spin1) { name = "VSSDecayer"; } else { name = "SSVDecayer"; if(out2==PDT::Spin0) swap(decay.children_.first,decay.children_.second); } break; case VVT : name = in==PDT::Spin2 ? "TVVDecayer" : "Unknown"; break; case FFT : name = in==PDT::Spin2 ? "TFFDecayer" : "Unknown"; break; case SST : name = in==PDT::Spin2 ? "TSSDecayer" : "Unknown"; break; case SSS : name = "SSSDecayer"; break; case VVV : name = "VVVDecayer"; break; case RFS : if(in==PDT::Spin1Half) { name = "FRSDecayer"; if(out2==PDT::Spin3Half) swap(decay.children_.first,decay.children_.second); } else if(in==PDT::Spin0) { name = "SRFDecayer"; if(out2==PDT::Spin3Half) swap(decay.children_.first,decay.children_.second); } else { name = "Unknown"; } break; case RFV : if(in==PDT::Spin1Half) { name = "FRVDecayer"; if(out2==PDT::Spin3Half) swap(decay.children_.first,decay.children_.second); } else name = "Unknown"; break; default : Throw() << "Error: Cannot assign " << decay.vertex_->fullName() << " to a decayer. " << "Decay is " << decay.parent_->PDGName() << " -> " << decay.children_.first ->PDGName() << " " << decay.children_.second->PDGName() << Exception::runerror; } if(name=="Unknown") Throw() << "Error: Cannot assign " << decay.vertex_->fullName() << " to a decayer. " << "Decay is " << decay.parent_->PDGName() << " -> " << decay.children_.first ->PDGName() << " " << decay.children_.second->PDGName() << Exception::runerror; ostringstream fullname; fullname << "/Herwig/Decays/" << name << "_" << decay.parent_->PDGName() << "_" << decay.children_.first ->PDGName() << "_" << decay.children_.second->PDGName(); string classname = "Herwig::" + name; GeneralTwoBodyDecayerPtr decayer; decayer = dynamic_ptr_cast (generator()->preinitCreate(classname,fullname.str())); if(!decayer) Throw() << "Error: Cannot assign " << decay.vertex_->fullName() << " to a decayer. " << "Decay is " << decay.parent_->PDGName() << " -> " << decay.children_.first ->PDGName() << " " << decay.children_.second->PDGName() << Exception::runerror; // set the strong coupling for radiation generator()->preinitInterface(decayer, "AlphaS" , "set", alphaQCD_->fullName()); // set the EM coupling for radiation generator()->preinitInterface(decayer, "AlphaEM", "set", alphaQED_->fullName()); // set the type of interactions for the correction if(inter_==ShowerInteraction::QCD) generator()->preinitInterface(decayer, "Interactions", "set", "QCD"); else if(inter_==ShowerInteraction::QED) generator()->preinitInterface(decayer, "Interactions", "set", "QED"); else generator()->preinitInterface(decayer, "Interactions", "set", "QCDandQED"); // get the vertices for radiation from the external legs map inRad,fourRad; vector > outRad(2); vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { inRad[inter] = radiationVertex(decay.parent_,inter); outRad[0][inter] = radiationVertex(decay.children_.first ,inter); outRad[1][inter] = radiationVertex(decay.children_.second,inter); // get any contributing 4 point vertices fourRad[inter] = radiationVertex(decay.parent_,inter, decay.children_); } // set info on decay decayer->setDecayInfo(decay.parent_,decay.children_,vertices, inRad,outRad,fourRad); // initialised the decayer setDecayerInterfaces(fullname.str()); decayer->init(); return decayer; } void TwoBodyDecayConstructor:: createDecayMode(multiset & decays) { tPDPtr inpart = decays.begin()->parent_; for( multiset::iterator dit = decays.begin(); dit != decays.end(); ) { TwoBodyDecay mode = *dit; // get all the moees with the same in and outgoing particles pair::iterator, multiset::iterator> range = decays.equal_range(mode); // construct the decay mode tPDPtr pb((mode).children_.first), pc((mode).children_.second); string tag = inpart->name() + "->" + pb->name() + "," + pc->name() + ";"; // Does it exist already ? tDMPtr dm = generator()->findDecayMode(tag); // find the vertices vector vertices; for ( multiset::iterator dit2 = range.first; dit2 != range.second; ++dit2) { vertices.push_back(dit2->vertex_); } dit=range.second; // now create DecayMode objects that do not already exist if( createDecayModes() && (!dm || inpart->id() == ParticleID::h0) ) { tDMPtr ndm = generator()->preinitCreateDecayMode(tag); if(ndm) { inpart->stable(false); GeneralTwoBodyDecayerPtr decayer=createDecayer(mode,vertices); if(!decayer) continue; generator()->preinitInterface(ndm, "Decayer", "set", decayer->fullName()); generator()->preinitInterface(ndm, "Active", "set", "Yes"); Energy width = decayer->partialWidth(make_pair(inpart,inpart->mass()), make_pair(pb,pb->mass()) , make_pair(pc,pc->mass())); setBranchingRatio(ndm, width); if(width==ZERO || ndm->brat()minimumBR()) { generator()->preinitInterface(decayer->fullName(), "Initialize", "set","0"); } } else Throw() << "TwoBodyDecayConstructor::createDecayMode - Needed to create " << "new decaymode but one could not be created for the tag " << tag << Exception::warning; } else if( dm ) { if(dm->brat()minimumBR()) { continue; } if((dm->decayer()->fullName()).find("Mambo") != string::npos) { inpart->stable(false); GeneralTwoBodyDecayerPtr decayer=createDecayer(mode,vertices); if(!decayer) continue; generator()->preinitInterface(dm, "Decayer", "set", decayer->fullName()); Energy width = decayer->partialWidth(make_pair(inpart,inpart->mass()), make_pair(pb,pb->mass()) , make_pair(pc,pc->mass())); if(width/(dm->brat()*inpart->width())<1e-10) { string message = "Herwig calculation of the partial width for the decay mode " + inpart->PDGName() + " -> " + pb->PDGName() + " " + pc->PDGName() + " is zero.\n This will cause problems with the calculation of" + " spin correlations.\n It is probably due to inconsistent parameters" + " and decay modes being passed to Herwig via the SLHA file.\n" + " Zeroing the branching ratio for this mode."; setBranchingRatio(dm,ZERO); generator()->logWarning(NBodyDecayConstructorError(message,Exception::warning)); } } } } // update CC mode if it exists if( inpart->CC() ) inpart->CC()->synchronize(); } VertexBasePtr TwoBodyDecayConstructor::radiationVertex(tPDPtr particle, ShowerInteraction inter, tPDPair children) { tHwSMPtr model = dynamic_ptr_cast(generator()->standardModel()); map::iterator rit = radiationVertices_[inter].find(particle); tPDPtr cc = particle->CC() ? particle->CC() : particle; if(children==tPDPair() && rit!=radiationVertices_[inter].end()) return rit->second; unsigned int nv(model->numberOfVertices()); long bosonID = inter==ShowerInteraction::QCD ? ParticleID::g : ParticleID::gamma; tPDPtr gluon = getParticleData(bosonID); // look for radiation vertices for incoming and outgoing particles for(unsigned int iv=0;ivvertex(iv); // look for 3 point vertices if (children==tPDPair()){ if( !vertex->isIncoming(particle) || vertex->getNpoint() != 3 || !vertex->isOutgoing(particle) || !vertex->isOutgoing(gluon)) continue; for(unsigned int list=0;list<3;++list) { tPDVector decaylist = vertex->search(list, particle); for( tPDVector::size_type i = 0; i < decaylist.size(); i += 3 ) { tPDPtr pa(decaylist[i]), pb(decaylist[i + 1]), pc(decaylist[i + 2]); if( pb->id() == bosonID ) swap(pa, pb); if( pc->id() == bosonID ) swap(pa, pc); if( pb->id() != particle->id()) swap(pb, pc); if( pa->id() != bosonID) continue; if( pb != particle) continue; if( pc != cc) continue; radiationVertices_[inter][particle] = vertex; return vertex; } } } // look for 4 point vertex including a gluon else { if( !vertex->isIncoming(particle) || vertex->getNpoint()!=4 || !vertex->isOutgoing(children.first) || !vertex->isOutgoing(children.second) || !vertex->isOutgoing(gluon)) continue; for(unsigned int list=0;list<4;++list) { tPDVector decaylist = vertex->search(list, particle); for( tPDVector::size_type i = 0; i < decaylist.size(); i += 4 ) { tPDPtr pa(decaylist[i]), pb(decaylist[i+1]), pc(decaylist[i+2]), pd(decaylist[i+3]); // order so that a = g, b = parent if( pb->id() == bosonID ) swap(pa, pb); if( pc->id() == bosonID ) swap(pa, pc); if( pd->id() == bosonID ) swap(pa, pd); if( pc->id() == particle->id()) swap(pb, pc); if( pd->id() == particle->id()) swap(pb, pd); if( pa->id() != bosonID) continue; if( pb->id() != particle->id()) continue; if( !((abs(pd->id()) == abs(children. first->id()) && abs(pc->id()) == abs(children.second->id())) || (abs(pc->id()) == abs(children. first->id()) && abs(pd->id()) == abs(children.second->id())))) continue; return vertex; } } } } return VertexBasePtr(); } diff --git a/Models/General/TwoBodyDecayConstructor.h b/Models/General/TwoBodyDecayConstructor.h --- a/Models/General/TwoBodyDecayConstructor.h +++ b/Models/General/TwoBodyDecayConstructor.h @@ -1,182 +1,187 @@ // -*- C++ -*- // // TwoBodyDecayConstructor.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_TwoBodyDecayConstructor_H #define HERWIG_TwoBodyDecayConstructor_H // // This is the declaration of the TwoBodyDecayConstructor class. // #include "NBodyDecayConstructorBase.h" #include "ThePEG/Helicity/Vertex/VertexBase.h" #include "Herwig/Decay/General/GeneralTwoBodyDecayer.fh" #include "Herwig/Shower/ShowerAlpha.h" #include "TwoBodyDecay.h" namespace Herwig { using namespace ThePEG; using Helicity::VertexBasePtr; using Helicity::tVertexBasePtr; /** * The TwoBodyDecayConstructor class inherits from the dummy base class * NBodyDecayConstructorBase and implements the necessary functions in * order to create the 2 body decay modes for a given set of vertices * stored in a Model class. * * @see \ref TwoBodyDecayConstructorInterfaces "The interfaces" * defined for TwoBodyDecayConstructor. * @see NBodyDecayConstructor **/ class TwoBodyDecayConstructor: public NBodyDecayConstructorBase { public: /** * The default constructor. */ - TwoBodyDecayConstructor() : inter_(ShowerInteraction::Both), weakMassCut_(-GeV) { + TwoBodyDecayConstructor() : inter_(ShowerInteraction::QEDQCD), weakMassCut_(-GeV) { radiationVertices_[ShowerInteraction::QCD] = map(); radiationVertices_[ShowerInteraction::QED] = map(); } /** * Function used to determine allowed decaymodes *@param part vector of ParticleData pointers containing particles in model */ - virtual void DecayList(const set & part); + virtual void DecayList(const set & particles); /** * Number of outgoing lines. Required for correct ordering. */ virtual unsigned int numBodies() const { return 2; } - + public: /** @name Functions used by the persistent I/O system. */ //@{ /** * Function used to write out object persistently. * @param os the persistent output stream written to. */ void persistentOutput(PersistentOStream & os) const; /** * Function used to read in object persistently. * @param is the persistent input stream read from. * @param version the version number of the object when written. */ void persistentInput(PersistentIStream & is, int version); //@} /** * The standard Init function used to initialize the interfaces. * Called exactly once for each class by the class description system * before the main function starts or * when this class is dynamically loaded. */ static void Init(); protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const; /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const; //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ TwoBodyDecayConstructor & operator=(const TwoBodyDecayConstructor &) = delete; private: - + /** @name Functions to create decayers and decaymodes. */ //@{ /** * Function to create decays - * @param inpart Incoming particle + * @param inpart Incoming particle * @param vert The vertex to create decays for * @param ilist Which list to search * @param iv Row number in _theExistingDecayers member * @return A vector a decay modes */ void createModes(tPDPtr inpart, VertexBasePtr vert, unsigned int ilist, multiset & modes); /** * Function to create decayer for specific vertex * @param decay decay mode for this decay * member variable */ GeneralTwoBodyDecayerPtr createDecayer(TwoBodyDecay decay, vector ); /** * Create decay mode(s) from given part and decay modes * @param decays The vector of decay modes * @param decayer The decayer responsible for this decay */ void createDecayMode(multiset & decays); //@} /** * Get the vertex for QED/QCD radiation */ VertexBasePtr radiationVertex(tPDPtr particle,ShowerInteraction inter, tPDPair children = tPDPair ()); private: /** * Map of particles and the vertices which generate their QCD * radiation */ map > radiationVertices_; /** * Default choice for the strong coupling object for hard QCD radiation */ ShowerAlphaPtr alphaQCD_; /** * Default choice for the strong coupling object for hard QED radiation */ ShowerAlphaPtr alphaQED_; /** * Which type of corrections to the decays to include */ - ShowerInteraction inter_; + ShowerInteraction inter_; /** * Cut off or decays via the weak current */ Energy weakMassCut_; - + + /** + * Cut off or decays via the weak current + */ + Energy weakMassCut_; + }; - + } #endif /* HERWIG_TwoBodyDecayConstructor_H */ diff --git a/Models/UED/UEDBase.cc b/Models/UED/UEDBase.cc --- a/Models/UED/UEDBase.cc +++ b/Models/UED/UEDBase.cc @@ -1,471 +1,473 @@ // -*- C++ -*- // // UEDBase.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the UEDBase class. // #include "UEDBase.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Repository/Repository.h" #include "ThePEG/Repository/CurrentGenerator.h" using namespace Herwig; UEDBase::UEDBase() : theRadCorr(true), theInvRadius(500.*GeV), theLambdaR(20.), theMbarH(), theSinThetaOne(0.), theVeV(246.*GeV), includeSMMass_(true), fixedCouplings_(false), includeGaugeMixing_(true) {} void UEDBase::doinit() { readDecays(false); BSMModel::doinit(); //level-1 masses and mixing angle calculateKKMasses(1); writeSpectrum(); //add the level-1 vertices. addVertex(theF1F1Z0Vertex); addVertex(theF1F1G0Vertex); addVertex(theF1F0G1Vertex); addVertex(theG1G1G0Vertex); addVertex(theG0G0G1G1Vertex); addVertex(theF1F1P0Vertex); addVertex(theF1F1W0Vertex); addVertex(theF1F0W1Vertex); addVertex(theF1F0H1Vertex); addVertex(theP0H1H1Vertex); addVertex(theZ0H1H1Vertex); addVertex(theW0A1H1Vertex); addVertex(theZ0A1h1Vertex); addVertex(theW0W1W1Vertex); readDecays(true); if(decayFile()=="") return; decayRead(); } void UEDBase::persistentOutput(PersistentOStream & os) const { os << theRadCorr << ounit(theInvRadius, GeV) << theLambdaR << theF1F1Z0Vertex << theF1F1G0Vertex << theF1F0G1Vertex << theG1G1G0Vertex << theG0G0G1G1Vertex << theF1F1P0Vertex << theF1F1W0Vertex << theF1F0W1Vertex << theF1F0H1Vertex << theP0H1H1Vertex << theZ0H1H1Vertex << theW0A1H1Vertex << theZ0A1h1Vertex << theW0W1W1Vertex << ounit(theVeV,GeV) << ounit(theMbarH, GeV) << theSinThetaOne << includeSMMass_ << fixedCouplings_ << includeGaugeMixing_; } void UEDBase::persistentInput(PersistentIStream & is, int) { is >> theRadCorr >> iunit(theInvRadius, GeV) >> theLambdaR >> theF1F1Z0Vertex >> theF1F1G0Vertex >> theF1F0G1Vertex >> theG1G1G0Vertex >> theG0G0G1G1Vertex >> theF1F1P0Vertex >> theF1F1W0Vertex >> theF1F0W1Vertex >> theF1F0H1Vertex >> theP0H1H1Vertex >> theZ0H1H1Vertex >> theW0A1H1Vertex >> theZ0A1h1Vertex >> theW0W1W1Vertex >> iunit(theVeV,GeV) >> iunit(theMbarH, GeV) >> theSinThetaOne >> includeSMMass_ >> fixedCouplings_ >> includeGaugeMixing_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigUEDBase("Herwig::UEDBase", "HwUED.so"); void UEDBase::Init() { static ClassDocumentation documentation ("This class implements/stores the necessary information for the simulation" " of a Universal Extra Dimensions model.", "Universal extra dimensions model based on \\cite{Cheng:2002iz,Appelquist:2000nn}.", "%\\cite{Cheng:2002iz}\n" "\\bibitem{Cheng:2002iz}\n" " H.~C.~Cheng, K.~T.~Matchev and M.~Schmaltz,\n" " ``Radiative corrections to Kaluza-Klein masses,''\n" " Phys.\\ Rev.\\ D {\\bf 66}, 036005 (2002)\n" " [arXiv:hep-ph/0204342].\n" " %%CITATION = PHRVA,D66,036005;%%\n" "%\\cite{Appelquist:2000nn}\n" "\\bibitem{Appelquist:2000nn}\n" " T.~Appelquist, H.~C.~Cheng and B.~A.~Dobrescu,\n" " ``Bounds on universal extra dimensions,''\n" " Phys.\\ Rev.\\ D {\\bf 64}, 035002 (2001)\n" " [arXiv:hep-ph/0012100].\n" " %%CITATION = PHRVA,D64,035002;%%\n" ); static Switch interfaceRadiativeCorrections ("RadiativeCorrections", "Calculate the radiative corrections to the masses", &UEDBase::theRadCorr, true, false, false); static SwitchOption interfaceRadiativeCorrectionsYes (interfaceRadiativeCorrections, "Yes", "Calculate the radiative corrections to the masses", true); static SwitchOption interfaceRadiativeCorrectionsNo (interfaceRadiativeCorrections, "No", "Leave the masses of the KK particles as n/R", false); static Parameter interfaceInverseRadius ("InverseRadius", "The inverse radius of the compactified dimension ", &UEDBase::theInvRadius, GeV, 500.*GeV, ZERO, ZERO, true, false, Interface::nolimits); static Parameter interfaceLambdaR ("LambdaR", "The product of the cut-off scale and the radius of compactification", &UEDBase::theLambdaR, 20.0, 0.0, 0, false, false, Interface::lowerlim); static Parameter interfaceBoundaryMass ("HiggsBoundaryMass", "The boundary mass for the Higgs", &UEDBase::theMbarH, GeV, ZERO, ZERO, ZERO, false, false, Interface::lowerlim); static Parameter interfaceVeV ("HiggsVEV", "The vacuum expectation value of the Higgs field", &UEDBase::theVeV, GeV, 246.*GeV, ZERO, ZERO, true, false, Interface::nolimits); static Reference interfaceF1F1Z ("Vertex/F1F1Z", "The F1F1Z UED Vertex", &UEDBase::theF1F1Z0Vertex, false, false, true, false, false); static Reference interfaceF1F1G0 ("Vertex/F1F1G0", "The F1F1G UED Vertex", &UEDBase::theF1F1G0Vertex, false, false, true, false, false); static Reference interfaceF1F0G1 ("Vertex/F1F0G1", "The F1F0G0 UED Vertex", &UEDBase::theF1F0G1Vertex, false, false, true, false, false); static Reference interfaceG1G1G0 ("Vertex/G1G1G0", "The G1G1G0 UED Vertex", &UEDBase::theG1G1G0Vertex, false, false, true, false, false); static Reference interfaceG0G0G1G1 ("Vertex/G0G0G1G1", "The G0G0G1G1 UED Vertex", &UEDBase::theG0G0G1G1Vertex, false, false, true, false, false); static Reference interfaceF1F1P ("Vertex/F1F1P", "The F1F1P UED Vertex", &UEDBase::theF1F1P0Vertex, false, false, true, false, false); static Reference interfaceF1F1W ("Vertex/F1F1W", "The F1F1W UED Vertex", &UEDBase::theF1F1W0Vertex, false, false, true, false, false); static Reference interfaceF1F0W1 ("Vertex/F1F0W1", "The F1F0W1 UED Vertex", &UEDBase::theF1F0W1Vertex, false, false, true, false, false); static Reference interfaceF1F0H1 ("Vertex/F1F0H1", "The F1F0H1 UED Vertex", &UEDBase::theF1F0H1Vertex, false, false, true, false, false); static Reference interfaceP0H1H1 ("Vertex/P0H1H1", "The P0H1H1 UED Vertex", &UEDBase::theP0H1H1Vertex, false, false, true, false, false); static Reference interfaceZ0H1H1 ("Vertex/Z0H1H1", "The Z0H1H1 UED Vertex", &UEDBase::theZ0H1H1Vertex, false, false, true, false, false); static Reference interfaceW0A1H1 ("Vertex/W0A1H1", "The W0A1H1 UED Vertex", &UEDBase::theW0A1H1Vertex, false, false, true, false, false); static Reference interfaceZ0A1h1 ("Vertex/Z0A1h1", "The W0A1H1 UED Vertex", &UEDBase::theZ0A1h1Vertex, false, false, true, false, false); static Reference interfaceW0W1W1 ("Vertex/W0W1W1", "The W0W1W1 UED Vertex", &UEDBase::theW0W1W1Vertex, false, false, true, false, false); static Switch interfaceIncludeSMMass ("IncludeSMMass", "Whether or not to include the SM mass in the calculation of the masses of the KK states.", &UEDBase::includeSMMass_, true, false, false); static SwitchOption interfaceIncludeSMMassYes (interfaceIncludeSMMass, "Yes", "Include them", true); static SwitchOption interfaceIncludeSMMassNo (interfaceIncludeSMMass, "No", "Don't include them", false); static Switch interfaceFixedCouplings ("FixedCouplings", "Use fixed or running couplings to calculate the masses.", &UEDBase::fixedCouplings_, false, false, false); static SwitchOption interfaceFixedCouplingsYes (interfaceFixedCouplings, "Yes", "Use fixed couplings", true); static SwitchOption interfaceFixedCouplingsNo (interfaceFixedCouplings, "No", "Use running couplings", false); static Switch interfaceIncludeGaugeMixing ("IncludeGaugeMixing", "Whether or not to include mixing between the KK photon" " and Z in the vertices, always included in the mass", &UEDBase::includeGaugeMixing_, true, false, false); static SwitchOption interfaceIncludeGaugeMixingYes (interfaceIncludeGaugeMixing, "Yes", "Include the mixing", true); static SwitchOption interfaceIncludeGaugeMixingNo (interfaceIncludeGaugeMixing, "No", "Don't include the mixing", false); } void UEDBase::calculateKKMasses(const unsigned int n) { useMe(); if(n == 0) throw InitException() << "UEDBase::resetKKMasses - " << "Trying to reset masses with KK number == 0!" << Exception::warning; if(theRadCorr) { fermionMasses(n); bosonMasses(n); } else { cerr << "Warning: Radiative corrections to particle masses have been " "turned off.\n The masses will be set to (n/R + m_sm)^1/2 and " "the spectrum will be\n highly degenerate so that no decays " "will occur.\n This is only meant to be used for debugging " "purposes.\n"; //set masses to tree level for each kk mode long level1 = 5000000 + n*100000; long level2 = 6000000 + n*100000; Energy2 ndmass2 = sqr(n*theInvRadius); for ( int i = 1; i < 38; ++i ) { if(i == 7 || i == 17) i += 4; if(i == 26) i += 10; Energy kkmass = sqrt( ndmass2 + sqr(getParticleData(i)->mass()) ); resetMass(level1 + i, kkmass); if( i < 7 || i == 11 || i == 13 || i == 15 ) resetMass(level2 + i, kkmass); } } } void UEDBase::bosonMasses(const unsigned int n) { + using Constants::zeta3; + using Constants::pi; // Common constants const Energy2 invRad2 = theInvRadius*theInvRadius; const double g_em2 = fixedCouplings_ ? - 4.*Constants::pi*alphaEMMZ() : 4.*Constants::pi*alphaEM(invRad2); + 4.*Constants::pi*alphaEMMZ() : 4.*pi*alphaEM(invRad2); const double g_s2 = fixedCouplings_ ? - 4.*Constants::pi*alphaS() : 4.*Constants::pi*alphaS(invRad2); + 4.*Constants::pi*alphaS() : 4.*pi*alphaS(invRad2); const double g_W2 = g_em2/sin2ThetaW(); const double g_P2 = g_em2/(1-sin2ThetaW()); //Should probably use a function to calculate zeta. - const double zeta3 = 1.20206; const Energy2 nmass2 = sqr(n*theInvRadius); - const double pi2 = sqr(Constants::pi); + const double pi2 = sqr(pi); const double norm = 1./16./pi2; const double nnlogLR = n*n*log(theLambdaR); long level = 5000000 + n*100000; //gluon Energy2 deltaGB = g_s2*invRad2*norm*(23.*nnlogLR - 3.*zeta3/2./pi2 ); resetMass(level + 21, sqrt(nmass2 + deltaGB)); //W+/- Energy2 deltaGW = g_W2*invRad2*norm*( 15.*nnlogLR - 5.*zeta3/2./pi2 ); Energy2 mw2 = sqr(getParticleData(24)->mass()); resetMass(level + 24, sqrt(mw2 + nmass2 + deltaGW)); //Z and gamma are a mixture of Bn and W3n deltaGB = -g_P2*invRad2*norm*( 39.*zeta3/2./pi2 + nnlogLR/3. ); Energy2 mz2 = sqr(getParticleData(23)->mass()); Energy2 fp = 0.5*(mz2 + deltaGB + deltaGW + 2.*nmass2); Energy2 sp = 0.5*sqrt( sqr(deltaGB - deltaGW - 2.*mw2 + mz2) - 4.*mw2*(mw2 - mz2) ); resetMass(level + 22, sqrt(fp - sp)); resetMass(level + 23, sqrt(fp + sp)); //mixing angle will now depend on both Z* and gamma* mass //Derived expression: // // cos^2_theta_N = ( (n/R)^2 + delta_GW + mw^2 - m_gam*^2)/(m_z*^2 - m_gam*^2) // if(includeGaugeMixing_) { double cn2 = (nmass2 + deltaGW + mw2 - fp + sp)/2./sp; double sn = sqrt(1. - cn2); theMixingAngles.insert(make_pair(n, sn)); if( n == 1 ) theSinThetaOne = sn; } else { theMixingAngles.insert(make_pair(n,0.)); if( n == 1 ) theSinThetaOne = 0.; } //scalars Energy2 mh2 = sqr(getParticleData(25)->mass()); double lambda_H = mh2/sqr(theVeV); deltaGB = nnlogLR*norm*invRad2*(3.*g_W2 + (3.*g_P2/2.) - 2.*lambda_H) + sqr(theMbarH); //H0 Energy2 new_m2 = nmass2 + deltaGB; resetMass(level + 25, sqrt( mh2 + new_m2 )); //A0 resetMass(level + 36, sqrt( mz2 + new_m2 )); //H+ resetMass(level + 37, sqrt( mw2 + new_m2 )); } void UEDBase::fermionMasses(const unsigned int n) { + using Constants::pi; const Energy2 invRad2 = theInvRadius*theInvRadius; const double g_em2 = fixedCouplings_ ? - 4.*Constants::pi*alphaEMMZ() : 4.*Constants::pi*alphaEM(invRad2); + 4.*pi*alphaEMMZ() : 4.*pi*alphaEM(invRad2); const double g_s2 = fixedCouplings_ ? - 4.*Constants::pi*alphaS() : 4.*Constants::pi*alphaS(invRad2); + 4.*pi*alphaS() : 4.*pi*alphaS(invRad2); const double g_W2 = g_em2/sin2ThetaW(); const double g_P2 = g_em2/(1-sin2ThetaW()); const Energy nmass = n*theInvRadius; const Energy norm = - nmass*log(theLambdaR)/16./Constants::pi/Constants::pi; + nmass*log(theLambdaR)/16./pi/pi; const Energy topMass = getParticleData(6)->mass(); const double ht = sqrt(2)*topMass/theVeV; //doublets Energy deltaL = norm*(6.*g_s2 + (27.*g_W2/8.) + (g_P2/8.)); Energy deltaQ = deltaL; Energy2 shift = sqr(nmass + deltaL); long level = 5000000 + n*100000; for(long i = 1; i < 17; ++i) { if(i == 5) { i += 6; deltaL = norm*( (27.*g_W2/8.) + (9.*g_P2/8.) ); shift = sqr(nmass + deltaL); } Energy2 new_m2 = includeSMMass_ ? sqr(getParticleData(i)->mass()) + shift : shift; resetMass(level + i, sqrt(new_m2)); } //singlet shifts const Energy deltaU = norm*(6.*g_s2 + 2.*g_P2); const Energy deltaD = norm*(6.*g_s2 + 0.5*g_P2); const Energy2 shiftU = sqr(nmass + deltaU); const Energy2 shiftD = sqr(nmass + deltaD); //Top quarks seperately as they have different corrections const Energy2 mt2 = sqr(topMass); const Energy delta_Q3 = -3.*ht*ht*norm/2.; const Energy deltaTD = deltaQ + delta_Q3; const Energy deltaTS = deltaU + 2.*delta_Q3; Energy second_term = 0.5*sqrt( sqr(2.*nmass + deltaTS + deltaTD) + 4.*mt2 ); //doublet resetMass(level + 6, abs(0.5*(deltaTD - deltaTS) - second_term) ); //singlet resetMass(level + 1000000 + 6, 0.5*(deltaTD - deltaTS) + second_term); //Bottom quarks const Energy2 mb2 = sqr(getParticleData(5)->mass()); const Energy deltaBS = deltaD; second_term = 0.5*sqrt( sqr(2.*nmass + deltaBS + deltaTD) + 4.*mb2 ); //doublet resetMass(level + 1000000 + 5, abs(0.5*(deltaTD - deltaBS) - second_term) ); //singlet resetMass(level + 5, 0.5*(deltaTD - deltaBS) + second_term); // others //lepton Energy delta = 9.*norm*g_P2/2.; shift = sqr(nmass + delta); level += 1000000; for(long i = 1; i < 17; ) { if(i == 5) i += 6; Energy2 smMass2(sqr(getParticleData(i)->mass())); if(i < 6) { Energy2 new_m2 = includeSMMass_ ? smMass2 : ZERO; if( i % 2 == 0) new_m2 = shiftU; else new_m2 = shiftD; resetMass(level + i, sqrt(new_m2)); ++i; } else { if(includeSMMass_) resetMass(level + i, sqrt(smMass2 + shift)); else resetMass(level + i, sqrt(shift)); i += 2; } } } void UEDBase::resetMass(long id, Energy mass) { theMasses.push_back(make_pair(id, mass)); StandardModel::resetMass(id,mass); } void UEDBase::writeSpectrum() { sort(theMasses.begin(), theMasses.end(), lowerMass); ostream & ofs = CurrentGenerator::current().misc(); ofs << "# MUED Model Particle Spectrum\n" << "# R^-1: " << theInvRadius/GeV << " GeV\n" << "# Lambda * R: " << theLambdaR << "\n" << "# Higgs Mass: " << getParticleData(25)->mass()/GeV << " GeV\n"; ofs << "#\n# ID\t\t\tMass(GeV)\n"; while (!theMasses.empty()) { IDMassPair tmp = theMasses.back(); tcPDPtr data = getParticleData(tmp.first); ofs << tmp.first << "\t\t\t" << tmp.second/GeV << "\t\t" << (data? data->PDGName() : "") << endl; theMasses.pop_back(); } ofs << "#\n"; } double UEDBase::sinThetaN(const unsigned int n) const { WAMap::const_iterator pos = theMixingAngles.find(n); if(pos != theMixingAngles.end()) return pos->second; else { throw Exception() << "UEDBase::sinThetaN() - A mixing angle has " << "been requested for a level that does not " << "exist. Check that the radiative corrections " << "for the " << n << "th level have been " << "calculated." << Exception::warning; return 0.0; } } diff --git a/Shower/Base/ShowerBasis.cc b/Shower/Base/ShowerBasis.cc new file mode 100644 --- /dev/null +++ b/Shower/Base/ShowerBasis.cc @@ -0,0 +1,81 @@ +// -*- C++ -*- +// +// This is the implementation of the non-inlined, non-templated member +// functions of the ShowerBasis class. +// + +#include "ShowerBasis.h" +#include "ShowerParticle.h" +#include "ThePEG/Interface/ClassDocumentation.h" +#include "ThePEG/EventRecord/Particle.h" +#include "ThePEG/Repository/UseRandom.h" +#include "ThePEG/Repository/EventGenerator.h" +#include "ThePEG/Utilities/DescribeClass.h" + +using namespace Herwig; + + +// The following static variable is needed for the type +// description system in ThePEG. +DescribeNoPIOClass +describeHerwigShowerBasis("Herwig::ShowerBasis", "libHerwig.so"); + +void ShowerBasis::setBasis(const Lorentz5Momentum & p, + const Lorentz5Momentum & n, + Frame inframe) { + pVector_ = p; + nVector_ = n; + frame(inframe); + Boost beta_bb; + if(frame()==BackToBack) { + beta_bb = -(pVector_ + nVector_).boostVector(); + } + else if(frame()==Rest) { + beta_bb = -pVector().boostVector(); + } + else + assert(false); + Lorentz5Momentum p_bb = pVector(); + Lorentz5Momentum n_bb = nVector(); + p_bb.boost( beta_bb ); + n_bb.boost( beta_bb ); + // rotate to have z-axis parallel to p/n + Axis axis; + if(frame()==BackToBack) { + axis = p_bb.vect().unit(); + } + else if(frame()==Rest) { + axis = n_bb.vect().unit(); + } + else + assert(false); + LorentzRotation rot; + if(axis.perp2()>1e-10) { + double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); + rot.rotate(acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); + } + else if(axis.z()<0.) { + rot.rotate(Constants::pi,Axis(1.,0.,0.)); + } + xPerp_=LorentzVector(1.,0.,0.,0.); + yPerp_=LorentzVector(0.,1.,0.,0.); + xPerp_.transform(rot); + yPerp_.transform(rot); + // boost back + xPerp_.boost( -beta_bb ); + yPerp_.boost( -beta_bb ); +} + +void ShowerBasis::transform(const LorentzRotation & r) { + pVector_ *= r; + nVector_ *= r; + xPerp_ *= r; + yPerp_ *= r; +} + +vector ShowerBasis::getBasis() const { + vector dum; + dum.push_back( pVector_ ); + dum.push_back( nVector_ ); + return dum; +} diff --git a/Shower/Base/ShowerBasis.fh b/Shower/Base/ShowerBasis.fh new file mode 100644 --- /dev/null +++ b/Shower/Base/ShowerBasis.fh @@ -0,0 +1,21 @@ +// -*- C++ -*- +// +// This is the forward declaration of the ShowerBasis class. +// +#ifndef Herwig_ShowerBasis_FH +#define Herwig_ShowerBasis_FH + +#include "ThePEG/Config/ThePEG.h" + +namespace Herwig { + +class ShowerBasis; +} + +namespace ThePEG { + +ThePEG_DECLARE_POINTERS(Herwig::ShowerBasis,ShowerBasisPtr); + +} + +#endif diff --git a/Shower/Base/ShowerBasis.h b/Shower/Base/ShowerBasis.h new file mode 100644 --- /dev/null +++ b/Shower/Base/ShowerBasis.h @@ -0,0 +1,135 @@ +// -*- C++ -*- +#ifndef Herwig_ShowerBasis_H +#define Herwig_ShowerBasis_H +// +// This is the declaration of the ShowerBasis class. +// + +#include "ShowerBasis.fh" +#include "ShowerParticle.fh" +#include "Herwig/Shower/ShowerConfig.h" +#include "ThePEG/Config/ThePEG.h" +#include "ThePEG/Vectors/Lorentz5Vector.h" + +namespace Herwig { + +using namespace ThePEG; + +/** + * The ShowerBasis class stores the basis vectors used by the shower + */ +class ShowerBasis: public Base { + +public: + + /** + * enum for the frame definition + */ + enum Frame {BackToBack,Rest}; + +public: + + /** + * The default constructor. + */ + ShowerBasis() {} + + /** + * Access to the frame definition + */ + Frame frame() const {return frame_;} + + /** + * Set the frame definition + */ + void frame(Frame frame) {frame_ = frame;} + + /** + * Implementation of the virtual function returning a set of basis vectors, specific to + * the type of evolution. This function will be used by the + * ForwardShowerEvolver in order to access \f$p\f$ + * and \f$n\f$. + */ + virtual vector getBasis() const; + + /** + * Set the basis vectors + */ + void setBasis(const Lorentz5Momentum &p, const Lorentz5Momentum & n, + Frame frame); + + /** + * Access to the \f$p\f$ vector used to describe the kinematics. + */ + const Lorentz5Momentum & pVector() const {return pVector_;} + + /** + * Access to the \f$n\f$ vector used to describe the kinematics. + */ + const Lorentz5Momentum & nVector() const {return nVector_;} + + /** + * Dot product of thew basis vectors + */ + Energy2 p_dot_n() const {return pVector_*nVector_;} + + /** + * Transform the shower kinematics (usually the reference vectors) + */ + virtual void transform(const LorentzRotation & r); + + /** + * Converts a Sudakov parametrization of a momentum w.r.t. the given + * basis \f$p\f$ and \f$n\f$ into a 5 momentum. + * @param alpha The \f$\alpha\f$ parameter of the Sudakov parameterisation + * @param beta The \f$\beta\f$ parameter of the Sudakov parameterisation + * @param px The \f$x\f$-component of the transverse momentum in the Sudakov + * parameterisation + * @param py The \f$x\f$-component of the transverse momentum in the Sudakov + * parameterisation + */ + Lorentz5Momentum sudakov2Momentum(double alpha, double beta, + Energy px, Energy py) const { + return alpha*pVector_ + beta*nVector_ + px*xPerp_ + py*yPerp_; + } + +private: + + /** + * The assignment operator is private and must never be called. + * In fact, it should not even be implemented. + */ + ShowerBasis & operator=(const ShowerBasis &) = delete; + +private: + + /** + * The frame in which the basis vectors are defined + */ + Frame frame_; + + /** + * The \f$p\f$ reference vector + */ + Lorentz5Momentum pVector_; + + /** + * The \f$n\f$ reference vector + */ + Lorentz5Momentum nVector_; + + /** + * x \f$q_\perp\f$ reference vector + */ + LorentzVector xPerp_; + + /** + * y \f$q_\perp\f$reference vector + */ + LorentzVector yPerp_; + +}; + +} + +#endif /* Herwig_ShowerBasis_H */ diff --git a/Shower/QTilde/Base/PartnerFinder.cc b/Shower/QTilde/Base/PartnerFinder.cc --- a/Shower/QTilde/Base/PartnerFinder.cc +++ b/Shower/QTilde/Base/PartnerFinder.cc @@ -1,591 +1,699 @@ // -*- C++ -*- // // PartnerFinder.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the PartnerFinder class. // #include "PartnerFinder.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Shower/QTilde/Base/ShowerParticle.h" -#include "ThePEG/Repository/UseRandom.h" +#include "ThePEG/Repository/UseRandom.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Utilities/Debug.h" #include "ThePEG/Utilities/DescribeClass.h" using namespace Herwig; DescribeClass describePartnerFinder ("Herwig::PartnerFinder","HwShower.so"); // some useful functions to avoid using #define namespace { // return bool if final-state particle inline bool FS(const tShowerParticlePtr a) { return a->isFinalState(); } - // return colour line pointer - inline Ptr::transient_pointer + // return colour line pointer + inline Ptr::transient_pointer CL(const tShowerParticlePtr a, unsigned int index=0) { return a->colourInfo()->colourLines().empty() ? ThePEG::tColinePtr() : const_ptr_cast(a->colourInfo()->colourLines()[index]); } // return colour line size inline size_t CLSIZE(const tShowerParticlePtr a) { return a->colourInfo()->colourLines().size(); } - + inline Ptr::transient_pointer ACL(const tShowerParticlePtr a, unsigned int index=0) { return a->colourInfo()->antiColourLines().empty() ? ThePEG::tColinePtr() : const_ptr_cast(a->colourInfo()->antiColourLines()[index]); } inline size_t ACLSIZE(const tShowerParticlePtr a) { return a->colourInfo()->antiColourLines().size(); } } void PartnerFinder::persistentOutput(PersistentOStream & os) const { os << partnerMethod_ << QEDPartner_ << scaleChoice_; } void PartnerFinder::persistentInput(PersistentIStream & is, int) { is >> partnerMethod_ >> QEDPartner_ >> scaleChoice_; } void PartnerFinder::Init() { static ClassDocumentation documentation ("This class is responsible for finding the partners for each interaction types ", "and within the evolution scale range specified by the ShowerVariables ", "then to determine the initial evolution scales for each pair of partners."); static Switch interfacePartnerMethod ("PartnerMethod", "Choice of partner finding method for gluon evolution.", &PartnerFinder::partnerMethod_, 0, false, false); static SwitchOption interfacePartnerMethodRandom (interfacePartnerMethod, "Random", "Choose partners of a gluon randomly.", 0); static SwitchOption interfacePartnerMethodMaximum (interfacePartnerMethod, "Maximum", "Choose partner of gluon with largest angle.", 1); static Switch interfaceQEDPartner ("QEDPartner", "Control of which particles to use as the partner for QED radiation", &PartnerFinder::QEDPartner_, 0, false, false); static SwitchOption interfaceQEDPartnerAll (interfaceQEDPartner, "All", "Consider all possible choices which give a positive contribution" " in the soft limit.", 0); static SwitchOption interfaceQEDPartnerIIandFF (interfaceQEDPartner, "IIandFF", "Only allow initial-initial or final-final combinations", 1); static SwitchOption interfaceQEDPartnerIF (interfaceQEDPartner, "IF", "Only allow initial-final combinations", 2); static Switch interfaceScaleChoice ("ScaleChoice", "The choice of the evolution scales", &PartnerFinder::scaleChoice_, 0, false, false); static SwitchOption interfaceScaleChoicePartner (interfaceScaleChoice, "Partner", "Scale of all interactions is that of the evolution partner", 0); static SwitchOption interfaceScaleChoiceDifferent (interfaceScaleChoice, "Different", "Allow each interaction to have different scales", 1); } void PartnerFinder::setInitialEvolutionScales(const ShowerParticleVector &particles, const bool isDecayCase, ShowerInteraction type, const bool setPartners) { // clear the existing partners for(ShowerParticleVector::const_iterator cit = particles.begin(); cit != particles.end(); ++cit) (*cit)->clearPartners(); // set them if(type==ShowerInteraction::QCD) { setInitialQCDEvolutionScales(particles,isDecayCase,setPartners); } else if(type==ShowerInteraction::QED) { setInitialQEDEvolutionScales(particles,isDecayCase,setPartners); } - else { + else if(type==ShowerInteraction::EW) { + setInitialEWEvolutionScales(particles,isDecayCase,false); + } + else if(type==ShowerInteraction::QEDQCD) { setInitialQCDEvolutionScales(particles,isDecayCase,setPartners); setInitialQEDEvolutionScales(particles,isDecayCase,false); } + else if(type==ShowerInteraction::ALL) { + setInitialQCDEvolutionScales(particles,isDecayCase,setPartners); + setInitialQEDEvolutionScales(particles,isDecayCase,false); + setInitialEWEvolutionScales(particles,isDecayCase,false); + } + else + assert(false); + // \todo EW scales here // print out for debugging if(Debug::level>=10) { for(ShowerParticleVector::const_iterator cit = particles.begin(); cit != particles.end(); ++cit) { generator()->log() << "Particle: " << **cit << "\n"; if(!(**cit).partner()) continue; generator()->log() << "Primary partner: " << *(**cit).partner() << "\n"; for(vector::const_iterator it= (**cit).partners().begin(); it!=(**cit).partners().end();++it) { generator()->log() << static_cast(it->type) << " " - << it->weight << " " - << it->scale/GeV << " " - << *(it->partner) + << it->weight << " " + << it->scale/GeV << " " + << *(it->partner) << "\n"; } } generator()->log() << flush; } } void PartnerFinder::setInitialQCDEvolutionScales(const ShowerParticleVector &particles, const bool isDecayCase, const bool setPartners) { // Loop over particles and consider only coloured particles which don't // have already their colour partner fixed and that don't have children - // (the latter requirement is relaxed in the case isDecayCase is true). - // Build a map which has as key one of these particles (i.e. a pointer + // (the latter requirement is relaxed in the case isDecayCase is true). + // Build a map which has as key one of these particles (i.e. a pointer // to a ShowerParticle object) and as a corresponding value the vector // of all its possible *normal* candidate colour partners, defined as follows: - // --- have colour, and no children (this is not required in the case + // --- have colour, and no children (this is not required in the case // isDecayCase is true); - // --- if both are initial (incoming) state particles, then the (non-null) colourLine() + // --- if both are initial (incoming) state particles, then the (non-null) colourLine() // of one of them must match the (non-null) antiColourLine() of the other. // --- if one is an initial (incoming) state particle and the other is // a final (outgoing) state particle, then both must have the // same (non-null) colourLine() or the same (non-null) antiColourLine(); // Notice that this definition exclude the special case of baryon-violating // processes (as in R-parity Susy), which will show up as particles // without candidate colour partners, and that we will be treated a part later // (this means that no modifications of the following loop is needed! - for ( const auto & sp : particles ) { - // Skip colourless particles - if(!sp->data().coloured()) continue; - // find the partners - auto partners = findQCDPartners(sp,particles); - // must have a partner - if(partners.empty()) { - throw Exception() << "`Failed to make colour connections in " - << "PartnerFinder::setQCDInitialEvolutionScales" - << *sp - << Exception::eventerror; + for ( const auto & sp : particles ) { + // Skip colourless particles + if(!sp->data().coloured()) continue; + // find the partners + auto partners = findQCDPartners(sp,particles); + // must have a partner + if(partners.empty()) { + throw Exception() << "`Failed to make colour connections in " + << "PartnerFinder::setQCDInitialEvolutionScales" + << *sp + << Exception::eventerror; + } + // Calculate the evolution scales for all possible pairs of of particles + vector > scales; + int position = -1; + for(size_t ix=0; ix< partners.size(); ++ix) { + scales.push_back(calculateInitialEvolutionScales(ShowerPPair(sp, partners[ix].second),isDecayCase)); + if (!setPartners && partners[ix].second) position = ix; + } + assert(setPartners || position >= 0); + + // set partners if required + if (setPartners) { + // In the case of more than one candidate colour partners, + // there are now two approaches to choosing the partner. The + // first method is based on two assumptions: + // 1) the choice of which is the colour partner is done + // *randomly* between the available candidates. + // 2) the choice of which is the colour partner is done + // *independently* from each particle: in other words, + // if for a particle "i" its selected colour partner is + // the particle "j", then the colour partner of "j" + // does not have to be necessarily "i". + // The second method always chooses the furthest partner + // for hard gluons and gluinos. + // random choice + if( partnerMethod_ == 0 ) { + // random choice of partner + position = UseRandom::irnd(partners.size()); } - // Calculate the evolution scales for all possible pairs of of particles - vector > scales; - int position = -1; - for(size_t ix=0; ix< partners.size(); ++ix) { - scales.push_back( - calculateInitialEvolutionScales( - ShowerPPair(sp, partners[ix].second), - isDecayCase - ) - ); - if (!setPartners && partners[ix].second) position = ix; - } - assert(setPartners || position >= 0); + // take the one with largest angle + else if (partnerMethod_ == 1 ) { + if (sp->perturbative() == 1 && + sp->dataPtr()->iColour()==PDT::Colour8 ) { + assert(partners.size()==2); + // Determine largest angle + double maxAngle(0.); + for(unsigned int ix=0;ixmomentum().vect(). + angle(partners[ix].second->momentum().vect()); + if(angle>maxAngle) { + maxAngle = angle; + position = ix; + } + } + } + else position = UseRandom::irnd(partners.size()); + } + else assert(false); + // set the evolution partner + sp->partner(partners[position].second); + } - // set partners if required - if (setPartners) { - // In the case of more than one candidate colour partners, - // there are now two approaches to choosing the partner. The - // first method is based on two assumptions: - // 1) the choice of which is the colour partner is done - // *randomly* between the available candidates. - // 2) the choice of which is the colour partner is done - // *independently* from each particle: in other words, - // if for a particle "i" its selected colour partner is - // the particle "j", then the colour partner of "j" - // does not have to be necessarily "i". - // The second method always chooses the furthest partner - // for hard gluons and gluinos. - // random choice - if( partnerMethod_ == 0 ) { - // random choice of partner - position = UseRandom::irnd(partners.size()); - } - // take the one with largest angle - else if (partnerMethod_ == 1 ) { - if (sp->perturbative() == 1 && - sp->dataPtr()->iColour()==PDT::Colour8 ) { - assert(partners.size()==2); - // Determine largest angle - double maxAngle(0.); - for(unsigned int ix=0;ixmomentum().vect(). - angle(partners[ix].second->momentum().vect()); - if(angle>maxAngle) { - maxAngle = angle; - position = ix; - } - } - } - else position = UseRandom::irnd(partners.size()); - } - else assert(false); - // set the evolution partner - sp->partner(partners[position].second); - } + // primary partner set, set the others and do the scale + for(size_t ix=0; ixaddPartner(ShowerParticle::EvolutionPartner(partners[ix].second,1.,partners[ix].first, + scales[ix].first)); + } - - // primary partner set, set the others and do the scale - for(size_t ix=0; ixaddPartner( - ShowerParticle::EvolutionPartner( - partners[ix].second, - 1., - partners[ix].first, - scales[ix].first - ) - ); + // set scales for all interactions to that of the partner, default + Energy scale = scales[position].first; + for(unsigned int ix=0;ixscales().QCD_c = + sp->scales().QCD_c_noAO = + (scaleChoice_==0 ? scale : scales[ix].first); } - - // set scales for all interactions to that of the partner, default - Energy scale = scales[position].first; - for(unsigned int ix=0;ixscales().QCD_c = - sp->scales().QCD_c_noAO = - (scaleChoice_==0 ? scale : scales[ix].first); - } - else if(partners[ix].first==ShowerPartnerType::QCDAntiColourLine) { - sp->scales().QCD_ac = - sp->scales().QCD_ac_noAO = - (scaleChoice_==0 ? scale : scales[ix].first); - } - else assert(false); + else if(partners[ix].first==ShowerPartnerType::QCDAntiColourLine) { + sp->scales().QCD_ac = + sp->scales().QCD_ac_noAO = + (scaleChoice_==0 ? scale : scales[ix].first); } + else assert(false); + } } } - - - void PartnerFinder::setInitialQEDEvolutionScales(const ShowerParticleVector &particles, const bool isDecayCase, const bool setPartners) { // loop over all the particles for(const auto & sp : particles) { // not charged or photon continue - if(!sp->dataPtr()->charged()) continue; + if(!sp->dataPtr()->charged() && sp->dataPtr()->id()!=ParticleID::gamma) continue; // find the potential partners vector > partners = findQEDPartners(sp,particles,isDecayCase); if(partners.empty()) { - throw Exception() << "Failed to find partner in " + throw Exception() << "Failed to find partner in " << "PartnerFinder::setQEDInitialEvolutionScales" << *sp << Exception::eventerror; } // calculate the probabilities double prob(0.); for(unsigned int ix=0;ixpartner()) { for(unsigned int ix=0;ixpartner()==partners[ix].second) { position = ix; break; } } } // set the partner if(setPartners||!sp->partner()||position<0) { prob = UseRandom::rnd(); for(unsigned int ix=0;ixprob) { position = ix; break; } prob -= partners[ix].first; } if(position>=0&&(setPartners||!sp->partner())) { sp->partner(partners[position].second); } } // must have a partner - if(position<0) throw Exception() << "Failed to find partner in " + if(position<0) throw Exception() << "Failed to find partner in " << "PartnerFinder::setQEDInitialEvolutionScales" - << *sp << Exception::eventerror; + << *sp << Exception::eventerror; // Calculate the evolution scales for all possible pairs of of particles vector > scales; for(unsigned int ix=0;ix< partners.size();++ix) { scales.push_back(calculateInitialEvolutionScales(ShowerPPair(sp,partners[ix].second), isDecayCase)); } // store all the possible partners for(unsigned int ix=0;ixaddPartner(ShowerParticle::EvolutionPartner(partners[ix].second, partners[ix].first, ShowerPartnerType::QED, scales[ix].first)); } // set scales sp->scales().QED = scales[position].first; sp->scales().QED_noAO = scales[position].first; } } pair PartnerFinder:: calculateInitialEvolutionScales(const ShowerPPair &particlePair, - const bool isDecayCase) { + const bool isDecayCase, int key) { bool FS1=FS(particlePair.first),FS2= FS(particlePair.second); - - if(FS1 && FS2) - return calculateFinalFinalScales(particlePair.first->momentum(), - particlePair.second->momentum()); + if(FS1 && FS2){ + return calculateFinalFinalScales(particlePair.first->momentum(),particlePair.second->momentum(), key); + } else if(FS1 && !FS2) { pair rval = calculateInitialFinalScales(particlePair.second->momentum(), particlePair.first->momentum(), isDecayCase); return { rval.second, rval.first }; } else if(!FS1 &&FS2) return calculateInitialFinalScales(particlePair.first->momentum(),particlePair.second->momentum(),isDecayCase); else return calculateInitialInitialScales(particlePair.first->momentum(),particlePair.second->momentum()); } -vector< pair > +vector< pair > PartnerFinder::findQCDPartners(tShowerParticlePtr particle, const ShowerParticleVector &particles) { vector< pair > partners; for(const auto & sp : particles) { if(!sp->data().coloured() || particle==sp) continue; // one initial-state and one final-state particle if(FS(particle) != FS(sp)) { // loop over all the colours of both particles for(size_t ix=0; ixsourceNeighbours().first) { tColinePair cpair = col->sourceNeighbours(); for(const auto & sp : particles) { if(( FS(sp) && ( CL(sp) == cpair.first || CL(sp) == cpair.second))|| (!FS(sp) && (ACL(sp) == cpair.first || ACL(sp) == cpair.second ))) { partners.push_back({ ShowerPartnerType:: QCDColourLine, sp }); } } } else if(col&&col->sinkNeighbours().first) { tColinePair cpair = col->sinkNeighbours(); for(const auto & sp : particles) { if(( FS(sp) && (ACL(sp) == cpair.first || ACL(sp) == cpair.second))|| (!FS(sp) && ( CL(sp) == cpair.first || CL(sp) == cpair.second))) { partners.push_back({ ShowerPartnerType:: QCDColourLine, sp }); } } } col = ACL(particle); if(FS(particle)&&col&&col->sinkNeighbours().first) { tColinePair cpair = col->sinkNeighbours(); for(const auto & sp : particles) { if(( FS(sp) && (ACL(sp) == cpair.first || ACL(sp) == cpair.second))|| (!FS(sp) && ( CL(sp) == cpair.first || CL(sp) == cpair.second ))) { partners.push_back({ ShowerPartnerType::QCDAntiColourLine, sp }); } } } else if(col&&col->sourceNeighbours().first) { tColinePair cpair = col->sourceNeighbours(); for(const auto & sp : particles) { if(( FS(sp) && ( CL(sp) == cpair.first || CL(sp) == cpair.second))|| (!FS(sp) && (ACL(sp) == cpair.first ||ACL(sp) == cpair.second))) { partners.push_back({ ShowerPartnerType::QCDAntiColourLine, sp }); } } } } // return the partners return partners; } -vector< pair > +vector< pair > PartnerFinder::findQEDPartners(tShowerParticlePtr particle, const ShowerParticleVector & particles, const bool isDecayCase) { vector< pair > partners; - const double pcharge = + const double pcharge = particle->id()==ParticleID::gamma ? 1 : double(particle->data().iCharge()); vector< pair > photons; for (const auto & sp : particles) { if (particle == sp) continue; if (sp->id()==ParticleID::gamma) photons.push_back(make_pair(1.,sp)); if (!sp->data().charged() ) continue; double charge = pcharge*double((sp)->data().iCharge()); if ( FS(particle) != FS(sp) ) charge *=-1.; if ( QEDPartner_ != 0 && !isDecayCase ) { // only include II and FF as requested if ( QEDPartner_ == 1 && FS(particle) != FS(sp) ) continue; // only include IF is requested else if (QEDPartner_ == 2 && FS(particle) == FS(sp) ) continue; } if (particle->id()==ParticleID::gamma) charge = -abs(charge); // only keep positive dipoles if (charge<0.) partners.push_back({ -charge, sp }); } - if (particle->id()==ParticleID::gamma && partners.empty()) { + if (particle->id()==ParticleID::gamma && partners.empty()) return photons; + return partners; +} + +void PartnerFinder::setInitialEWEvolutionScales(const ShowerParticleVector &particles, + const bool isDecayCase, + const bool setPartners) { + // loop over all the particles + for(ShowerParticleVector::const_iterator cit = particles.begin(); + cit != particles.end(); ++cit) { + // if not weakly interacting continue + if( !weaklyInteracting( (**cit).dataPtr())) + continue; + // find the potential partners + vector > partners = findEWPartners(*cit,particles,isDecayCase); + if(partners.empty()) { + throw Exception() << "Failed to find partner in " + << "PartnerFinder::setEWInitialEvolutionScales" + << (**cit) << Exception::eventerror; + } + // calculate the probabilities + double prob(0.); + for(unsigned int ix=0;ixpartner()) { + for(unsigned int ix=0;ixpartner()==partners[ix].second) { + position = ix; + break; + } + } + } + // set the partner + if(setPartners||!(*cit)->partner()||position<0) { + prob = UseRandom::rnd(); + for(unsigned int ix=0;ixprob) { + position = ix; + break; + } + prob -= partners[ix].first; + } + if(position>=0&&(setPartners||!(*cit)->partner())) { + (*cit)->partner(partners[position].second); + } + } + // must have a partner + if(position<0) throw Exception() << "Failed to find partner in " + << "PartnerFinder::setEWInitialEvolutionScales" + << (**cit) << Exception::eventerror; + // Calculate the evolution scales for all possible pairs of of particles + vector > scales; + for(unsigned int ix=0;ix< partners.size();++ix) { + scales.push_back(calculateInitialEvolutionScales(ShowerPPair(*cit,partners[ix].second), + isDecayCase, 0)); + } + // store all the possible partners + for(unsigned int ix=0;ix > +PartnerFinder::findEWPartners(tShowerParticlePtr particle, + const ShowerParticleVector &particles, + const bool isDecayCase ) { + vector< pair > partners; + for(ShowerParticlePtr partner : particles) { + if(particle==partner || !weaklyInteracting(partner->dataPtr())) + continue; + partners.push_back(make_pair(1.,partner)); } return partners; } -pair +pair PartnerFinder::calculateFinalFinalScales( const Lorentz5Momentum & p1, - const Lorentz5Momentum & p2) + const Lorentz5Momentum & p2, int key) { static const double eps=1e-7; // Using JHEP 12(2003)045 we find that we need ktilde = 1/2(1+b-c+lambda) // ktilde = qtilde^2/Q^2 therefore qtilde = sqrt(ktilde*Q^2) // find momenta in rest frame of system // calculate quantities for the scales Energy2 Q2 = (p1+p2).m2(); double b = p1.mass2()/Q2; double c = p2.mass2()/Q2; if(b<0.) { if(b<-eps) { throw Exception() << "Negative Mass squared b = " << b << "in PartnerFinder::calculateFinalFinalScales()" << Exception::eventerror; } b = 0.; } if(c<0.) { if(c<-eps) { throw Exception() << "Negative Mass squared c = " << c << "in PartnerFinder::calculateFinalFinalScales()" << Exception::eventerror; } c = 0.; } - // KMH & PR - 16 May 2008 - swapped lambda calculation from - // double lam=2.*p1.vect().mag()/Q; to sqrt(kallen(1,b,c)), + // KMH & PR - 16 May 2008 - swapped lambda calculation from + // double lam=2.*p1.vect().mag()/Q; to sqrt(kallen(1,b,c)), // which should be identical for p1 & p2 onshell in their COM // but in the inverse construction for the Nason method, this - // was not the case, leading to misuse. + // was not the case, leading to misuse. const double lam=sqrt((1.+sqrt(b)+sqrt(c))*(1.-sqrt(b)-sqrt(c)) *(sqrt(b)-1.-sqrt(c))*(sqrt(c)-1.-sqrt(b))); - // symmetric case - return { sqrt(0.5*Q2*(1.+b-c+lam)), sqrt(0.5*Q2*(1.-b+c+lam)) }; + + Energy firstQ, secondQ; + double kappab(0.), kappac(0.); + //key = 0; // symmetric case pre-selection + switch(key) { + case 0: // symmetric case + firstQ = sqrt(0.5*Q2*(1.+b-c+lam)); + secondQ = sqrt(0.5*Q2*(1.-b+c+lam)); + break; + case 1: // maximum emission from both legs + kappab=4.*(1.-2.*sqrt(c)-b+c); + kappac=4.*(1.-2.*sqrt(b)-c+b); + firstQ = sqrt(Q2*kappab); + secondQ = sqrt(Q2*kappac); + break; + default: + assert(false); + } + // calculate the scales + return pair(firstQ, secondQ); } - pair PartnerFinder::calculateInitialFinalScales(const Lorentz5Momentum& pb, const Lorentz5Momentum& pc, - const bool isDecayCase) { - if(!isDecayCase) { + const bool isDecayCase) { + if(!isDecayCase) { // In this case from JHEP 12(2003)045 we find the conditions // ktilde_b = (1+c) and ktilde_c = (1+2c) // We also find that c = m_c^2/Q^2. The process is a+b->c where // particle a is not colour connected (considered as a colour singlet). - // Therefore we simply find that q_b = sqrt(Q^2+m_c^2) and + // Therefore we simply find that q_b = sqrt(Q^2+m_c^2) and // q_c = sqrt(Q^2+2 m_c^2) // We also assume that the first particle in the pair is the initial - // state particle and the second is the final state one c + // state particle and the second is the final state one c const Energy2 mc2 = sqr(pc.mass()); const Energy2 Q2 = -(pb-pc).m2(); return { sqrt(Q2+mc2), sqrt(Q2+2*mc2) }; } - else { + else { // In this case from JHEP 12(2003)045 we find, for the decay // process b->c+a(neutral), the condition - // (ktilde_b-1)*(ktilde_c-c)=(1/4)*sqr(1-a+c+lambda). + // (ktilde_b-1)*(ktilde_c-c)=(1/4)*sqr(1-a+c+lambda). // We also assume that the first particle in the pair is the initial // state particle (b) and the second is the final state one (c). - // - We find maximal phase space coverage through emissions from + // - We find maximal phase space coverage through emissions from // c if we set ktilde_c = 4.*(sqr(1.-sqrt(a))-c) // - We find the most 'symmetric' way to populate the phase space - // occurs for (ktilde_b-1)=(ktilde_c-c)=(1/2)*(1-a+c+lambda) + // occurs for (ktilde_b-1)=(ktilde_c-c)=(1/2)*(1-a+c+lambda) // - We find the most 'smooth' way to populate the phase space // occurs for... Energy2 mb2(sqr(pb.mass())); double a=(pb-pc).m2()/mb2; double c=sqr(pc.mass())/mb2; double lambda = 1. + a*a + c*c - 2.*a - 2.*c - 2.*a*c; lambda = sqrt(max(lambda,0.)); const double PROD = 0.25*sqr(1. - a + c + lambda); - const double ktilde_c = 0.5*(1-a+c+lambda) + c ; - const double ktilde_b = 1.+PROD/(ktilde_c-c) ; + int key = 0; + double ktilde_b, ktilde_c, cosi = 0.; + switch (key) { + case 0: // the 'symmetric' choice + ktilde_c = 0.5*(1-a+c+lambda) + c ; + ktilde_b = 1.+PROD/(ktilde_c-c) ; + break; + case 1: // the 'maximal' choice + ktilde_c = 4.0*(sqr(1.-sqrt(a))-c); + ktilde_b = 1.+PROD/(ktilde_c-c) ; + break; + case 2: // the 'smooth' choice + c = max(c,1.*GeV2/mb2); + cosi = (sqr(1-sqrt(c))-a)/lambda; + ktilde_b = 2.0/(1.0-cosi); + ktilde_c = (1.0-a+c+lambda)*(1.0+c-a-lambda*cosi)/(2.0*(1.0+cosi)); + break; + } return { sqrt(mb2*ktilde_b), sqrt(mb2*ktilde_c) }; } } pair PartnerFinder::calculateInitialInitialScales(const Lorentz5Momentum& p1, const Lorentz5Momentum& p2) { // This case is quite simple. From JHEP 12(2003)045 we find the condition // that ktilde_b = ktilde_c = 1. In this case we have the process // b+c->a so we need merely boost to the CM frame of the two incoming // particles and then qtilde is equal to the energy in that frame const Energy Q = sqrt((p1+p2).m2()); return {Q,Q}; } diff --git a/Shower/QTilde/Base/PartnerFinder.h b/Shower/QTilde/Base/PartnerFinder.h --- a/Shower/QTilde/Base/PartnerFinder.h +++ b/Shower/QTilde/Base/PartnerFinder.h @@ -1,230 +1,256 @@ // -*- C++ -*- // // PartnerFinder.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_PartnerFinder_H #define HERWIG_PartnerFinder_H // // This is the declaration of the PartnerFinder class. // #include "Herwig/Shower/QTilde/ShowerConfig.h" #include "ThePEG/Interface/Interfaced.h" #include "PartnerFinder.fh" namespace Herwig { using namespace ThePEG; /** * typedef of a pair of particle for calculating the evolution scales */ typedef pair ShowerPPair; /** \ingroup Shower * * This class is responsible of two related tasks: * - it finds the partners * - for each pair of partners (and interaction therefore) * it sets the initial evolution scales of both of them. * * In general the finding of the partners is performed by this class but * the calculation of the initial evolution scales should be implemented * for different shower evolution models in classes inheriting from this one. * Notice that a given particle has, in general, a different partner * for each different interaction; however, given a partner, its * initial evolution scale, Q, is purely a kinematical relationship * between the pair, without dependence on the dynamics (i.e. type of interaction). * * @see \ref PartnerFinderInterfaces "The interfaces" * defined for PartnerFinder. */ class PartnerFinder: public Interfaced { public: /** * The default constructor. */ PartnerFinder() : partnerMethod_(0), QEDPartner_(0), scaleChoice_(0) {} /** * Given in input a collection of particles (ShowerParticle objects), * each of these methods set the initial evolution scales of those particles, * between the ones given in input, that do not have yet their * evolution scale set. * The input collection of particles can be either the full collection of * showering particles (kept in the main class ShowerHandler, * in the case isDecayCase is false, or simply, in the case isDecayCase * is true, the decaying particle and its decay products. * The methods returns true, unless something wrong (inconsistencies, * or undefined values) happens. * * These methods are virtual but in most cases inheriting classes should not * need to overide them as they simply find the relevant partner and call * one of the calculateScale members to calculate the scale. */ //@{ /** * Set the initial scales * @param particles The particles to be considered * @param isDecayCase Whether or not this is a decay * @param setPartners Whether to set the colour partners or just the scales */ virtual void setInitialEvolutionScales(const ShowerParticleVector &particles, const bool isDecayCase, ShowerInteraction, const bool setPartners=true); //@} protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const {return new_ptr(*this);} /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const {return new_ptr(*this);} //@} public: /** @name Functions used by the persistent I/O system. */ //@{ /** * Function used to write out object persistently. * @param os the persistent output stream written to. */ void persistentOutput(PersistentOStream & os) const; /** * Function used to read in object persistently. * @param is the persistent input stream read from. * @param version the version number of the object when written. */ void persistentInput(PersistentIStream & is, int version); //@} /** * The standard Init function used to initialize the interfaces. * Called exactly once for each class by the class description system * before the main function starts or * when this class is dynamically loaded. */ static void Init(); protected: /** * Members to set the scales for different interactions */ //@{ /** * Set initial scales for a QCD interaction */ virtual void setInitialQCDEvolutionScales(const ShowerParticleVector &particles, const bool isDecayCase, const bool setPartners=true); /** * Set initial scales for a QED interaction */ virtual void setInitialQEDEvolutionScales(const ShowerParticleVector &particles, const bool isDecayCase, const bool setPartners=true); + + /** + * Set initial scales for a EW interaction + */ + virtual void setInitialEWEvolutionScales(const ShowerParticleVector &particles, + const bool isDecayCase, + const bool setPartners=true); //@} /** * Find the QCD partners * @param particle The particle to find the partners for * @param particles The full set of particles to search */ vector< pair > findQCDPartners(tShowerParticlePtr particle, const ShowerParticleVector &particles); /** * Find the QED partners * @param particle The particle to find the partners for * @param particles The full set of particles to search */ - vector< pair > + vector< pair > findQEDPartners(tShowerParticlePtr particle, const ShowerParticleVector &particles, const bool isDecayCase); public: /** + * Find the EW partners + * @param particle The particle to find the partners for + * @param particles The full set of particles to search + */ + vector< pair > + findEWPartners(tShowerParticlePtr particle, const ShowerParticleVector &particles, + const bool isDecayCase); + + /** * Given a pair of particles, supposedly partners w.r.t. an interaction, * this method returns their initial evolution scales as a pair. * If something wrong happens, it returns the null (ZERO,ZERO) pair. * This method is used by the above setXXXInitialEvolutionScales * methods. * These methods must be overiden in inheriting classes */ //@{ /** * General method to calculate the initial evolution scales */ pair calculateInitialEvolutionScales(const ShowerPPair &, - const bool isDecayCase); + const bool isDecayCase, int key=0); /** * Calculate the initial evolution scales given momenta */ pair calculateFinalFinalScales(const Lorentz5Momentum & p1, - const Lorentz5Momentum & p2); + const Lorentz5Momentum & p2, int key=0); /** * Calculate the initial evolution scales given momenta */ pair calculateInitialInitialScales(const Lorentz5Momentum& p1, const Lorentz5Momentum& p2); /** * Calculate the initial evolution scales given momenta */ pair calculateInitialFinalScales(const Lorentz5Momentum& pb, const Lorentz5Momentum& pc, const bool isDecayCase); //@} +protected: + + /** + * Find weakling interacting particles + */ + bool weaklyInteracting(tcPDPtr pd) { + long id = abs(pd->id()); + return ( id==ParticleID::Wplus || id ==ParticleID::Z0 || (id>=1 && id<=6 ) || (id>=11 && id<=16)); + } + private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ PartnerFinder & operator=(const PartnerFinder &) = delete; private: /** * Method for choosing colour partner */ int partnerMethod_; /** * Choice for the QED radiation partner */ int QEDPartner_; /** * Choice of the scale */ int scaleChoice_; }; } #endif /* HERWIG_PartnerFinder_H */ diff --git a/Shower/QTilde/Base/ShowerParticle.cc b/Shower/QTilde/Base/ShowerParticle.cc --- a/Shower/QTilde/Base/ShowerParticle.cc +++ b/Shower/QTilde/Base/ShowerParticle.cc @@ -1,583 +1,584 @@ // -*- C++ -*- // // ShowerParticle.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the ShowerParticle class. // #include "ShowerParticle.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include using namespace Herwig; PPtr ShowerParticle::clone() const { return new_ptr(*this); } PPtr ShowerParticle::fullclone() const { return new_ptr(*this); } ClassDescription ShowerParticle::initShowerParticle; // Definition of the static class description member. void ShowerParticle::vetoEmission(ShowerPartnerType, Energy scale) { scales_.QED = min(scale,scales_.QED ); scales_.QED_noAO = min(scale,scales_.QED_noAO ); scales_.QCD_c = min(scale,scales_.QCD_c ); scales_.QCD_c_noAO = min(scale,scales_.QCD_c_noAO ); scales_.QCD_ac = min(scale,scales_.QCD_ac ); scales_.QCD_ac_noAO = min(scale,scales_.QCD_ac_noAO); + scales_.EW = min(scale,scales_.EW ); if(spinInfo()) spinInfo()->undecay(); } void ShowerParticle::addPartner(EvolutionPartner in ) { partners_.push_back(in); } namespace { LorentzRotation boostToShower(Lorentz5Momentum & porig, tShowerBasisPtr basis) { LorentzRotation output; assert(basis); if(basis->frame()==ShowerBasis::BackToBack) { // we are doing the evolution in the back-to-back frame // work out the boostvector Boost boostv(-(basis->pVector()+basis->nVector()).boostVector()); // momentum of the parton Lorentz5Momentum ptest(basis->pVector()); // construct the Lorentz boost output = LorentzRotation(boostv); ptest *= output; Axis axis(ptest.vect().unit()); // now rotate so along the z axis as needed for the splitting functions if(axis.perp2()>1e-10) { double sinth(sqrt(1.-sqr(axis.z()))); output.rotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); } else if(axis.z()<0.) { output.rotate(Constants::pi,Axis(1.,0.,0.)); } porig = output*basis->pVector(); porig.setX(ZERO); porig.setY(ZERO); } else { output = LorentzRotation(-basis->pVector().boostVector()); porig = output*basis->pVector(); porig.setX(ZERO); porig.setY(ZERO); porig.setZ(ZERO); } return output; } RhoDMatrix bosonMapping(ShowerParticle & particle, const Lorentz5Momentum & porig, VectorSpinPtr vspin, const LorentzRotation & rot, Helicity::Direction dir) { // rotate the original basis vector sbasis; for(unsigned int ix=0;ix<3;++ix) { sbasis.push_back(vspin->getProductionBasisState(ix)); sbasis.back().transform(rot); } // splitting basis vector fbasis; bool massless(particle.id()==ParticleID::g||particle.id()==ParticleID::gamma); VectorWaveFunction wave(porig,particle.dataPtr(),dir==outgoing ? incoming : outgoing); for(unsigned int ix=0;ix<3;++ix) { if(massless&&ix==1) { fbasis.push_back(LorentzPolarizationVector()); } else { wave.reset(ix,vector_phase); fbasis.push_back(wave.wave()); } } // work out the mapping RhoDMatrix mapping=RhoDMatrix(PDT::Spin1,false); for(unsigned int ix=0;ix<3;++ix) { for(unsigned int iy=0;iy<3;++iy) { mapping(ix,iy)= -conj(sbasis[ix].dot(fbasis[iy])); if(particle.id()<0) mapping(ix,iy)=conj(mapping(ix,iy)); } } return mapping; } RhoDMatrix fermionMapping(ShowerParticle & particle, const Lorentz5Momentum & porig, FermionSpinPtr fspin, const LorentzRotation & rot) { // extract the original basis states vector > sbasis; for(unsigned int ix=0;ix<2;++ix) { sbasis.push_back(fspin->getProductionBasisState(ix)); sbasis.back().transform(rot); } // calculate the states in the splitting basis vector > fbasis; SpinorWaveFunction wave(porig,particle.dataPtr(), particle.id()>0 ? incoming : outgoing); for(unsigned int ix=0;ix<2;++ix) { wave.reset(ix); fbasis.push_back(wave.dimensionedWave()); } RhoDMatrix mapping=RhoDMatrix(PDT::Spin1Half,false); for(unsigned int ix=0;ix<2;++ix) { if(fbasis[0].s2()==complex()) { mapping(ix,0) = sbasis[ix].s3()/fbasis[0].s3(); mapping(ix,1) = sbasis[ix].s2()/fbasis[1].s2(); } else { mapping(ix,0) = sbasis[ix].s2()/fbasis[0].s2(); mapping(ix,1) = sbasis[ix].s3()/fbasis[1].s3(); } } return mapping; } FermionSpinPtr createFermionSpinInfo(ShowerParticle & particle, const Lorentz5Momentum & porig, const LorentzRotation & rot, Helicity::Direction dir) { // calculate the splitting basis for the branching // and rotate back to construct the basis states LorentzRotation rinv = rot.inverse(); SpinorWaveFunction wave; if(particle.id()>0) wave=SpinorWaveFunction(porig,particle.dataPtr(),incoming); else wave=SpinorWaveFunction(porig,particle.dataPtr(),outgoing); FermionSpinPtr fspin = new_ptr(FermionSpinInfo(particle.momentum(),dir==outgoing)); for(unsigned int ix=0;ix<2;++ix) { wave.reset(ix); LorentzSpinor basis = wave.dimensionedWave(); basis.transform(rinv); fspin->setBasisState(ix,basis); } particle.spinInfo(fspin); return fspin; } VectorSpinPtr createVectorSpinInfo(ShowerParticle & particle, const Lorentz5Momentum & porig, const LorentzRotation & rot, Helicity::Direction dir) { // calculate the splitting basis for the branching // and rotate back to construct the basis states LorentzRotation rinv = rot.inverse(); bool massless(particle.id()==ParticleID::g||particle.id()==ParticleID::gamma); VectorWaveFunction wave(porig,particle.dataPtr(),dir); VectorSpinPtr vspin = new_ptr(VectorSpinInfo(particle.momentum(),dir==outgoing)); for(unsigned int ix=0;ix<3;++ix) { LorentzPolarizationVector basis; if(massless&&ix==1) { basis = LorentzPolarizationVector(); } else { wave.reset(ix,vector_phase); basis = wave.wave(); } basis *= rinv; vspin->setBasisState(ix,basis); } particle.spinInfo(vspin); vspin-> DMatrix() = RhoDMatrix(PDT::Spin1); vspin->rhoMatrix() = RhoDMatrix(PDT::Spin1); if(massless) { vspin-> DMatrix()(0,0) = 0.5; vspin->rhoMatrix()(0,0) = 0.5; vspin-> DMatrix()(2,2) = 0.5; vspin->rhoMatrix()(2,2) = 0.5; } return vspin; } } RhoDMatrix ShowerParticle::extractRhoMatrix(bool forward) { // get the spin density matrix and the mapping RhoDMatrix mapping; SpinPtr inspin; bool needMapping = getMapping(inspin,mapping); // set the decayed flag inspin->decay(); // get the spin density matrix RhoDMatrix rho = forward ? inspin->rhoMatrix() : inspin->DMatrix(); // map to the shower basis if needed if(needMapping) { RhoDMatrix rhop(rho.iSpin(),false); for(int ixb=0;ixbperturbative()) { // mapping is the identity output=this->spinInfo(); mapping=RhoDMatrix(this->dataPtr()->iSpin()); if(output) { return false; } else { Lorentz5Momentum porig; LorentzRotation rot = boostToShower(porig,showerBasis()); Helicity::Direction dir = this->isFinalState() ? outgoing : incoming; if(this->dataPtr()->iSpin()==PDT::Spin0) { assert(false); } else if(this->dataPtr()->iSpin()==PDT::Spin1Half) { output = createFermionSpinInfo(*this,porig,rot,dir); } else if(this->dataPtr()->iSpin()==PDT::Spin1) { output = createVectorSpinInfo(*this,porig,rot,dir); } else { assert(false); } return false; } } // if particle is final-state and is from the hard process else if(this->isFinalState()) { assert(this->perturbative()==1 || this->perturbative()==2); // get transform to shower frame Lorentz5Momentum porig; LorentzRotation rot = boostToShower(porig,showerBasis()); // the rest depends on the spin of the particle PDT::Spin spin(this->dataPtr()->iSpin()); mapping=RhoDMatrix(spin,false); // do the spin dependent bit if(spin==PDT::Spin0) { ScalarSpinPtr sspin=dynamic_ptr_cast(this->spinInfo()); if(!sspin) { ScalarWaveFunction::constructSpinInfo(this,outgoing,true); } output=this->spinInfo(); return false; } else if(spin==PDT::Spin1Half) { FermionSpinPtr fspin=dynamic_ptr_cast(this->spinInfo()); // spin info exists get information from it if(fspin) { output=fspin; mapping = fermionMapping(*this,porig,fspin,rot); return true; } // spin info does not exist create it else { output = createFermionSpinInfo(*this,porig,rot,outgoing); return false; } } else if(spin==PDT::Spin1) { VectorSpinPtr vspin=dynamic_ptr_cast(this->spinInfo()); // spin info exists get information from it if(vspin) { output=vspin; mapping = bosonMapping(*this,porig,vspin,rot,outgoing); return true; } else { output = createVectorSpinInfo(*this,porig,rot,outgoing); return false; } } // not scalar/fermion/vector else assert(false); } // incoming to hard process else if(this->perturbative()==1 && !this->isFinalState()) { // get the basis vectors // get transform to shower frame Lorentz5Momentum porig; LorentzRotation rot = boostToShower(porig,showerBasis()); porig *= this->x(); // the rest depends on the spin of the particle PDT::Spin spin(this->dataPtr()->iSpin()); mapping=RhoDMatrix(spin); // do the spin dependent bit if(spin==PDT::Spin0) { cerr << "testing spin 0 not yet implemented " << endl; assert(false); } // spin-1/2 else if(spin==PDT::Spin1Half) { FermionSpinPtr fspin=dynamic_ptr_cast(this->spinInfo()); // spin info exists get information from it if(fspin) { output=fspin; mapping = fermionMapping(*this,porig,fspin,rot); return true; } // spin info does not exist create it else { output = createFermionSpinInfo(*this,porig,rot,incoming); return false; } } // spin-1 else if(spin==PDT::Spin1) { VectorSpinPtr vspin=dynamic_ptr_cast(this->spinInfo()); // spinInfo exists map it if(vspin) { output=vspin; mapping = bosonMapping(*this,porig,vspin,rot,incoming); return true; } // create the spininfo else { output = createVectorSpinInfo(*this,porig,rot,incoming); return false; } } assert(false); } // incoming to decay else if(this->perturbative() == 2 && !this->isFinalState()) { // get the basis vectors Lorentz5Momentum porig; - //LorentzRotation rot=boostToShower(porig,showerBasis()); + LorentzRotation rot=boostToShower(porig,showerBasis()); // the rest depends on the spin of the particle PDT::Spin spin(this->dataPtr()->iSpin()); mapping=RhoDMatrix(spin); // do the spin dependent bit if(spin==PDT::Spin0) { cerr << "testing spin 0 not yet implemented " << endl; assert(false); } // spin-1/2 else if(spin==PDT::Spin1Half) { // FermionSpinPtr fspin=dynamic_ptr_cast(this->spinInfo()); // // spin info exists get information from it // if(fspin) { // output=fspin; // mapping = fermionMapping(*this,porig,fspin,rot); // return true; // // spin info does not exist create it // else { // output = createFermionSpinInfo(*this,porig,rot,incoming); // return false; // } // } assert(false); } // // spin-1 // else if(spin==PDT::Spin1) { // VectorSpinPtr vspin=dynamic_ptr_cast(this->spinInfo()); // // spinInfo exists map it // if(vspin) { // output=vspin; // mapping = bosonMapping(*this,porig,vspin,rot); // return true; // } // // create the spininfo // else { // output = createVectorSpinInfo(*this,porig,rot,incoming); // return false; // } // } // assert(false); assert(false); } else assert(false); return true; } void ShowerParticle::constructSpinInfo(bool timeLike) { // now construct the required spininfo and calculate the basis states PDT::Spin spin(dataPtr()->iSpin()); if(spin==PDT::Spin0) { ScalarWaveFunction::constructSpinInfo(this,outgoing,timeLike); } // calculate the basis states and construct the SpinInfo for a spin-1/2 particle else if(spin==PDT::Spin1Half) { // outgoing particle if(id()>0) { vector > stemp; SpinorBarWaveFunction::calculateWaveFunctions(stemp,this,outgoing); SpinorBarWaveFunction::constructSpinInfo(stemp,this,outgoing,timeLike); } // outgoing antiparticle else { vector > stemp; SpinorWaveFunction::calculateWaveFunctions(stemp,this,outgoing); SpinorWaveFunction::constructSpinInfo(stemp,this,outgoing,timeLike); } } // calculate the basis states and construct the SpinInfo for a spin-1 particle else if(spin==PDT::Spin1) { bool massless(id()==ParticleID::g||id()==ParticleID::gamma); vector vtemp; VectorWaveFunction::calculateWaveFunctions(vtemp,this,outgoing,massless,vector_phase); VectorWaveFunction::constructSpinInfo(vtemp,this,outgoing,timeLike,massless); } else { throw Exception() << "Spins higher than 1 are not yet implemented in " << "FS_QtildaShowerKinematics1to2::constructVertex() " << Exception::runerror; } } void ShowerParticle::initializeDecay() { Lorentz5Momentum p, n, ppartner, pcm; assert(perturbative()!=1); // this is for the initial decaying particle if(perturbative()==2) { ShowerBasisPtr newBasis; p = momentum(); Lorentz5Momentum ppartner(partner()->momentum()); // removed to make inverse recon work properly //if(partner->thePEGBase()) ppartner=partner->thePEGBase()->momentum(); pcm=ppartner; Boost boost(p.findBoostToCM()); pcm.boost(boost); n = Lorentz5Momentum( ZERO,0.5*p.mass()*pcm.vect().unit()); n.boost( -boost); newBasis = new_ptr(ShowerBasis()); newBasis->setBasis(p,n,ShowerBasis::Rest); showerBasis(newBasis,false); } else { showerBasis(dynamic_ptr_cast(parents()[0])->showerBasis(),true); } } void ShowerParticle::initializeInitialState(PPtr parent) { // For the time being we are considering only 1->2 branching Lorentz5Momentum p, n, pthis, pcm; assert(perturbative()!=2); if(perturbative()==1) { ShowerBasisPtr newBasis; // find the partner and its momentum if(!partner()) return; if(partner()->isFinalState()) { Lorentz5Momentum pa = -momentum()+partner()->momentum(); Lorentz5Momentum pb = momentum(); Energy scale=parent->momentum().t(); Lorentz5Momentum pbasis(ZERO,parent->momentum().vect().unit()*scale); Axis axis(pa.vect().unit()); LorentzRotation rot; double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); 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.-pa.e()/pa.vect().mag())>1e-6) rot.boostZ( pa.e()/pa.vect().mag()); pb *= rot; if(pb.perp2()/GeV2>1e-20) { Boost trans = -1./pb.e()*pb.vect(); trans.setZ(0.); rot.boost(trans); } pbasis *=rot; rot.invert(); n = rot*Lorentz5Momentum(ZERO,-pbasis.vect()); p = rot*Lorentz5Momentum(ZERO, pbasis.vect()); } else { pcm = parent->momentum(); p = Lorentz5Momentum(ZERO, pcm.vect()); n = Lorentz5Momentum(ZERO, -pcm.vect()); } newBasis = new_ptr(ShowerBasis()); newBasis->setBasis(p,n,ShowerBasis::BackToBack); showerBasis(newBasis,false); } else { showerBasis(dynamic_ptr_cast(children()[0])->showerBasis(),true); } } void ShowerParticle::initializeFinalState() { // set the basis vectors Lorentz5Momentum p,n; if(perturbative()!=0) { ShowerBasisPtr newBasis; // find the partner() and its momentum if(!partner()) return; Lorentz5Momentum ppartner(partner()->momentum()); // momentum of the emitting particle p = momentum(); Lorentz5Momentum pcm; // if the partner is a final-state particle then the reference // vector is along the partner in the rest frame of the pair if(partner()->isFinalState()) { Boost boost=(p + ppartner).findBoostToCM(); pcm = ppartner; pcm.boost(boost); n = Lorentz5Momentum(ZERO,pcm.vect()); n.boost( -boost); } else if(!partner()->isFinalState()) { // if the partner is an initial-state particle then the reference // vector is along the partner which should be massless if(perturbative()==1) { n = Lorentz5Momentum(ZERO,ppartner.vect()); } // if the partner is an initial-state decaying particle then the reference // vector is along the backwards direction in rest frame of decaying particle else { Boost boost=ppartner.findBoostToCM(); pcm = p; pcm.boost(boost); n = Lorentz5Momentum( ZERO, -pcm.vect()); n.boost( -boost); } } newBasis = new_ptr(ShowerBasis()); newBasis->setBasis(p,n,ShowerBasis::BackToBack); showerBasis(newBasis,false); } else if(initiatesTLS()) { showerBasis(dynamic_ptr_cast(parents()[0]->children()[0])->showerBasis(),true); } else { showerBasis(dynamic_ptr_cast(parents()[0])->showerBasis(),true); } } void ShowerParticle::setShowerMomentum(bool timeLike) { Energy m = this->mass() > ZERO ? this->mass() : this->data().mass(); // calculate the momentum of the assuming on-shell Energy2 pt2 = sqr(this->showerParameters().pt); double alpha = timeLike ? this->showerParameters().alpha : this->x(); double beta = 0.5*(sqr(m) + pt2 - sqr(alpha)*showerBasis()->pVector().m2())/(alpha*showerBasis()->p_dot_n()); Lorentz5Momentum porig=showerBasis()->sudakov2Momentum(alpha,beta, this->showerParameters().ptx, this->showerParameters().pty); porig.setMass(m); this->set5Momentum(porig); } diff --git a/Shower/QTilde/Base/ShowerParticle.h b/Shower/QTilde/Base/ShowerParticle.h --- a/Shower/QTilde/Base/ShowerParticle.h +++ b/Shower/QTilde/Base/ShowerParticle.h @@ -1,523 +1,529 @@ // -*- C++ -*- // // ShowerParticle.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_ShowerParticle_H #define HERWIG_ShowerParticle_H // // This is the declaration of the ShowerParticle class. // #include "ThePEG/EventRecord/Particle.h" #include "Herwig/Shower/QTilde/SplittingFunctions/SplittingFunction.fh" #include "Herwig/Shower/QTilde/ShowerConfig.h" #include "Herwig/Shower/QTilde/Kinematics/ShowerBasis.h" #include "Herwig/Shower/QTilde/Kinematics/ShowerKinematics.h" #include "ShowerParticle.fh" #include namespace Herwig { using namespace ThePEG; /** \ingroup Shower * This class represents a particle in the showering process. * It inherits from the Particle class of ThePEG and has some * specifics information useful only during the showering process. * * Notice that: * - for forward evolution, it is clear what is meant by parent/child; * for backward evolution, however, it depends whether we want * to keep a physical picture or a Monte-Carlo effective one. * In the former case, an incoming particle (emitting particle) * splits into an emitted particle and the emitting particle after * the emission: the latter two are then children of the * emitting particle, the parent. In the Monte-Carlo effective * picture, we have that the particle close to the hard subprocess, * with higher (space-like) virtuality, splits into an emitted particle * and the emitting particle at lower virtuality: the latter two are, * in this case, the children of the first one, the parent. However we * choose a more physical picture where the new emitting particle is the * parented of the emitted final-state particle and the original emitting * particle. * - the pointer to a SplitFun object is set only in the case * that the particle has undergone a shower emission. This is similar to * the case of the decay of a normal Particle where * the pointer to a Decayer object is set only in the case * that the particle has undergone to a decay. * In the case of particle connected directly to the hard subprocess, * there is no pointer to the hard subprocess, but there is a method * isFromHardSubprocess() which returns true only in this case. * * @see Particle * @see ShowerConfig * @see ShowerKinematics */ class ShowerParticle: public Particle { public: /** * Struct for all the info on an evolution partner */ struct EvolutionPartner { /** * Constructor */ EvolutionPartner(tShowerParticlePtr p,double w, ShowerPartnerType t, Energy s) : partner(p), weight(w), type(t), scale(s) {} /** * The partner */ tShowerParticlePtr partner; /** * Weight */ double weight; /** * Type */ ShowerPartnerType type; /** * The assoicated evolution scale */ Energy scale; }; /** * Struct to store the evolution scales */ struct EvolutionScales { /** * Constructor */ EvolutionScales() : QED(),QCD_c(),QCD_ac(), QED_noAO(),QCD_c_noAO(),QCD_ac_noAO() {} /** * QED scale */ Energy QED; /** * QCD colour scale */ Energy QCD_c; /** * QCD anticolour scale */ Energy QCD_ac; /** * QED scale */ Energy QED_noAO; /** * QCD colour scale */ Energy QCD_c_noAO; /** * QCD anticolour scale */ Energy QCD_ac_noAO; + /** + * EW scales + */ + Energy EW; + }; /** @name Construction and descruction functions. */ //@{ /** * Standard Constructor. Note that the default constructor is * private - there is no particle without a pointer to a * ParticleData object. * @param x the ParticleData object * @param fs Whether or not the particle is an inital or final-state particle * @param tls Whether or not the particle initiates a time-like shower */ ShowerParticle(tcEventPDPtr x, bool fs, bool tls=false) : Particle(x), _isFinalState(fs), _perturbative(0), _initiatesTLS(tls), _x(1.0), _showerKinematics(), _vMass(ZERO), _thePEGBase() {} /** * Copy constructor from a ThePEG Particle * @param x ThePEG particle * @param pert Where the particle came from * @param fs Whether or not the particle is an inital or final-state particle * @param tls Whether or not the particle initiates a time-like shower */ ShowerParticle(const Particle & x, unsigned int pert, bool fs, bool tls=false) : Particle(x), _isFinalState(fs), _perturbative(pert), _initiatesTLS(tls), _x(1.0), _showerKinematics(), _vMass(ZERO), _thePEGBase(&x) {} //@} public: /** * Set a preliminary momentum for the particle */ void setShowerMomentum(bool timelike); /** * Construct the spin info object for a shower particle */ void constructSpinInfo(bool timelike); /** * Perform any initial calculations needed after the branching has been selected */ void initializeDecay(); /** * Perform any initial calculations needed after the branching has been selected * @param parent The beam particle */ void initializeInitialState(PPtr parent); /** * Perform any initial calculations needed after the branching has been selected */ void initializeFinalState(); /** * Access/Set various flags about the state of the particle */ //@{ /** * Access the flag that tells if the particle is final state * or initial state. */ bool isFinalState() const { return _isFinalState; } /** * Access the flag that tells if the particle is initiating a * time like shower when it has been emitted in an initial state shower. */ bool initiatesTLS() const { return _initiatesTLS; } /** * Access the flag which tells us where the particle came from * This is 0 for a particle produced in the shower, 1 if the particle came * from the hard sub-process and 2 is it came from a decay. */ unsigned int perturbative() const { return _perturbative; } //@} /** * Set/Get the momentum fraction for initial-state particles */ //@{ /** * For an initial state particle get the fraction of the beam momentum */ void x(double x) { _x = x; } /** * For an initial state particle set the fraction of the beam momentum */ double x() const { return _x; } //@} /** * Set/Get methods for the ShowerKinematics objects */ //@{ /** * Access/ the ShowerKinematics object. */ const ShoKinPtr & showerKinematics() const { return _showerKinematics; } /** * Set the ShowerKinematics object. */ void showerKinematics(const ShoKinPtr in) { _showerKinematics = in; } //@} /** * Set/Get methods for the ShowerBasis objects */ //@{ /** * Access/ the ShowerBasis object. */ const ShowerBasisPtr & showerBasis() const { return _showerBasis; } /** * Set the ShowerBasis object. */ void showerBasis(const ShowerBasisPtr in, bool copy) { if(!copy) _showerBasis = in; else { _showerBasis = new_ptr(ShowerBasis()); _showerBasis->setBasis(in->pVector(),in->nVector(),in->frame()); } } //@} - /** + /** * Members relating to the initial evolution scale and partner for the particle */ //@{ /** * Veto emission at a given scale */ void vetoEmission(ShowerPartnerType type, Energy scale); /** * Access to the evolution scales */ const EvolutionScales & scales() const {return scales_;} /** * Access to the evolution scales */ EvolutionScales & scales() {return scales_;} /** * Return the virtual mass\f$ */ Energy virtualMass() const { return _vMass; } /** * Set the virtual mass */ void virtualMass(Energy mass) { _vMass = mass; } /** * Return the partner */ tShowerParticlePtr partner() const { return _partner; } /** * Set the partner */ void partner(const tShowerParticlePtr partner) { _partner = partner; } /** * Get the possible partners */ vector & partners() { return partners_; } /** * Add a possible partners */ void addPartner(EvolutionPartner in ); /** * Clear the evolution partners */ void clearPartners() { partners_.clear(); } /** * Return the progenitor of the shower */ tShowerParticlePtr progenitor() const { return _progenitor; } /** * Set the progenitor of the shower */ void progenitor(const tShowerParticlePtr progenitor) { _progenitor = progenitor; } //@} /** * Members to store and provide access to variables for a specific * shower evolution scheme */ //@{ struct Parameters { Parameters() : alpha(1.), beta(), ptx(), pty(), pt() {} double alpha; double beta; Energy ptx; Energy pty; Energy pt; }; /** * Set the vector containing dimensionless variables */ Parameters & showerParameters() { return _parameters; } //@} /** * If this particle came from the hard process get a pointer to ThePEG particle * it came from */ const tcPPtr thePEGBase() const { return _thePEGBase; } public: /** * Extract the rho matrix including mapping needed in the shower */ RhoDMatrix extractRhoMatrix(bool forward); /** * For a particle which came from the hard process get the spin density and * the mapping required to the basis used in the Shower * @param rho The \f$\rho\f$ matrix * @param mapping The mapping * @param showerkin The ShowerKinematics object */ bool getMapping(SpinPtr &, RhoDMatrix & map); protected: /** * Standard clone function. */ virtual PPtr clone() const; /** * Standard clone function. */ virtual PPtr fullclone() const; private: /** * The static object used to initialize the description of this class. * Indicates that this is a concrete class with persistent data. */ static ClassDescription initShowerParticle; /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ ShowerParticle & operator=(const ShowerParticle &) = delete; private: /** * Whether the particle is in the final or initial state */ bool _isFinalState; /** * Whether the particle came from */ unsigned int _perturbative; /** * Does a particle produced in the backward shower initiate a time-like shower */ bool _initiatesTLS; /** * Dimensionless parameters */ Parameters _parameters; /** * The beam energy fraction for particle's in the initial state */ double _x; /** * The shower kinematics for the particle */ ShoKinPtr _showerKinematics; /** * The shower basis for the particle */ ShowerBasisPtr _showerBasis; /** * Storage of the evolution scales */ EvolutionScales scales_; /** * Virtual mass */ Energy _vMass; /** * Partners */ tShowerParticlePtr _partner; /** * Pointer to ThePEG Particle this ShowerParticle was created from */ const tcPPtr _thePEGBase; /** * Progenitor */ tShowerParticlePtr _progenitor; /** * Partners */ vector partners_; }; inline ostream & operator<<(ostream & os, const ShowerParticle::EvolutionScales & es) { os << "Scales: QED=" << es.QED / GeV << " QCD_c=" << es.QCD_c / GeV << " QCD_ac=" << es.QCD_ac / GeV + << " EW=" << es.EW / GeV << " QED_noAO=" << es.QED_noAO / GeV << " QCD_c_noAO=" << es.QCD_c_noAO / GeV << " QCD_ac_noAO=" << es.QCD_ac_noAO / GeV << '\n'; return os; } } #include "ThePEG/Utilities/ClassTraits.h" namespace ThePEG { /** @cond TRAITSPECIALIZATIONS */ /** This template specialization informs ThePEG about the * base classes of ShowerParticle. */ template <> struct BaseClassTrait { /** Typedef of the first base class of ShowerParticle. */ typedef Particle NthBase; }; /** This template specialization informs ThePEG about the name of * the ShowerParticle class and the shared object where it is defined. */ template <> struct ClassTraits : public ClassTraitsBase { /** Return a platform-independent class name */ static string className() { return "Herwig::ShowerParticle"; } /** Create a Event object. */ static TPtr create() { return TPtr::Create(Herwig::ShowerParticle(tcEventPDPtr(),true)); } }; /** @endcond */ } #endif /* HERWIG_ShowerParticle_H */ diff --git a/Shower/QTilde/Base/ShowerProgenitor.h b/Shower/QTilde/Base/ShowerProgenitor.h --- a/Shower/QTilde/Base/ShowerProgenitor.h +++ b/Shower/QTilde/Base/ShowerProgenitor.h @@ -1,263 +1,263 @@ // -*- C++ -*- // // ShowerProgenitor.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_ShowerProgenitor_H #define HERWIG_ShowerProgenitor_H // // This is the declaration of the ShowerProgenitor struct. // #include "ThePEG/Config/ThePEG.h" #include "Herwig/Shower/QTilde/ShowerConfig.h" #include "Herwig/Shower/QTilde/Base/ShowerParticle.h" #include "ShowerProgenitor.fh" #include "ThePEG/PDF/BeamParticleData.h" namespace Herwig { using namespace ThePEG; /** \ingroup Shower * A struct to store information on the perturbative particle which * initiates a shower */ class ShowerProgenitor : public Base { public: /** * Enum for the reconstruction state of this progentitor */ enum Reconstructed { notReconstructed=0, done, dontReconstruct}; /** * Typedef for the BeamParticleData objects */ typedef Ptr::transient_const_pointer tcBeamPtr; public: /** * Constructor for the class * @param original The original particle * @param copy The colour isolated copy * @param particle The ShowerPArticle copy * @param pT The \f$p_t\f$ of the hardest emission * @param emitted Whether or not the particle has radiated */ ShowerProgenitor(PPtr original,PPtr copy, ShowerParticlePtr particle, Energy pT=ZERO,bool emitted=false) : _original(original), _copy(copy), _perturbative(true), _particle(particle), _highestpT(pT), _maxHardPt(ZERO), _hardScale(ZERO), _hasEmitted(emitted), _reconstructed(notReconstructed) { // get the BeamParticleData object if ( original->parents().empty() ) { _beam=dynamic_ptr_cast(original->dataPtr()); } else { _beam=dynamic_ptr_cast(original->parents()[0]->dataPtr()); } } /** * Access to the particle */ ShowerParticlePtr progenitor() const { return _particle; } /** * Set the particle */ void progenitor(ShowerParticlePtr in) { _particle=in; } /** * Access to the original particle */ PPtr original() const { return _original; } /** * Access to the colour isolated copy */ PPtr copy() const { return _copy; } /** * Set the copy */ void copy(PPtr in) { _copy=in; } /** * Whether the particle came from the hard process or was added by * the matrix element correction */ bool perturbative() const { return _perturbative; } /** * Whether the particle came from the hard process or was added by * the matrix element correction */ void perturbative(bool in) { _perturbative=in; } /** * Set/Get methods for the hardest \f$p_T\f$ so far */ //@{ /** * Access the \f$p_T\f$ of the hardest emission so far */ Energy highestpT() const { return _highestpT; } /** * Set the \f$p_T\f$ of the hardest emission so far */ void highestpT(Energy in) { _highestpT=in; } //@} /** * Set/Get methods for the maximum \f$p_T\f$ */ //@{ /** * Access the maximum \f$p_T\f$ for radiation */ Energy maximumpT(ShowerInteraction type) const { - assert(type!=ShowerInteraction::Both); + assert(type!=ShowerInteraction::QEDQCD && type!=ShowerInteraction::ALL && type!=ShowerInteraction::UNDEFINED); map::const_iterator it = _maxpT.find(type); return it !=_maxpT.end() ? it->second : Constants::MaxEnergy; } /** * Set the maximum \f$p_T\f$ for radiation */ void maximumpT(Energy in,ShowerInteraction type) { _maxpT[type]=in; } //@} /** * Set/Get methods for whether the particle has radiated */ //@{ /** * Access the maximum hard \f$p_T\f$, given by the hard process */ Energy maxHardPt() const { return _maxHardPt; } /** * Set the maximum hard \f$p_T\f$, given by the hard process */ void maxHardPt(Energy in) { _maxHardPt = in; } /** * Access the relevant hard scale to be used in profile scales; usually * this is taken to be the maximum pt, except for other choices such as * hfact. */ Energy hardScale() const { return _hardScale; } /** * Set the relevant hard scale to be used in profile scales; usually * this is taken to be the maximum pt, except for other choices such as * hfact. */ void hardScale(Energy in) { _hardScale = in; } /** * Has this particle radiated */ bool hasEmitted() const { return _hasEmitted; } /** * Set whether or not this particle has radiated */ void hasEmitted(bool in) { _hasEmitted=in; } //@} /** * The id of the particle */ long id() const { return _particle->id(); } /** * The BeamParticleData object */ tcBeamPtr beam() { return _beam; } /** * Whether or not the recon has been performed */ Reconstructed reconstructed() const {return _reconstructed;} /** * Whether or not the recon has been performed */ void reconstructed(Reconstructed recon) {_reconstructed = recon;} private: /** * Pointer to the original particle */ PPtr _original; /** * Pointer to the colour isolated copy of the original particle */ PPtr _copy; /** * Whether the particle came from the hard process or was added by * the matrix element correction */ bool _perturbative; /** * Pointer to the ShowerParticle */ ShowerParticlePtr _particle; /** * Highest \f$p_T\f$ emitted in the shower from this particle */ Energy _highestpT; /** * Maximum allowed \f$p_T\f$ for emission from this particle */ map _maxpT; /** * maximum hard \f$p_T\f$ from the hard process */ Energy _maxHardPt; /** * The relevant hard scale to be used in profile scales; usually * this is taken to be the maximum pt, except for other choices such as * hfact. */ Energy _hardScale; /** * Has there been radiation */ bool _hasEmitted; /** * The BeamParticleData object */ tcBeamPtr _beam; /** * Whether or not the reconstruction has been performed */ Reconstructed _reconstructed; }; } #endif /* HERWIG_ShowerProgenitor_H */ diff --git a/Shower/QTilde/Kinematics/IS_QTildeShowerKinematics1to2.cc b/Shower/QTilde/Kinematics/IS_QTildeShowerKinematics1to2.cc --- a/Shower/QTilde/Kinematics/IS_QTildeShowerKinematics1to2.cc +++ b/Shower/QTilde/Kinematics/IS_QTildeShowerKinematics1to2.cc @@ -1,184 +1,184 @@ // -*- C++ -*- // // IS_QTildeShowerKinematics1to2.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the IS_QTildeShowerKinematics1to2 class. // #include "IS_QTildeShowerKinematics1to2.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "Herwig/Shower/QTilde/Base/ShowerParticle.h" #include "ThePEG/Utilities/Debug.h" #include "Herwig/Shower/QTilde/QTildeShowerHandler.h" #include "Herwig/Shower/QTilde/Base/PartnerFinder.h" #include "Herwig/Shower/QTilde/Kinematics/KinematicsReconstructor.h" #include "Herwig/Shower/QTilde/Base/ShowerVertex.h" #include using namespace Herwig; void IS_QTildeShowerKinematics1to2:: updateChildren( const tShowerParticlePtr theParent, const ShowerParticleVector & children, ShowerPartnerType) const { const ShowerParticle::Parameters & parent = theParent->showerParameters(); ShowerParticle::Parameters & child0 = children[0]->showerParameters(); ShowerParticle::Parameters & child1 = children[1]->showerParameters(); double cphi = cos(phi()); double sphi = sin(phi()); child1.alpha = (1.-z()) * parent.alpha; child1.ptx = (1.-z()) * parent.ptx - cphi * pT(); child1.pty = (1.-z()) * parent.pty - sphi * pT(); child1.pt = sqrt( sqr(child1.ptx) + sqr(child1.pty) ); // space-like child child0.alpha = parent.alpha - child1.alpha; child0.beta = parent.beta - child1.beta; child0.ptx = parent.ptx - child1.ptx; child0.pty = parent.pty - child1.pty; } void IS_QTildeShowerKinematics1to2:: updateParent(const tShowerParticlePtr parent, const ShowerParticleVector & children, unsigned int , ShowerPartnerType partnerType) const { // calculate the scales splittingFn()->evaluateInitialStateScales(partnerType,scale(),z(),parent, children[0],children[1]); // set proper colour connections splittingFn()->colourConnection(parent,children[0],children[1], partnerType,true); // set proper parent/child relationships parent->addChild(children[0]); parent->addChild(children[1]); parent->x(children[0]->x()/z()); // sort out the helicity stuff // construct the spin info for parent and timelike child // temporary assignment of shower parameters to calculate correlations parent->showerParameters().alpha = parent->x(); children[1]->showerParameters().alpha = (1.-z()) * parent->x(); children[1]->showerParameters().ptx = - cos(phi()) * pT(); children[1]->showerParameters().pty = - sin(phi()) * pT(); children[1]->showerParameters().pt = pT(); parent ->showerBasis(children[0]->showerBasis(),true); children[1]->showerBasis(children[0]->showerBasis(),true); parent ->setShowerMomentum(false); children[1]->setShowerMomentum(true); if(! dynamic_ptr_cast(ShowerHandler::currentHandler())->correlations()) return; SpinPtr pspin(children[0]->spinInfo()); if(!pspin || !dynamic_ptr_cast(ShowerHandler::currentHandler())->spinCorrelations() ) return; // compute the matrix element for spin correlations IdList ids; ids.push_back(parent->dataPtr()); ids.push_back(children[0]->dataPtr()); ids.push_back(children[1]->dataPtr()); Energy2 t = (1.-z())*sqr(scale())/z(); // create the vertex SVertexPtr vertex(new_ptr(ShowerVertex())); // set the matrix element vertex->ME(splittingFn()->matrixElement(z(),t,ids,phi(),false)); // set the incoming particle for the vertex // (in reality the first child as going backwards) pspin->decayVertex(vertex); // construct the spin infos parent ->constructSpinInfo(false); children[1]->constructSpinInfo(true); // connect the spinInfo objects to the vertex parent ->spinInfo()->productionVertex(vertex); children[1]->spinInfo()->productionVertex(vertex); } void IS_QTildeShowerKinematics1to2:: reconstructParent(const tShowerParticlePtr parent, const ParticleVector & children ) const { PPtr c1 = children[0]; ShowerParticlePtr c2 = dynamic_ptr_cast(children[1]); ShowerParticle::Parameters & c2param = c2->showerParameters(); // get shower variables from 1st child in order to keep notation // parent->(c1, c2) clean even though the splitting was initiated // from c1. The name updateParent is still referring to the // timelike branching though. // on-shell child auto m= ShowerHandler::currentHandler()->retConstituentMasses()? c2->data().constituentMass(): c2->data().mass(); c2param.beta = 0.5*( sqr(m) + sqr(c2param.pt) ) / ( c2param.alpha * parent->showerBasis()->p_dot_n() ); Lorentz5Momentum pnew = parent->showerBasis()-> sudakov2Momentum(c2param.alpha, c2param.beta, c2param.ptx , c2param.pty); pnew.setMass(m); pnew.rescaleEnergy(); // fix the spin info AHHHH if(c2->spinInfo()&&abs(c2->id())==ParticleID::tauminus) { // rotate old momentum along z Axis axis(c2->momentum().vect().unit()); double sinth(sqrt(1.-sqr(axis.z()))); LorentzRotation r1; if(axis.perp2()>1e-10) { r1.rotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); } Lorentz5Momentum p1 = r1*c2->momentum(); // rotate new momentum along z axis = pnew.vect().unit(); sinth = sqrt(1.-sqr(axis.z())); LorentzRotation r2; if(axis.perp2()>1e-10) { r2.rotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); } Lorentz5Momentum p2 = r2*pnew; // compute boost along z old -> new // full result double a = p2.t()/p2.z(); double b1 = (p1.t()-a*p1.z())/(p1.z()-a*p1.t()); // small mass expansion Energy2 o2 = sqr(p1.z()), n2=sqr(p2.z()); double b2 = (o2-n2)/(o2+n2)*(1. - sqr(p1.mass())/(n2+o2) +pow<4,1>(p1.mass())*(0.125/(n2*o2)+1./sqr(n2+o2))); // compute the total boost LorentzRotation r3; r3.boostZ(b1); LorentzRotation r4; r4.boostZ(b2); Energy t1 = p2.t(), t2 = (r3*p1).t(), t3 = (r4*p1).t(); LorentzRotation r = abs(t1-t2)transform(r); } else c2->set5Momentum( pnew ); // spacelike child Lorentz5Momentum pc1(parent->momentum() - c2->momentum()); pc1.rescaleMass(); c1->set5Momentum(pc1); } void IS_QTildeShowerKinematics1to2:: updateLast( const tShowerParticlePtr theLast,Energy px,Energy py) const { - if(theLast->isFinalState()) return; + if(theLast->isFinalState()) return; + Lorentz5Momentum pVector = theLast->showerBasis()->pVector(); ShowerParticle::Parameters & last = theLast->showerParameters(); - Lorentz5Momentum pVector = theLast->showerBasis()->pVector(); Energy2 pt2 = sqr(px) + sqr(py); last.alpha = theLast->x(); last.beta = 0.5 * pt2 / last.alpha / theLast->showerBasis()->p_dot_n(); last.ptx = ZERO; last.pty = ZERO; last.pt = ZERO; // momentum Lorentz5Momentum ntemp = Lorentz5Momentum(ZERO,-pVector.vect()); double beta = 0.5 * pt2 / last.alpha / ( pVector * ntemp); Lorentz5Momentum plast = Lorentz5Momentum( (pVector.z()>ZERO ? px : -px), py, ZERO, ZERO) + theLast->x() * pVector + beta * ntemp; plast.rescaleMass(); theLast->set5Momentum(plast); } diff --git a/Shower/QTilde/Makefile.am b/Shower/QTilde/Makefile.am --- a/Shower/QTilde/Makefile.am +++ b/Shower/QTilde/Makefile.am @@ -1,46 +1,51 @@ SUBDIRS = Matching pkglib_LTLIBRARIES = HwShower.la HwShower_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 29:0:0 HwShower_la_SOURCES = \ Couplings/ShowerAlphaQCD.h Couplings/ShowerAlphaQCD.cc \ Couplings/ShowerAlphaQED.h Couplings/ShowerAlphaQED.cc\ QTildeShowerHandler.h QTildeShowerHandler.fh QTildeShowerHandler.cc \ SplittingFunctions/HalfHalfOneSplitFn.h SplittingFunctions/HalfHalfOneSplitFn.cc\ +SplittingFunctions/HalfHalfOneEWSplitFn.h SplittingFunctions/HalfHalfOneEWSplitFn.cc\ +SplittingFunctions/HalfHalfZeroEWSplitFn.h SplittingFunctions/HalfHalfZeroEWSplitFn.cc\ +SplittingFunctions/OneOneOneEWSplitFn.h SplittingFunctions/OneOneOneEWSplitFn.cc\ +SplittingFunctions/OneOneOneQEDSplitFn.h SplittingFunctions/OneOneOneQEDSplitFn.cc\ +SplittingFunctions/OneOneZeroEWSplitFn.h SplittingFunctions/OneOneZeroEWSplitFn.cc\ SplittingFunctions/OneOneOneSplitFn.h SplittingFunctions/OneOneOneSplitFn.cc\ SplittingFunctions/OneOneOneMassiveSplitFn.h SplittingFunctions/OneOneOneMassiveSplitFn.cc\ SplittingFunctions/ZeroZeroOneSplitFn.h SplittingFunctions/ZeroZeroOneSplitFn.cc\ SplittingFunctions/OneHalfHalfSplitFn.h SplittingFunctions/OneHalfHalfSplitFn.cc\ SplittingFunctions/HalfOneHalfSplitFn.h SplittingFunctions/HalfOneHalfSplitFn.cc\ SplittingFunctions/CMWOneOneOneSplitFn.h SplittingFunctions/CMWOneOneOneSplitFn.cc\ SplittingFunctions/CMWHalfHalfOneSplitFn.h SplittingFunctions/CMWHalfHalfOneSplitFn.cc\ Kinematics/Decay_QTildeShowerKinematics1to2.cc \ Kinematics/Decay_QTildeShowerKinematics1to2.h \ Kinematics/IS_QTildeShowerKinematics1to2.cc Kinematics/IS_QTildeShowerKinematics1to2.h \ Kinematics/FS_QTildeShowerKinematics1to2.cc Kinematics/FS_QTildeShowerKinematics1to2.h \ Kinematics/KinematicHelpers.h \ Kinematics/KinematicsReconstructor.cc \ Kinematics/KinematicsReconstructor.tcc \ Kinematics/KinematicsReconstructor.h \ Kinematics/KinematicsReconstructor.fh \ Base/HardTree.cc Base/HardTree.h Base/HardTree.fh \ Base/HardBranching.h Base/HardBranching.fh Base/HardBranching.cc\ Base/PartnerFinder.h Base/PartnerFinder.fh Base/PartnerFinder.cc \ Base/ShowerVeto.h Base/ShowerVeto.fh Base/ShowerVeto.cc \ Base/FullShowerVeto.h Base/FullShowerVeto.fh Base/FullShowerVeto.cc \ SplittingFunctions/SplittingGenerator.cc SplittingFunctions/SplittingGenerator.h\ SplittingFunctions/SplittingGenerator.fh \ Base/ShowerTree.h Base/ShowerTree.fh Base/ShowerTree.cc \ ShowerConfig.h ShowerConfig.cc \ Base/Branching.h \ Base/ShowerParticle.cc Base/ShowerParticle.fh Base/ShowerParticle.h \ Kinematics/ShowerKinematics.fh Kinematics/ShowerKinematics.h Kinematics/ShowerKinematics.cc \ Kinematics/ShowerBasis.fh Kinematics/ShowerBasis.h Kinematics/ShowerBasis.cc \ Base/ShowerProgenitor.fh Base/ShowerProgenitor.h \ SplittingFunctions/SudakovFormFactor.cc SplittingFunctions/SudakovFormFactor.h SplittingFunctions/SudakovFormFactor.fh \ SplittingFunctions/SudakovCutOff.cc SplittingFunctions/SudakovCutOff.h SplittingFunctions/SudakovCutOff.fh \ SplittingFunctions/PTCutOff.cc SplittingFunctions/PTCutOff.h \ SplittingFunctions/MassCutOff.cc SplittingFunctions/MassCutOff.h \ SplittingFunctions/VariableMassCutOff.cc SplittingFunctions/VariableMassCutOff.h \ SplittingFunctions/SplittingFunction.h SplittingFunctions/SplittingFunction.fh \ SplittingFunctions/SplittingFunction.cc \ Base/ShowerVertex.cc Base/ShowerVertex.fh Base/ShowerVertex.h diff --git a/Shower/QTilde/Matching/PowhegShowerHandler.cc b/Shower/QTilde/Matching/PowhegShowerHandler.cc --- a/Shower/QTilde/Matching/PowhegShowerHandler.cc +++ b/Shower/QTilde/Matching/PowhegShowerHandler.cc @@ -1,1103 +1,1104 @@ // -*- C++ -*- // // PowhegShowerHandler.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the PowhegShowerHandler class. // #include #include "PowhegShowerHandler.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/RefVector.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Utilities/DescribeClass.h" // include theses to have complete types #include "Herwig/Shower/QTilde/Base/ShowerParticle.h" #include "Herwig/PDF/MPIPDF.h" #include "Herwig/PDF/MinBiasPDF.h" #include "Herwig/Shower/QTilde/Base/ShowerTree.h" #include "Herwig/Shower/QTilde/Kinematics/KinematicsReconstructor.h" #include "Herwig/Shower/QTilde/Base/PartnerFinder.h" #include "Herwig/PDF/HwRemDecayer.h" #include "Herwig/Shower/QTilde/Base/ShowerProgenitor.h" #include "Herwig/Shower/QTilde/Base/HardBranching.h" #include "Herwig/Shower/QTilde/Base/HardTree.h" #include "Herwig/MatrixElement/HwMEBase.h" #include "ThePEG/MatrixElement/MEBase.h" #include "ThePEG/MatrixElement/DiagramBase.fh" #include "ThePEG/PDF/PartonExtractor.h" #include "Herwig/MatrixElement/Matchbox/MatchboxFactory.h" #include "Herwig/MatrixElement/Matchbox/Utility/DiagramDrawer.h" using namespace Herwig; namespace { struct ParticleOrdering { bool operator()(tcPDPtr p1, tcPDPtr p2) { return abs(p1->id()) > abs(p2->id()) || ( abs(p1->id()) == abs(p2->id()) && p1->id() > p2->id() ) || ( p1->id() == p2->id() && p1->fullName() > p2->fullName() ); } }; } IBPtr PowhegShowerHandler::clone() const { return new_ptr(*this); } IBPtr PowhegShowerHandler::fullclone() const { return new_ptr(*this); } HardTreePtr PowhegShowerHandler::generateCKKW(ShowerTreePtr showerTree) const { // hard subprocess tSubProPtr sub = lastXCombPtr()->subProcess(); // real emission sub-process tSubProPtr real = Factory()->hardTreeSubprocess(); // born emitter emitter_ = Factory()->hardTreeEmitter(); spectator_ = Factory()->hardTreeSpectator(); // if no hard emission return if ( !(real && emitter_>-1) ) return HardTreePtr(); // check emission if(sub->outgoing().size()>=real->outgoing().size()) return HardTreePtr(); // check if decay has radiated don't add it if(showerTree->outgoingLines().size() != sub->outgoing().size()) { // loop over the decay trees for(map >::const_iterator tit=showerTree->treelinks().begin(); tit != showerTree->treelinks().end(); ++tit) { if(tit->first->outgoingLines().empty()) continue; // match the particles set decayProducts; set outgoing(real->outgoing().begin(),real->outgoing().end()); for(map::const_iterator oit=tit->first->outgoingLines().begin(); oit!=tit->first->outgoingLines().end();++oit) { tPPtr decayProd; Energy2 dmin( 1e30*GeV2 ); tPPtr part = oit->second->original(); for( set::const_iterator it = outgoing.begin(); it != outgoing.end(); ++it ) { if((**it).id()!=part->id()) continue; Energy2 dtest = sqr( part->momentum().x() - (**it).momentum().x() ) + sqr( part->momentum().y() - (**it).momentum().y() ) + sqr( part->momentum().z() - (**it).momentum().z() ) + sqr( part->momentum().t() - (**it).momentum().t() ); dtest += 1e10*sqr(part->momentum().m()-(**it).momentum().m()); if( dtest < dmin ) { decayProd = *it; dmin = dtest; } } if(!decayProd) { throw Exception() << "PowhegShowerHandler::generateCKKW(). Can't match shower and hard trees." << Exception::eventerror; } outgoing .erase (decayProd); decayProducts.insert(decayProd); } bool coloured = false, foundParent = true; tPPtr parent,emitted; unsigned int nprod(0); for( set::const_iterator it = decayProducts.begin(); it != decayProducts.end(); ++it ) { coloured |= (**it).dataPtr()->coloured(); tPPtr newParent = !(**it).parents().empty() ? (**it).parents()[0] : tPPtr(); ++nprod; // check if from emission if(newParent->id()==(**it).id()) { if(newParent->children().size()!=2) foundParent=false; bool foundChild(false), foundGluon(false); for(unsigned int ix=0;ixchildren().size();++ix) { if(newParent->children()[ix]==*it) { foundChild = true; continue; } else if(newParent->children()[ix]->id()==ParticleID::g) { foundGluon = true; continue; } } if(foundChild && foundGluon) { newParent = !newParent->parents().empty() ? newParent->parents()[0] : tPPtr(); ++nprod; } else foundParent = false; } if(!newParent) { foundParent = false; } else if(!parent) { parent = newParent; } else { if(parent!=newParent) foundParent = false; } } if(nprod!=tit->first->outgoingLines().size()&&foundParent) { if(decayRadiation_==0) { throw Exception() << "The radiation generated in this event\n " << *real << "\n has been interepted as occuring in the " << "decay \nof a colour-singlet object and cannot be handled " << "you can either not simulated this process, " << "veto this class of events by using\n" << "set " << fullName() << ":DecayRadiation VetoEvent\n" << "or throw the hard radiation away using \n" << "set " << fullName() << ":DecayRadiation VetoRadiation\n" << "Please contact us at herwig@hepforge.org for advice\n" << "on how to simulate this process\n" << Exception::runerror; } else if(decayRadiation_==1) { throw Exception() << "The radiation generated in this event\n " << *real << "\n has been interepted as occuring in the " << "decay \nof a colour-singlet object and cannot be handled " << "vetoing event\n" << Exception::eventerror; } else if(decayRadiation_==2) { generator()->log() << "The radiation generated in this event\n " << *real << "\n has been interepted as occuring in the " << "decay \nof a colour-singlet object and cannot be handled " << "vetoing radiation\n"; return HardTreePtr(); } else assert(false); } } } tStdXCombPtr lastXC = dynamic_ptr_cast(lastXCombPtr()); tStdXCombPtr headXC = lastXC->head(); if (headXC) matrixElement_ = dynamic_ptr_cast(headXC->matrixElement()); else if (lastXC) matrixElement_ = dynamic_ptr_cast(lastXC->matrixElement()); if (lastXC){ tStdXCombPtr projector= lastXC->lastProjector(); if (projector){ matrixElement_ = dynamic_ptr_cast(projector->matrixElement()); setSubtractionIntegral(true); } else setSubtractionIntegral(false); } assert(matrixElement_); // create a hard tree by clustering the event try { hardTree(doClustering(real,showerTree)); } catch(exception &e) { throw Exception() << "Caught a problem in PowhegShowerHandler::doClustering " << e.what() << Exception::eventerror; } // Get the HardTree from the CKKW handler. CKKWTreePtr hardtree = hardTree().tree(); // zero to avoid MPI problems Factory()->setHardTreeEmitter(-1); Factory()->setHardTreeSubprocess(SubProPtr()); return hardtree; } PotentialTree PowhegShowerHandler::doClustering(tSubProPtr real,ShowerTreePtr showerTree) const { // clear storage of the protoTrees protoBranchings().clear(); protoTrees().clear(); hardTrees_.clear(); assert( matrixElement() ); // extract the XComb for the Born process tStdXCombPtr lastXC; if (subtractionIntegral()){ tStdXCombPtr lastXCReal = dynamic_ptr_cast(lastXCombPtr()); lastXC = lastXCReal->lastProjector(); } else lastXC = dynamic_ptr_cast(lastXCombPtr()); const StandardXComb xc= *lastXC; // get the particles for the born process PPair incomingBorn = xc.subProcess()->incoming(); ParticleVector outgoingBorn = xc.subProcess()->outgoing(); // get particles from the XComb object for the real process ParticleVector outgoing = real->outgoing(); PPair incoming = real->incoming(); // loop through the FS particles and create ProtoBranchings for( unsigned int i = 0; i < outgoing.size(); ++i) { tPPtr parent = outgoing[i]->parents()[0]; ProtoBranchingPtr currentBranching = new_ptr(ProtoBranching(outgoing[i]->dataPtr(),HardBranching::Outgoing, outgoing[i]->momentum(),tSudakovPtr())); currentBranching-> colourLine(outgoing[i]-> colourLine()); currentBranching->antiColourLine(outgoing[i]->antiColourLine()); protoBranchings().insert(currentBranching); } // add IS hardBranchings ProtoBranchingPtr currentBranching = new_ptr(ProtoBranching(incoming.first ->dataPtr(),HardBranching::Incoming, incoming.first ->momentum(),tSudakovPtr())); currentBranching-> colourLine(incoming.first-> colourLine()); currentBranching->antiColourLine(incoming.first->antiColourLine()); protoBranchings().insert(currentBranching); currentBranching = new_ptr(ProtoBranching(incoming.second->dataPtr(),HardBranching::Incoming, incoming.second->momentum(),tSudakovPtr())); currentBranching-> colourLine(incoming.second-> colourLine()); currentBranching->antiColourLine(incoming.second->antiColourLine()); protoBranchings().insert(currentBranching); // create and initialise the first tree ProtoTreePtr initialProtoTree = new_ptr( ProtoTree() ); for(set::const_iterator it=protoBranchings().begin(); it!=protoBranchings().end();++it) { initialProtoTree->addBranching(*it); } // fill _proto_trees with all possible trees protoTrees().insert(initialProtoTree ); fillProtoTrees( initialProtoTree , xc.mePartonData()[emitter_]->id() ); // create a HardTree from each ProtoTree and fill hardTrees() for( set< ProtoTreePtr >::const_iterator cit = protoTrees().begin(); cit != protoTrees().end(); ++cit ) { set bornParticles(outgoingBorn.begin(),outgoingBorn.end()); bornParticles.insert(incomingBorn.first ); bornParticles.insert(incomingBorn.second); PotentialTree newTree; newTree.tree((**cit).createHardTree()); // new check based on the colour structure map cmap; // make the colour connections in the tree ShowerParticleVector branchingParticles; map branchingMap; bool matched(true); int iemitter(-1); HardBranchingPtr emitter; map locMap; for( set< HardBranchingPtr >::iterator it = newTree.tree()->branchings().begin(); it != newTree.tree()->branchings().end(); ++it ) { matched = true; // map the particle to the branching for future use branchingParticles.push_back((**it).branchingParticle()); branchingMap.insert(make_pair((**it).branchingParticle(),*it)); tPPtr bornPartner; if((**it).status()==HardBranching::Incoming) { HardBranchingPtr parent=*it; while(parent->parent()) { parent = parent->parent(); }; if(parent->branchingParticle()->momentum().z()/incomingBorn.first->momentum().z()>0.) { bornPartner = incomingBorn.first; if(!parent->children().empty()) { iemitter = 0; emitter = *it; } locMap[0] = *it; } else { bornPartner = incomingBorn.second; if(!parent->children().empty()) { iemitter = 1; emitter = *it; } locMap[1] = *it; } } else { Energy2 dmin( 1e30*GeV2 ); for(set::const_iterator bit=bornParticles.begin();bit!=bornParticles.end(); ++bit) { if((**it).branchingParticle()->id()!=(**bit).id()) continue; if(*bit==incomingBorn.first||*bit==incomingBorn.second) continue; Energy2 dtest = sqr( (**bit).momentum().x() - (**it).branchingParticle()->momentum().x() ) + sqr( (**bit).momentum().y() - (**it).branchingParticle()->momentum().y() ) + sqr( (**bit).momentum().z() - (**it).branchingParticle()->momentum().z() ) + sqr( (**bit).momentum().t() - (**it).branchingParticle()->momentum().t() ); dtest += 1e10*sqr((**bit).momentum().m()-(**it).branchingParticle()->momentum().m()); if( dtest < dmin ) { bornPartner = *bit; dmin = dtest; } } // find the map int iloc(-1); for(unsigned int ix=0;ixcolourLine()) { if(cmap.find((**it).branchingParticle()->colourLine())!=cmap.end()) { if(cmap[(**it).branchingParticle()->colourLine()]!=bornPartner->colourLine()) { matched=false; } } else { cmap[(**it).branchingParticle()->colourLine()] = bornPartner->colourLine(); } } if((**it).branchingParticle()->antiColourLine()) { if(cmap.find((**it).branchingParticle()->antiColourLine())!=cmap.end()) { if(cmap[(**it).branchingParticle()->antiColourLine()]!=bornPartner->antiColourLine()) { matched=false; } } else { cmap[(**it).branchingParticle()->antiColourLine()] = bornPartner->antiColourLine(); } } // require a match if(!matched) break; } // if no match continue if(!matched) continue; // now sort out any decays if(showerTree->outgoingLines().size()+showerTree->incomingLines().size() != newTree.tree()->branchings().size()) { if(showerTree->treelinks().empty()) { matched = false; continue; } // loop over the decay trees for(map >::const_iterator tit=showerTree->treelinks().begin(); tit != showerTree->treelinks().end(); ++tit) { if(tit->first->outgoingLines().empty()) continue; set decayProducts; set branchings = newTree.tree()->branchings(); // match the particles for(map::const_iterator oit=tit->first->outgoingLines().begin(); oit!=tit->first->outgoingLines().end();++oit) { HardBranchingPtr decayProd; Energy2 dmin( 1e30*GeV2 ); tPPtr part = oit->second->original(); for( set< HardBranchingPtr >::iterator it = branchings.begin(); it != branchings.end(); ++it ) { if((**it).status()==HardBranching::Incoming ) continue; if((**it).branchingParticle()->id()!=part->id()) continue; Energy2 dtest = sqr( part->momentum().x() - (**it).branchingParticle()->momentum().x() ) + sqr( part->momentum().y() - (**it).branchingParticle()->momentum().y() ) + sqr( part->momentum().z() - (**it).branchingParticle()->momentum().z() ) + sqr( part->momentum().t() - (**it).branchingParticle()->momentum().t() ); dtest += 1e10*sqr(part->momentum().m()-(**it).branchingParticle()->momentum().m()); if( dtest < dmin ) { decayProd = *it; dmin = dtest; } } if(!decayProd) { throw Exception() << "PowhegShowerHandler::generateCKKW(). Can't match shower and hard trees." << Exception::eventerror; } branchings .erase (decayProd); decayProducts.insert(decayProd); } // erase the decay products Lorentz5Momentum pnew,pshower; for(set::iterator it = decayProducts.begin(); it!=decayProducts.end(); ++it) { newTree.tree()->branchings().erase(*it); pnew += (**it).branchingParticle()->momentum(); pshower += (**it).showerMomentum(); } pnew .setMass(tit->second.second->mass()); pshower.setMass(tit->second.second->mass()); pnew .rescaleEnergy(); pshower.rescaleEnergy(); // create the decaying particle ShowerParticlePtr particle = new_ptr( ShowerParticle( tit->second.second->dataPtr() , true ) ); particle->set5Momentum( pnew ); HardBranchingPtr newBranch = new_ptr( HardBranching( particle, tSudakovPtr(), HardBranchingPtr(), HardBranching::Outgoing ) ); newBranch->showerMomentum(pshower); newTree.tree()->branchings().insert(newBranch); } } // if no match continue if(!matched) continue; // find the colour partners try { partnerFinder() ->setInitialEvolutionScales(branchingParticles,false, ShowerInteraction::QCD,true); } catch( Exception & e ) { generator()->log() << "Problem in set evolution scales in " << "PowhegShowerHandler::doClustering(). Exception was" << e.what(); continue; } for(unsigned int ix=0;ixpartner()) { HardBranchingPtr partner = branchingMap[branchingParticles[ix]->partner()]; branchingMap[branchingParticles[ix]]->colourPartner(partner); } } if(forcePartners_) { locMap[emitter_ ]->colourPartner(locMap[spectator_]); locMap[spectator_]->colourPartner(locMap[emitter_ ]); locMap[emitter_ ]->branchingParticle()->partner(locMap[spectator_]->branchingParticle()); locMap[spectator_]->branchingParticle()->partner(locMap[emitter_ ]->branchingParticle()); } newTree.tree()->partnersSet(true); // set the beam particles PPair beams = lastXCombPtr()->lastParticles(); // remove children of beams PVector beam_children = beams.first->children(); if( (**newTree.tree()->incoming().begin()).branchingParticle()->momentum().z() / beams.first->momentum().z() < 0.) swap( beams.first, beams.second ); set::iterator it = newTree.tree()->incoming().begin(); HardBranchingPtr br = *it; br->beam( beams.first ); while ( !br->children().empty() ) { for(unsigned int ix = 0; ix < br->children().size(); ++ix ) { if( br->children()[ix]->status() == HardBranching::Incoming ) { br = br->children()[ix]; break; } } br->beam( beams.first ); } ++it; br = *it; br->beam( beams.second ); while ( !br->children().empty() ) { for( unsigned int ix = 0; ix < br->children().size(); ++ix ) { if( br->children()[ix]->status() == HardBranching::Incoming ) { br = br->children()[ix]; break; } } br->beam( beams.second ); } // check the emitter and the spectator some how if(iemitter!=emitter_) continue; //do inverse momentum reconstruction if( !kinematicsReconstructor() ->deconstructHardJets( newTree.tree(), ShowerInteraction::QCD ) ) continue; newTree.tree()->findNodes(); newTree.weight(1.); hardTrees_.push_back( make_pair( newTree, 1. ) ); } // select the tree PotentialTree chosen_hardTree; if (hardTrees_.size()==1) { chosen_hardTree = hardTrees_[0].first; } else { // if multiple trees pick the one with matching // intermediate particle momenta for (unsigned int il=0; il > particles; PotentialTree testTree = hardTrees_[il].first; CKKWTreePtr check = testTree.tree(); // get id and momenta of particles in hard tree for (set< HardBranchingPtr >::iterator it=check->branchings().begin(); it!=check->branchings().end(); ++it) { particles.push_back(make_pair((*it)->branchingParticle()->id(), (*it)->branchingParticle()->momentum())); if (!(*it)->children().empty()){ for (unsigned int ic=0; ic<(*it)->children().size(); ++ic) particles.push_back(make_pair((*it)->children()[ic]->branchingParticle()->id(), (*it)->children()[ic]->branchingParticle()->momentum())); } if ((*it)->parent()){ particles.push_back(make_pair((*it)->parent()->branchingParticle()->id(), (*it)->parent()->branchingParticle()->momentum())); if (!(*it)->parent()->children().empty()) { for (unsigned int ic=0; ic<(*it)->parent()->children().size(); ++ic) { if(*it==(*it)->parent()->children()[ic]) continue; particles.push_back(make_pair((*it)->parent()->children()[ic]->branchingParticle()->id(), (*it)->parent()->children()[ic]->branchingParticle()->momentum())); } } } } // loop through and match to particles in real subprocess vector >::iterator part = particles.begin(); // incoming for (; part!=particles.end(); ++part){ if ((*part).first==real->incoming().first->id() && fuzzyEqual((*part).second, real->incoming().first->momentum())) break; } if (part!=particles.end()) particles.erase(part); part = particles.begin(); for (; part!=particles.end(); ++part){ if ((*part).first==real->incoming().second->id() && fuzzyEqual((*part).second, real->incoming().second->momentum())) break; } if (part!=particles.end()) particles.erase(part); // outgoing for (unsigned int io=0; iooutgoing().size(); ++io){ part = particles.begin(); for (; part!=particles.end(); ++part){ if ((*part).first==real->outgoing()[io]->id() && fuzzyEqual((*part).second, real->outgoing()[io]->momentum())) break; } if (part!=particles.end()) particles.erase(part); } // intermediate for (unsigned int ii=0; iiintermediates().size(); ++ii){ part = particles.begin(); for (; part!=particles.end(); ++part){ if ((*part).first==real->intermediates()[ii]->id() && fuzzyEqual((*part).second, real->intermediates()[ii]->momentum())) break; } if (part!=particles.end()) particles.erase(part); } // intermediate CC with -1*momentum for (unsigned int ii=0; iiintermediates().size(); ++ii){ part = particles.begin(); for (; part!=particles.end(); ++part){ if (!real->intermediates()[ii]->coloured() || (real->intermediates()[ii]->hasColour() && real->intermediates()[ii]->hasAntiColour())){ if ((*part).first==real->intermediates()[ii]->id() && fuzzyEqual((*part).second, -1.*real->intermediates()[ii]->momentum()) ) break; } else { if ((*part).first==-1.*real->intermediates()[ii]->id() && fuzzyEqual((*part).second, -1.*real->intermediates()[ii]->momentum()) ) break; } } if (part!=particles.end()) particles.erase(part); } // if all particles match, set as hardtree if (particles.empty()){ chosen_hardTree = testTree; break; } } } protoBranchings().clear(); protoTrees().clear(); hardTrees_.clear(); if(! chosen_hardTree.tree() ) { return PotentialTree(); } else return chosen_hardTree; } bool PowhegShowerHandler::checkDiagram(PotentialTree & tree, tcDiagPtr loDiagram) const { set::const_iterator cit; tcPDPair incoming; multiset outgoing; //get the incoming and outgoing partons involved in hard process for( cit = tree.tree()->branchings().begin(); cit != tree.tree()->branchings().end(); ++cit ){ if( (*cit)->status() ==HardBranching::Incoming) { HardBranchingPtr parent = *cit; while(parent->parent()) parent = parent->parent(); if( parent->branchingParticle()->momentum().z()>ZERO ) incoming.first = (*cit)->branchingParticle()->dataPtr(); else incoming.second = (*cit)->branchingParticle()->dataPtr(); } else { outgoing.insert( (*cit)->branchingParticle()->dataPtr() ); } } if(!incoming.first || !incoming.second) return 0.; pair tag; tag.first = incoming.first ->PDGName() + "," + incoming.second->PDGName() + "->"; tag.second = incoming.second ->PDGName() + "," + incoming.first ->PDGName() + "->"; string tag_out; for ( multiset::iterator i = outgoing.begin(); i != outgoing.end(); ++i ) { if ( i != outgoing.begin() ) tag_out += ","; tag_out += (**i).PDGName(); } tag.first += tag_out; tag.second += tag_out; // find the diagrams if( tag.first == loDiagram->getTag() || tag.second == loDiagram->getTag() ) tree.diagram(loDiagram); // check this is allowed return tree.diagram(); } void PowhegShowerHandler::fillProtoTrees( ProtoTreePtr currentProtoTree,long id ) const { if(currentProtoTree->branchings().size()==(lastXCombPtr()->subProcess()->outgoing().size()+2)) return; for( set::const_iterator ita = currentProtoTree->branchings().begin(); ita!=currentProtoTree->branchings().end();++ita) { for( set::const_iterator itb = currentProtoTree->branchings().begin(); itb!=ita;++itb) { // can't merge two incoming branchings if( (**ita).status() == HardBranching::Incoming && (**itb).status() == HardBranching::Incoming ) continue; // if branching must be outgoing, skip incoming if(emitter_>=2 && ( (**ita).status() == HardBranching::Incoming || (**itb).status() == HardBranching::Incoming )) continue; // if branching must be incoming, skip outgoing if(emitter_<2 && ( (**ita).status() != HardBranching::Incoming && (**itb).status() != HardBranching::Incoming )) continue; // get a new branching for this pair ProtoBranchingPtr currentBranching = getCluster(*ita,*itb); // check branching with the right PID if( ! currentBranching || currentBranching->id() != id) continue; // branching allowed so make a new Tree out of these branchings set< tProtoBranchingPtr > newTreeBranchings = currentProtoTree->branchings(); newTreeBranchings.erase(*ita); newTreeBranchings.erase(*itb); newTreeBranchings.insert(currentBranching); ProtoTreePtr newProtoTree = new_ptr( ProtoTree( newTreeBranchings ) ); // remove duplicate trees if( ! repeatProtoTree( newProtoTree ) ) protoTrees().insert( newProtoTree ); // remove the current tree if it hasn't already been removed if( protoTrees().find( currentProtoTree ) != protoTrees().end() ) protoTrees().erase( currentProtoTree ); // do recursion fillProtoTrees( newProtoTree , id); } } } bool PowhegShowerHandler::repeatProtoTree( ProtoTreePtr currentProtoTree ) const { // loop over all prototrees and see // how many ProtoBranchings of current ProtoTree are found in each for( set< ProtoTreePtr >::const_iterator cit = protoTrees().begin(); cit != protoTrees().end(); ++cit ) { unsigned int no_matches = 0; for( set< tProtoBranchingPtr >::const_iterator ckt = currentProtoTree->branchings().begin(); ckt != currentProtoTree->branchings().end(); ckt++ ) { if( (*cit)->branchings().find( *ckt ) != (*cit)->branchings().end() ) ++no_matches; } // return true if all match if( no_matches == currentProtoTree->branchings().size() ) return true; } return false; } tProtoBranchingPtr PowhegShowerHandler::getCluster( tProtoBranchingPtr b1, tProtoBranchingPtr b2 ) const { // look for the clustered pair in protoBranchings_ for(set::const_iterator cit = protoBranchings().begin(); cit != protoBranchings().end(); ++cit) { // both outgoing if(b1->status()==HardBranching::Outgoing && b2->status()==HardBranching::Outgoing) { if((**cit).status()!=HardBranching::Outgoing|| (**cit).children().empty()) continue; if( ( b1 == (**cit).children()[0] && b2 == (**cit).children()[1] ) || ( b1 == (**cit).children()[1] && b2 == (**cit).children()[0] ) ) return *cit; } // first incoming else if(b1->status()==HardBranching::Incoming) { if((**cit).backChildren().empty() ) continue; if(b1!=(**cit).backChildren()[0]) continue; if(b2==(**cit).backChildren()[1]) return *cit; } // second incoming else if(b2->status()==HardBranching::Incoming) { if((**cit).backChildren().empty() ) continue; if(b2!=(**cit).backChildren()[0]) continue; if(b1==(**cit).backChildren()[1]) return *cit; } } // is branching incoming or outgoing bool incoming = b1->status()==HardBranching::Incoming || b2->status()==HardBranching::Incoming; // get the branching BranchingElement theBranching; if( !incoming ) theBranching = allowedFinalStateBranching( b1, b2 ); else theBranching = allowedInitialStateBranching( b1, b2 ); //if branching is not allowed return null ProtoBrancing if( !theBranching.sudakov ) return ProtoBranchingPtr(); // get the ParticleData object for the new branching tcPDPtr particle_data = incoming ? theBranching.particles[1] : theBranching.particles[0]; - + // create clustered ProtoBranching ProtoBranchingPtr clusteredBranch; // outgoing if( !incoming ) { Lorentz5Momentum pairMomentum = b1->momentum() + b2->momentum(); pairMomentum.setMass(ZERO); clusteredBranch = new_ptr(ProtoBranching(particle_data,HardBranching::Outgoing, pairMomentum, theBranching.sudakov)); if(particle_data->iColour()==PDT::Colour0) return ProtoBranchingPtr(); else if(particle_data->iColour()==PDT::Colour3) { if(b1->particle()->iColour()==PDT::Colour3 && b2->particle()->iColour()==PDT::Colour8) { if(b1->colourLine()!=b2->antiColourLine()) return ProtoBranchingPtr(); clusteredBranch->colourLine(b2->colourLine()); } else if(b2->particle()->iColour()==PDT::Colour3 && b1->particle()->iColour()==PDT::Colour8) { if(b2->colourLine()!=b1->antiColourLine()) return ProtoBranchingPtr(); clusteredBranch->antiColourLine(b1->colourLine()); } else assert(false); clusteredBranch->type(ShowerPartnerType::QCDColourLine); } else if(particle_data->iColour()==PDT::Colour3bar) { if(b1->particle()->iColour()==PDT::Colour3bar && b2->particle()->iColour()==PDT::Colour8) { if(b1->antiColourLine()!=b2->colourLine()) return ProtoBranchingPtr(); clusteredBranch->antiColourLine(b2->antiColourLine()); } else if(b2->particle()->iColour()==PDT::Colour3bar && b1->particle()->iColour()==PDT::Colour8) { if(b2->antiColourLine()!=b1->colourLine()) return ProtoBranchingPtr(); clusteredBranch->antiColourLine(b1->antiColourLine()); } else assert(false); clusteredBranch->type(ShowerPartnerType::QCDAntiColourLine); } else if(particle_data->iColour()==PDT::Colour8) { tProtoBranchingPtr coloured,antiColoured; if(b1->particle()->iColour()==PDT::Colour3 && b2->particle()->iColour()==PDT::Colour3bar) { coloured = b1; antiColoured = b2; } else if(b2->particle()->iColour()==PDT::Colour3 && b1->particle()->iColour()==PDT::Colour3bar) { coloured = b2; antiColoured = b1; } else if(b1->particle()->iColour()==PDT::Colour8 && b2->particle()->iColour()==PDT::Colour8 ) { if(b1->colourLine()==b2->antiColourLine()) { coloured = b2; antiColoured = b1; } else if(b2->colourLine()==b1->antiColourLine()) { coloured = b1; antiColoured = b2; } else return ProtoBranchingPtr(); } else assert(false); // can't have colour self connected gluons if(coloured-> colourLine()==antiColoured->antiColourLine()) return ProtoBranchingPtr(); clusteredBranch-> colourLine( coloured-> colourLine()); clusteredBranch->antiColourLine(antiColoured->antiColourLine()); // softest particle is the emitted if(coloured->momentum().t()>antiColoured->momentum().t()) { clusteredBranch->type(ShowerPartnerType::QCDAntiColourLine); } else { clusteredBranch->type(ShowerPartnerType::QCDColourLine); } } else assert(false); } // incoming else { Lorentz5Momentum pairMomentum = b1->momentum() - b2->momentum(); pairMomentum.setMass( ZERO ); // check for CC if( particle_data->CC() && ( b1->id() != theBranching.particles[0]->id() || b2->id() != theBranching.particles[2]->id() ) ) { particle_data = particle_data->CC(); } clusteredBranch = new_ptr(ProtoBranching(particle_data,HardBranching::Incoming, pairMomentum,theBranching.sudakov)); // work out the type of branching if(b1->particle()->iColour()==PDT::Colour3) { b1->type(ShowerPartnerType::QCDColourLine); if(b2->particle()->iColour()==PDT::Colour3 && particle_data->iColour()==PDT::Colour8) { if(b1->colourLine()==b2->colourLine()) return ProtoBranchingPtr(); clusteredBranch-> colourLine(b1->colourLine()); clusteredBranch->antiColourLine(b2->colourLine()); } else if(b2->particle()->iColour()==PDT::Colour8 && particle_data->iColour()==PDT::Colour3) { if(b1->colourLine()!=b2->colourLine()) return ProtoBranchingPtr(); clusteredBranch->colourLine(b2->antiColourLine()); } else assert(false); } else if(b1->particle()->iColour()==PDT::Colour3bar) { b1->type(ShowerPartnerType::QCDAntiColourLine); if(b2->particle()->iColour()==PDT::Colour3bar && particle_data->iColour()==PDT::Colour8) { if(b1->antiColourLine()==b2->antiColourLine()) return ProtoBranchingPtr(); clusteredBranch-> colourLine(b2->antiColourLine()); clusteredBranch->antiColourLine(b1->antiColourLine()); } else if(b2->particle()->iColour()==PDT::Colour8 && particle_data->iColour()==PDT::Colour3bar) { if(b1->antiColourLine()!=b2->antiColourLine()) return ProtoBranchingPtr(); clusteredBranch->antiColourLine(b2->colourLine()); } else assert(false); } else if(b1->particle()->iColour()==PDT::Colour8) { if(b2->particle()->iColour()==PDT::Colour3) { if(b1->colourLine()!=b2->colourLine()) return ProtoBranchingPtr(); clusteredBranch->antiColourLine(b1->antiColourLine()); b1->type(ShowerPartnerType::QCDColourLine); } else if(b2->particle()->iColour()==PDT::Colour3bar) { if(b1->antiColourLine()!=b2->antiColourLine()) return ProtoBranchingPtr(); clusteredBranch-> colourLine(b1->colourLine()); b1->type(ShowerPartnerType::QCDAntiColourLine); } else if(b2->particle()->iColour()==PDT::Colour8) { if(b1->colourLine()==b2->colourLine()) { b1->type(ShowerPartnerType::QCDColourLine); clusteredBranch->antiColourLine(b1->antiColourLine()); clusteredBranch->colourLine(b2->antiColourLine()); } else if(b1->antiColourLine()==b2->antiColourLine()) { b1->type(ShowerPartnerType::QCDAntiColourLine); clusteredBranch-> colourLine(b1->colourLine()); clusteredBranch->antiColourLine(b2->colourLine()); } else { return ProtoBranchingPtr(); } } else assert(false); } else assert(false); } protoBranchings().insert(clusteredBranch); //set children relations // outgoing if( !incoming ){ clusteredBranch->addChild( b1 ); clusteredBranch->addChild( b2 ); } else { clusteredBranch->addBackChild( b1 ); clusteredBranch->addBackChild( b2 ); } return clusteredBranch; } BranchingElement PowhegShowerHandler:: allowedFinalStateBranching( tProtoBranchingPtr & b1, tProtoBranchingPtr & b2) const { // check with normal ID's pair< long, long > ptest = make_pair( b1->id(), b2->id() ); map< pair< long, long >, BranchingElement >::const_iterator split = allowedFinal_.find(ptest); if( split != allowedFinal_.end() ) { if( split->second.particles[1]->id() != ptest.first ) swap( b1, b2 ); return split->second; } // check with CC if( b1->particle()->CC() ) ptest.first *= -1; if( b2->particle()->CC() ) ptest.second *= -1; split = allowedFinal_.find( ptest ); if( split != allowedFinal_.end() ) { // cc the idlist only be for qbar g clusterings BranchingElement ccBranch = split->second; swap(ccBranch.particles,ccBranch.conjugateParticles); if( split->second.particles[1]->id() != ptest.first ) swap( b1, b2); return ccBranch; } // not found found null pointer return BranchingElement(); } BranchingElement PowhegShowerHandler::allowedInitialStateBranching( tProtoBranchingPtr & b1, tProtoBranchingPtr & b2) const { if(b2->status()==HardBranching::Incoming) swap(b1,b2); // is initial parton an antiparticle bool cc = b1->id() < 0; //gives range of allowedInitial_ with matching first abs( id ) pair< multimap< long, BranchingElement >::const_iterator, multimap< long, BranchingElement >::const_iterator > location = allowedInitial_.equal_range( abs( b1->id() ) ); //iterates over this range for( multimap< long, BranchingElement >::const_iterator it = location.first; it != location.second; ++it ) { + //test id for second particle in pair long idtest = cc ? it->second.conjugateParticles[2]->id() : it->second.particles[2]->id(); // does second id match the test if( idtest == b2->id() ) return it->second; //if the the IS parton is a gluon and charge conjugate of second parton mathes accept if( idtest == -b2->id() && ! b1->particle()->CC() ) return it->second; } // not found found null pointer return BranchingElement(); } bool PowhegShowerHandler::fuzzyEqual(Lorentz5Momentum a, Lorentz5Momentum b) const{ // check momenta are within 1% of each other if ( (a.e()==ZERO && b.e()==ZERO) || (a.e()/b.e()>0.99 && a.e()/b.e()<1.01) ){ if ((a.x()==ZERO && b.x()==ZERO) || (a.x()/b.x()>0.99 && a.x()/b.x()<1.01) ){ if ((a.y()==ZERO && b.y()==ZERO) || (a.y()/b.y()>0.99 && a.y()/b.y()<1.01) ){ if ((a.z()==ZERO && b.z()==ZERO) || (a.z()/b.z()>0.99 && a.z()/b.z()<1.01) ) return true; } } } return false; } void PowhegShowerHandler::doinit() { QTildeShowerHandler::doinit(); // extract the allowed branchings // final-state for(BranchingList::const_iterator it = splittingGenerator()->finalStateBranchings().begin(); it != splittingGenerator()->finalStateBranchings().end(); ++it) { pair prod(make_pair(it->second.particles[1]->id(), it->second.particles[2]->id())); allowedFinal_.insert(make_pair(prod,it->second)); swap(prod.first,prod.second); allowedFinal_.insert(make_pair(prod,it->second)); } // initial-state for(BranchingList::const_iterator it = splittingGenerator()->initialStateBranchings().begin(); it != splittingGenerator()->initialStateBranchings().end(); ++it) { allowedInitial_.insert(make_pair(it->second.particles[0]->id(),it->second)); } } void PowhegShowerHandler::persistentOutput(PersistentOStream & os) const { os << allowedInitial_ << allowedFinal_ << subtractionIntegral_ << enforceColourConsistency_ << forcePartners_ << decayRadiation_; } void PowhegShowerHandler::persistentInput(PersistentIStream & is, int) { is >> allowedInitial_ >> allowedFinal_ >> subtractionIntegral_ >> enforceColourConsistency_ >> forcePartners_ >> decayRadiation_; } // Static variable needed for the type description system in ThePEG. DescribeClass describeHerwigPowhegShowerHandler("Herwig::PowhegShowerHandler", "HwMatchbox.so HwMatching.so"); void PowhegShowerHandler::Init() { static ClassDocumentation documentation ("The PowhegShowerHandler class"); static Switch interfaceEnforceColourConsistency ("EnforceColourConsistency", "Force the Born and real emission colour flows to be consistent", &PowhegShowerHandler::enforceColourConsistency_, false, false, false); static SwitchOption interfaceEnforceColourConsistencyYes (interfaceEnforceColourConsistency, "Yes", "Enforce the consistency", true); static SwitchOption interfaceEnforceColourConsistencyNo (interfaceEnforceColourConsistency, "No", "Don't enforce consistency", false); static Switch interfaceForcePartners ("ForcePartners", "Whether or not to force the partners to be those from the kinematic generation", &PowhegShowerHandler::forcePartners_, false, false, false); static SwitchOption interfaceForcePartnersYes (interfaceForcePartners, "Yes", "Force them", true); static SwitchOption interfaceForcePartnersNo (interfaceForcePartners, "No", "Don't force them", false); static Switch interfaceDecayRadiation ("DecayRadiation", "Handling of radiation which is interpretted as having come from decays", &PowhegShowerHandler::decayRadiation_, 0, false,false); static SwitchOption interfaceDecayRadiationNotAllowed (interfaceDecayRadiation, "NotAllowed", "Not allowed at all, run error will be thrown", 0); static SwitchOption interfaceDecayRadiationVetoEvent (interfaceDecayRadiation, "VetoEvent", "Veto the whole event", 1); static SwitchOption interfaceDecayRadiationVetoRadiation (interfaceDecayRadiation, "VetoRadiation", "Throw the radiation away but keep the event", 2); } diff --git a/Shower/QTilde/QTildeShowerHandler.cc b/Shower/QTilde/QTildeShowerHandler.cc --- a/Shower/QTilde/QTildeShowerHandler.cc +++ b/Shower/QTilde/QTildeShowerHandler.cc @@ -1,3218 +1,3232 @@ // -*- C++ -*- // // QTildeShowerHandler.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // This is the implementation of the non-inlined, non-templated member // functions of the QTildeShowerHandler class. // #include "QTildeShowerHandler.h" #include "ThePEG/Interface/Deleted.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/RefVector.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/EventRecord/Particle.h" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Utilities/EnumIO.h" #include "Herwig/Shower/QTilde/Base/ShowerParticle.h" #include "Herwig/PDF/MPIPDF.h" #include "Herwig/PDF/MinBiasPDF.h" #include "Herwig/Shower/QTilde/Base/ShowerTree.h" #include "Herwig/Shower/QTilde/Base/HardTree.h" #include "Herwig/Shower/QTilde/Kinematics/KinematicsReconstructor.h" #include "Herwig/Shower/QTilde/Base/PartnerFinder.h" #include "Herwig/PDF/HwRemDecayer.h" #include "Herwig/Shower/QTilde/Base/ShowerVertex.h" #include "ThePEG/Repository/CurrentGenerator.h" #include "Herwig/MatrixElement/Matchbox/Base/SubtractedME.h" #include "Herwig/MatrixElement/Matchbox/MatchboxFactory.h" #include "ThePEG/PDF/PartonExtractor.h" #include "Herwig/Shower/RealEmissionProcess.h" #include "Herwig/Shower/QTilde/Kinematics/FS_QTildeShowerKinematics1to2.h" #include "Herwig/Shower/QTilde/Kinematics/IS_QTildeShowerKinematics1to2.h" #include "Herwig/Shower/QTilde/Kinematics/Decay_QTildeShowerKinematics1to2.h" #include "Herwig/MatrixElement/MEMinBias.h" using namespace Herwig; bool QTildeShowerHandler::_hardEmissionWarn = true; bool QTildeShowerHandler::_missingTruncWarn = true; QTildeShowerHandler::QTildeShowerHandler() : _maxtry(100), _meCorrMode(1), _evolutionScheme(1), _hardVetoReadOption(false), _iptrms(ZERO), _beta(0.), _gamma(ZERO), _iptmax(), _limitEmissions(0), _initialenhance(1.), _finalenhance(1.), _nReWeight(100), _reWeight(false), - interaction_(ShowerInteraction::Both), + interaction_(ShowerInteraction::QEDQCD), _trunc_Mode(true), _hardEmission(1), _softOpt(2), _hardPOWHEG(false), muPt(ZERO) {} QTildeShowerHandler::~QTildeShowerHandler() {} IBPtr QTildeShowerHandler::clone() const { return new_ptr(*this); } IBPtr QTildeShowerHandler::fullclone() const { return new_ptr(*this); } void QTildeShowerHandler::persistentOutput(PersistentOStream & os) const { os << _splittingGenerator << _maxtry << _meCorrMode << _hardVetoReadOption << _limitEmissions << _softOpt << _hardPOWHEG << ounit(_iptrms,GeV) << _beta << ounit(_gamma,GeV) << ounit(_iptmax,GeV) << _vetoes << _fullShowerVetoes << _nReWeight << _reWeight << _trunc_Mode << _hardEmission << _evolutionScheme << ounit(muPt,GeV) << oenum(interaction_) << _reconstructor << _partnerfinder; } void QTildeShowerHandler::persistentInput(PersistentIStream & is, int) { is >> _splittingGenerator >> _maxtry >> _meCorrMode >> _hardVetoReadOption >> _limitEmissions >> _softOpt >> _hardPOWHEG >> iunit(_iptrms,GeV) >> _beta >> iunit(_gamma,GeV) >> iunit(_iptmax,GeV) >> _vetoes >> _fullShowerVetoes >> _nReWeight >> _reWeight >> _trunc_Mode >> _hardEmission >> _evolutionScheme >> iunit(muPt,GeV) >> ienum(interaction_) >> _reconstructor >> _partnerfinder; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigQTildeShowerHandler("Herwig::QTildeShowerHandler", "HwShower.so"); void QTildeShowerHandler::Init() { static ClassDocumentation documentation ("TheQTildeShowerHandler class is the main class" " for the angular-ordered parton shower", "The Shower evolution was performed using an algorithm described in " "\\cite{Marchesini:1983bm,Marchesini:1987cf,Gieseke:2003rz,Bahr:2008pv}.", "%\\cite{Marchesini:1983bm}\n" "\\bibitem{Marchesini:1983bm}\n" " G.~Marchesini and B.~R.~Webber,\n" " ``Simulation Of QCD Jets Including Soft Gluon Interference,''\n" " Nucl.\\ Phys.\\ B {\\bf 238}, 1 (1984).\n" " %%CITATION = NUPHA,B238,1;%%\n" "%\\cite{Marchesini:1987cf}\n" "\\bibitem{Marchesini:1987cf}\n" " G.~Marchesini and B.~R.~Webber,\n" " ``Monte Carlo Simulation of General Hard Processes with Coherent QCD\n" " Radiation,''\n" " Nucl.\\ Phys.\\ B {\\bf 310}, 461 (1988).\n" " %%CITATION = NUPHA,B310,461;%%\n" "%\\cite{Gieseke:2003rz}\n" "\\bibitem{Gieseke:2003rz}\n" " S.~Gieseke, P.~Stephens and B.~Webber,\n" " ``New formalism for QCD parton showers,''\n" " JHEP {\\bf 0312}, 045 (2003)\n" " [arXiv:hep-ph/0310083].\n" " %%CITATION = JHEPA,0312,045;%%\n" ); static Reference interfaceSplitGen("SplittingGenerator", "A reference to the SplittingGenerator object", &Herwig::QTildeShowerHandler::_splittingGenerator, false, false, true, false); static Parameter interfaceMaxTry ("MaxTry", "The maximum number of attempts to generate the shower from a" " particular ShowerTree", &QTildeShowerHandler::_maxtry, 100, 1, 100000, false, false, Interface::limited); static Parameter interfaceNReWeight ("NReWeight", "The number of attempts for the shower when reweighting", &QTildeShowerHandler::_nReWeight, 100, 10, 10000, false, false, Interface::limited); static Switch ifaceMECorrMode ("MECorrMode", "Choice of the ME Correction Mode", &QTildeShowerHandler::_meCorrMode, 1, false, false); static SwitchOption on (ifaceMECorrMode,"HardPlusSoft","hard+soft on", 1); static SwitchOption hard (ifaceMECorrMode,"Hard","only hard on", 2); static SwitchOption soft (ifaceMECorrMode,"Soft","only soft on", 3); static Switch ifaceHardVetoReadOption ("HardVetoReadOption", "Apply read-in scale veto to all collisions or just the primary one?", &QTildeShowerHandler::_hardVetoReadOption, false, false, false); static SwitchOption AllCollisions (ifaceHardVetoReadOption, "AllCollisions", "Read-in pT veto applied to primary and secondary collisions.", false); static SwitchOption PrimaryCollision (ifaceHardVetoReadOption, "PrimaryCollision", "Read-in pT veto applied to primary but not secondary collisions.", true); static Parameter ifaceiptrms ("IntrinsicPtGaussian", "RMS of intrinsic pT of Gaussian distribution:\n" "2*(1-Beta)*exp(-sqr(intrinsicpT/RMS))/sqr(RMS)", &QTildeShowerHandler::_iptrms, GeV, ZERO, ZERO, 1000000.0*GeV, false, false, Interface::limited); static Parameter ifacebeta ("IntrinsicPtBeta", "Proportion of inverse quadratic distribution in generating intrinsic pT.\n" "(1-Beta) is the proportion of Gaussian distribution", &QTildeShowerHandler::_beta, 0, 0, 1, false, false, Interface::limited); static Parameter ifacegamma ("IntrinsicPtGamma", "Parameter for inverse quadratic:\n" "2*Beta*Gamma/(sqr(Gamma)+sqr(intrinsicpT))", &QTildeShowerHandler::_gamma,GeV, ZERO, ZERO, 100000.0*GeV, false, false, Interface::limited); static Parameter ifaceiptmax ("IntrinsicPtIptmax", "Upper bound on intrinsic pT for inverse quadratic", &QTildeShowerHandler::_iptmax,GeV, ZERO, ZERO, 100000.0*GeV, false, false, Interface::limited); static RefVector ifaceVetoes ("Vetoes", "The vetoes to be checked during showering", &QTildeShowerHandler::_vetoes, -1, false,false,true,true,false); static RefVector interfaceFullShowerVetoes ("FullShowerVetoes", "The vetos to be appliede on the full final state of the shower", &QTildeShowerHandler::_fullShowerVetoes, -1, false, false, true, false, false); static Switch interfaceLimitEmissions ("LimitEmissions", "Limit the number and type of emissions for testing", &QTildeShowerHandler::_limitEmissions, 0, false, false); static SwitchOption interfaceLimitEmissionsNoLimit (interfaceLimitEmissions, "NoLimit", "Allow an arbitrary number of emissions", 0); static SwitchOption interfaceLimitEmissionsOneInitialStateEmission (interfaceLimitEmissions, "OneInitialStateEmission", "Allow one emission in the initial state and none in the final state", 1); static SwitchOption interfaceLimitEmissionsOneFinalStateEmission (interfaceLimitEmissions, "OneFinalStateEmission", "Allow one emission in the final state and none in the initial state", 2); static SwitchOption interfaceLimitEmissionsHardOnly (interfaceLimitEmissions, "HardOnly", "Only allow radiation from the hard ME correction", 3); static SwitchOption interfaceLimitEmissionsOneEmission (interfaceLimitEmissions, "OneEmission", "Allow one emission in either the final state or initial state, but not both", 4); static Switch interfaceTruncMode ("TruncatedShower", "Include the truncated shower?", &QTildeShowerHandler::_trunc_Mode, 1, false, false); static SwitchOption interfaceTruncMode0 (interfaceTruncMode,"No","Truncated Shower is OFF", 0); static SwitchOption interfaceTruncMode1 (interfaceTruncMode,"Yes","Truncated Shower is ON", 1); static Switch interfaceHardEmission ("HardEmission", "Whether to use ME corrections or POWHEG for the hardest emission", &QTildeShowerHandler::_hardEmission, 0, false, false); static SwitchOption interfaceHardEmissionNone (interfaceHardEmission, "None", "No Corrections", 0); static SwitchOption interfaceHardEmissionMECorrection (interfaceHardEmission, "MECorrection", "Old fashioned ME correction", 1); static SwitchOption interfaceHardEmissionPOWHEG (interfaceHardEmission, "POWHEG", "Powheg style hard emission", 2); static Switch interfaceInteractions ("Interactions", "The interactions to be used in the shower", - &QTildeShowerHandler::interaction_, ShowerInteraction::Both, false, false); + &QTildeShowerHandler::interaction_, ShowerInteraction::QEDQCD, false, false); static SwitchOption interfaceInteractionsQCD (interfaceInteractions, "QCD", "Only QCD radiation", ShowerInteraction::QCD); static SwitchOption interfaceInteractionsQED (interfaceInteractions, "QED", "Only QEd radiation", ShowerInteraction::QED); - static SwitchOption interfaceInteractionsQCDandQED + static SwitchOption interfaceInteractionEWOnly (interfaceInteractions, - "QCDandQED", - "Both QED and QCD radiation", - ShowerInteraction::Both); + "EWOnly", + "Only EW", + ShowerInteraction::EW); + static SwitchOption interfaceInteractionQEDQCD + (interfaceInteractions, + "QEDQCD", + "QED and QCD", + ShowerInteraction::QEDQCD); + static SwitchOption interfaceInteractionALL + (interfaceInteractions, + "ALL", + "QED, QCD and EW", + ShowerInteraction::ALL); static Deleted delReconstructionOption ("ReconstructionOption", "The old reconstruction option switch has been replaced with" " the new EvolutionScheme switch, see arXiv:1904.11866 for details"); static Switch interfaceEvolutionScheme ("EvolutionScheme", "The scheme to interpret the evolution variable in the case of multple emission.", &QTildeShowerHandler::_evolutionScheme, 1, false, false); static SwitchOption interfaceEvolutionSchemepT (interfaceEvolutionScheme, "pT", "pT scheme", 0); static SwitchOption interfaceEvolutionSchemeDotProduct (interfaceEvolutionScheme, "DotProduct", "Dot-product scheme", 1); static SwitchOption interfaceEvolutionSchemeQ2 (interfaceEvolutionScheme, "Q2", "Q2 scheme", 2); static Switch interfaceSoftCorrelations ("SoftCorrelations", "Option for the treatment of soft correlations in the parton shower", &QTildeShowerHandler::_softOpt, 2, false, false); static SwitchOption interfaceSoftCorrelationsNone (interfaceSoftCorrelations, "No", "No soft correlations", 0); static SwitchOption interfaceSoftCorrelationsFull (interfaceSoftCorrelations, "Full", "Use the full eikonal", 1); static SwitchOption interfaceSoftCorrelationsSingular (interfaceSoftCorrelations, "Singular", "Use original Webber-Marchisini form", 2); static Switch interfaceHardPOWHEG ("HardPOWHEG", "Treatment of powheg emissions which are too hard to have a shower interpretation", &QTildeShowerHandler::_hardPOWHEG, false, false, false); static SwitchOption interfaceHardPOWHEGAsShower (interfaceHardPOWHEG, "AsShower", "Still interpret as shower emissions", false); static SwitchOption interfaceHardPOWHEGRealEmission (interfaceHardPOWHEG, "RealEmission", "Generate shower from the real emmission configuration", true); static Reference interfaceKinematicsReconstructor ("KinematicsReconstructor", "Reference to the KinematicsReconstructor object", &QTildeShowerHandler::_reconstructor, false, false, true, false, false); static Reference interfacePartnerFinder ("PartnerFinder", "Reference to the PartnerFinder object", &QTildeShowerHandler::_partnerfinder, false, false, true, false, false); } tPPair QTildeShowerHandler::cascade(tSubProPtr sub, XCPtr xcomb) { // use me for reference in tex file etc useMe(); prepareCascade(sub); // set things up in the base class resetWeights(); hard_=ShowerTreePtr(); decay_.clear(); done_.clear(); // start of the try block for the whole showering process unsigned int countFailures=0; while (countFailuresoutgoing().begin(), currentSubProcess()->outgoing().end()), hard,decay); ShowerTree::constructTrees(hard_,decay_,hard,decay); // if no hard process if(!hard_) throw Exception() << "Shower starting with a decay" << "is not implemented" << Exception::runerror; // perform the shower for the hard process showerHardProcess(hard_,xcomb); done_.push_back(hard_); hard_->updateAfterShower(decay_); // if no decaying particles to shower break out of the loop if(decay_.empty()) break; // shower the decay products while(!decay_.empty()) { // find particle whose production process has been showered ShowerDecayMap::iterator dit = decay_.begin(); while(!dit->second->parent()->hasShowered() && dit!=decay_.end()) ++dit; assert(dit!=decay_.end()); // get the particle ShowerTreePtr decayingTree = dit->second; // remove it from the multimap decay_.erase(dit); // make sure the particle has been decayed QTildeShowerHandler::decay(decayingTree,decay_); // now shower the decay showerDecay(decayingTree); done_.push_back(decayingTree); decayingTree->updateAfterShower(decay_); } // suceeded break out of the loop break; } catch (KinematicsReconstructionVeto) { resetWeights(); ++countFailures; } catch ( ... ) { hard_=ShowerTreePtr(); decay_.clear(); done_.clear(); throw; } } // if loop exited because of too many tries, throw event away if (countFailures >= maxtry()) { resetWeights(); hard_=ShowerTreePtr(); decay_.clear(); done_.clear(); throw Exception() << "Too many tries for main while loop " << "in QTildeShowerHandler::cascade()." << Exception::eventerror; } //enter the particles in the event record fillEventRecord(); // clear storage hard_=ShowerTreePtr(); decay_.clear(); done_.clear(); // non hadronic case return if (!isResolvedHadron(incomingBeams().first ) && !isResolvedHadron(incomingBeams().second) ) return incomingBeams(); // remake the remnants (needs to be after the colours are sorted // out in the insertion into the event record) if ( firstInteraction() ) return remakeRemnant(sub->incoming()); //Return the new pair of incoming partons. remakeRemnant is not //necessary here, because the secondary interactions are not yet //connected to the remnants. return make_pair(findFirstParton(sub->incoming().first ), findFirstParton(sub->incoming().second)); } void QTildeShowerHandler::fillEventRecord() { // create a new step StepPtr pstep = newStep(); assert(!done_.empty()); assert(done_[0]->isHard()); // insert the steps for(unsigned int ix=0;ixfillEventRecord(pstep,doISR(),doFSR()); } } HardTreePtr QTildeShowerHandler::generateCKKW(ShowerTreePtr ) const { return HardTreePtr(); } void QTildeShowerHandler::doinit() { ShowerHandler::doinit(); // check on the reweighting for(unsigned int ix=0;ix<_fullShowerVetoes.size();++ix) { if(_fullShowerVetoes[ix]->behaviour()==1) { _reWeight = true; break; } } if(_reWeight && maximumTries()<_nReWeight) { throw Exception() << "Reweight being performed in the shower but the number of attempts for the" << "shower is less than that for the reweighting.\n" << "Maximum number of attempt for the shower " << fullName() << ":MaxTry is " << maximumTries() << "\nand for reweighting is " << fullName() << ":NReWeight is " << _nReWeight << "\n" << "we recommend the number of attempts is 10 times the number for reweighting\n" << Exception::runerror; } ShowerTree::_vmin2 = vMin(); ShowerTree::_spaceTime = includeSpaceTime(); } void QTildeShowerHandler::doinitrun() { ShowerHandler::doinitrun(); ShowerTree::_vmin2 = vMin(); ShowerTree::_spaceTime = includeSpaceTime(); } void QTildeShowerHandler::generateIntrinsicpT(vector particlesToShower) { if ( !ipTon() || !doISR() ) return; // don't do anything for the moment for secondary scatters if( !firstInteraction() ) return; // generate intrinsic pT for(unsigned int ix=0;ixprogenitor()->isFinalState()) continue; if(!particlesToShower[ix]->progenitor()->dataPtr()->coloured()) continue; Energy ipt; if(UseRandom::rnd() > _beta) { ipt=_iptrms*sqrt(-log(UseRandom::rnd())); } else { ipt=_gamma*sqrt(pow(1.+sqr(_iptmax/_gamma), UseRandom::rnd())-1.); } pair pt = make_pair(ipt,UseRandom::rnd(Constants::twopi)); _intrinsic[particlesToShower[ix]] = pt; } } void QTildeShowerHandler::setupMaximumScales(const vector & p, XCPtr xcomb) { // let POWHEG events radiate freely if(_hardEmission==2&&hardTree()) { vector::const_iterator ckt = p.begin(); for (; ckt != p.end(); ckt++) (*ckt)->maxHardPt(Constants::MaxEnergy); return; } // return if no vetos if (!restrictPhasespace()) return; // find out if hard partonic subprocess. bool isPartonic(false); map::const_iterator cit = _currenttree->incomingLines().begin(); Lorentz5Momentum pcm; for(; cit!=currentTree()->incomingLines().end(); ++cit) { pcm += cit->first->progenitor()->momentum(); isPartonic |= cit->first->progenitor()->coloured(); } // find minimum pt from hard process, the maximum pt from all outgoing // coloured lines (this is simpler and more general than // 2stu/(s^2+t^2+u^2)). Maximum scale for scattering processes will // be transverse mass. Energy ptmax = generator()->maximumCMEnergy(); // general case calculate the scale if ( !hardScaleIsMuF() || (hardVetoReadOption()&&!firstInteraction()) ) { // scattering process if(currentTree()->isHard()) { assert(xcomb); // coloured incoming particles if (isPartonic) { map::const_iterator cjt = currentTree()->outgoingLines().begin(); for(; cjt!=currentTree()->outgoingLines().end(); ++cjt) { if (cjt->first->progenitor()->coloured()) ptmax = min(ptmax,cjt->first->progenitor()->momentum().mt()); } } if (ptmax == generator()->maximumCMEnergy() ) ptmax = pcm.m(); if(hardScaleIsMuF()&&hardVetoReadOption()&& !firstInteraction()) { ptmax=min(ptmax,sqrt(xcomb->lastShowerScale())); } } // decay, incoming() is the decaying particle. else { ptmax = currentTree()->incomingLines().begin()->first ->progenitor()->momentum().mass(); } } // hepeup.SCALUP is written into the lastXComb by the // LesHouchesReader itself - use this by user's choice. // Can be more general than this. else { if(currentTree()->isHard()) { assert(xcomb); ptmax = sqrt( xcomb->lastShowerScale() ); } else { ptmax = currentTree()->incomingLines().begin()->first ->progenitor()->momentum().mass(); } } ptmax *= hardScaleFactor(); // set maxHardPt for all progenitors. For partonic processes this // is now the max pt in the FS, for non-partonic processes or // processes with no coloured FS the invariant mass of the IS vector::const_iterator ckt = p.begin(); for (; ckt != p.end(); ckt++) (*ckt)->maxHardPt(ptmax); } void QTildeShowerHandler::setupHardScales(const vector & p, XCPtr xcomb) { if ( hardScaleIsMuF() && (!hardVetoReadOption() || firstInteraction()) ) { Energy hardScale = ZERO; if(currentTree()->isHard()) { assert(xcomb); hardScale = sqrt( xcomb->lastShowerScale() ); } else { hardScale = currentTree()->incomingLines().begin()->first ->progenitor()->momentum().mass(); } hardScale *= hardScaleFactor(); vector::const_iterator ckt = p.begin(); for (; ckt != p.end(); ckt++) (*ckt)->hardScale(hardScale); muPt = hardScale; } } void QTildeShowerHandler::showerHardProcess(ShowerTreePtr hard, XCPtr xcomb) { _hardme = HwMEBasePtr(); // extract the matrix element tStdXCombPtr lastXC = dynamic_ptr_cast(xcomb); if(lastXC) { _hardme = dynamic_ptr_cast(lastXC->matrixElement()); } _decayme = HwDecayerBasePtr(); // set the current tree currentTree(hard); hardTree(HardTreePtr()); // work out the type of event currentTree()->xcombPtr(dynamic_ptr_cast(xcomb)); currentTree()->identifyEventType(); checkFlags(); // generate the showering doShowering(true,xcomb); } RealEmissionProcessPtr QTildeShowerHandler::hardMatrixElementCorrection(bool hard) { // set the initial enhancement factors for the soft correction _initialenhance = 1.; _finalenhance = 1.; // see if we can get the correction from the matrix element // or decayer RealEmissionProcessPtr real; if(hard) { if(_hardme&&_hardme->hasMECorrection()) { _hardme->initializeMECorrection(_currenttree->perturbativeProcess(), _initialenhance,_finalenhance); if(hardMEC()) real = _hardme->applyHardMatrixElementCorrection(_currenttree->perturbativeProcess()); } } else { if(_decayme&&_decayme->hasMECorrection()) { _decayme->initializeMECorrection(_currenttree->perturbativeProcess(), _initialenhance,_finalenhance); if(hardMEC()) real = _decayme->applyHardMatrixElementCorrection(_currenttree->perturbativeProcess()); } } return real; } ShowerParticleVector QTildeShowerHandler::createTimeLikeChildren(tShowerParticlePtr, IdList ids) { // Create the ShowerParticle objects for the two children of // the emitting particle; set the parent/child relationship // if same as definition create particles, otherwise create cc ShowerParticleVector children; for(unsigned int ix=0;ix<2;++ix) { children.push_back(new_ptr(ShowerParticle(ids[ix+1],true))); if(children[ix]->id()==_progenitor->id()&&!ids[ix+1]->stable()&&abs(ids[ix+1]->id())!=ParticleID::tauminus) children[ix]->set5Momentum(Lorentz5Momentum(_progenitor->progenitor()->mass())); else children[ix]->set5Momentum(Lorentz5Momentum(ids[ix+1]->mass())); } return children; } bool QTildeShowerHandler::timeLikeShower(tShowerParticlePtr particle, ShowerInteraction type, Branching fb, bool first) { // don't do anything if not needed if(_limitEmissions == 1 || hardOnly() || ( _limitEmissions == 2 && _nfs != 0) || ( _limitEmissions == 4 && _nfs + _nis != 0) ) { if(particle->spinInfo()) particle->spinInfo()->develop(); return false; } // generate the emission ShowerParticleVector children; // generate the emission if(!fb.kinematics) fb = selectTimeLikeBranching(particle,type,HardBranchingPtr()); // no emission, return if(!fb.kinematics) { if(particle->spinInfo()) particle->spinInfo()->develop(); return false; } Branching fc[2] = {Branching(),Branching()}; assert(fb.kinematics); // has emitted // Assign the shower kinematics to the emitting particle. particle->showerKinematics(fb.kinematics); // check highest pT if(fb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(fb.kinematics->pT()); // create the children children = createTimeLikeChildren(particle,fb.ids); // update the children particle->showerKinematics()-> updateChildren(particle, children,fb.type); // update number of emissions ++_nfs; if(_limitEmissions!=0) { if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); if(particle->spinInfo()) particle->spinInfo()->develop(); return true; } // select branchings for children fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr()); fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr()); // shower the first particle if(fc[0].kinematics) timeLikeShower(children[0],type,fc[0],false); if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); // shower the second particle if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],false); if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); particle->showerKinematics()->updateParent(particle, children,_evolutionScheme,fb.type); // branching has happened if(first&&!children.empty()) particle->showerKinematics()->resetChildren(particle,children); if(particle->spinInfo()) particle->spinInfo()->develop(); return true; } bool QTildeShowerHandler::spaceLikeShower(tShowerParticlePtr particle, PPtr beam, ShowerInteraction type) { //using the pdf's associated with the ShowerHandler assures, that //modified pdf's are used for the secondary interactions via //CascadeHandler::resetPDFs(...) tcPDFPtr pdf; if(beam == incomingBeams().first) pdf = firstPDF().pdf(); if(beam == incomingBeams().second) pdf = secondPDF().pdf(); Energy freeze = pdfFreezingScale(); // don't do anything if not needed if(_limitEmissions == 2 || hardOnly() || ( _limitEmissions == 1 && _nis != 0 ) || ( _limitEmissions == 4 && _nis + _nfs != 0 ) ) { if(particle->spinInfo()) particle->spinInfo()->develop(); return false; } Branching bb; // generate branching while (true) { bb=_splittingGenerator->chooseBackwardBranching(*particle,beam, _initialenhance, _beam,type, pdf,freeze); // return if no emission if(!bb.kinematics) { if(particle->spinInfo()) particle->spinInfo()->develop(); return false; } // if not vetoed break if(!spaceLikeVetoed(bb,particle)) break; // otherwise reset scale and continue particle->vetoEmission(bb.type,bb.kinematics->scale()); if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr()); } // assign the splitting function and shower kinematics particle->showerKinematics(bb.kinematics); if(bb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(bb.kinematics->pT()); // For the time being we are considering only 1->2 branching // particles as in Sudakov form factor tcPDPtr part[2]={bb.ids[0],bb.ids[2]}; // Now create the actual particles, make the otherChild a final state // particle, while the newParent is not ShowerParticlePtr newParent = new_ptr(ShowerParticle(part[0],false)); ShowerParticlePtr otherChild = new_ptr(ShowerParticle(part[1],true,true)); ShowerParticleVector theChildren; theChildren.push_back(particle); theChildren.push_back(otherChild); //this updates the evolution scale particle->showerKinematics()-> updateParent(newParent, theChildren,_evolutionScheme,bb.type); // update the history if needed _currenttree->updateInitialStateShowerProduct(_progenitor,newParent); _currenttree->addInitialStateBranching(particle,newParent,otherChild); // for the reconstruction of kinematics, parent/child // relationships are according to the branching process: // now continue the shower ++_nis; bool emitted = _limitEmissions==0 ? spaceLikeShower(newParent,beam,type) : false; if(newParent->spinInfo()) newParent->spinInfo()->develop(); // now reconstruct the momentum if(!emitted) { if(_intrinsic.find(_progenitor)==_intrinsic.end()) { bb.kinematics->updateLast(newParent,ZERO,ZERO); } else { pair kt=_intrinsic[_progenitor]; bb.kinematics->updateLast(newParent, kt.first*cos(kt.second), kt.first*sin(kt.second)); } } particle->showerKinematics()-> updateChildren(newParent, theChildren,bb.type); if(_limitEmissions!=0) { if(particle->spinInfo()) particle->spinInfo()->develop(); return true; } // perform the shower of the final-state particle timeLikeShower(otherChild,type,Branching(),true); updateHistory(otherChild); if(theChildren[1]->spinInfo()) theChildren[1]->spinInfo()->develop(); // return the emitted if(particle->spinInfo()) particle->spinInfo()->develop(); return true; } void QTildeShowerHandler::showerDecay(ShowerTreePtr decay) { // work out the type of event currentTree()->xcombPtr(StdXCombPtr()); currentTree()->identifyEventType(); _decayme = HwDecayerBasePtr(); _hardme = HwMEBasePtr(); // find the decayer // try the normal way if possible tDMPtr dm = decay->incomingLines().begin()->first->original() ->decayMode(); if(!dm) dm = decay->incomingLines().begin()->first->copy() ->decayMode(); if(!dm) dm = decay->incomingLines().begin()->first->progenitor()->decayMode(); // otherwise make a string and look it up if(!dm) { string tag = decay->incomingLines().begin()->first->original()->dataPtr()->name() + "->"; OrderedParticles outgoing; for(map::const_iterator it=decay->outgoingLines().begin();it!=decay->outgoingLines().end();++it) { if(abs(decay->incomingLines().begin()->first->original()->id()) == ParticleID::t && abs(it->first->original()->id())==ParticleID::Wplus && decay->treelinks().size() == 1) { ShowerTreePtr Wtree = decay->treelinks().begin()->first; for(map::const_iterator it2=Wtree->outgoingLines().begin();it2!=Wtree->outgoingLines().end();++it2) { outgoing.insert(it2->first->original()->dataPtr()); } } else { outgoing.insert(it->first->original()->dataPtr()); } } for(OrderedParticles::const_iterator it=outgoing.begin(); it!=outgoing.end();++it) { if(it!=outgoing.begin()) tag += ","; tag +=(**it).name(); } tag += ";"; dm = findDecayMode(tag); } if(dm) _decayme = dynamic_ptr_cast(dm->decayer()); // set the ShowerTree to be showered currentTree(decay); decay->applyTransforms(); hardTree(HardTreePtr()); // generate the showering doShowering(false,XCPtr()); // if no vetos // force calculation of spin correlations SpinPtr spInfo = decay->incomingLines().begin()->first->progenitor()->spinInfo(); if(spInfo) { if(!spInfo->developed()) spInfo->needsUpdate(); spInfo->develop(); } } bool QTildeShowerHandler::spaceLikeDecayShower(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minmass,ShowerInteraction type, Branching fb) { // don't do anything if not needed if(_limitEmissions == 1 || hardOnly() || ( _limitEmissions == 3 && _nis != 0) || ( _limitEmissions == 4 && _nfs + _nis != 0) ) { return false; } // generate the emission ShowerParticleVector children; // generate the emission if(!fb.kinematics) fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type, HardBranchingPtr()); // no emission, return if(!fb.kinematics) return false; Branching fc[2]; if(particle->virtualMass()==ZERO) particle->virtualMass(_progenitor->progenitor()->mass()); fc[0] = Branching(); fc[1] = Branching(); assert(fb.kinematics); // has emitted // Assign the shower kinematics to the emitting particle. particle->showerKinematics(fb.kinematics); if(fb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(fb.kinematics->pT()); // create the ShowerParticle objects for the two children children = createTimeLikeChildren(particle,fb.ids); // updateChildren the children particle->showerKinematics()-> updateChildren(particle, children, fb.type); // select branchings for children fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass, type,HardBranchingPtr()); fc[1] = selectTimeLikeBranching (children[1],type,HardBranchingPtr()); // old default ++_nis; // shower the first particle _currenttree->updateInitialStateShowerProduct(_progenitor,children[0]); _currenttree->addInitialStateBranching(particle,children[0],children[1]); if(fc[0].kinematics) spaceLikeDecayShower(children[0],maxScales,minmass,type,Branching()); // shower the second particle if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],true); updateHistory(children[1]); // TODO NEED AN UPDATE HERE FOR RECONOPT!=0 // branching has happened return true; } vector QTildeShowerHandler::setupShower(bool hard) { RealEmissionProcessPtr real; // generate hard me if needed if(_hardEmission==1) { real = hardMatrixElementCorrection(hard); if(real&&!real->outgoing().empty()) setupMECorrection(real); } // generate POWHEG hard emission if needed else if(_hardEmission==2) hardestEmission(hard); // set the initial colour partners setEvolutionPartners(hard,interaction_,false); // get the particles to be showered vector particlesToShower = currentTree()->extractProgenitors(); // return the answer return particlesToShower; } void QTildeShowerHandler::setEvolutionPartners(bool hard,ShowerInteraction type, bool clear) { // match the particles in the ShowerTree and hardTree if(hardTree() && !hardTree()->connect(currentTree())) throw Exception() << "Can't match trees in " << "QTildeShowerHandler::setEvolutionPartners()" << Exception::eventerror; // extract the progenitors vector particles = currentTree()->extractProgenitorParticles(); // clear the partners if needed if(clear) { for(unsigned int ix=0;ixpartner(ShowerParticlePtr()); particles[ix]->clearPartners(); } } // sort out the colour partners if(hardTree()) { // find the partner for(unsigned int ix=0;ixparticles()[particles[ix]]->branchingParticle()->partner(); if(!partner) continue; for(map::const_iterator it=hardTree()->particles().begin(); it!=hardTree()->particles().end();++it) { if(it->second->branchingParticle()==partner) { particles[ix]->partner(it->first); break; } } if(!particles[ix]->partner()) throw Exception() << "Can't match partners in " << "QTildeShowerHandler::setEvolutionPartners()" << Exception::eventerror; } } // Set the initial evolution scales partnerFinder()-> setInitialEvolutionScales(particles,!hard,interaction_,!_hardtree); if(hardTree() && _hardPOWHEG) { bool tooHard=false; map::const_iterator eit=hardTree()->particles().end(); for(unsigned int ix=0;ix::const_iterator mit = hardTree()->particles().find(particles[ix]); Energy hardScale(ZERO); ShowerPartnerType type(ShowerPartnerType::Undefined); // final-state if(particles[ix]->isFinalState()) { if(mit!= eit && !mit->second->children().empty()) { hardScale = mit->second->scale(); type = mit->second->type(); } } // initial-state else { if(mit!= eit && mit->second->parent()) { hardScale = mit->second->parent()->scale(); type = mit->second->parent()->type(); } } if(type!=ShowerPartnerType::Undefined) { if(type==ShowerPartnerType::QED) { tooHard |= particles[ix]->scales().QED_noAOscales().QCD_c_noAOscales().QCD_ac_noAOscales().EWchildren().empty()) { ShowerParticleVector theChildren; for(unsigned int ix=0;ixchildren().size();++ix) { ShowerParticlePtr part = dynamic_ptr_cast (particle->children()[ix]); theChildren.push_back(part); } // update the history if needed if(particle==_currenttree->getFinalStateShowerProduct(_progenitor)) _currenttree->updateFinalStateShowerProduct(_progenitor, particle,theChildren); _currenttree->addFinalStateBranching(particle,theChildren); for(unsigned int ix=0;ixprogenitor()->partner()) return false; progenitor()->progenitor()->initializeFinalState(); if(hardTree()) { map::const_iterator eit=hardTree()->particles().end(), mit = hardTree()->particles().find(progenitor()->progenitor()); if( mit != eit && !mit->second->children().empty() ) { bool output=truncatedTimeLikeShower(progenitor()->progenitor(), mit->second ,type,Branching(),true); if(output) updateHistory(progenitor()->progenitor()); return output; } } // do the shower bool output = hardOnly() ? false : timeLikeShower(progenitor()->progenitor() ,type,Branching(),true) ; if(output) updateHistory(progenitor()->progenitor()); return output; } bool QTildeShowerHandler::startSpaceLikeShower(PPtr parent, ShowerInteraction type) { // initialise the basis vectors if(!progenitor()->progenitor()->partner()) return false; progenitor()->progenitor()->initializeInitialState(parent); if(hardTree()) { map::const_iterator eit =hardTree()->particles().end(), mit = hardTree()->particles().find(progenitor()->progenitor()); if( mit != eit && mit->second->parent() ) { return truncatedSpaceLikeShower( progenitor()->progenitor(), parent, mit->second->parent(), type ); } } // perform the shower return hardOnly() ? false : spaceLikeShower(progenitor()->progenitor(),parent,type); } bool QTildeShowerHandler:: startSpaceLikeDecayShower(const ShowerParticle::EvolutionScales & maxScales, Energy minimumMass,ShowerInteraction type) { // set up the particle basis vectors if(!progenitor()->progenitor()->partner()) return false; progenitor()->progenitor()->initializeDecay(); if(hardTree()) { map::const_iterator eit =hardTree()->particles().end(), mit = hardTree()->particles().find(progenitor()->progenitor()); if( mit != eit && mit->second->parent() ) { HardBranchingPtr branch=mit->second; while(branch->parent()) branch=branch->parent(); return truncatedSpaceLikeDecayShower(progenitor()->progenitor(),maxScales, minimumMass, branch ,type, Branching()); } } // perform the shower return hardOnly() ? false : spaceLikeDecayShower(progenitor()->progenitor(),maxScales,minimumMass,type,Branching()); } bool QTildeShowerHandler::timeLikeVetoed(const Branching & fb, ShowerParticlePtr particle) { // work out type of interaction ShowerInteraction type = convertInteraction(fb.type); // check whether emission was harder than largest pt of hard subprocess if ( restrictPhasespace() && fb.kinematics->pT() > _progenitor->maxHardPt() ) return true; // soft matrix element correction veto if( softMEC()) { if(_hardme && _hardme->hasMECorrection()) { if(_hardme->softMatrixElementVeto(particle, _progenitor->progenitor(), particle->isFinalState(), _progenitor->highestpT(), fb.ids, fb.kinematics->z(), fb.kinematics->scale(), fb.kinematics->pT())) return true; } else if(_decayme && _decayme->hasMECorrection()) { if(_decayme->softMatrixElementVeto(particle, _progenitor->progenitor(), particle->isFinalState(), _progenitor->highestpT(), fb.ids, fb.kinematics->z(), fb.kinematics->scale(), fb.kinematics->pT())) return true; } } // veto on maximum pt if(fb.kinematics->pT()>_progenitor->maximumpT(type)) return true; // general vetos if (fb.kinematics && !_vetoes.empty()) { bool vetoed=false; for (vector::iterator v = _vetoes.begin(); v != _vetoes.end(); ++v) { bool test = (**v).vetoTimeLike(_progenitor,particle,fb,currentTree()); switch((**v).vetoType()) { case ShowerVeto::Emission: vetoed |= test; break; case ShowerVeto::Shower: if(test) throw VetoShower(); break; case ShowerVeto::Event: if(test) throw Veto(); break; } } if(vetoed) return true; } if ( firstInteraction() && profileScales() ) { double weight = profileScales()-> hardScaleProfile(_progenitor->hardScale(),fb.kinematics->pT()); if ( UseRandom::rnd() > weight ) return true; } return false; } bool QTildeShowerHandler::spaceLikeVetoed(const Branching & bb, ShowerParticlePtr particle) { // work out type of interaction ShowerInteraction type = convertInteraction(bb.type); // check whether emission was harder than largest pt of hard subprocess if (restrictPhasespace() && bb.kinematics->pT() > _progenitor->maxHardPt()) return true; // apply the soft correction if( softMEC() && _hardme && _hardme->hasMECorrection() ) { if(_hardme->softMatrixElementVeto(particle, _progenitor->progenitor(), particle->isFinalState(), _progenitor->highestpT(), bb.ids, bb.kinematics->z(), bb.kinematics->scale(), bb.kinematics->pT())) return true; } // the more general vetos // check vs max pt for the shower if(bb.kinematics->pT()>_progenitor->maximumpT(type)) return true; if (!_vetoes.empty()) { bool vetoed=false; for (vector::iterator v = _vetoes.begin(); v != _vetoes.end(); ++v) { bool test = (**v).vetoSpaceLike(_progenitor,particle,bb,currentTree()); switch ((**v).vetoType()) { case ShowerVeto::Emission: vetoed |= test; break; case ShowerVeto::Shower: if(test) throw VetoShower(); break; case ShowerVeto::Event: if(test) throw Veto(); break; } } if (vetoed) return true; } if ( firstInteraction() && profileScales() ) { double weight = profileScales()-> hardScaleProfile(_progenitor->hardScale(),bb.kinematics->pT()); if ( UseRandom::rnd() > weight ) return true; } return false; } bool QTildeShowerHandler::spaceLikeDecayVetoed( const Branching & fb, ShowerParticlePtr particle) { // work out type of interaction ShowerInteraction type = convertInteraction(fb.type); // apply the soft correction if( softMEC() && _decayme && _decayme->hasMECorrection() ) { if(_decayme->softMatrixElementVeto(particle, _progenitor->progenitor(), particle->isFinalState(), _progenitor->highestpT(), fb.ids, fb.kinematics->z(), fb.kinematics->scale(), fb.kinematics->pT())) return true; } // veto on hardest pt in the shower if(fb.kinematics->pT()> _progenitor->maximumpT(type)) return true; // general vetos if (!_vetoes.empty()) { bool vetoed=false; for (vector::iterator v = _vetoes.begin(); v != _vetoes.end(); ++v) { bool test = (**v).vetoSpaceLike(_progenitor,particle,fb,currentTree()); switch((**v).vetoType()) { case ShowerVeto::Emission: vetoed |= test; break; case ShowerVeto::Shower: if(test) throw VetoShower(); break; case ShowerVeto::Event: if(test) throw Veto(); break; } if (vetoed) return true; } } return false; } void QTildeShowerHandler::hardestEmission(bool hard) { HardTreePtr ISRTree; // internal POWHEG in production or decay if( (( _hardme && _hardme->hasPOWHEGCorrection()!=0 ) || ( _decayme && _decayme->hasPOWHEGCorrection()!=0 ) ) ) { RealEmissionProcessPtr real; unsigned int type(0); // production if(_hardme) { assert(hard); real = _hardme->generateHardest( currentTree()->perturbativeProcess(), interaction_); type = _hardme->hasPOWHEGCorrection(); } // decay else { assert(!hard); real = _decayme->generateHardest( currentTree()->perturbativeProcess() ); type = _decayme->hasPOWHEGCorrection(); } if(real) { // set up ther hard tree if(!real->outgoing().empty()) _hardtree = new_ptr(HardTree(real)); // set up the vetos currentTree()->setVetoes(real->pT(),type); } // store initial state POWHEG radiation if(_hardtree && _hardme && _hardme->hasPOWHEGCorrection()==1) ISRTree = _hardtree; } else if (hard) { // Get minimum pT cutoff used in shower approximation Energy maxpt = 1.*GeV; if ( currentTree()->showerApproximation() ) { int colouredIn = 0; int colouredOut = 0; for( map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it = currentTree()->outgoingLines().begin(); it != currentTree()->outgoingLines().end(); ++it ) { if( it->second->coloured() ) ++colouredOut; } for( map< ShowerProgenitorPtr, ShowerParticlePtr >::iterator it = currentTree()->incomingLines().begin(); it != currentTree()->incomingLines().end(); ++it ) { if( it->second->coloured() ) ++colouredIn; } if ( currentTree()->showerApproximation()->ffPtCut() == currentTree()->showerApproximation()->fiPtCut() && currentTree()->showerApproximation()->ffPtCut() == currentTree()->showerApproximation()->iiPtCut() ) maxpt = currentTree()->showerApproximation()->ffPtCut(); else if ( colouredIn == 2 && colouredOut == 0 ) maxpt = currentTree()->showerApproximation()->iiPtCut(); else if ( colouredIn == 0 && colouredOut > 1 ) maxpt = currentTree()->showerApproximation()->ffPtCut(); else if ( colouredIn == 2 && colouredOut == 1 ) maxpt = min(currentTree()->showerApproximation()->iiPtCut(), currentTree()->showerApproximation()->fiPtCut()); else if ( colouredIn == 1 && colouredOut > 1 ) maxpt = min(currentTree()->showerApproximation()->ffPtCut(), currentTree()->showerApproximation()->fiPtCut()); else maxpt = min(min(currentTree()->showerApproximation()->iiPtCut(), currentTree()->showerApproximation()->fiPtCut()), currentTree()->showerApproximation()->ffPtCut()); } // Generate hardtree from born and real emission subprocesses _hardtree = generateCKKW(currentTree()); // Find transverse momentum of hardest emission if (_hardtree){ for(set::iterator it=_hardtree->branchings().begin(); it!=_hardtree->branchings().end();++it) { if ((*it)->parent() && (*it)->status()==HardBranching::Incoming) maxpt=(*it)->branchingParticle()->momentum().perp(); if ((*it)->children().size()==2 && (*it)->status()==HardBranching::Outgoing){ if ((*it)->branchingParticle()->id()!=21 && abs((*it)->branchingParticle()->id())>5 ){ if ((*it)->children()[0]->branchingParticle()->id()==21 || abs((*it)->children()[0]->branchingParticle()->id())<6) maxpt=(*it)->children()[0]->branchingParticle()->momentum().perp(); else if ((*it)->children()[1]->branchingParticle()->id()==21 || abs((*it)->children()[1]->branchingParticle()->id())<6) maxpt=(*it)->children()[1]->branchingParticle()->momentum().perp(); } else { if ( abs((*it)->branchingParticle()->id())<6){ if (abs((*it)->children()[0]->branchingParticle()->id())<6) maxpt = (*it)->children()[1]->branchingParticle()->momentum().perp(); else maxpt = (*it)->children()[0]->branchingParticle()->momentum().perp(); } else maxpt = (*it)->children()[1]->branchingParticle()->momentum().perp(); } } } } // Hardest (pt) emission should be the first powheg emission. maxpt=min(sqrt(lastXCombPtr()->lastShowerScale()),maxpt); // set maximum pT for subsequent emissions from S events if ( currentTree()->isPowhegSEvent() ) { for( map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it = currentTree()->outgoingLines().begin(); it != currentTree()->outgoingLines().end(); ++it ) { if( ! it->second->coloured() ) continue; it->first->maximumpT(maxpt, ShowerInteraction::QCD ); } for( map< ShowerProgenitorPtr, ShowerParticlePtr >::iterator it = currentTree()->incomingLines().begin(); it != currentTree()->incomingLines().end(); ++it ) { if( ! it->second->coloured() ) continue; it->first->maximumpT(maxpt, ShowerInteraction::QCD ); } } } else _hardtree = generateCKKW(currentTree()); // if hard me doesn't have a FSR powheg // correction use decay powheg correction if (_hardme && _hardme->hasPOWHEGCorrection()<2) { addFSRUsingDecayPOWHEG(ISRTree); } // connect the trees if(_hardtree) { connectTrees(currentTree(),_hardtree,hard); } } void QTildeShowerHandler::addFSRUsingDecayPOWHEG(HardTreePtr ISRTree) { // check for intermediate colour singlet resonance const ParticleVector inter = _hardme->subProcess()->intermediates(); if (inter.size()!=1 || inter[0]->momentum().m2()/GeV2 < 0 || inter[0]->dataPtr()->iColour()!=PDT::Colour0) { return; } // ignore cases where outgoing particles are not coloured map out = currentTree()->outgoingLines(); if (out.size() != 2 || out. begin()->second->dataPtr()->iColour()==PDT::Colour0 || out.rbegin()->second->dataPtr()->iColour()==PDT::Colour0) { return; } // look up decay mode tDMPtr dm; string tag; string inParticle = inter[0]->dataPtr()->name() + "->"; vector outParticles; outParticles.push_back(out.begin ()->first->progenitor()->dataPtr()->name()); outParticles.push_back(out.rbegin()->first->progenitor()->dataPtr()->name()); for (int it=0; it<2; ++it){ tag = inParticle + outParticles[it] + "," + outParticles[(it+1)%2] + ";"; dm = generator()->findDecayMode(tag); if(dm) break; } // get the decayer HwDecayerBasePtr decayer; if(dm) decayer = dynamic_ptr_cast(dm->decayer()); // check if decayer has a FSR POWHEG correction if (!decayer || decayer->hasPOWHEGCorrection()<2) { return; } // generate the hardest emission // create RealEmissionProcess PPtr in = new_ptr(*inter[0]); RealEmissionProcessPtr newProcess(new_ptr(RealEmissionProcess())); newProcess->bornIncoming().push_back(in); newProcess->bornOutgoing().push_back(out.begin ()->first->progenitor()); newProcess->bornOutgoing().push_back(out.rbegin()->first->progenitor()); // generate the FSR newProcess = decayer->generateHardest(newProcess); HardTreePtr FSRTree; if(newProcess) { // set up ther hard tree if(!newProcess->outgoing().empty()) FSRTree = new_ptr(HardTree(newProcess)); // set up the vetos currentTree()->setVetoes(newProcess->pT(),2); } if(!FSRTree) return; // if there is no ISRTree make _hardtree from FSRTree if (!ISRTree){ vector inBranch,hardBranch; for(map::const_iterator cit =currentTree()->incomingLines().begin(); cit!=currentTree()->incomingLines().end();++cit ) { inBranch.push_back(new_ptr(HardBranching(cit->second,SudakovPtr(), HardBranchingPtr(), HardBranching::Incoming))); inBranch.back()->beam(cit->first->original()->parents()[0]); hardBranch.push_back(inBranch.back()); } if(inBranch[0]->branchingParticle()->dataPtr()->coloured()) { inBranch[0]->colourPartner(inBranch[1]); inBranch[1]->colourPartner(inBranch[0]); } for(set::iterator it=FSRTree->branchings().begin(); it!=FSRTree->branchings().end();++it) { if((**it).branchingParticle()->id()!=in->id()) hardBranch.push_back(*it); } hardBranch[2]->colourPartner(hardBranch[3]); hardBranch[3]->colourPartner(hardBranch[2]); HardTreePtr newTree = new_ptr(HardTree(hardBranch,inBranch, ShowerInteraction::QCD)); _hardtree = newTree; } // Otherwise modify the ISRTree to include the emission in FSRTree else { vector FSROut, ISROut; set::iterator itFSR, itISR; // get outgoing particles for(itFSR =FSRTree->branchings().begin(); itFSR!=FSRTree->branchings().end();++itFSR){ if ((**itFSR).status()==HardBranching::Outgoing) FSROut.push_back((*itFSR)->branchingParticle()); } for(itISR =ISRTree->branchings().begin(); itISR!=ISRTree->branchings().end();++itISR){ if ((**itISR).status()==HardBranching::Outgoing) ISROut.push_back((*itISR)->branchingParticle()); } // find COM frame formed by outgoing particles LorentzRotation eventFrameFSR, eventFrameISR; eventFrameFSR = ((FSROut[0]->momentum()+FSROut[1]->momentum()).findBoostToCM()); eventFrameISR = ((ISROut[0]->momentum()+ISROut[1]->momentum()).findBoostToCM()); // find rotation between ISR and FSR frames int j=0; if (ISROut[0]->id()!=FSROut[0]->id()) j=1; eventFrameISR.rotateZ( (eventFrameFSR*FSROut[0]->momentum()).phi()- (eventFrameISR*ISROut[j]->momentum()).phi() ); eventFrameISR.rotateY( (eventFrameFSR*FSROut[0]->momentum()).theta()- (eventFrameISR*ISROut[j]->momentum()).theta() ); eventFrameISR.invert(); for (itFSR=FSRTree->branchings().begin(); itFSR!=FSRTree->branchings().end();++itFSR){ if ((**itFSR).branchingParticle()->id()==in->id()) continue; for (itISR =ISRTree->branchings().begin(); itISR!=ISRTree->branchings().end();++itISR){ if ((**itISR).status()==HardBranching::Incoming) continue; if ((**itFSR).branchingParticle()->id()== (**itISR).branchingParticle()->id()){ // rotate FSRTree particle to ISRTree event frame (**itISR).branchingParticle()->setMomentum(eventFrameISR* eventFrameFSR* (**itFSR).branchingParticle()->momentum()); (**itISR).branchingParticle()->rescaleMass(); // add the children of the FSRTree particles to the ISRTree if(!(**itFSR).children().empty()){ (**itISR).addChild((**itFSR).children()[0]); (**itISR).addChild((**itFSR).children()[1]); // rotate momenta to ISRTree event frame (**itISR).children()[0]->branchingParticle()->setMomentum(eventFrameISR* eventFrameFSR* (**itFSR).children()[0]->branchingParticle()->momentum()); (**itISR).children()[1]->branchingParticle()->setMomentum(eventFrameISR* eventFrameFSR* (**itFSR).children()[1]->branchingParticle()->momentum()); } } } } _hardtree = ISRTree; } } bool QTildeShowerHandler::truncatedTimeLikeShower(tShowerParticlePtr particle, HardBranchingPtr branch, ShowerInteraction type, Branching fb, bool first) { // select a branching if we don't have one if(!fb.kinematics) fb = selectTimeLikeBranching(particle,type,branch); // must be an emission, the forced one it not a truncated one assert(fb.kinematics); ShowerParticleVector children; Branching fc[2] = {Branching(),Branching()}; // Assign the shower kinematics to the emitting particle. particle->showerKinematics(fb.kinematics); if(fb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(fb.kinematics->pT()); // create the children children = createTimeLikeChildren(particle,fb.ids); // update the children particle->showerKinematics()-> updateChildren(particle, children,fb.type); // select branchings for children if(!fc[0].kinematics) { // select branching for first particle if(!fb.hard && fb.iout ==1 ) fc[0] = selectTimeLikeBranching(children[0],type,branch); else if(fb.hard && !branch->children()[0]->children().empty() ) fc[0] = selectTimeLikeBranching(children[0],type,branch->children()[0]); else fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr()); } // select branching for the second particle if(!fc[1].kinematics) { // select branching for first particle if(!fb.hard && fb.iout ==2 ) fc[1] = selectTimeLikeBranching(children[1],type,branch); else if(fb.hard && !branch->children()[1]->children().empty() ) fc[1] = selectTimeLikeBranching(children[1],type,branch->children()[1]); else fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr()); } // shower the first particle if(fc[0].kinematics) { // the parent has truncated emission and following line if(!fb.hard && fb.iout == 1) truncatedTimeLikeShower(children[0],branch,type,fc[0],false); // hard emission and subsquent hard emissions else if(fb.hard && !branch->children()[0]->children().empty() ) truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false); // normal shower else timeLikeShower(children[0],type,fc[0],false); } if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); // shower the second particle if(fc[1].kinematics) { // the parent has truncated emission and following line if(!fb.hard && fb.iout == 2) truncatedTimeLikeShower(children[1],branch,type,fc[1],false); // hard emission and subsquent hard emissions else if(fb.hard && !branch->children()[1]->children().empty() ) truncatedTimeLikeShower(children[1],branch->children()[1],type,fc[1],false); else timeLikeShower(children[1],type,fc[1],false); } if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); // branching has happened particle->showerKinematics()->updateParent(particle, children,_evolutionScheme,fb.type); if(first&&!children.empty()) particle->showerKinematics()->resetChildren(particle,children); if(particle->spinInfo()) particle->spinInfo()->develop(); // TODO NEED AN UPDATE HERE FOR RECONOPT!=0 ? return true; } bool QTildeShowerHandler::truncatedSpaceLikeShower(tShowerParticlePtr particle, PPtr beam, HardBranchingPtr branch, ShowerInteraction type) { tcPDFPtr pdf; if(firstPDF().particle() == beamParticle()) pdf = firstPDF().pdf(); if(secondPDF().particle() == beamParticle()) pdf = secondPDF().pdf(); Energy freeze = pdfFreezingScale(); Branching bb; // parameters of the force branching double z(0.); HardBranchingPtr timelike; for( unsigned int ix = 0; ix < branch->children().size(); ++ix ) { if( branch->children()[ix]->status() ==HardBranching::Outgoing) { timelike = branch->children()[ix]; } if( branch->children()[ix]->status() ==HardBranching::Incoming ) z = branch->children()[ix]->z(); } // generate truncated branching tcPDPtr part[2]; if(z>=0.&&z<=1.) { while (true) { if( !isTruncatedShowerON() || hardOnly() ) break; bb = splittingGenerator()->chooseBackwardBranching( *particle, beam, 1., beamParticle(), type , pdf,freeze); if( !bb.kinematics || bb.kinematics->scale() < branch->scale() ) { bb = Branching(); break; } // particles as in Sudakov form factor part[0] = bb.ids[0]; part[1] = bb.ids[2]; double zsplit = bb.kinematics->z(); // apply the vetos for the truncated shower // if doesn't carry most of momentum ShowerInteraction type2 = convertInteraction(bb.type); if(type2==branch->sudakov()->interactionType() && zsplit < 0.5) { particle->vetoEmission(bb.type,bb.kinematics->scale()); continue; } // others if( part[0]->id() != particle->id() || // if particle changes type bb.kinematics->pT() > progenitor()->maximumpT(type2) || // pt veto bb.kinematics->scale() < branch->scale()) { // angular ordering veto particle->vetoEmission(bb.type,bb.kinematics->scale()); continue; } // and those from the base class if(spaceLikeVetoed(bb,particle)) { particle->vetoEmission(bb.type,bb.kinematics->scale()); continue; } break; } } if( !bb.kinematics ) { //do the hard emission ShoKinPtr kinematics = new_ptr(IS_QTildeShowerKinematics1to2( branch->scale(), z, branch->phi(), branch->children()[0]->pT(), branch->sudakov() )); // assign the splitting function and shower kinematics particle->showerKinematics( kinematics ); if(kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(kinematics->pT()); // For the time being we are considering only 1->2 branching // Now create the actual particles, make the otherChild a final state // particle, while the newParent is not ShowerParticlePtr newParent = new_ptr( ShowerParticle( branch->branchingParticle()->dataPtr(), false ) ); ShowerParticlePtr otherChild = new_ptr( ShowerParticle( timelike->branchingParticle()->dataPtr(), true, true ) ); ShowerParticleVector theChildren; theChildren.push_back( particle ); theChildren.push_back( otherChild ); particle->showerKinematics()-> updateParent( newParent, theChildren,_evolutionScheme, branch->type()); // update the history if needed currentTree()->updateInitialStateShowerProduct( progenitor(), newParent ); currentTree()->addInitialStateBranching( particle, newParent, otherChild ); // for the reconstruction of kinematics, parent/child // relationships are according to the branching process: // now continue the shower bool emitted=false; if(!hardOnly()) { if( branch->parent() ) { emitted = truncatedSpaceLikeShower( newParent, beam, branch->parent() , type); } else { emitted = spaceLikeShower( newParent, beam , type); } } if( !emitted ) { if( intrinsicpT().find( progenitor() ) == intrinsicpT().end() ) { kinematics->updateLast( newParent, ZERO, ZERO ); } else { pair kt = intrinsicpT()[progenitor()]; kinematics->updateLast( newParent, kt.first*cos( kt.second ), kt.first*sin( kt.second ) ); } } particle->showerKinematics()-> updateChildren( newParent, theChildren,bb.type); if(hardOnly()) return true; // perform the shower of the final-state particle if( timelike->children().empty() ) { timeLikeShower( otherChild , type,Branching(),true); } else { truncatedTimeLikeShower( otherChild, timelike , type,Branching(), true); } updateHistory(otherChild); // return the emitted return true; } // assign the splitting function and shower kinematics particle->showerKinematics( bb.kinematics ); if(bb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(bb.kinematics->pT()); // For the time being we are considering only 1->2 branching // Now create the actual particles, make the otherChild a final state // particle, while the newParent is not ShowerParticlePtr newParent = new_ptr( ShowerParticle( part[0], false ) ); ShowerParticlePtr otherChild = new_ptr( ShowerParticle( part[1], true, true ) ); ShowerParticleVector theChildren; theChildren.push_back( particle ); theChildren.push_back( otherChild ); particle->showerKinematics()-> updateParent( newParent, theChildren,_evolutionScheme, bb.type); // update the history if needed currentTree()->updateInitialStateShowerProduct( progenitor(), newParent ); currentTree()->addInitialStateBranching( particle, newParent, otherChild ); // for the reconstruction of kinematics, parent/child // relationships are according to the branching process: // now continue the shower bool emitted = truncatedSpaceLikeShower( newParent, beam, branch,type); // now reconstruct the momentum if( !emitted ) { if( intrinsicpT().find( progenitor() ) == intrinsicpT().end() ) { bb.kinematics->updateLast( newParent, ZERO, ZERO ); } else { pair kt = intrinsicpT()[ progenitor() ]; bb.kinematics->updateLast( newParent, kt.first*cos( kt.second ), kt.first*sin( kt.second ) ); } } particle->showerKinematics()-> updateChildren( newParent, theChildren, bb.type); // perform the shower of the final-state particle timeLikeShower( otherChild , type,Branching(),true); updateHistory(otherChild); // return the emitted return true; } bool QTildeShowerHandler:: truncatedSpaceLikeDecayShower(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minmass, HardBranchingPtr branch, ShowerInteraction type, Branching fb) { // select a branching if we don't have one if(!fb.kinematics) fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type,branch); // must be an emission, the forced one it not a truncated one assert(fb.kinematics); ShowerParticleVector children; Branching fc[2]={Branching(),Branching()}; // Assign the shower kinematics to the emitting particle. particle->showerKinematics(fb.kinematics); if(fb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(fb.kinematics->pT()); // create the ShowerParticle objects for the two children children = createTimeLikeChildren(particle,fb.ids); // updateChildren the children particle->showerKinematics()-> updateChildren(particle, children, fb.type); // select branchings for children if(!fc[0].kinematics) { if(children[0]->id()==particle->id()) { // select branching for first particle if(!fb.hard) fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type,branch); else if(fb.hard && ! branch->children()[0]->children().empty() ) fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type, branch->children()[0]); else fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type, HardBranchingPtr()); } else { // select branching for first particle if(fb.hard && !branch->children()[0]->children().empty() ) fc[0] = selectTimeLikeBranching(children[0],type,branch->children()[0]); else fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr()); } } // select branching for the second particle if(!fc[1].kinematics) { if(children[1]->id()==particle->id()) { // select branching for first particle if(!fb.hard) fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type,branch); else if(fb.hard && ! branch->children()[1]->children().empty() ) fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type, branch->children()[1]); else fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type, HardBranchingPtr()); } else { if(fb.hard && !branch->children()[1]->children().empty() ) fc[1] = selectTimeLikeBranching(children[1],type,branch->children()[1]); else fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr()); } } // old default // update the history if needed currentTree()->updateInitialStateShowerProduct(progenitor(),children[0]); currentTree()->addInitialStateBranching(particle,children[0],children[1]); // shower the first particle if(fc[0].kinematics) { if(children[0]->id()==particle->id()) { if(!fb.hard) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch,type,fc[0]); else if(fb.hard && ! branch->children()[0]->children().empty() ) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch->children()[0],type,fc[0]); else spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[0]); } else { if(fb.hard && !branch->children()[0]->children().empty() ) truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false); // normal shower else timeLikeShower(children[0],type,fc[0],false); } } // shower the second particle if(fc[1].kinematics) { if(children[0]->id()==particle->id()) { if(!fb.hard) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch,type,fc[1]); else if(fb.hard && ! branch->children()[0]->children().empty() ) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch->children()[0],type,fc[1]); else spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[1]); } else { if(fb.hard && !branch->children()[0]->children().empty() ) truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[1],false); // normal shower else timeLikeShower(children[0],type,fc[1],false); } } updateHistory(children[1]); // TODO DO WE NEED A CHECK IF RECONPT !=0 return true; } void QTildeShowerHandler::connectTrees(ShowerTreePtr showerTree, HardTreePtr hardTree, bool hard ) { ShowerParticleVector particles; // find the Sudakovs for(set::iterator cit=hardTree->branchings().begin(); cit!=hardTree->branchings().end();++cit) { // Sudakovs for ISR if((**cit).parent()&&(**cit).status()==HardBranching::Incoming) { ++_nis; array br; br[0] = (**cit).parent()->branchingParticle()->id(); br[1] = (**cit). branchingParticle()->id(); br[2] = (**cit).parent()->children()[0]==*cit ? (**cit).parent()->children()[1]->branchingParticle()->id() : (**cit).parent()->children()[0]->branchingParticle()->id(); BranchingList branchings = splittingGenerator()->initialStateBranchings(); if(br[1]<0&&br[0]==br[1]) { br[0] = abs(br[0]); br[1] = abs(br[1]); } else if(br[1]<0) { br[1] = -br[1]; br[2] = -br[2]; } long index = abs(br[1]); SudakovPtr sudakov; for(BranchingList::const_iterator cjt = branchings.lower_bound(index); cjt != branchings.upper_bound(index); ++cjt ) { IdList ids = cjt->second.particles; if(ids[0]->id()==br[0]&&ids[1]->id()==br[1]&&ids[2]->id()==br[2]) { sudakov=cjt->second.sudakov; break; } } if(!sudakov) throw Exception() << "Can't find Sudakov for the hard emission in " << "QTildeShowerHandler::connectTrees() for ISR" << Exception::runerror; (**cit).parent()->sudakov(sudakov); } // Sudakovs for FSR else if(!(**cit).children().empty()) { ++_nfs; array br; br[0] = (**cit) .branchingParticle()->id(); br[1] = (**cit).children()[0]->branchingParticle()->id(); br[2] = (**cit).children()[1]->branchingParticle()->id(); BranchingList branchings = splittingGenerator()->finalStateBranchings(); if(br[0]<0) { br[0] = abs(br[0]); br[1] = abs(br[1]); br[2] = abs(br[2]); } long index = br[0]; SudakovPtr sudakov; for(BranchingList::const_iterator cjt = branchings.lower_bound(index); cjt != branchings.upper_bound(index); ++cjt ) { IdList ids = cjt->second.particles; if(ids[0]->id()==br[0]&&ids[1]->id()==br[1]&&ids[2]->id()==br[2]) { sudakov=cjt->second.sudakov; break; } } if(!sudakov) { throw Exception() << "Can't find Sudakov for the hard emission in " << "QTildeShowerHandler::connectTrees()" << Exception::runerror; } (**cit).sudakov(sudakov); } } // calculate the evolution scale for(set::iterator cit=hardTree->branchings().begin(); cit!=hardTree->branchings().end();++cit) { particles.push_back((*cit)->branchingParticle()); } partnerFinder()-> setInitialEvolutionScales(particles,!hard,interaction_,true); hardTree->partnersSet(true); // inverse reconstruction if(hard) { kinematicsReconstructor()-> deconstructHardJets(hardTree,interaction_); } else kinematicsReconstructor()-> deconstructDecayJets(hardTree,interaction_); // now reset the momenta of the showering particles vector particlesToShower=showerTree->extractProgenitors(); // match them map partners; for(set::const_iterator bit=hardTree->branchings().begin(); bit!=hardTree->branchings().end();++bit) { Energy2 dmin( 1e30*GeV2 ); ShowerProgenitorPtr partner; for(vector::const_iterator pit=particlesToShower.begin(); pit!=particlesToShower.end();++pit) { if(partners.find(*pit)!=partners.end()) continue; if( (**bit).branchingParticle()->id() != (**pit).progenitor()->id() ) continue; if( (**bit).branchingParticle()->isFinalState() != (**pit).progenitor()->isFinalState() ) continue; if( (**pit).progenitor()->isFinalState() ) { Energy2 dtest = sqr( (**pit).progenitor()->momentum().x() - (**bit).showerMomentum().x() ) + sqr( (**pit).progenitor()->momentum().y() - (**bit).showerMomentum().y() ) + sqr( (**pit).progenitor()->momentum().z() - (**bit).showerMomentum().z() ) + sqr( (**pit).progenitor()->momentum().t() - (**bit).showerMomentum().t() ); // add mass difference for identical particles (e.g. Z0 Z0 production) dtest += 1e10*sqr((**pit).progenitor()->momentum().m()-(**bit).showerMomentum().m()); if( dtest < dmin ) { partner = *pit; dmin = dtest; } } else { // ensure directions are right if((**pit).progenitor()->momentum().z()/(**bit).showerMomentum().z()>ZERO) { partner = *pit; break; } } } if(!partner) throw Exception() << "Failed to match shower and hard trees in QTildeShowerHandler::hardestEmission" << Exception::eventerror; partners[partner] = *bit; } for(vector::const_iterator pit=particlesToShower.begin(); pit!=particlesToShower.end();++pit) { HardBranchingPtr partner = partners[*pit]; if((**pit).progenitor()->dataPtr()->stable()) { (**pit).progenitor()->set5Momentum(partner->showerMomentum()); (**pit).copy()->set5Momentum(partner->showerMomentum()); } else { Lorentz5Momentum oldMomentum = (**pit).progenitor()->momentum(); Lorentz5Momentum newMomentum = partner->showerMomentum(); LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass()); (**pit).progenitor()->transform(boost); (**pit).copy() ->transform(boost); boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass()); (**pit).progenitor()->transform(boost); (**pit).copy() ->transform(boost); } } // correction boosts for daughter trees for(map >::const_iterator tit = showerTree->treelinks().begin(); tit != showerTree->treelinks().end();++tit) { ShowerTreePtr decayTree = tit->first; map::const_iterator cit = decayTree->incomingLines().begin(); // reset the momentum of the decay particle Lorentz5Momentum oldMomentum = cit->first->progenitor()->momentum(); Lorentz5Momentum newMomentum = tit->second.second->momentum(); LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass()); decayTree->transform(boost,true); boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass()); decayTree->transform(boost,true); } } void QTildeShowerHandler::doShowering(bool hard,XCPtr xcomb) { // zero number of emissions _nis = _nfs = 0; // if MC@NLO H event and limited emissions // indicate both final and initial state emission if ( currentTree()->isMCatNLOHEvent() && _limitEmissions != 0 ) { _nis = _nfs = 1; } // extract particles to shower vector particlesToShower(setupShower(hard)); // check if we should shower bool colCharge = false; for(unsigned int ix=0;ixprogenitor()->dataPtr()->coloured() || particlesToShower[ix]->progenitor()->dataPtr()->charged()) { colCharge = true; break; } } if(!colCharge) { _currenttree->hasShowered(true); return; } // setup the maximum scales for the shower if (restrictPhasespace()) setupMaximumScales(particlesToShower,xcomb); // set the hard scales for the profiles setupHardScales(particlesToShower,xcomb); // specific stuff for hard processes and decays Energy minmass(ZERO), mIn(ZERO); // hard process generate the intrinsic p_T once and for all bool minBias = dynamic_ptr_cast::ptr>(_hardme); if(hard) { _intrinsic.clear(); if(!minBias) generateIntrinsicpT(particlesToShower); } // decay compute the minimum mass of the final-state else { for(unsigned int ix=0;ixprogenitor()->isFinalState()) { - if(particlesToShower[ix]->progenitor()->dataPtr()->stable()){ + if(particlesToShower[ix]->progenitor()->dataPtr()->stable()) { auto dm= ShowerHandler::currentHandler()->retConstituentMasses()? - particlesToShower[ix]->progenitor()->dataPtr()->constituentMass(): - particlesToShower[ix]->progenitor()->dataPtr()->mass(); + particlesToShower[ix]->progenitor()->dataPtr()->constituentMass(): + particlesToShower[ix]->progenitor()->dataPtr()->mass(); minmass += dm; - }else + } + else minmass += particlesToShower[ix]->progenitor()->mass(); } else { mIn = particlesToShower[ix]->progenitor()->mass(); } } // throw exception if decay can't happen if ( minmass > mIn ) { throw Exception() << "QTildeShowerHandler.cc: Mass of decaying particle is " << "below constituent masses of decay products." << Exception::eventerror; } } // setup for reweighted bool reWeighting = _reWeight && hard && ShowerHandler::currentHandler()->firstInteraction(); double eventWeight=0.; unsigned int nTryReWeight(0); // create random particle vector (only need to do once) vector tmp; unsigned int nColouredIncoming = 0; while(particlesToShower.size()>0){ unsigned int xx=UseRandom::irnd(particlesToShower.size()); tmp.push_back(particlesToShower[xx]); particlesToShower.erase(particlesToShower.begin()+xx); } particlesToShower=tmp; for(unsigned int ix=0;ixprogenitor()->isFinalState() && particlesToShower[ix]->progenitor()->coloured()) ++nColouredIncoming; } bool switchRecon = hard && nColouredIncoming !=1; // main shower loop unsigned int ntry(0); bool reconstructed = false; do { // type of recon to use bool generalRecon = minBias >> (switchRecon && ntry>maximumTries()/2); // clear results of last attempt if needed if(ntry!=0) { currentTree()->clear(); setEvolutionPartners(hard,interaction_,true); _nis = _nfs = 0; // if MC@NLO H event and limited emissions // indicate both final and initial state emission if ( currentTree()->isMCatNLOHEvent() && _limitEmissions != 0 ) { _nis = _nfs = 1; } for(unsigned int ix=0; ixprogenitor()->spinInfo(); if(spin && spin->decayVertex() && dynamic_ptr_cast(spin->decayVertex())) { spin->decayVertex(VertexPtr()); } } for(unsigned int ix=0;ixprogenitor()->isFinalState() || (hard && !particlesToShower[ix]->progenitor()->isFinalState())) { if(particlesToShower[ix]->progenitor()->spinInfo()) particlesToShower[ix]->progenitor()->spinInfo()->reset(); } } } // loop over particles for(unsigned int ix=0;ixprogenitor()->isFinalState()) { if(!doFSR()) continue; // perform shower progenitor()->hasEmitted(startTimeLikeShower(interaction_)); } // initial-state radiation else { if(!doISR()) continue; // hard process if(hard) { // get the PDF setBeamParticle(_progenitor->beam()); if(!beamParticle()) { throw Exception() << "Incorrect type of beam particle in " << "QTildeShowerHandler::doShowering(). " << "This should not happen for conventional choices but may happen if you have used a" << " non-default choice and have not changed the create ParticleData line in the input files" << " for this particle to create BeamParticleData." << Exception::runerror; } // perform the shower // set the beam particle tPPtr beamparticle=progenitor()->original(); if(!beamparticle->parents().empty()) beamparticle=beamparticle->parents()[0]; // generate the shower progenitor()->hasEmitted(startSpaceLikeShower(beamparticle, interaction_)); } // decay else { // skip colour and electrically neutral particles if(!progenitor()->progenitor()->dataPtr()->coloured() && !progenitor()->progenitor()->dataPtr()->charged()) { progenitor()->hasEmitted(false); continue; } // perform shower // set the scales correctly. The current scale is the maximum scale for // emission not the starting scale ShowerParticle::EvolutionScales maxScales(progenitor()->progenitor()->scales()); progenitor()->progenitor()->scales() = ShowerParticle::EvolutionScales(); if(progenitor()->progenitor()->dataPtr()->charged()) { progenitor()->progenitor()->scales().QED = progenitor()->progenitor()->mass(); progenitor()->progenitor()->scales().QED_noAO = progenitor()->progenitor()->mass(); } if(progenitor()->progenitor()->hasColour()) { progenitor()->progenitor()->scales().QCD_c = progenitor()->progenitor()->mass(); progenitor()->progenitor()->scales().QCD_c_noAO = progenitor()->progenitor()->mass(); } if(progenitor()->progenitor()->hasAntiColour()) { progenitor()->progenitor()->scales().QCD_ac = progenitor()->progenitor()->mass(); progenitor()->progenitor()->scales().QCD_ac_noAO = progenitor()->progenitor()->mass(); } // perform the shower progenitor()->hasEmitted(startSpaceLikeDecayShower(maxScales,minmass, interaction_)); } } } // do the kinematic reconstruction, checking if it worked reconstructed = hard ? kinematicsReconstructor()-> reconstructHardJets (currentTree(),intrinsicpT(),interaction_,generalRecon) : kinematicsReconstructor()-> reconstructDecayJets(currentTree(),interaction_); if(!reconstructed) continue; // apply vetos on the full shower for(vector::const_iterator it=_fullShowerVetoes.begin(); it!=_fullShowerVetoes.end();++it) { int veto = (**it).applyVeto(currentTree()); if(veto<0) continue; // veto the shower if(veto==0) { reconstructed = false; break; } // veto the shower and reweight else if(veto==1) { reconstructed = false; break; } // veto the event else if(veto==2) { throw Veto(); } } if(reWeighting) { if(reconstructed) eventWeight += 1.; reconstructed=false; ++nTryReWeight; if(nTryReWeight==_nReWeight) { reWeighting = false; if(eventWeight==0.) throw Veto(); } } } while(!reconstructed&&maximumTries()>++ntry); // check if failed to generate the shower if(ntry==maximumTries()) { if(hard) throw ShowerHandler::ShowerTriesVeto(ntry); else throw Exception() << "Failed to generate the shower after " << ntry << " attempts in QTildeShowerHandler::showerDecay()" << Exception::eventerror; } // handle the weights and apply any reweighting required if(nTryReWeight>0) { tStdEHPtr seh = dynamic_ptr_cast(generator()->currentEventHandler()); static bool first = true; if(seh) { seh->reweight(eventWeight/double(nTryReWeight)); } else if(first) { generator()->log() << "Reweighting the shower only works with internal Herwig7 processes" << "Presumably you are showering Les Houches Events. These will not be" << "reweighted\n"; first = false; } } // tree has now showered _currenttree->hasShowered(true); hardTree(HardTreePtr()); } void QTildeShowerHandler:: convertHardTree(bool hard,ShowerInteraction type) { map cmap; // incoming particles for(map::const_iterator cit=currentTree()->incomingLines().begin();cit!=currentTree()->incomingLines().end();++cit) { map::const_iterator mit = hardTree()->particles().find(cit->first->progenitor()); // put the colour lines in the map ShowerParticlePtr oldParticle = cit->first->progenitor(); ShowerParticlePtr newParticle = mit->second->branchingParticle(); ColinePtr cLine = oldParticle-> colourLine(); ColinePtr aLine = oldParticle->antiColourLine(); if(newParticle->colourLine() && cmap.find(newParticle-> colourLine())==cmap.end()) cmap[newParticle-> colourLine()] = cLine; if(newParticle->antiColourLine() && cmap.find(newParticle->antiColourLine())==cmap.end()) cmap[newParticle->antiColourLine()] = aLine; // check whether or not particle emits bool emission = mit->second->parent(); if(emission) { if(newParticle->colourLine()) { ColinePtr ctemp = newParticle-> colourLine(); ctemp->removeColoured(newParticle); } if(newParticle->antiColourLine()) { ColinePtr ctemp = newParticle->antiColourLine(); ctemp->removeAntiColoured(newParticle); } newParticle = mit->second->parent()->branchingParticle(); } // get the new colour lines ColinePtr newCLine,newALine; // sort out colour lines if(newParticle->colourLine()) { ColinePtr ctemp = newParticle-> colourLine(); ctemp->removeColoured(newParticle); if(cmap.find(ctemp)!=cmap.end()) { newCLine = cmap[ctemp]; } else { newCLine = new_ptr(ColourLine()); cmap[ctemp] = newCLine; } } // and anticolour lines if(newParticle->antiColourLine()) { ColinePtr ctemp = newParticle->antiColourLine(); ctemp->removeAntiColoured(newParticle); if(cmap.find(ctemp)!=cmap.end()) { newALine = cmap[ctemp]; } else { newALine = new_ptr(ColourLine()); cmap[ctemp] = newALine; } } // remove colour lines from old particle if(aLine) { aLine->removeAntiColoured(cit->first->copy()); aLine->removeAntiColoured(cit->first->progenitor()); } if(cLine) { cLine->removeColoured(cit->first->copy()); cLine->removeColoured(cit->first->progenitor()); } // add particle to colour lines if(newCLine) newCLine->addColoured (newParticle); if(newALine) newALine->addAntiColoured(newParticle); // insert new particles cit->first->copy(newParticle); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newParticle,1,false))); cit->first->progenitor(sp); currentTree()->incomingLines()[cit->first]=sp; cit->first->perturbative(!emission); // and the emitted particle if needed if(emission) { ShowerParticlePtr newOut = mit->second->parent()->children()[1]->branchingParticle(); if(newOut->colourLine()) { ColinePtr ctemp = newOut-> colourLine(); ctemp->removeColoured(newOut); assert(cmap.find(ctemp)!=cmap.end()); cmap[ctemp]->addColoured (newOut); } if(newOut->antiColourLine()) { ColinePtr ctemp = newOut->antiColourLine(); ctemp->removeAntiColoured(newOut); assert(cmap.find(ctemp)!=cmap.end()); cmap[ctemp]->addAntiColoured(newOut); } ShowerParticlePtr sout=new_ptr(ShowerParticle(*newOut,1,true)); ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(cit->first->original(),newOut,sout)); out->perturbative(false); currentTree()->outgoingLines().insert(make_pair(out,sout)); } if(hard) { // sort out the value of x if(mit->second->beam()->momentum().z()>ZERO) { sp->x(newParticle->momentum(). plus()/mit->second->beam()->momentum(). plus()); } else { sp->x(newParticle->momentum().minus()/mit->second->beam()->momentum().minus()); } } } // outgoing particles for(map::const_iterator cit=currentTree()->outgoingLines().begin();cit!=currentTree()->outgoingLines().end();++cit) { map >::const_iterator tit; for(tit = currentTree()->treelinks().begin(); tit != currentTree()->treelinks().end();++tit) { if(tit->second.first && tit->second.second==cit->first->progenitor()) break; } map::const_iterator mit = hardTree()->particles().find(cit->first->progenitor()); if(mit==hardTree()->particles().end()) continue; // put the colour lines in the map ShowerParticlePtr oldParticle = cit->first->progenitor(); ShowerParticlePtr newParticle = mit->second->branchingParticle(); ShowerParticlePtr newOut; ColinePtr cLine = oldParticle-> colourLine(); ColinePtr aLine = oldParticle->antiColourLine(); if(newParticle->colourLine() && cmap.find(newParticle-> colourLine())==cmap.end()) cmap[newParticle-> colourLine()] = cLine; if(newParticle->antiColourLine() && cmap.find(newParticle->antiColourLine())==cmap.end()) cmap[newParticle->antiColourLine()] = aLine; // check whether or not particle emits bool emission = !mit->second->children().empty(); if(emission) { if(newParticle->colourLine()) { ColinePtr ctemp = newParticle-> colourLine(); ctemp->removeColoured(newParticle); } if(newParticle->antiColourLine()) { ColinePtr ctemp = newParticle->antiColourLine(); ctemp->removeAntiColoured(newParticle); } newParticle = mit->second->children()[0]->branchingParticle(); newOut = mit->second->children()[1]->branchingParticle(); if(newParticle->id()!=oldParticle->id()&&newParticle->id()==newOut->id()) swap(newParticle,newOut); } // get the new colour lines ColinePtr newCLine,newALine; // sort out colour lines if(newParticle->colourLine()) { ColinePtr ctemp = newParticle-> colourLine(); ctemp->removeColoured(newParticle); if(cmap.find(ctemp)!=cmap.end()) { newCLine = cmap[ctemp]; } else { newCLine = new_ptr(ColourLine()); cmap[ctemp] = newCLine; } } // and anticolour lines if(newParticle->antiColourLine()) { ColinePtr ctemp = newParticle->antiColourLine(); ctemp->removeAntiColoured(newParticle); if(cmap.find(ctemp)!=cmap.end()) { newALine = cmap[ctemp]; } else { newALine = new_ptr(ColourLine()); cmap[ctemp] = newALine; } } // remove colour lines from old particle if(aLine) { aLine->removeAntiColoured(cit->first->copy()); aLine->removeAntiColoured(cit->first->progenitor()); } if(cLine) { cLine->removeColoured(cit->first->copy()); cLine->removeColoured(cit->first->progenitor()); } // special for unstable particles if(newParticle->id()==oldParticle->id() && (tit!=currentTree()->treelinks().end()||!oldParticle->dataPtr()->stable())) { Lorentz5Momentum oldMomentum = oldParticle->momentum(); Lorentz5Momentum newMomentum = newParticle->momentum(); LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass()); if(tit!=currentTree()->treelinks().end()) tit->first->transform(boost,false); oldParticle->transform(boost); boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass()); oldParticle->transform(boost); if(tit!=currentTree()->treelinks().end()) tit->first->transform(boost,false); newParticle=oldParticle; } // add particle to colour lines if(newCLine) newCLine->addColoured (newParticle); if(newALine) newALine->addAntiColoured(newParticle); // insert new particles cit->first->copy(newParticle); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newParticle,1,true))); cit->first->progenitor(sp); currentTree()->outgoingLines()[cit->first]=sp; cit->first->perturbative(!emission); // and the emitted particle if needed if(emission) { if(newOut->colourLine()) { ColinePtr ctemp = newOut-> colourLine(); ctemp->removeColoured(newOut); assert(cmap.find(ctemp)!=cmap.end()); cmap[ctemp]->addColoured (newOut); } if(newOut->antiColourLine()) { ColinePtr ctemp = newOut->antiColourLine(); ctemp->removeAntiColoured(newOut); assert(cmap.find(ctemp)!=cmap.end()); cmap[ctemp]->addAntiColoured(newOut); } ShowerParticlePtr sout=new_ptr(ShowerParticle(*newOut,1,true)); ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(cit->first->original(),newOut,sout)); out->perturbative(false); currentTree()->outgoingLines().insert(make_pair(out,sout)); } // update any decay products if(tit!=currentTree()->treelinks().end()) currentTree()->updateLink(tit->first,make_pair(cit->first,sp)); } // reset the tree currentTree()->resetShowerProducts(); // reextract the particles and set the colour partners vector particles = currentTree()->extractProgenitorParticles(); // clear the partners for(unsigned int ix=0;ixpartner(ShowerParticlePtr()); particles[ix]->clearPartners(); } // clear the tree hardTree(HardTreePtr()); // Set the initial evolution scales partnerFinder()-> setInitialEvolutionScales(particles,!hard,type,!_hardtree); } Branching QTildeShowerHandler::selectTimeLikeBranching(tShowerParticlePtr particle, ShowerInteraction type, HardBranchingPtr branch) { Branching fb; unsigned int iout=0; while (true) { // break if doing truncated shower and no truncated shower needed if(branch && (!isTruncatedShowerON()||hardOnly())) break; fb=_splittingGenerator->chooseForwardBranching(*particle,_finalenhance,type); // no emission break if(!fb.kinematics) break; // special for truncated shower if(branch) { // check haven't evolved too far if(fb.kinematics->scale() < branch->scale()) { fb=Branching(); break; } // find the truncated line iout=0; if(fb.ids[1]->id()!=fb.ids[2]->id()) { if(fb.ids[1]->id()==particle->id()) iout=1; else if (fb.ids[2]->id()==particle->id()) iout=2; } else if(fb.ids[1]->id()==particle->id()) { if(fb.kinematics->z()>0.5) iout=1; else iout=2; } // apply the vetos for the truncated shower // no flavour changing branchings if(iout==0) { particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } double zsplit = iout==1 ? fb.kinematics->z() : 1-fb.kinematics->z(); // only if same interaction for forced branching ShowerInteraction type2 = convertInteraction(fb.type); // and evolution if(type2==branch->sudakov()->interactionType()) { if(zsplit < 0.5 || // hardest line veto fb.kinematics->scale()*zsplit < branch->scale() ) { // angular ordering veto particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } } // pt veto if(fb.kinematics->pT() > progenitor()->maximumpT(type2)) { particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } } // standard vetos for all emissions if(timeLikeVetoed(fb,particle)) { particle->vetoEmission(fb.type,fb.kinematics->scale()); if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr()); continue; } // special for already decayed particles // don't allow flavour changing branchings bool vetoDecay = false; for(map >::const_iterator tit = currentTree()->treelinks().begin(); tit != currentTree()->treelinks().end();++tit) { if(tit->second.first == progenitor()) { map::const_iterator it = currentTree()->outgoingLines().find(progenitor()); if(it!=currentTree()->outgoingLines().end() && particle == it->second && fb.ids[0]!=fb.ids[1] && fb.ids[1]!=fb.ids[2]) { vetoDecay = true; break; } } } if(vetoDecay) { particle->vetoEmission(fb.type,fb.kinematics->scale()); if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr()); continue; } break; } // normal case if(!branch) { if(fb.kinematics) fb.hard = false; return fb; } // truncated emission if(fb.kinematics) { fb.hard = false; fb.iout = iout; return fb; } // otherwise need to return the hard emission // construct the kinematics for the hard emission ShoKinPtr showerKin = new_ptr(FS_QTildeShowerKinematics1to2( branch->scale(), branch->children()[0]->z(), branch->phi(), branch->children()[0]->pT(), branch->sudakov() )); IdList idlist(3); idlist[0] = particle->dataPtr(); idlist[1] = branch->children()[0]->branchingParticle()->dataPtr(); idlist[2] = branch->children()[1]->branchingParticle()->dataPtr(); fb = Branching( showerKin, idlist, branch->sudakov(),branch->type() ); fb.hard = true; fb.iout=0; // return it return fb; } Branching QTildeShowerHandler::selectSpaceLikeDecayBranching(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minmass,ShowerInteraction type, HardBranchingPtr branch) { Branching fb; unsigned int iout=0; while (true) { // break if doing truncated shower and no truncated shower needed if(branch && (!isTruncatedShowerON()||hardOnly())) break; // select branching fb=_splittingGenerator->chooseDecayBranching(*particle,maxScales,minmass, _initialenhance,type); // return if no radiation if(!fb.kinematics) break; // special for truncated shower if(branch) { // check haven't evolved too far if(fb.kinematics->scale() < branch->scale()) { fb=Branching(); break; } // find the truncated line iout=0; if(fb.ids[1]->id()!=fb.ids[2]->id()) { if(fb.ids[1]->id()==particle->id()) iout=1; else if (fb.ids[2]->id()==particle->id()) iout=2; } else if(fb.ids[1]->id()==particle->id()) { if(fb.kinematics->z()>0.5) iout=1; else iout=2; } // apply the vetos for the truncated shower // no flavour changing branchings if(iout==0) { particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } ShowerInteraction type2 = convertInteraction(fb.type); double zsplit = iout==1 ? fb.kinematics->z() : 1-fb.kinematics->z(); if(type2==branch->sudakov()->interactionType()) { if(zsplit < 0.5 || // hardest line veto fb.kinematics->scale()*zsplit < branch->scale() ) { // angular ordering veto particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } } // pt veto if(fb.kinematics->pT() > progenitor()->maximumpT(type2)) { particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } } // if not vetoed break if(spaceLikeDecayVetoed(fb,particle)) { // otherwise reset scale and continue particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } break; } // normal case if(!branch) { if(fb.kinematics) fb.hard = false; return fb; } // truncated emission if(fb.kinematics) { fb.hard = false; fb.iout = iout; return fb; } // otherwise need to return the hard emission // construct the kinematics for the hard emission ShoKinPtr showerKin = new_ptr(Decay_QTildeShowerKinematics1to2( branch->scale(), branch->children()[0]->z(), branch->phi(), branch->children()[0]->pT(), branch->sudakov())); IdList idlist(3); idlist[0] = particle->dataPtr(); idlist[1] = branch->children()[0]->branchingParticle()->dataPtr(); idlist[2] = branch->children()[1]->branchingParticle()->dataPtr(); // create the branching fb = Branching( showerKin, idlist, branch->sudakov(),ShowerPartnerType::QCDColourLine ); fb.hard=true; fb.iout=0; // return it return fb; } void QTildeShowerHandler::checkFlags() { string error = "Inconsistent hard emission set-up in QTildeShowerHandler::showerHardProcess(). "; if ( ( currentTree()->isMCatNLOSEvent() || currentTree()->isMCatNLOHEvent() ) ) { if (_hardEmission ==2 ) throw Exception() << error << "Cannot generate POWHEG matching with MC@NLO shower " << "approximation. Add 'set QTildeShowerHandler:HardEmission 0' to input file." << Exception::runerror; if ( canHandleMatchboxTrunc() ) throw Exception() << error << "Cannot use truncated qtilde shower with MC@NLO shower " << "approximation. Set LHCGenerator:EventHandler" << ":CascadeHandler to '/Herwig/Shower/ShowerHandler' or " << "'/Herwig/Shower/Dipole/DipoleShowerHandler'." << Exception::runerror; } else if ( ((currentTree()->isPowhegSEvent() || currentTree()->isPowhegHEvent()) ) && _hardEmission != 2){ if ( canHandleMatchboxTrunc()) throw Exception() << error << "Unmatched events requested for POWHEG shower " << "approximation. Set QTildeShowerHandler:HardEmission to " << "'POWHEG'." << Exception::runerror; else if (_hardEmissionWarn) { _hardEmissionWarn = false; _hardEmission=2; throw Exception() << error << "Unmatched events requested for POWHEG shower " << "approximation. Changing QTildeShowerHandler:HardEmission from " << _hardEmission << " to 2" << Exception::warning; } } if ( currentTree()->isPowhegSEvent() || currentTree()->isPowhegHEvent()) { if (currentTree()->showerApproximation()->needsTruncatedShower() && !canHandleMatchboxTrunc() ) throw Exception() << error << "Current shower handler cannot generate truncated shower. " << "Set Generator:EventHandler:CascadeHandler to " << "'/Herwig/Shower/PowhegShowerHandler'." << Exception::runerror; } else if ( currentTree()->truncatedShower() && _missingTruncWarn) { _missingTruncWarn=false; throw Exception() << "Warning: POWHEG shower approximation used without " << "truncated shower. Set Generator:EventHandler:" << "CascadeHandler to '/Herwig/Shower/PowhegShowerHandler' and " << "'MEMatching:TruncatedShower Yes'." << Exception::warning; } // else if ( !dipme && _hardEmissionMode > 1 && // firstInteraction()) // throw Exception() << error // << "POWHEG matching requested for LO events. Include " // << "'set Factory:ShowerApproximation MEMatching' in input file." // << Exception::runerror; } tPPair QTildeShowerHandler::remakeRemnant(tPPair oldp){ // get the parton extractor PartonExtractor & pex = *lastExtractor(); // get the new partons tPPair newp = make_pair(findFirstParton(oldp.first ), findFirstParton(oldp.second)); // if the same do nothing if(newp == oldp) return oldp; // Creates the new remnants and returns the new PartonBinInstances // ATTENTION Broken here for very strange configuration PBIPair newbins = pex.newRemnants(oldp, newp, newStep()); newStep()->addIntermediate(newp.first); newStep()->addIntermediate(newp.second); // return the new partons return newp; } PPtr QTildeShowerHandler::findFirstParton(tPPtr seed) const{ if(seed->parents().empty()) return seed; tPPtr parent = seed->parents()[0]; //if no parent there this is a loose end which will //be connected to the remnant soon. if(!parent || parent == incomingBeams().first || parent == incomingBeams().second ) return seed; else return findFirstParton(parent); } void QTildeShowerHandler::decay(ShowerTreePtr tree, ShowerDecayMap & decay) { // must be one incoming particle assert(tree->incomingLines().size()==1); // apply any transforms tree->applyTransforms(); // if already decayed return if(!tree->outgoingLines().empty()) return; // now we need to replace the particle with a new copy after the shower // find particle after the shower map >::const_iterator tit = tree->parent()->treelinks().find(tree); assert(tit!=tree->parent()->treelinks().end()); ShowerParticlePtr newparent=tit->second.second; PerturbativeProcessPtr newProcess = new_ptr(PerturbativeProcess()); newProcess->incoming().push_back(make_pair(newparent,PerturbativeProcessPtr())); DecayProcessMap decayMap; ShowerHandler::decay(newProcess,decayMap); ShowerTree::constructTrees(tree,decay,newProcess,decayMap); } namespace { ShowerProgenitorPtr findFinalStateLine(ShowerTreePtr tree, long id, Lorentz5Momentum momentum) { map::iterator partner; Energy2 dmin(1e30*GeV2); for(map::iterator cit =tree->outgoingLines().begin(); cit!=tree->outgoingLines().end(); ++cit) { if(cit->second->id()!=id) continue; Energy2 test = sqr(cit->second->momentum().x()-momentum.x())+ sqr(cit->second->momentum().y()-momentum.y())+ sqr(cit->second->momentum().z()-momentum.z())+ sqr(cit->second->momentum().t()-momentum.t()); if(testfirst; } ShowerProgenitorPtr findInitialStateLine(ShowerTreePtr tree, long id, Lorentz5Momentum momentum) { map::iterator partner; Energy2 dmin(1e30*GeV2); for(map::iterator cit =tree->incomingLines().begin(); cit!=tree->incomingLines().end(); ++cit) { if(cit->second->id()!=id) continue; Energy2 test = sqr(cit->second->momentum().x()-momentum.x())+ sqr(cit->second->momentum().y()-momentum.y())+ sqr(cit->second->momentum().z()-momentum.z())+ sqr(cit->second->momentum().t()-momentum.t()); if(testfirst; } void fixSpectatorColours(PPtr newSpect,ShowerProgenitorPtr oldSpect, ColinePair & cline,ColinePair & aline, bool reconnect) { cline.first = oldSpect->progenitor()->colourLine(); cline.second = newSpect->colourLine(); aline.first = oldSpect->progenitor()->antiColourLine(); aline.second = newSpect->antiColourLine(); if(!reconnect) return; if(cline.first) { cline.first ->removeColoured(oldSpect->copy()); cline.first ->removeColoured(oldSpect->progenitor()); cline.second->removeColoured(newSpect); cline.first ->addColoured(newSpect); } if(aline.first) { aline.first ->removeAntiColoured(oldSpect->copy()); aline.first ->removeAntiColoured(oldSpect->progenitor()); aline.second->removeAntiColoured(newSpect); aline.first ->addAntiColoured(newSpect); } } void fixInitialStateEmitter(ShowerTreePtr tree, PPtr newEmit,PPtr emitted, ShowerProgenitorPtr emitter, ColinePair cline,ColinePair aline,double x) { // sort out the colours if(emitted->dataPtr()->iColour()==PDT::Colour8) { // emitter if(cline.first && cline.first == emitter->progenitor()->antiColourLine() && cline.second !=newEmit->antiColourLine()) { // sort out not radiating line ColinePtr col = emitter->progenitor()->colourLine(); if(col) { col->removeColoured(emitter->copy()); col->removeColoured(emitter->progenitor()); newEmit->colourLine()->removeColoured(newEmit); col->addColoured(newEmit); } } else if(aline.first && aline.first == emitter->progenitor()->colourLine() && aline.second !=newEmit->colourLine()) { // sort out not radiating line ColinePtr anti = emitter->progenitor()->antiColourLine(); if(anti) { anti->removeAntiColoured(emitter->copy()); anti->removeAntiColoured(emitter->progenitor()); newEmit->colourLine()->removeAntiColoured(newEmit); anti->addAntiColoured(newEmit); } } else assert(false); // emitted if(cline.first && cline.second==emitted->colourLine()) { cline.second->removeColoured(emitted); cline.first->addColoured(emitted); } else if(aline.first && aline.second==emitted->antiColourLine()) { aline.second->removeAntiColoured(emitted); aline.first->addAntiColoured(emitted); } else assert(false); } else { if(emitter->progenitor()->antiColourLine() ) { ColinePtr col = emitter->progenitor()->antiColourLine(); col->removeAntiColoured(emitter->copy()); col->removeAntiColoured(emitter->progenitor()); if(newEmit->antiColourLine()) { newEmit->antiColourLine()->removeAntiColoured(newEmit); col->addAntiColoured(newEmit); } else if (emitted->colourLine()) { emitted->colourLine()->removeColoured(emitted); col->addColoured(emitted); } else assert(false); } if(emitter->progenitor()->colourLine() ) { ColinePtr col = emitter->progenitor()->colourLine(); col->removeColoured(emitter->copy()); col->removeColoured(emitter->progenitor()); if(newEmit->colourLine()) { newEmit->colourLine()->removeColoured(newEmit); col->addColoured(newEmit); } else if (emitted->antiColourLine()) { emitted->antiColourLine()->removeAntiColoured(emitted); col->addAntiColoured(emitted); } else assert(false); } } // update the emitter emitter->copy(newEmit); ShowerParticlePtr sp = new_ptr(ShowerParticle(*newEmit,1,false)); sp->x(x); emitter->progenitor(sp); tree->incomingLines()[emitter]=sp; emitter->perturbative(false); // add emitted sp=new_ptr(ShowerParticle(*emitted,1,true)); ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(emitter->original(),emitted,sp)); gluon->perturbative(false); tree->outgoingLines().insert(make_pair(gluon,sp)); } void fixFinalStateEmitter(ShowerTreePtr tree, PPtr newEmit,PPtr emitted, ShowerProgenitorPtr emitter, ColinePair cline,ColinePair aline) { map >::const_iterator tit; // special case if decayed for(tit = tree->treelinks().begin(); tit != tree->treelinks().end();++tit) { if(tit->second.first && tit->second.second==emitter->progenitor()) break; } // sort out the colour lines if(cline.first && cline.first == emitter->progenitor()->antiColourLine() && cline.second !=newEmit->antiColourLine()) { // sort out not radiating line ColinePtr col = emitter->progenitor()->colourLine(); if(col) { col->removeColoured(emitter->copy()); col->removeColoured(emitter->progenitor()); newEmit->colourLine()->removeColoured(newEmit); col->addColoured(newEmit); } } else if(aline.first && aline.first == emitter->progenitor()->colourLine() && aline.second !=newEmit->colourLine()) { // sort out not radiating line ColinePtr anti = emitter->progenitor()->antiColourLine(); if(anti) { anti->removeAntiColoured(emitter->copy()); anti->removeAntiColoured(emitter->progenitor()); newEmit->colourLine()->removeAntiColoured(newEmit); anti->addAntiColoured(newEmit); } } else assert(false); // update the emitter emitter->copy(newEmit); ShowerParticlePtr sp = new_ptr(ShowerParticle(*newEmit,1,true)); emitter->progenitor(sp); tree->outgoingLines()[emitter]=sp; emitter->perturbative(false); // update for decaying particles if(tit!=tree->treelinks().end()) tree->updateLink(tit->first,make_pair(emitter,sp)); // add the emitted particle // sort out the colour if(cline.first && cline.second==emitted->antiColourLine()) { cline.second->removeAntiColoured(emitted); cline.first->addAntiColoured(emitted); } else if(aline.first && aline.second==emitted->colourLine()) { aline.second->removeColoured(emitted); aline.first->addColoured(emitted); } else assert(false); sp=new_ptr(ShowerParticle(*emitted,1,true)); ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(emitter->original(), emitted,sp)); gluon->perturbative(false); tree->outgoingLines().insert(make_pair(gluon,sp)); } } void QTildeShowerHandler::setupMECorrection(RealEmissionProcessPtr real) { assert(real); // II emission if(real->emitter() < real->incoming().size() && real->spectator() < real->incoming().size()) { // recoiling system for( map::const_iterator cjt= currentTree()->outgoingLines().begin(); cjt != currentTree()->outgoingLines().end();++cjt ) { cjt->first->progenitor()->transform(real->transformation()); cjt->first->copy()->transform(real->transformation()); } // the the radiating system ShowerProgenitorPtr emitter,spectator; unsigned int iemit = real->emitter(); unsigned int ispect = real->spectator(); int ig = int(real->emitted())-int(real->incoming().size()); emitter = findInitialStateLine(currentTree(), real->bornIncoming()[iemit]->id(), real->bornIncoming()[iemit]->momentum()); spectator = findInitialStateLine(currentTree(), real->bornIncoming()[ispect]->id(), real->bornIncoming()[ispect]->momentum()); // sort out the colours ColinePair cline,aline; fixSpectatorColours(real->incoming()[ispect],spectator,cline,aline,true); // update the spectator spectator->copy(real->incoming()[ispect]); ShowerParticlePtr sp(new_ptr(ShowerParticle(*real->incoming()[ispect],1,false))); sp->x(ispect ==0 ? real->x().first :real->x().second); spectator->progenitor(sp); currentTree()->incomingLines()[spectator]=sp; spectator->perturbative(true); // now for the emitter fixInitialStateEmitter(currentTree(),real->incoming()[iemit],real->outgoing()[ig], emitter,cline,aline,iemit ==0 ? real->x().first :real->x().second); } // FF emission else if(real->emitter() >= real->incoming().size() && real->spectator() >= real->incoming().size()) { assert(real->outgoing()[real->emitted()-real->incoming().size()]->id()==ParticleID::g); // find the emitter and spectator in the shower tree ShowerProgenitorPtr emitter,spectator; int iemit = int(real->emitter())-int(real->incoming().size()); emitter = findFinalStateLine(currentTree(), real->bornOutgoing()[iemit]->id(), real->bornOutgoing()[iemit]->momentum()); int ispect = int(real->spectator())-int(real->incoming().size()); spectator = findFinalStateLine(currentTree(), real->bornOutgoing()[ispect]->id(), real->bornOutgoing()[ispect]->momentum()); map >::const_iterator tit; // first the spectator // special case if decayed for(tit = currentTree()->treelinks().begin(); tit != currentTree()->treelinks().end();++tit) { if(tit->second.first && tit->second.second==spectator->progenitor()) break; } // sort out the colours ColinePair cline,aline; fixSpectatorColours(real->outgoing()[ispect],spectator,cline,aline,true); // update the spectator spectator->copy(real->outgoing()[ispect]); ShowerParticlePtr sp(new_ptr(ShowerParticle(*real->outgoing()[ispect],1,true))); spectator->progenitor(sp); currentTree()->outgoingLines()[spectator]=sp; spectator->perturbative(true); // update for decaying particles if(tit!=currentTree()->treelinks().end()) currentTree()->updateLink(tit->first,make_pair(spectator,sp)); // now the emitting particle int ig = int(real->emitted())-int(real->incoming().size()); fixFinalStateEmitter(currentTree(),real->outgoing()[iemit], real->outgoing()[ig], emitter,cline,aline); } // IF emission else { // scattering process if(real->incoming().size()==2) { ShowerProgenitorPtr emitter,spectator; unsigned int iemit = real->emitter(); unsigned int ispect = real->spectator(); int ig = int(real->emitted())-int(real->incoming().size()); ColinePair cline,aline; // incoming spectator if(ispect<2) { spectator = findInitialStateLine(currentTree(), real->bornIncoming()[ispect]->id(), real->bornIncoming()[ispect]->momentum()); fixSpectatorColours(real->incoming()[ispect],spectator,cline,aline,true); // update the spectator spectator->copy(real->incoming()[ispect]); ShowerParticlePtr sp(new_ptr(ShowerParticle(*real->incoming()[ispect],1,false))); sp->x(ispect ==0 ? real->x().first :real->x().second); spectator->progenitor(sp); currentTree()->incomingLines()[spectator]=sp; spectator->perturbative(true); } // outgoing spectator else { spectator = findFinalStateLine(currentTree(), real->bornOutgoing()[ispect-real->incoming().size()]->id(), real->bornOutgoing()[ispect-real->incoming().size()]->momentum()); // special case if decayed map >::const_iterator tit; for(tit = currentTree()->treelinks().begin(); tit != currentTree()->treelinks().end();++tit) { if(tit->second.first && tit->second.second==spectator->progenitor()) break; } fixSpectatorColours(real->outgoing()[ispect-real->incoming().size()],spectator,cline,aline,true); // update the spectator spectator->copy(real->outgoing()[ispect-real->incoming().size()]); ShowerParticlePtr sp(new_ptr(ShowerParticle(*real->outgoing()[ispect-real->incoming().size()],1,true))); spectator->progenitor(sp); currentTree()->outgoingLines()[spectator]=sp; spectator->perturbative(true); // update for decaying particles if(tit!=currentTree()->treelinks().end()) currentTree()->updateLink(tit->first,make_pair(spectator,sp)); } // incoming emitter if(iemit<2) { emitter = findInitialStateLine(currentTree(), real->bornIncoming()[iemit]->id(), real->bornIncoming()[iemit]->momentum()); fixInitialStateEmitter(currentTree(),real->incoming()[iemit],real->outgoing()[ig], emitter,aline,cline,iemit ==0 ? real->x().first :real->x().second); } // outgoing emitter else { emitter = findFinalStateLine(currentTree(), real->bornOutgoing()[iemit-real->incoming().size()]->id(), real->bornOutgoing()[iemit-real->incoming().size()]->momentum()); fixFinalStateEmitter(currentTree(),real->outgoing()[iemit-real->incoming().size()], real->outgoing()[ig],emitter,aline,cline); } } // decay process else { assert(real->spectator()==0); unsigned int iemit = real->emitter()-real->incoming().size(); int ig = int(real->emitted())-int(real->incoming().size()); ColinePair cline,aline; // incoming spectator ShowerProgenitorPtr spectator = findInitialStateLine(currentTree(), real->bornIncoming()[0]->id(), real->bornIncoming()[0]->momentum()); fixSpectatorColours(real->incoming()[0],spectator,cline,aline,false); // find the emitter ShowerProgenitorPtr emitter = findFinalStateLine(currentTree(), real->bornOutgoing()[iemit]->id(), real->bornOutgoing()[iemit]->momentum()); // recoiling system for( map::const_iterator cjt= currentTree()->outgoingLines().begin(); cjt != currentTree()->outgoingLines().end();++cjt ) { if(cjt->first==emitter) continue; cjt->first->progenitor()->transform(real->transformation()); cjt->first->copy()->transform(real->transformation()); } // sort out the emitter fixFinalStateEmitter(currentTree(),real->outgoing()[iemit], real->outgoing()[ig],emitter,aline,cline); } } // clean up the shower tree _currenttree->resetShowerProducts(); } diff --git a/Shower/QTilde/ShowerConfig.h b/Shower/QTilde/ShowerConfig.h --- a/Shower/QTilde/ShowerConfig.h +++ b/Shower/QTilde/ShowerConfig.h @@ -1,151 +1,153 @@ // -*- C++ -*- // // ShowerConfig.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_ShowerConfig_H #define HERWIG_ShowerConfig_H // // This is the declaration of the ShowerConfig class. #include "ThePEG/Config/ThePEG.h" #include "ThePEG/PDT/ParticleData.h" #include "Herwig/Shower/QTilde/Base/ShowerParticle.fh" #include "Herwig/Shower/QTilde/SplittingFunctions/SudakovFormFactor.fh" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Shower/ShowerInteraction.h" namespace Herwig { using namespace ThePEG; /** \ingroup Shower * * Handy header file to be included in all Shower classes. * It contains only some useful typedefs. */ /** * Pointer to a ColourLine */ typedef Ptr::pointer ColinePtr; /** * Transient Pointer to a ColourLine */ typedef Ptr::transient_pointer tColinePtr; /** * A pair of ColourLine pointers */ typedef pair ColinePair; /** * A pair of transient ColourLine pointers */ typedef pair tColinePair; /** * A Vector of ShowerParticle pointers */ typedef vector ShowerParticleVector; /** * A Vector of transient ShowerParticle pointers */ typedef vector tShowerParticleVector; /** * Definition of the IdList for branchings */ typedef vector IdList; inline ShowerInteraction convertInteraction(ShowerPartnerType partner) { if (partner==ShowerPartnerType::QCDColourLine || partner==ShowerPartnerType::QCDAntiColourLine) return ShowerInteraction::QCD; else if (partner==ShowerPartnerType::QED) return ShowerInteraction::QED; + else if(partner==ShowerPartnerType::EW) + return ShowerInteraction::EW; else return ShowerInteraction::UNDEFINED; } /** * typedef to pair the SudakovFormFactor and the particles in a branching */ struct BranchingElement { - + /** * Constructor */ BranchingElement(); /** * Constructor */ BranchingElement(SudakovPtr sud, IdList part); /** * Destructor */ ~BranchingElement(); /** * Access to the Sudakov */ SudakovPtr sudakov; /** * Access to the particles */ IdList particles; /** * Access to the charge conjugate particles */ IdList conjugateParticles; /** * Compare two BranchingElements **/ bool operator == (const BranchingElement& x) const{ return sudakov == x.sudakov && particles == x.particles && conjugateParticles == x.conjugateParticles; } }; /** * typedef to pair the PDG code of the particle and the BranchingElement */ typedef multimap BranchingList; /** * typedef to create a structure which can be inserted into a BranchingList */ typedef pair BranchingInsert; } namespace ThePEG { /** * Output operator to allow the structure */ PersistentOStream & operator << (PersistentOStream & os, const Herwig::BranchingElement & x); /** * Input operator to allow the structure */ PersistentIStream & operator >> (PersistentIStream & is, Herwig::BranchingElement & x); } #endif // HERWIG_ShowerConfig_H diff --git a/Shower/QTilde/SplittingFunctions/HalfHalfOneEWSplitFn.cc b/Shower/QTilde/SplittingFunctions/HalfHalfOneEWSplitFn.cc new file mode 100644 --- /dev/null +++ b/Shower/QTilde/SplittingFunctions/HalfHalfOneEWSplitFn.cc @@ -0,0 +1,216 @@ +// -*- C++ -*- +// +// This is the implementation of the non-inlined, non-templated member +// functions of the HalfHalfOneEWSplitFn class. +// + +#include "HalfHalfOneEWSplitFn.h" +#include "ThePEG/StandardModel/StandardModelBase.h" +#include "ThePEG/Repository/EventGenerator.h" +#include "ThePEG/Interface/ClassDocumentation.h" +#include "ThePEG/Utilities/DescribeClass.h" +#include "ThePEG/Persistency/PersistentOStream.h" +#include "ThePEG/Persistency/PersistentIStream.h" +#include "ThePEG/PDT/ParticleData.h" +#include "Herwig/Decay/TwoBodyDecayMatrixElement.h" + +using namespace Herwig; + +IBPtr HalfHalfOneEWSplitFn::clone() const { + return new_ptr(*this); +} + +IBPtr HalfHalfOneEWSplitFn::fullclone() const { + return new_ptr(*this); +} + +void HalfHalfOneEWSplitFn::persistentOutput(PersistentOStream & os) const { + os << gZ_ << gWL_; +} + +void HalfHalfOneEWSplitFn::persistentInput(PersistentIStream & is, int) { + is >> gZ_ >> gWL_; +} + +// The following static variable is needed for the type description system in ThePEG. +DescribeClass +describeHerwigHalfHalfOneEWSplitFn("Herwig::HalfHalfOneEWSplitFn", "HwShower.so"); + +void HalfHalfOneEWSplitFn::Init() { + + static ClassDocumentation documentation + ("The HalfHalfOneEWSplitFn class implements the splitting q->qWand q->qZ"); + +} + +void HalfHalfOneEWSplitFn::doinit() { + SplittingFunction::doinit(); + tcSMPtr sm = generator()->standardModel(); + double sw2 = sm->sin2ThetaW(); + // left-handled W coupling + gWL_ = 1./sqrt(2.*sw2); + // Z couplings + double fact = 0.25/sqrt(sw2*(1.-sw2)); + for(int ix=1;ix<4;++ix) { + gZ_[2*ix-1] = make_pair(fact*(sm->vd() + sm->ad()), + fact*(sm->vd() - sm->ad() )); + gZ_[2*ix ] = make_pair(fact*(sm->vu() + sm->au() ), + fact*(sm->vu() - sm->au() )); + gZ_[2*ix+9 ] = make_pair(fact*(sm->ve() + sm->ae() ), + fact*(sm->ve() - sm->ae() )); + gZ_[2*ix+10] = make_pair(fact*(sm->vnu() + sm->anu()), + fact*(sm->vnu() - sm->anu())); + } +} + +void HalfHalfOneEWSplitFn::getCouplings(double & gL, double & gR, const IdList & ids) const { + if(ids[2]->id()==ParticleID::Z0) { + map >::const_iterator it = gZ_.find(abs(ids[0]->id())); + assert(it!=gZ_.end()); + gL = it->second.first ; + gR = it->second.second; + } + else if(abs(ids[2]->id())==ParticleID::Wplus) { + gL = gWL_; + } + else + assert(false); + if(ids[0]->id()<0) swap(gL,gR); +} + +double HalfHalfOneEWSplitFn::P(const double z, const Energy2 t, + const IdList &ids, const bool mass, const RhoDMatrix & rho) const { + double gL(0.),gR(0.); + getCouplings(gL,gR,ids); + double val = (1. + sqr(z))/(1.-z); + if(mass) { + Energy m = ids[2]->mass(); + val -= sqr(m)/t; + } + val *= (sqr(gL)*abs(rho(0,0))+sqr(gR)*abs(rho(1,1))); + return colourFactor(ids)*val; +} + + +double HalfHalfOneEWSplitFn::overestimateP(const double z, + const IdList & ids) const { + double gL(0.),gR(0.); + getCouplings(gL,gR,ids); + return 2.*max(sqr(gL),sqr(gR))*colourFactor(ids)/(1.-z); +} + +double HalfHalfOneEWSplitFn::ratioP(const double z, const Energy2 t, + const IdList & ids, const bool mass, + const RhoDMatrix & rho) const { + double gL(0.),gR(0.); + getCouplings(gL,gR,ids); + double val = 1. + sqr(z); + if(mass) { + Energy m = ids[2]->mass(); + val -= (1.-z)*sqr(m)/t; + } + val *= (sqr(gL)*abs(rho(0,0))+sqr(gR)*abs(rho(1,1)))/max(sqr(gL),sqr(gR)); + return 0.5*val; +} + +double HalfHalfOneEWSplitFn::integOverP(const double z, + const IdList & ids, + unsigned int PDFfactor) const { + double gL(0.),gR(0.); + getCouplings(gL,gR,ids); + double pre = colourFactor(ids)*max(sqr(gL),sqr(gR)); + switch (PDFfactor) { + case 0: + return -2.*pre*Math::log1m(z); + case 1: + return 2.*pre*log(z/(1.-z)); + case 2: + return 2.*pre/(1.-z); + case 3: + default: + throw Exception() << "HalfHalfOneEWSplitFn::integOverP() invalid PDFfactor = " + << PDFfactor << Exception::runerror; + } +} + +double HalfHalfOneEWSplitFn::invIntegOverP(const double r, const IdList & ids, + unsigned int PDFfactor) const { + double gL(0.),gR(0.); + getCouplings(gL,gR,ids); + double pre = colourFactor(ids)*max(sqr(gL),sqr(gR)); + switch (PDFfactor) { + case 0: + return 1. - exp(- 0.5*r/pre); + case 1: + return 1./(1.-exp(-0.5*r/pre)); + case 2: + return 1.-2.*pre/r; + case 3: + default: + throw Exception() << "HalfHalfOneEWSplitFn::invIntegOverP() invalid PDFfactor = " + << PDFfactor << Exception::runerror; + } +} + +bool HalfHalfOneEWSplitFn::accept(const IdList &ids) const { + if(ids.size()!=3) return false; + if(ids[2]->id()==ParticleID::Z0) { + if(ids[0]->id()==ids[1]->id() && + ((ids[0]->id()>=1 && ids[0]->id()<=6) || (ids[0]->id()>=11&&ids[0]->id()<=16) )) return true; + } + else if(abs(ids[2]->id())==ParticleID::Wplus) { + if(!((ids[0]->id()>=1 && ids[0]->id()<=6) || (ids[0]->id()>=11&&ids[0]->id()<=16) )) return false; + if(!((ids[1]->id()>=1 && ids[1]->id()<=6) || (ids[1]->id()>=11&&ids[1]->id()<=16) )) return false; + if(ids[0]->id()+1!=ids[1]->id() && ids[0]->id()-1!=ids[1]->id()) return false; + int out = ids[1]->iCharge()+ids[2]->iCharge(); + if(ids[0]->iCharge()==out) return true; + } + return false; +} + +vector > +HalfHalfOneEWSplitFn::generatePhiForward(const double, const Energy2, const IdList & , + const RhoDMatrix &) { + // no dependence on the spin density matrix, dependence on off-diagonal terms cancels + // and rest = splitting function for Tr(rho)=1 as required by defn + return vector >(1,make_pair(0,1.)); +} + +vector > +HalfHalfOneEWSplitFn::generatePhiBackward(const double, const Energy2, const IdList & , + const RhoDMatrix &) { + // no dependence on the spin density matrix, dependence on off-diagonal terms cancels + // and rest = splitting function for Tr(rho)=1 as required by defn + return vector >(1,make_pair(0,1.)); +} + +DecayMEPtr HalfHalfOneEWSplitFn::matrixElement(const double z, const Energy2 t, + const IdList & ids, const double phi, + bool) { + // calculate the kernal + DecayMEPtr kernal(new_ptr(TwoBodyDecayMatrixElement(PDT::Spin1Half,PDT::Spin1Half,PDT::Spin1))); + Energy m = ids[2]->mass(); + double gL(0.),gR(0.); + getCouplings(gL,gR,ids); + double mt = m/sqrt(t); + double root = sqrt(1.-sqr(m)/t/(1-z)); + double romz = sqrt(1.-z); + double rz = sqrt(z); + double r2 = sqrt(2.); + Complex phase = exp(Complex(0.,1.)*phi); + Complex cphase = conj(phase); + (*kernal)(0,0,0) = -phase*root*gL/romz; + (*kernal)(1,1,2) = cphase*root*gR/romz; + (*kernal)(0,0,2) = cphase*z*root*gL/romz; + (*kernal)(1,1,0) = -phase*z*root*gR/romz; + // long terms + (*kernal)(1,1,1) =-gR*mt*r2*rz/(1-z); + (*kernal)(0,0,1) =-gL*mt*r2*rz/(1-z); + // +- -+ terms zero due quark mass + for(unsigned int ix=0;ix<3;++ix) { + (*kernal)(1,0,ix) = 0.; + (*kernal)(0,1,ix) = 0.; + } + // return the answer + return kernal; +} diff --git a/Shower/QTilde/SplittingFunctions/HalfHalfOneEWSplitFn.h b/Shower/QTilde/SplittingFunctions/HalfHalfOneEWSplitFn.h new file mode 100644 --- /dev/null +++ b/Shower/QTilde/SplittingFunctions/HalfHalfOneEWSplitFn.h @@ -0,0 +1,212 @@ +// -*- C++ -*- +#ifndef Herwig_HalfHalfOneEWSplitFn_H +#define Herwig_HalfHalfOneEWSplitFn_H +// +// This is the declaration of the HalfHalfOneEWSplitFn class. +// + +#include "SplittingFunction.h" + +namespace Herwig { + +using namespace ThePEG; + +/** + * The HalfHalfOneEWSplitFn class implements the splitting function for + * \f$\frac12\to q\frac12 1\f$ where the spin-1 particle is a massive electroweak gauge boson. + * + * @see \ref HalfHalfOneEWSplitFnInterfaces "The interfaces" + * defined for HalfHalfOneEWSplitFn. + */ +class HalfHalfOneEWSplitFn: public SplittingFunction { + +public: + + /** + * Concrete implementation of the method to determine whether this splitting + * function can be used for a given set of particles. + * @param ids The PDG codes for the particles in the splitting. + */ + virtual bool accept(const IdList & ids) const; + + /** + * Methods to return the splitting function. + */ + //@{ + /** + * The concrete implementation of the splitting function, \f$P(z,t)\f$. + * @param z The energy fraction. + * @param t The scale. + * @param ids The PDG codes for the particles in the splitting. + * @param mass Whether or not to include the mass dependent terms + * @param rho The spin density matrix + */ + virtual double P(const double z, const Energy2 t, const IdList & ids, + const bool mass, const RhoDMatrix & rho) const; + + /** + * The concrete implementation of the overestimate of the splitting function, + * \f$P_{\rm over}\f$. + * @param z The energy fraction. + * @param ids The PDG codes for the particles in the splitting. + */ + virtual double overestimateP(const double z, const IdList & ids) const; + + /** + * The concrete implementation of the + * the ratio of the splitting function to the overestimate, i.e. + * \f$P(z,t)/P_{\rm over}(z)\f$. + * @param z The energy fraction. + * @param t The scale. + * @param ids The PDG codes for the particles in the splitting. + * @param mass Whether or not to include the mass dependent terms + * @param rho The spin density matrix + */ + virtual double ratioP(const double z, const Energy2 t, const IdList & ids, + const bool mass, const RhoDMatrix & rho) const; + + /** + * The concrete implementation of the indefinite integral of the + * overestimated splitting function, \f$P_{\rm over}\f$. + * @param z The energy fraction. + * @param ids The PDG codes for the particles in the splitting. + * @param PDFfactor Which additional factor to include for the PDF + * 0 is no additional factor, + * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ + */ + virtual double integOverP(const double z, const IdList & ids, + unsigned int PDFfactor=0) const; + + /** + * The concrete implementation of the inverse of the indefinite integral. + * @param r Value of the splitting function to be inverted + * @param ids The PDG codes for the particles in the splitting. + * @param PDFfactor Which additional factor to include for the PDF + * 0 is no additional factor, + * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ + */ + virtual double invIntegOverP(const double r, const IdList & ids, + unsigned int PDFfactor=0) const; + //@} + + /** + * Method to calculate the azimuthal angle + * @param z The energy fraction + * @param t The scale \f$t=2p_j\cdot p_k\f$. + * @param ids The PDG codes for the particles in the splitting. + * @param The azimuthal angle, \f$\phi\f$. + * @return The weight + */ + virtual vector > + generatePhiForward(const double z, const Energy2 t, const IdList & ids, + const RhoDMatrix &); + + /** + * Method to calculate the azimuthal angle for backward evolution + * @param z The energy fraction + * @param t The scale \f$t=2p_j\cdot p_k\f$. + * @param ids The PDG codes for the particles in the splitting. + * @param The azimuthal angle, \f$\phi\f$. + * @return The weight + */ + virtual vector > + generatePhiBackward(const double z, const Energy2 t, const IdList & ids, + const RhoDMatrix &); + + /** + * Calculate the matrix element for the splitting + * @param z The energy fraction + * @param t The scale \f$t=2p_j\cdot p_k\f$. + * @param ids The PDG codes for the particles in the splitting. + * @param The azimuthal angle, \f$\phi\f$. + */ + virtual DecayMEPtr matrixElement(const double z, const Energy2 t, + const IdList & ids, const double phi, bool timeLike); + +protected: + + /** + * Get the couplings + */ + void getCouplings(double & gL, double & gR, const IdList & ids) const; + +public: + + /** @name Functions used by the persistent I/O system. */ + //@{ + /** + * Function used to write out object persistently. + * @param os the persistent output stream written to. + */ + void persistentOutput(PersistentOStream & os) const; + + /** + * Function used to read in object persistently. + * @param is the persistent input stream read from. + * @param version the version number of the object when written. + */ + void persistentInput(PersistentIStream & is, int version); + //@} + + /** + * The standard Init function used to initialize the interfaces. + * Called exactly once for each class by the class description system + * before the main function starts or + * when this class is dynamically loaded. + */ + static void Init(); + +protected: + + /** @name Clone Methods. */ + //@{ + /** + * Make a simple clone of this object. + * @return a pointer to the new object. + */ + virtual IBPtr clone() const; + + /** Make a clone of this object, possibly modifying the cloned object + * to make it sane. + * @return a pointer to the new object. + */ + virtual IBPtr fullclone() const; + //@} + +protected: + + /** @name Standard Interfaced functions. */ + //@{ + /** + * Initialize this object after the setup phase before saving an + * EventGenerator to disk. + * @throws InitException if object could not be initialized properly. + */ + virtual void doinit(); + //@} + +private: + + /** + * The assignment operator is private and must never be called. + * In fact, it should not even be implemented. + */ + HalfHalfOneEWSplitFn & operator=(const HalfHalfOneEWSplitFn &) = delete; + +private: + + /** + * Z couplings + */ + map > gZ_; + + /** + * W couplings + */ + double gWL_; + +}; + +} + +#endif /* Herwig_HalfHalfOneEWSplitFn_H */ diff --git a/Shower/QTilde/SplittingFunctions/HalfHalfOneSplitFn.cc b/Shower/QTilde/SplittingFunctions/HalfHalfOneSplitFn.cc --- a/Shower/QTilde/SplittingFunctions/HalfHalfOneSplitFn.cc +++ b/Shower/QTilde/SplittingFunctions/HalfHalfOneSplitFn.cc @@ -1,134 +1,134 @@ // -*- C++ -*- // // HalfHalfOneSplitFn.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the HalfHalfOneSplitFn class. // #include "HalfHalfOneSplitFn.h" #include "ThePEG/PDT/ParticleData.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Utilities/DescribeClass.h" #include "Herwig/Decay/TwoBodyDecayMatrixElement.h" using namespace Herwig; DescribeNoPIOClass describeHalfHalfOneSplitFn ("Herwig::HalfHalfOneSplitFn","HwShower.so"); void HalfHalfOneSplitFn::Init() { static ClassDocumentation documentation ("The HalfHalfOneSplitFn class implements the q -> qg splitting function"); } double HalfHalfOneSplitFn::P(const double z, const Energy2 t, - const IdList &ids, const bool mass, const RhoDMatrix & ) const { + const IdList &ids, const bool mass, const RhoDMatrix &) const { double val = (1. + sqr(z))/(1.-z); if(mass) { Energy m = ids[0]->mass(); val -= 2.*sqr(m)/t; } return colourFactor(ids)*val; } double HalfHalfOneSplitFn::overestimateP(const double z, const IdList & ids) const { return 2.*colourFactor(ids)/(1.-z); } double HalfHalfOneSplitFn::ratioP(const double z, const Energy2 t, - const IdList & ids, const bool mass, const RhoDMatrix & ) const { + const IdList & ids, const bool mass, const RhoDMatrix &) const { double val = 1. + sqr(z); if(mass) { Energy m = ids[0]->mass(); val -= 2.*sqr(m)*(1.-z)/t; } return 0.5*val; } double HalfHalfOneSplitFn::integOverP(const double z, const IdList & ids, unsigned int PDFfactor) const { switch (PDFfactor) { case 0: return -2.*colourFactor(ids)*Math::log1m(z); case 1: return 2.*colourFactor(ids)*log(z/(1.-z)); case 2: return 2.*colourFactor(ids)/(1.-z); case 3: default: throw Exception() << "HalfHalfOneSplitFn::integOverP() invalid PDFfactor = " << PDFfactor << Exception::runerror; } } double HalfHalfOneSplitFn::invIntegOverP(const double r, const IdList & ids, unsigned int PDFfactor) const { switch (PDFfactor) { case 0: return 1. - exp(- 0.5*r/colourFactor(ids)); case 1: return 1./(1.-exp(-0.5*r/colourFactor(ids))); case 2: return 1.-2.*colourFactor(ids)/r; case 3: default: throw Exception() << "HalfHalfOneSplitFn::invIntegOverP() invalid PDFfactor = " << PDFfactor << Exception::runerror; } } bool HalfHalfOneSplitFn::accept(const IdList &ids) const { // 3 particles and in and out fermion same if(ids.size()!=3 || ids[0]!=ids[1]) return false; if(ids[0]->iSpin()!=PDT::Spin1Half || ids[2]->iSpin()!=PDT::Spin1) return false; return checkColours(ids); } vector > HalfHalfOneSplitFn::generatePhiForward(const double, const Energy2, const IdList & , const RhoDMatrix &) { // no dependence on the spin density matrix, dependence on off-diagonal terms cancels // and rest = splitting function for Tr(rho)=1 as required by defn return {{ {0, 1.} }}; } vector > HalfHalfOneSplitFn::generatePhiBackward(const double, const Energy2, const IdList & , const RhoDMatrix &) { // no dependence on the spin density matrix, dependence on off-diagonal terms cancels // and rest = splitting function for Tr(rho)=1 as required by defn return {{ {0, 1.} }}; } DecayMEPtr HalfHalfOneSplitFn::matrixElement(const double z, const Energy2 t, const IdList & ids, const double phi, bool timeLike) { // calculate the kernal DecayMEPtr kernal(new_ptr(TwoBodyDecayMatrixElement(PDT::Spin1Half,PDT::Spin1Half,PDT::Spin1))); Energy m = !timeLike ? ZERO : ids[0]->mass(); double mt = m/sqrt(t); double root = sqrt(1.-(1.-z)*sqr(m)/z/t); double romz = sqrt(1.-z); double rz = sqrt(z); Complex phase = exp(Complex(0.,1.)*phi); (*kernal)(0,0,0) = -root/romz*phase; (*kernal)(1,1,2) = -conj((*kernal)(0,0,0)); (*kernal)(0,0,2) = root/romz*z/phase; (*kernal)(1,1,0) = -conj((*kernal)(0,0,2)); (*kernal)(1,0,2) = mt*(1.-z)/rz; (*kernal)(0,1,0) = conj((*kernal)(1,0,2)); (*kernal)(0,1,2) = 0.; (*kernal)(1,0,0) = 0.; return kernal; } diff --git a/Shower/QTilde/SplittingFunctions/HalfHalfZeroEWSplitFn.cc b/Shower/QTilde/SplittingFunctions/HalfHalfZeroEWSplitFn.cc new file mode 100644 --- /dev/null +++ b/Shower/QTilde/SplittingFunctions/HalfHalfZeroEWSplitFn.cc @@ -0,0 +1,243 @@ +// -*- C++ -*- +// +// This is the implementation of the non-inlined, non-templated member +// functions of the HalfHalfZeroEWSplitFn class. +// + +#include "HalfHalfZeroEWSplitFn.h" +#include "ThePEG/StandardModel/StandardModelBase.h" +#include "ThePEG/Repository/EventGenerator.h" +#include "ThePEG/Interface/ClassDocumentation.h" +#include "ThePEG/Utilities/DescribeClass.h" +#include "ThePEG/Persistency/PersistentOStream.h" +#include "ThePEG/Persistency/PersistentIStream.h" +#include "ThePEG/PDT/ParticleData.h" +#include "Herwig/Decay/TwoBodyDecayMatrixElement.h" +#include "Herwig/Models/StandardModel/SMFFHVertex.h" + +using namespace Herwig; + +IBPtr HalfHalfZeroEWSplitFn::clone() const { + return new_ptr(*this); +} + +IBPtr HalfHalfZeroEWSplitFn::fullclone() const { + return new_ptr(*this); +} + +void HalfHalfZeroEWSplitFn::persistentOutput(PersistentOStream & os) const { + os << ghqq_ << _theSM; +} + +void HalfHalfZeroEWSplitFn::persistentInput(PersistentIStream & is, int) { + is >> ghqq_ >> _theSM; +} + +// The following static variable is needed for the type description system in ThePEG. +DescribeClass +describeHerwigHalfHalfZeroEWSplitFn("Herwig::HalfHalfZeroEWSplitFn", "HwShower.so"); + +void HalfHalfZeroEWSplitFn::Init() { + + static ClassDocumentation documentation + ("The HalfHalfZeroEWSplitFn class implements the splitting q->qH"); + +} + +void HalfHalfZeroEWSplitFn::doinit() { + SplittingFunction::doinit(); + tcSMPtr sm = generator()->standardModel(); + double sw2 = sm->sin2ThetaW(); + ghqq_ = 1./sqrt(4.*sw2); + + _theSM = dynamic_ptr_cast(generator()->standardModel()); +} + +void HalfHalfZeroEWSplitFn::getCouplings(double & gH, const IdList & ids) const { + if(abs(ids[2]->id())==ParticleID::h0) { + //get quark masses + Energy mq; + if(abs(ids[0]->id())==ParticleID::c) + mq = getParticleData(ParticleID::c)->mass(); + else if(abs(ids[0]->id())==ParticleID::b) + mq = getParticleData(ParticleID::b)->mass(); + else if(abs(ids[0]->id())==ParticleID::t) + mq = getParticleData(ParticleID::t)->mass(); + Energy mW = getParticleData(ParticleID::Wplus)->mass(); + gH = ghqq_*(mq/mW); + } + else + assert(false); +} + +void HalfHalfZeroEWSplitFn::getCouplings(double & gH, const IdList & ids, const Energy2 t) const { + if(abs(ids[2]->id())==ParticleID::h0) { + //get quark masses + Energy mq; + if(abs(ids[0]->id())==ParticleID::c) + mq = _theSM->mass(t,getParticleData(ParticleID::c)); + else if(abs(ids[0]->id())==ParticleID::b) + mq = _theSM->mass(t,getParticleData(ParticleID::b)); + else if(abs(ids[0]->id())==ParticleID::t) + mq = _theSM->mass(t,getParticleData(ParticleID::t)); + Energy mW = getParticleData(ParticleID::Wplus)->mass(); + //Energy mW = _theSM->mass(t,getParticleData(ParticleID::Wplus)); + gH = ghqq_*(mq/mW); + } + else + assert(false); +} + +double HalfHalfZeroEWSplitFn::P(const double z, const Energy2 t, + const IdList &ids, const bool mass, const RhoDMatrix & rho) const { + double gH(0.); + getCouplings(gH,ids,t); + double val = (1.-z); + Energy mq, mH; + //get masses + if(mass) { + mq = ids[0]->mass(); + mH = ids[2]->mass(); + } + else { // to assure the particle mass in non-zero + if(abs(ids[0]->id())==ParticleID::c) + mq = getParticleData(ParticleID::c)->mass(); + else if(abs(ids[0]->id())==ParticleID::b) + mq = getParticleData(ParticleID::b)->mass(); + else if(abs(ids[0]->id())==ParticleID::t) + mq = getParticleData(ParticleID::t)->mass(); + mH = getParticleData(ParticleID::h0)->mass(); + } + val += (4.*sqr(mq) - sqr(mH))/(t*(1. - z)*z); + val *= sqr(gH); + return colourFactor(ids)*val; +} + + +double HalfHalfZeroEWSplitFn::overestimateP(const double z, + const IdList & ids) const { + double gH(0.); + getCouplings(gH,ids); + return sqr(gH)*colourFactor(ids)*(1.-z); +} + +double HalfHalfZeroEWSplitFn::ratioP(const double z, const Energy2 t, + const IdList & ids, const bool mass, + const RhoDMatrix & rho) const { + double gH(0.); + getCouplings(gH,ids,t); + double val = 1.; + Energy mq, mH; + if(mass) { + mq = ids[0]->mass(); + mH = ids[2]->mass(); + } + else { // to assure the particle mass in non-zero + if(abs(ids[0]->id())==ParticleID::c) + mq = getParticleData(ParticleID::c)->mass(); + else if(abs(ids[0]->id())==ParticleID::b) + mq = getParticleData(ParticleID::b)->mass(); + else if(abs(ids[0]->id())==ParticleID::t) + mq = getParticleData(ParticleID::t)->mass(); + mH = getParticleData(ParticleID::h0)->mass(); + } + val += (4.*sqr(mq) - sqr(mH))/(t*(1. - z)*z); + return val; +} + +double HalfHalfZeroEWSplitFn::integOverP(const double z, + const IdList & ids, + unsigned int PDFfactor) const { + double gH(0.); + getCouplings(gH,ids); + double pre = colourFactor(ids)*sqr(gH); + switch (PDFfactor) { + case 0: //OverP + return pre*(z-sqr(z)/2.); + case 1: //OverP/z + return pre*(log(z)-z); + case 2: //OverP/(1-z) + return pre*z; + case 3: //OverP/[z(1-z)] + return pre*log(z); + default: + throw Exception() << "HalfHalfZeroEWSplitFn::integOverP() invalid PDFfactor = " + << PDFfactor << Exception::runerror; + } +} + +double HalfHalfZeroEWSplitFn::invIntegOverP(const double r, const IdList & ids, + unsigned int PDFfactor) const { + double gH(0.); + getCouplings(gH,ids); + double pre = colourFactor(ids)*sqr(gH); + switch (PDFfactor) { + case 0: + return 1. - sqrt(1. - 2.*r/pre); + case 1: //OverP/z + case 2: //OverP/(1-z) + return r/pre; + case 3: //OverP/[z(1-z)] + return exp(r/pre); + default: + throw Exception() << "HalfHalfZeroEWSplitFn::invIntegOverP() invalid PDFfactor = " + << PDFfactor << Exception::runerror; + } +} + +bool HalfHalfZeroEWSplitFn::accept(const IdList &ids) const { + if(ids.size()!=3) return false; + if(ids[2]->id()==ParticleID::h0) { + if(ids[0]->id()==ids[1]->id() && (ids[0]->id()==4 || ids[0]->id()==5 || ids[0]->id()==6)) + return true; + } + return false; +} + +vector > +HalfHalfZeroEWSplitFn::generatePhiForward(const double, const Energy2, const IdList & , + const RhoDMatrix &) { + // no dependence on the spin density matrix, dependence on off-diagonal terms cancels + // and rest = splitting function for Tr(rho)=1 as required by defn + return vector >(1,make_pair(0,1.)); +} + +vector > +HalfHalfZeroEWSplitFn::generatePhiBackward(const double, const Energy2, const IdList & , + const RhoDMatrix &) { + // no dependence on the spin density matrix, dependence on off-diagonal terms cancels + // and rest = splitting function for Tr(rho)=1 as required by defn + return vector >(1,make_pair(0,1.)); +} + +DecayMEPtr HalfHalfZeroEWSplitFn::matrixElement(const double z, const Energy2 t, + const IdList & ids, const double phi, + bool) { + // calculate the kernal + DecayMEPtr kernal(new_ptr(TwoBodyDecayMatrixElement(PDT::Spin1Half,PDT::Spin1Half,PDT::Spin0))); + //get masses + Energy mq, mH; + if(abs(ids[0]->id())==ParticleID::c) + mq = getParticleData(ParticleID::c)->mass(); + else if(abs(ids[0]->id())==ParticleID::b) + mq = getParticleData(ParticleID::b)->mass(); + else if(abs(ids[0]->id())==ParticleID::t) + mq = getParticleData(ParticleID::t)->mass(); + mH = getParticleData(ParticleID::h0)->mass(); + double gH(0.); + Energy2 tC = t/(z*(1-z)); + getCouplings(gH,ids,tC); + double mqt = mq/sqrt(tC); + double mHt = mH/sqrt(tC); + double num1 = gH*(1.+z)*mqt; + double num2 = gH*sqrt(-sqr(mqt)*(1.-z) - sqr(mHt)*z + z*(1.-z)*(sqr(mqt)+z*(1.-z))); //watch this + double dnum = sqrt(2.)*sqrt((1.-z)*sqr(z)); + Complex phase = exp(Complex(0.,1.)*phi); + Complex cphase = conj(phase); + (*kernal)(0,0,0) = num1/dnum; + (*kernal)(0,1,0) = cphase*num2/dnum; + (*kernal)(1,0,0) = -phase*num2/dnum; + (*kernal)(1,1,0) = num1/dnum; + // return the answer + return kernal; +} diff --git a/Shower/QTilde/SplittingFunctions/HalfHalfZeroEWSplitFn.h b/Shower/QTilde/SplittingFunctions/HalfHalfZeroEWSplitFn.h new file mode 100644 --- /dev/null +++ b/Shower/QTilde/SplittingFunctions/HalfHalfZeroEWSplitFn.h @@ -0,0 +1,219 @@ +// -*- C++ -*- +#ifndef Herwig_HalfHalfZeroEWSplitFn_H +#define Herwig_HalfHalfZeroEWSplitFn_H +// +// This is the declaration of the HalfHalfZeroEWSplitFn class. +// + +#include "SplittingFunction.h" +#include "Herwig/Models/StandardModel/StandardModel.h" + +namespace Herwig { + +using namespace ThePEG; + +/** + * The HalfHalfZeroEWSplitFn class implements the splitting function for + * \f$\frac12\to q\frac12 h\f$ where the spin-0 higgs particle is a massive scalar boson. + * + * @see \ref HalfHalfZeroEWSplitFnInterfaces "The interfaces" + * defined for HalfHalfZeroEWSplitFn. + */ +class HalfHalfZeroEWSplitFn: public SplittingFunction { + +public: + + /** + * Concrete implementation of the method to determine whether this splitting + * function can be used for a given set of particles. + * @param ids The PDG codes for the particles in the splitting. + */ + virtual bool accept(const IdList & ids) const; + + /** + * Methods to return the splitting function. + */ + //@{ + /** + * The concrete implementation of the splitting function, \f$P(z,t)\f$. + * @param z The energy fraction. + * @param t The scale. + * @param ids The PDG codes for the particles in the splitting. + * @param mass Whether or not to include the mass dependent terms + * @param rho The spin density matrix + */ + virtual double P(const double z, const Energy2 t, const IdList & ids, + const bool mass, const RhoDMatrix & rho) const; + + /** + * The concrete implementation of the overestimate of the splitting function, + * \f$P_{\rm over}\f$. + * @param z The energy fraction. + * @param ids The PDG codes for the particles in the splitting. + */ + virtual double overestimateP(const double z, const IdList & ids) const; + + /** + * The concrete implementation of the + * the ratio of the splitting function to the overestimate, i.e. + * \f$P(z,t)/P_{\rm over}(z)\f$. + * @param z The energy fraction. + * @param t The scale. + * @param ids The PDG codes for the particles in the splitting. + * @param mass Whether or not to include the mass dependent terms + * @param rho The spin density matrix + */ + virtual double ratioP(const double z, const Energy2 t, const IdList & ids, + const bool mass, const RhoDMatrix & rho) const; + + /** + * The concrete implementation of the indefinite integral of the + * overestimated splitting function, \f$P_{\rm over}\f$. + * @param z The energy fraction. + * @param ids The PDG codes for the particles in the splitting. + * @param PDFfactor Which additional factor to include for the PDF + * 0 is no additional factor, + * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ + */ + virtual double integOverP(const double z, const IdList & ids, + unsigned int PDFfactor=0) const; + + /** + * The concrete implementation of the inverse of the indefinite integral. + * @param r Value of the splitting function to be inverted + * @param ids The PDG codes for the particles in the splitting. + * @param PDFfactor Which additional factor to include for the PDF + * 0 is no additional factor, + * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ + */ + virtual double invIntegOverP(const double r, const IdList & ids, + unsigned int PDFfactor=0) const; + //@} + + /** + * Method to calculate the azimuthal angle + * @param z The energy fraction + * @param t The scale \f$t=2p_j\cdot p_k\f$. + * @param ids The PDG codes for the particles in the splitting. + * @param The azimuthal angle, \f$\phi\f$. + * @return The weight + */ + virtual vector > + generatePhiForward(const double z, const Energy2 t, const IdList & ids, + const RhoDMatrix &); + + /** + * Method to calculate the azimuthal angle for backward evolution + * @param z The energy fraction + * @param t The scale \f$t=2p_j\cdot p_k\f$. + * @param ids The PDG codes for the particles in the splitting. + * @param The azimuthal angle, \f$\phi\f$. + * @return The weight + */ + virtual vector > + generatePhiBackward(const double z, const Energy2 t, const IdList & ids, + const RhoDMatrix &); + + /** + * Calculate the matrix element for the splitting + * @param z The energy fraction + * @param t The scale \f$t=2p_j\cdot p_k\f$. + * @param ids The PDG codes for the particles in the splitting. + * @param The azimuthal angle, \f$\phi\f$. + */ + virtual DecayMEPtr matrixElement(const double z, const Energy2 t, + const IdList & ids, const double phi, bool timeLike); + +protected: + + /** + * Get the couplings without running masses + */ + void getCouplings(double & gH, const IdList & ids) const; + + /** + * Get the couplings with running masses + */ + void getCouplings(double & gH, const IdList & ids, const Energy2 t) const; + +public: + + /** @name Functions used by the persistent I/O system. */ + //@{ + /** + * Function used to write out object persistently. + * @param os the persistent output stream written to. + */ + void persistentOutput(PersistentOStream & os) const; + + /** + * Function used to read in object persistently. + * @param is the persistent input stream read from. + * @param version the version number of the object when written. + */ + void persistentInput(PersistentIStream & is, int version); + //@} + + /** + * The standard Init function used to initialize the interfaces. + * Called exactly once for each class by the class description system + * before the main function starts or + * when this class is dynamically loaded. + */ + static void Init(); + +protected: + + /** @name Clone Methods. */ + //@{ + /** + * Make a simple clone of this object. + * @return a pointer to the new object. + */ + virtual IBPtr clone() const; + + /** Make a clone of this object, possibly modifying the cloned object + * to make it sane. + * @return a pointer to the new object. + */ + virtual IBPtr fullclone() const; + //@} + +protected: + + /** @name Standard Interfaced functions. */ + //@{ + /** + * Initialize this object after the setup phase before saving an + * EventGenerator to disk. + * @throws InitException if object could not be initialized properly. + */ + virtual void doinit(); + //@} + +private: + + /** + * The assignment operator is private and must never be called. + * In fact, it should not even be implemented. + */ + HalfHalfZeroEWSplitFn & operator=(const HalfHalfZeroEWSplitFn &) = delete; + +private: + + /** + * Higgs couplings + */ + double ghqq_; + + + /** + * Pointer to the SM object. + */ + tcHwSMPtr _theSM; + +}; + +} + +#endif /* Herwig_HalfHalfZeroEWSplitFn_H */ diff --git a/Shower/QTilde/SplittingFunctions/OneHalfHalfSplitFn.cc b/Shower/QTilde/SplittingFunctions/OneHalfHalfSplitFn.cc --- a/Shower/QTilde/SplittingFunctions/OneHalfHalfSplitFn.cc +++ b/Shower/QTilde/SplittingFunctions/OneHalfHalfSplitFn.cc @@ -1,150 +1,150 @@ // -*- C++ -*- // // OneHalfHalfSplitFn.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the OneHalfHalfSplitFn class. // #include "OneHalfHalfSplitFn.h" #include "ThePEG/PDT/ParticleData.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Utilities/DescribeClass.h" #include "Herwig/Decay/TwoBodyDecayMatrixElement.h" using namespace Herwig; DescribeNoPIOClass describeOneHalfHalfSplitFn ("Herwig::OneHalfHalfSplitFn","HwShower.so"); void OneHalfHalfSplitFn::Init() { static ClassDocumentation documentation ("The OneHalfHalfSplitFn class implements the splitting function for g->q qbar"); } double OneHalfHalfSplitFn::P(const double z, const Energy2 t, const IdList &ids, const bool mass, const RhoDMatrix &) const { double zz = z*(1.-z); double val=1.-2.*zz; if(mass) { Energy m = ids[1]->mass(); val +=2.*sqr(m)/t; } return colourFactor(ids)*val; } double OneHalfHalfSplitFn::overestimateP(const double, const IdList &ids) const { return colourFactor(ids); } -double OneHalfHalfSplitFn::ratioP(const double z, const Energy2 t, - const IdList &ids, const bool mass, const RhoDMatrix &) const { +double OneHalfHalfSplitFn::ratioP(const double z, const Energy2 t, + const IdList &ids, const bool mass, const RhoDMatrix &) const { double zz = z*(1.-z); double val = 1.-2.*zz; if(mass) { Energy m = ids[1]->mass(); val+= 2.*sqr(m)/t; } return val; } double OneHalfHalfSplitFn::integOverP(const double z, const IdList & ids, unsigned int PDFfactor) const { switch(PDFfactor) { case 0: return colourFactor(ids)*z; case 1: return colourFactor(ids)*log(z); case 2: return -colourFactor(ids)*log(1.-z); case 3: return colourFactor(ids)*log(z/(1.-z)); case 4: return colourFactor(ids)*2.*sqrt(z); case 5: return colourFactor(ids)*(2./3.)*z*sqrt(z); default: throw Exception() << "OneHalfHalfSplitFn::integOverP() invalid PDFfactor = " << PDFfactor << Exception::runerror; } } double OneHalfHalfSplitFn::invIntegOverP(const double r, const IdList & ids, unsigned int PDFfactor) const { switch(PDFfactor) { case 0: return r/colourFactor(ids); case 1: return exp(r/colourFactor(ids)); case 2: return 1.-exp(-r/colourFactor(ids)); case 3: return 1./(1.+exp(-r/colourFactor(ids))); case 4: return 0.25*sqr(r/colourFactor(ids)); case 5: return pow(1.5*r/colourFactor(ids),2./3.); default: throw Exception() << "OneHalfHalfSplitFn::integOverP() invalid PDFfactor = " << PDFfactor << Exception::runerror; } } bool OneHalfHalfSplitFn::accept(const IdList &ids) const { if(ids.size()!=3) return false; if(ids[1]!=ids[2]->CC()) return false; if(ids[1]->iSpin()!=PDT::Spin1Half) return false; if(ids[0]->iSpin()!=PDT::Spin1) return false; return checkColours(ids); } vector > OneHalfHalfSplitFn::generatePhiForward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix & rho) { assert(rho.iSpin()==PDT::Spin1); double modRho = abs(rho(0,2)); Energy mq = ids[1]->mass(); Energy2 mq2 = sqr(mq); double fact = z*(1.-z)-mq2/t; double max = 1.+2.*fact*(-1.+2.*modRho); vector > output; output.push_back(make_pair( 0,(rho(0,0)+rho(2,2))*(1.-2.*fact)/max)); output.push_back(make_pair(-2,2.*fact*rho(0,2)/max)); output.push_back(make_pair( 2,2.*fact*rho(2,0)/max)); return output; } vector > OneHalfHalfSplitFn::generatePhiBackward(const double, const Energy2, const IdList &, const RhoDMatrix & ) { // no dependance return {{ {0, 1.} }}; } DecayMEPtr OneHalfHalfSplitFn::matrixElement(const double z, const Energy2 t, const IdList & ids, const double phi, bool timeLike) { static const Complex ii(0.,1.); // calculate the kernal DecayMEPtr kernal(new_ptr(TwoBodyDecayMatrixElement(PDT::Spin1,PDT::Spin1Half,PDT::Spin1Half))); double mt = !timeLike ? ZERO : ids[1]->mass()/sqrt(t); double root =sqrt(1.-sqr(mt)/z/(1.-z)); (*kernal)(0,0,0) = mt/sqrt(z*(1.-z)); (*kernal)(2,1,1) = (*kernal)(0,0,0); (*kernal)(0,0,1) = -z*root*exp(-ii*phi); (*kernal)(2,1,0) = -conj((*kernal)(0,0,1)); (*kernal)(0,1,0) = (1.-z)*exp(-ii*phi)*root; (*kernal)(2,0,1) = -conj((*kernal)(0,1,0)); (*kernal)(0,1,1) = 0.; (*kernal)(2,0,0) = 0.; return kernal; } diff --git a/Shower/QTilde/SplittingFunctions/OneOneOneEWSplitFn.cc b/Shower/QTilde/SplittingFunctions/OneOneOneEWSplitFn.cc new file mode 100644 --- /dev/null +++ b/Shower/QTilde/SplittingFunctions/OneOneOneEWSplitFn.cc @@ -0,0 +1,258 @@ +// -*- C++ -*- +// +// This is the implementation of the non-inlined, non-templated member +// functions of the OneOneOneEWSplitFn class. +// + +#include "OneOneOneEWSplitFn.h" +#include "ThePEG/StandardModel/StandardModelBase.h" +#include "ThePEG/Repository/EventGenerator.h" +#include "ThePEG/Interface/ClassDocumentation.h" +#include "ThePEG/Utilities/DescribeClass.h" +#include "ThePEG/Persistency/PersistentOStream.h" +#include "ThePEG/Persistency/PersistentIStream.h" +#include "ThePEG/PDT/ParticleData.h" +#include "Herwig/Decay/TwoBodyDecayMatrixElement.h" +#include "Herwig/Models/StandardModel/SMFFHVertex.h" + +using namespace Herwig; + +IBPtr OneOneOneEWSplitFn::clone() const { + return new_ptr(*this); +} + +IBPtr OneOneOneEWSplitFn::fullclone() const { + return new_ptr(*this); +} + +void OneOneOneEWSplitFn::persistentOutput(PersistentOStream & os) const { + os << gWWG_ << gWWZ_ << _theSM; +} + +void OneOneOneEWSplitFn::persistentInput(PersistentIStream & is, int) { + is >> gWWG_ >> gWWZ_ >> _theSM; +} + +// The following static variable is needed for the type description system in ThePEG. +DescribeClass +describeHerwigOneOneOneEWSplitFn("Herwig::OneOneOneEWSplitFn", "HwShower.so"); + + +void OneOneOneEWSplitFn::Init() { + + static ClassDocumentation documentation + ("The OneOneOneEWSplitFn class implements the splitting W->WG, W->WZ and Z->ZZ"); + +} + + +void OneOneOneEWSplitFn::doinit() { + SplittingFunction::doinit(); + tcSMPtr sm = generator()->standardModel(); + double sw2 = sm->sin2ThetaW(); + // WWZ coupling + gWWZ_ = sqrt((1.-sw2)/sw2); + // WWG coupling + gWWG_ = 1.; + // to employ running masses, wherever needed + _theSM = dynamic_ptr_cast(generator()->standardModel()); +} + + +void OneOneOneEWSplitFn::getCouplings(double & gvvv, const IdList & ids) const { + // Z > WW + if(ids[0]->id()==ParticleID::Z0 && abs(ids[1]->id())==ParticleID::Wplus + && abs(ids[2]->id())==ParticleID::Wplus){ + gvvv = gWWZ_; + } + // W > WG + else if(abs(ids[0]->id())==ParticleID::Wplus && abs(ids[1]->id())==ParticleID::Wplus + && ids[2]->id()==ParticleID::gamma){ + gvvv = gWWG_; + } + // W > WZ + else if(abs(ids[0]->id())==ParticleID::Wplus && abs(ids[1]->id())==ParticleID::Wplus + && ids[2]->id()==ParticleID::Z0){ + gvvv = gWWZ_; + } + else + assert(false); +} + + +double OneOneOneEWSplitFn::P(const double z, const Energy2 t, + const IdList &ids, const bool mass, const RhoDMatrix & rho) const { + double gvvv(0.); + getCouplings(gvvv,ids); + double abs_rho_00 = abs(rho(0,0)); + double abs_rho_11 = abs(rho(1,1)); + double abs_rho_22 = abs(rho(2,2)); + // massless limit + double val = ((2.*sqr(1.-(1.-z)*z))/((1.-z)*z))*(abs_rho_00+abs_rho_22); + // massive limits + if(mass) { + double m0t2 = sqr(ids[0]->mass())/t; + double m1t2 = sqr(ids[1]->mass())/t; + double m2t2 = sqr(ids[2]->mass())/t; + val += (-2.*(m2t2*(1.-sqr(1.-z)*z)+m1t2*(1.-(1.-z)*sqr(z)))*(abs_rho_00+abs_rho_22))/((1.-z)*z) + + (2.*m0t2*(2.*pow(1.-z,3)*z*abs_rho_11+sqr(1.-(1.-z)*z)*(abs_rho_00+abs_rho_22)))/((1.-z)*z); + } + return sqr(gvvv)*val; +} + + +double OneOneOneEWSplitFn::overestimateP(const double z, + const IdList & ids) const { + double gvvv(0.); + getCouplings(gvvv,ids); + return sqr(gvvv)*(2./(z*(1.-z))); +} + + +double OneOneOneEWSplitFn::ratioP(const double z, const Energy2 t, + const IdList & ids, const bool mass, + const RhoDMatrix & rho) const { + double val(0.); + double abs_rho_00 = abs(rho(0,0)); + double abs_rho_11 = abs(rho(1,1)); + double abs_rho_22 = abs(rho(2,2)); + // massless limit + val = sqr(1.-(1.-z)*z)*(abs_rho_00+abs_rho_22); + // massive limit + if(mass) { + double m0t2 = sqr(ids[0]->mass())/t; + double m1t2 = sqr(ids[1]->mass())/t; + double m2t2 = sqr(ids[2]->mass())/t; + val += -(m2t2*(1.-sqr(1.-z)*z) + m1t2*(1.-(1.-z)*sqr(z)))*(abs_rho_00+abs_rho_22) + + m0t2*(2.*pow(1.-z,3)*z*abs_rho_11+sqr(1.-(1.-z)*z)*(abs_rho_00+abs_rho_22)); + } + return val; +} + + +double OneOneOneEWSplitFn::integOverP(const double z, + const IdList & ids, + unsigned int PDFfactor) const { + double gvvv(0.); + getCouplings(gvvv,ids); + double pre = sqr(gvvv); + switch (PDFfactor) { + case 0: + return 2.*pre*(log(z)-log(1.-z)); + case 1: + //return -2.*pre*(1./z+log(1.-z)-log(z)); + case 2: + //return 2.*pre*(2.*log(z)+(2.*z-1.)/(z*(1.-z))-2.*log(1.-z)); + case 3: + //return 2.*pre*(1./(1.-z)-1./z-2.*log(1.-z)+2.*log(z)); + default: + throw Exception() << "OneOneOneEWSplitFn::integOverP() invalid PDFfactor = " + << PDFfactor << Exception::runerror; + } +} + +double OneOneOneEWSplitFn::invIntegOverP(const double r, const IdList & ids, + unsigned int PDFfactor) const { + double gvvv(0.); + getCouplings(gvvv,ids); + double pre = sqr(gvvv); + switch (PDFfactor) { + case 0: + return exp(0.5*r/pre)/(1.+exp(0.5*r/pre)); + case 1: + case 2: + case 3: + default: + throw Exception() << "OneOneOneEWSplitFn::invIntegOverP() invalid PDFfactor = " + << PDFfactor << Exception::runerror; + } +} + +bool OneOneOneEWSplitFn::accept(const IdList &ids) const { + if(ids.size()!=3) return false; + // Z > WW + if(ids[0]->id()==ParticleID::Z0 && abs(ids[1]->id())==ParticleID::Wplus + && ids[1]->id()==-ids[2]->id()) + return true; + + if(abs(ids[0]->id())==ParticleID::Wplus) { + // W > WG + if(ids[1]->id()==ids[0]->id() && ids[2]->id()==ParticleID::gamma) + return true; + // W > WZ + if(ids[1]->id()==ids[0]->id() && ids[2]->id()==ParticleID::Z0) + return true; + } + return false; +} + + +vector > +OneOneOneEWSplitFn::generatePhiForward(const double, const Energy2, const IdList & , + const RhoDMatrix &) { + // no dependence on the spin density matrix, dependence on off-diagonal terms cancels + // and rest = splitting function for Tr(rho)=1 as required by defn + return vector >(1,make_pair(0,1.)); +} + + +vector > +OneOneOneEWSplitFn::generatePhiBackward(const double, const Energy2, const IdList & , + const RhoDMatrix &) { + // no dependence on the spin density matrix, dependence on off-diagonal terms cancels + // and rest = splitting function for Tr(rho)=1 as required by defn + return vector >(1,make_pair(0,1.)); +} + + +DecayMEPtr OneOneOneEWSplitFn::matrixElement(const double z, const Energy2 t, + const IdList & ids, const double phi, + bool) { + // calculate the kernal + DecayMEPtr kernal(new_ptr(TwoBodyDecayMatrixElement(PDT::Spin1,PDT::Spin1,PDT::Spin1))); + double gvvv(0.); + getCouplings(gvvv,ids); + // defining dummies + double m0t = ids[0]->mass()/sqrt(t); + double m1t = ids[1]->mass()/sqrt(t); + double m2t = ids[2]->mass()/sqrt(t); + Complex phase = exp(Complex(0.,1.)*phi); + Complex cphase = conj(phase); + + double z1_z = z*(1.-z); + double sqrtmass = sqrt(sqr(m0t)-sqr(m1t)/z-sqr(m2t)/(1.-z)+1.); + double r2 = sqrt(2.); + // assign kernel + (*kernal)(0,0,0) = gvvv*phase*(1./sqrt(z1_z))*sqrtmass; + (*kernal)(0,0,1) = gvvv*r2*m2t*(z/(1.-z)); //2>4 + (*kernal)(0,0,2) = -gvvv*cphase*sqrt(z/(1.-z))*sqrtmass; + (*kernal)(0,1,0) = -gvvv*r2*m1t*(1.-z)/z; //2>4 + (*kernal)(0,1,1) = 0.; + (*kernal)(0,1,2) = 0.; + (*kernal)(0,2,0) = -gvvv*(1.-z)*cphase*sqrt((1.-z)/z)*sqrtmass; + (*kernal)(0,2,1) = 0.; + (*kernal)(0,2,2) = 0.; + + (*kernal)(1,0,0) = 0.; + (*kernal)(1,0,1) = 0.; //2>4 + (*kernal)(1,0,2) = -gvvv*r2*m0t*(1.-z); //2>4 + (*kernal)(1,1,0) = 0.; //221>441 + (*kernal)(1,1,1) = 0.; //222>444 + (*kernal)(1,1,2) = 0.; //223>443 + (*kernal)(1,2,0) = -gvvv*r2*m0t*(1.-z); //2>4 + (*kernal)(1,2,1) = 0.; //2>4 + (*kernal)(1,2,2) = 0.; //2>4 + + (*kernal)(2,0,0) = 0.; + (*kernal)(2,0,1) = 0.; + (*kernal)(2,0,2) = gvvv*(1.-z)*phase*sqrt((1.-z)/z)*sqrtmass; + (*kernal)(2,1,0) = 0.; + (*kernal)(2,1,1) = 0.; //2>4 + (*kernal)(2,1,2) = -gvvv*r2*m1t*((1.-z)/z);//2>4 + (*kernal)(2,2,0) = gvvv*phase*sqrt(z/(1.-z))*sqrtmass; + (*kernal)(2,2,1) = gvvv*r2*m2t*(z/(1.-z)); //2>4 + (*kernal)(2,2,2) = -gvvv*cphase*(1./sqrt(z1_z))*sqrtmass; + + // return the answer + return kernal; +} diff --git a/Shower/QTilde/SplittingFunctions/OneOneOneEWSplitFn.h b/Shower/QTilde/SplittingFunctions/OneOneOneEWSplitFn.h new file mode 100644 --- /dev/null +++ b/Shower/QTilde/SplittingFunctions/OneOneOneEWSplitFn.h @@ -0,0 +1,217 @@ +// -*- C++ -*- +#ifndef Herwig_OneOneOneEWSplitFn_H +#define Herwig_OneOneOneEWSplitFn_H +// +// This is the declaration of the OneOneOneEWSplitFn class. +// + +#include "SplittingFunction.h" +#include "Herwig/Models/StandardModel/StandardModel.h" + +namespace Herwig { + +using namespace ThePEG; + +/** + * The OneOneOneEWSplitFn class implements the splitting function for + * \f$\1\to q\1 1\f$ where the spin-1 particles are massive electroweak gauge bosons. + * + * @see \ref OneOneOneEWSplitFnInterfaces "The interfaces" + * defined for OneOneOneEWSplitFn. + */ +class OneOneOneEWSplitFn: public SplittingFunction { + +public: + + /** + * Concrete implementation of the method to determine whether this splitting + * function can be used for a given set of particles. + * @param ids The PDG codes for the particles in the splitting. + */ + virtual bool accept(const IdList & ids) const; + + /** + * Methods to return the splitting function. + */ + //@{ + /** + * The concrete implementation of the splitting function, \f$P(z,t)\f$. + * @param z The energy fraction. + * @param t The scale. + * @param ids The PDG codes for the particles in the splitting. + * @param mass Whether or not to include the mass dependent terms + * @param rho The spin density matrix + */ + virtual double P(const double z, const Energy2 t, const IdList & ids, + const bool mass, const RhoDMatrix & rho) const; + + /** + * The concrete implementation of the overestimate of the splitting function, + * \f$P_{\rm over}\f$. + * @param z The energy fraction. + * @param ids The PDG codes for the particles in the splitting. + */ + virtual double overestimateP(const double z, const IdList & ids) const; + + /** + * The concrete implementation of the + * the ratio of the splitting function to the overestimate, i.e. + * \f$P(z,t)/P_{\rm over}(z)\f$. + * @param z The energy fraction. + * @param t The scale. + * @param ids The PDG codes for the particles in the splitting. + * @param mass Whether or not to include the mass dependent terms + * @param rho The spin density matrix + */ + virtual double ratioP(const double z, const Energy2 t, const IdList & ids, + const bool mass, const RhoDMatrix & rho) const; + + /** + * The concrete implementation of the indefinite integral of the + * overestimated splitting function, \f$P_{\rm over}\f$. + * @param z The energy fraction. + * @param ids The PDG codes for the particles in the splitting. + * @param PDFfactor Which additional factor to include for the PDF + * 0 is no additional factor, + * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ + */ + virtual double integOverP(const double z, const IdList & ids, + unsigned int PDFfactor=0) const; + + /** + * The concrete implementation of the inverse of the indefinite integral. + * @param r Value of the splitting function to be inverted + * @param ids The PDG codes for the particles in the splitting. + * @param PDFfactor Which additional factor to include for the PDF + * 0 is no additional factor, + * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ + */ + virtual double invIntegOverP(const double r, const IdList & ids, + unsigned int PDFfactor=0) const; + //@} + + /** + * Method to calculate the azimuthal angle + * @param z The energy fraction + * @param t The scale \f$t=2p_j\cdot p_k\f$. + * @param ids The PDG codes for the particles in the splitting. + * @param The azimuthal angle, \f$\phi\f$. + * @return The weight + */ + virtual vector > + generatePhiForward(const double z, const Energy2 t, const IdList & ids, + const RhoDMatrix &); + + /** + * Method to calculate the azimuthal angle for backward evolution + * @param z The energy fraction + * @param t The scale \f$t=2p_j\cdot p_k\f$. + * @param ids The PDG codes for the particles in the splitting. + * @param The azimuthal angle, \f$\phi\f$. + * @return The weight + */ + virtual vector > + generatePhiBackward(const double z, const Energy2 t, const IdList & ids, + const RhoDMatrix &); + + /** + * Calculate the matrix element for the splitting + * @param z The energy fraction + * @param t The scale \f$t=2p_j\cdot p_k\f$. + * @param ids The PDG codes for the particles in the splitting. + * @param The azimuthal angle, \f$\phi\f$. + */ + virtual DecayMEPtr matrixElement(const double z, const Energy2 t, + const IdList & ids, const double phi, bool timeLike); + +protected: + + /** + * Get the couplings + */ + void getCouplings(double & gvvv, const IdList & ids) const; + +public: + + /** @name Functions used by the persistent I/O system. */ + //@{ + /** + * Function used to write out object persistently. + * @param os the persistent output stream written to. + */ + void persistentOutput(PersistentOStream & os) const; + + /** + * Function used to read in object persistently. + * @param is the persistent input stream read from. + * @param version the version number of the object when written. + */ + void persistentInput(PersistentIStream & is, int version); + //@} + + /** + * The standard Init function used to initialize the interfaces. + * Called exactly once for each class by the class description system + * before the main function starts or + * when this class is dynamically loaded. + */ + static void Init(); + +protected: + + /** @name Clone Methods. */ + //@{ + /** + * Make a simple clone of this object. + * @return a pointer to the new object. + */ + virtual IBPtr clone() const; + + /** Make a clone of this object, possibly modifying the cloned object + * to make it sane. + * @return a pointer to the new object. + */ + virtual IBPtr fullclone() const; + //@} + +protected: + + /** @name Standard Interfaced functions. */ + //@{ + /** + * Initialize this object after the setup phase before saving an + * EventGenerator to disk. + * @throws InitException if object could not be initialized properly. + */ + virtual void doinit(); + //@} + +private: + + /** + * The assignment operator is private and must never be called. + * In fact, it should not even be implemented. + */ + OneOneOneEWSplitFn & operator=(const OneOneOneEWSplitFn &) = delete; + +private: + + /** + * W^{\pm} -> W^{\pm} G couplings + */ + double gWWG_; + + /** + * W^{\pm} -> W^{\pm} Z couplings + */ + double gWWZ_; + + /** + * Pointer to the SM object. + */ + tcHwSMPtr _theSM; +}; + +} + +#endif /* Herwig_OneOneOneEWSplitFn_H */ diff --git a/Shower/QTilde/SplittingFunctions/OneOneOneQEDSplitFn.cc b/Shower/QTilde/SplittingFunctions/OneOneOneQEDSplitFn.cc new file mode 100644 --- /dev/null +++ b/Shower/QTilde/SplittingFunctions/OneOneOneQEDSplitFn.cc @@ -0,0 +1,236 @@ +// -*- C++ -*- +// +// This is the implementation of the non-inlined, non-templated member +// functions of the OneOneOneQEDSplitFn class. +// + +#include "OneOneOneQEDSplitFn.h" +#include "ThePEG/StandardModel/StandardModelBase.h" +#include "ThePEG/Repository/EventGenerator.h" +#include "ThePEG/Interface/ClassDocumentation.h" +#include "ThePEG/Utilities/DescribeClass.h" +#include "ThePEG/Persistency/PersistentOStream.h" +#include "ThePEG/Persistency/PersistentIStream.h" +#include "ThePEG/PDT/ParticleData.h" +#include "Herwig/Decay/TwoBodyDecayMatrixElement.h" +#include "Herwig/Models/StandardModel/SMFFHVertex.h" + +using namespace Herwig; + +IBPtr OneOneOneQEDSplitFn::clone() const { + return new_ptr(*this); +} + +IBPtr OneOneOneQEDSplitFn::fullclone() const { + return new_ptr(*this); +} + +void OneOneOneQEDSplitFn::persistentOutput(PersistentOStream & os) const { + os << gWWG_ << _theSM; +} + +void OneOneOneQEDSplitFn::persistentInput(PersistentIStream & is, int) { + is >> gWWG_ >> _theSM; +} + +// The following static variable is needed for the type description system in ThePEG. +DescribeClass +describeHerwigOneOneOneQEDSplitFn("Herwig::OneOneOneQEDSplitFn", "HwShower.so"); + + +void OneOneOneQEDSplitFn::Init() { + + static ClassDocumentation documentation + ("The OneOneOneQEDSplitFn class implements the gamma->WW EW splitting."); + +} + + +void OneOneOneQEDSplitFn::doinit() { + SplittingFunction::doinit(); + tcSMPtr sm = generator()->standardModel(); + double sw2 = sm->sin2ThetaW(); + // WWG coupling + gWWG_ = 1.; + // to employ running masses, wherever needed + _theSM = dynamic_ptr_cast(generator()->standardModel()); +} + + +void OneOneOneQEDSplitFn::getCouplings(double & gvvv, const IdList & ids) const { + // G > WW + if(ids[0]->id()==ParticleID::gamma && abs(ids[1]->id())==ParticleID::Wplus + && abs(ids[2]->id())==ParticleID::Wplus){ + gvvv = gWWG_; + } + else + assert(false); +} + + +double OneOneOneQEDSplitFn::P(const double z, const Energy2 t, + const IdList &ids, const bool mass, const RhoDMatrix & rho) const { + double gvvv(0.); + getCouplings(gvvv,ids); + double abs_rho_00 = abs(rho(0,0)); + double abs_rho_11 = abs(rho(1,1)); + double abs_rho_22 = abs(rho(2,2)); + // massless limit + double val = ((2.*sqr(1.-(1.-z)*z))/((1.-z)*z))*(abs_rho_00+abs_rho_22); + // massive limits + if(mass) { + double m0t2 = sqr(ids[0]->mass())/t; + double m1t2 = sqr(ids[1]->mass())/t; + double m2t2 = sqr(ids[2]->mass())/t; + val += (-2.*(m2t2*(1.-sqr(1.-z)*z)+m1t2*(1.-(1.-z)*sqr(z)))*(abs_rho_00+abs_rho_22))/((1.-z)*z) + + (2.*m0t2*(2.*pow(1.-z,3)*z*abs_rho_11+sqr(1.-(1.-z)*z)*(abs_rho_00+abs_rho_22)))/((1.-z)*z); + } + return sqr(gvvv)*val; +} + + +double OneOneOneQEDSplitFn::overestimateP(const double z, + const IdList & ids) const { + double gvvv(0.); + getCouplings(gvvv,ids); + return sqr(gvvv)*(2./(z*(1.-z))); +} + + +double OneOneOneQEDSplitFn::ratioP(const double z, const Energy2 t, + const IdList & ids, const bool mass, + const RhoDMatrix & rho) const { + double val(0.); + double abs_rho_00 = abs(rho(0,0)); + double abs_rho_11 = abs(rho(1,1)); + double abs_rho_22 = abs(rho(2,2)); + // massless limit + val = sqr(1.-(1.-z)*z)*(abs_rho_00+abs_rho_22); + // massive limit + if(mass) { + double m0t2 = sqr(ids[0]->mass())/t; + double m1t2 = sqr(ids[1]->mass())/t; + double m2t2 = sqr(ids[2]->mass())/t; + val += -(m2t2*(1.-sqr(1.-z)*z) + m1t2*(1.-(1.-z)*sqr(z)))*(abs_rho_00+abs_rho_22) + + m0t2*(2.*pow(1.-z,3)*z*abs_rho_11+sqr(1.-(1.-z)*z)*(abs_rho_00+abs_rho_22)); + } + return val; +} + + +double OneOneOneQEDSplitFn::integOverP(const double z, + const IdList & ids, + unsigned int PDFfactor) const { + double gvvv(0.); + getCouplings(gvvv,ids); + double pre = sqr(gvvv); + switch (PDFfactor) { + case 0: + return 2.*pre*(log(z)-log(1.-z)); + case 1: + //return -2.*pre*(1./z+log(1.-z)-log(z)); + case 2: + //return 2.*pre*(2.*log(z)+(2.*z-1.)/(z*(1.-z))-2.*log(1.-z)); + case 3: + //return 2.*pre*(1./(1.-z)-1./z-2.*log(1.-z)+2.*log(z)); + default: + throw Exception() << "OneOneOneQEDSplitFn::integOverP() invalid PDFfactor = " + << PDFfactor << Exception::runerror; + } +} + +double OneOneOneQEDSplitFn::invIntegOverP(const double r, const IdList & ids, + unsigned int PDFfactor) const { + double gvvv(0.); + getCouplings(gvvv,ids); + double pre = sqr(gvvv); + switch (PDFfactor) { + case 0: + return exp(0.5*r/pre)/(1.+exp(0.5*r/pre)); + case 1: + case 2: + case 3: + default: + throw Exception() << "OneOneOneQEDSplitFn::invIntegOverP() invalid PDFfactor = " + << PDFfactor << Exception::runerror; + } +} + +bool OneOneOneQEDSplitFn::accept(const IdList &ids) const { + if(ids.size()!=3) return false; + if(ids[0]->id()==ParticleID::gamma && abs(ids[1]->id())==ParticleID::Wplus + && ids[1]->id()==-ids[2]->id()) + return true; + return false; +} + + +vector > +OneOneOneQEDSplitFn::generatePhiForward(const double, const Energy2, const IdList & , + const RhoDMatrix &) { + // no dependence on the spin density matrix, dependence on off-diagonal terms cancels + // and rest = splitting function for Tr(rho)=1 as required by defn + return vector >(1,make_pair(0,1.)); +} + + +vector > +OneOneOneQEDSplitFn::generatePhiBackward(const double, const Energy2, const IdList & , + const RhoDMatrix &) { + // no dependence on the spin density matrix, dependence on off-diagonal terms cancels + // and rest = splitting function for Tr(rho)=1 as required by defn + return vector >(1,make_pair(0,1.)); +} + + +DecayMEPtr OneOneOneQEDSplitFn::matrixElement(const double z, const Energy2 t, + const IdList & ids, const double phi, + bool) { + // calculate the kernal + DecayMEPtr kernal(new_ptr(TwoBodyDecayMatrixElement(PDT::Spin1,PDT::Spin1,PDT::Spin1))); + double gvvv(0.); + getCouplings(gvvv,ids); + // defining dummies + double m0t = ids[0]->mass()/sqrt(t); + double m1t = ids[1]->mass()/sqrt(t); + double m2t = ids[2]->mass()/sqrt(t); + Complex phase = exp(Complex(0.,1.)*phi); + Complex cphase = conj(phase); + + double z1_z = z*(1.-z); + double sqrtmass = sqrt(sqr(m0t)-sqr(m1t)/z-sqr(m2t)/(1.-z)+1.); + double r2 = sqrt(2.); + // assign kernel + (*kernal)(0,0,0) = gvvv*phase*(1./sqrt(z1_z))*sqrtmass; + (*kernal)(0,0,1) = gvvv*r2*m2t*(z/(1.-z)); //2>4 + (*kernal)(0,0,2) = -gvvv*cphase*sqrt(z/(1.-z))*sqrtmass; + (*kernal)(0,1,0) = -gvvv*r2*m1t*(1.-z)/z; //2>4 + (*kernal)(0,1,1) = 0.; + (*kernal)(0,1,2) = 0.; + (*kernal)(0,2,0) = -gvvv*(1.-z)*cphase*sqrt((1.-z)/z)*sqrtmass; + (*kernal)(0,2,1) = 0.; + (*kernal)(0,2,2) = 0.; + + (*kernal)(1,0,0) = 0.; + (*kernal)(1,0,1) = 0.; //2>4 + (*kernal)(1,0,2) = -gvvv*r2*m0t*(1.-z); //2>4 + (*kernal)(1,1,0) = 0.; //221>441 + (*kernal)(1,1,1) = 0.; //222>444 + (*kernal)(1,1,2) = 0.; //223>443 + (*kernal)(1,2,0) = -gvvv*r2*m0t*(1.-z); //2>4 + (*kernal)(1,2,1) = 0.; //2>4 + (*kernal)(1,2,2) = 0.; //2>4 + + (*kernal)(2,0,0) = 0.; + (*kernal)(2,0,1) = 0.; + (*kernal)(2,0,2) = gvvv*(1.-z)*phase*sqrt((1.-z)/z)*sqrtmass; + (*kernal)(2,1,0) = 0.; + (*kernal)(2,1,1) = 0.; //2>4 + (*kernal)(2,1,2) = -gvvv*r2*m1t*((1.-z)/z);//2>4 + (*kernal)(2,2,0) = gvvv*phase*sqrt(z/(1.-z))*sqrtmass; + (*kernal)(2,2,1) = gvvv*r2*m2t*(z/(1.-z)); //2>4 + (*kernal)(2,2,2) = -gvvv*cphase*(1./sqrt(z1_z))*sqrtmass; + + // return the answer + return kernal; +} diff --git a/Shower/QTilde/SplittingFunctions/OneOneOneQEDSplitFn.h b/Shower/QTilde/SplittingFunctions/OneOneOneQEDSplitFn.h new file mode 100644 --- /dev/null +++ b/Shower/QTilde/SplittingFunctions/OneOneOneQEDSplitFn.h @@ -0,0 +1,212 @@ +// -*- C++ -*- +#ifndef Herwig_OneOneOneQEDSplitFn_H +#define Herwig_OneOneOneQEDSplitFn_H +// +// This is the declaration of the OneOneOneQEDSplitFn class. +// + +#include "SplittingFunction.h" +#include "Herwig/Models/StandardModel/StandardModel.h" + +namespace Herwig { + +using namespace ThePEG; + +/** + * The OneOneOneQEDSplitFn class implements the splitting function for + * \f$\1\to q\1 1\f$ where the spin-1 particles are massive electroweak gauge bosons. + * + * @see \ref OneOneOneQEDSplitFnInterfaces "The interfaces" + * defined for OneOneOneQEDSplitFn. + */ +class OneOneOneQEDSplitFn: public SplittingFunction { + +public: + + /** + * Concrete implementation of the method to determine whether this splitting + * function can be used for a given set of particles. + * @param ids The PDG codes for the particles in the splitting. + */ + virtual bool accept(const IdList & ids) const; + + /** + * Methods to return the splitting function. + */ + //@{ + /** + * The concrete implementation of the splitting function, \f$P(z,t)\f$. + * @param z The energy fraction. + * @param t The scale. + * @param ids The PDG codes for the particles in the splitting. + * @param mass Whether or not to include the mass dependent terms + * @param rho The spin density matrix + */ + virtual double P(const double z, const Energy2 t, const IdList & ids, + const bool mass, const RhoDMatrix & rho) const; + + /** + * The concrete implementation of the overestimate of the splitting function, + * \f$P_{\rm over}\f$. + * @param z The energy fraction. + * @param ids The PDG codes for the particles in the splitting. + */ + virtual double overestimateP(const double z, const IdList & ids) const; + + /** + * The concrete implementation of the + * the ratio of the splitting function to the overestimate, i.e. + * \f$P(z,t)/P_{\rm over}(z)\f$. + * @param z The energy fraction. + * @param t The scale. + * @param ids The PDG codes for the particles in the splitting. + * @param mass Whether or not to include the mass dependent terms + * @param rho The spin density matrix + */ + virtual double ratioP(const double z, const Energy2 t, const IdList & ids, + const bool mass, const RhoDMatrix & rho) const; + + /** + * The concrete implementation of the indefinite integral of the + * overestimated splitting function, \f$P_{\rm over}\f$. + * @param z The energy fraction. + * @param ids The PDG codes for the particles in the splitting. + * @param PDFfactor Which additional factor to include for the PDF + * 0 is no additional factor, + * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ + */ + virtual double integOverP(const double z, const IdList & ids, + unsigned int PDFfactor=0) const; + + /** + * The concrete implementation of the inverse of the indefinite integral. + * @param r Value of the splitting function to be inverted + * @param ids The PDG codes for the particles in the splitting. + * @param PDFfactor Which additional factor to include for the PDF + * 0 is no additional factor, + * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ + */ + virtual double invIntegOverP(const double r, const IdList & ids, + unsigned int PDFfactor=0) const; + //@} + + /** + * Method to calculate the azimuthal angle + * @param z The energy fraction + * @param t The scale \f$t=2p_j\cdot p_k\f$. + * @param ids The PDG codes for the particles in the splitting. + * @param The azimuthal angle, \f$\phi\f$. + * @return The weight + */ + virtual vector > + generatePhiForward(const double z, const Energy2 t, const IdList & ids, + const RhoDMatrix &); + + /** + * Method to calculate the azimuthal angle for backward evolution + * @param z The energy fraction + * @param t The scale \f$t=2p_j\cdot p_k\f$. + * @param ids The PDG codes for the particles in the splitting. + * @param The azimuthal angle, \f$\phi\f$. + * @return The weight + */ + virtual vector > + generatePhiBackward(const double z, const Energy2 t, const IdList & ids, + const RhoDMatrix &); + + /** + * Calculate the matrix element for the splitting + * @param z The energy fraction + * @param t The scale \f$t=2p_j\cdot p_k\f$. + * @param ids The PDG codes for the particles in the splitting. + * @param The azimuthal angle, \f$\phi\f$. + */ + virtual DecayMEPtr matrixElement(const double z, const Energy2 t, + const IdList & ids, const double phi, bool timeLike); + +protected: + + /** + * Get the couplings + */ + void getCouplings(double & gvvv, const IdList & ids) const; + +public: + + /** @name Functions used by the persistent I/O system. */ + //@{ + /** + * Function used to write out object persistently. + * @param os the persistent output stream written to. + */ + void persistentOutput(PersistentOStream & os) const; + + /** + * Function used to read in object persistently. + * @param is the persistent input stream read from. + * @param version the version number of the object when written. + */ + void persistentInput(PersistentIStream & is, int version); + //@} + + /** + * The standard Init function used to initialize the interfaces. + * Called exactly once for each class by the class description system + * before the main function starts or + * when this class is dynamically loaded. + */ + static void Init(); + +protected: + + /** @name Clone Methods. */ + //@{ + /** + * Make a simple clone of this object. + * @return a pointer to the new object. + */ + virtual IBPtr clone() const; + + /** Make a clone of this object, possibly modifying the cloned object + * to make it sane. + * @return a pointer to the new object. + */ + virtual IBPtr fullclone() const; + //@} + +protected: + + /** @name Standard Interfaced functions. */ + //@{ + /** + * Initialize this object after the setup phase before saving an + * EventGenerator to disk. + * @throws InitException if object could not be initialized properly. + */ + virtual void doinit(); + //@} + +private: + + /** + * The assignment operator is private and must never be called. + * In fact, it should not even be implemented. + */ + OneOneOneQEDSplitFn & operator=(const OneOneOneQEDSplitFn &) = delete; + +private: + + /** + * W^{\pm} -> W^{\pm} G couplings + */ + double gWWG_; + + /** + * Pointer to the SM object. + */ + tcHwSMPtr _theSM; +}; + +} + +#endif /* Herwig_OneOneOneQEDSplitFn_H */ diff --git a/Shower/QTilde/SplittingFunctions/OneOneZeroEWSplitFn.cc b/Shower/QTilde/SplittingFunctions/OneOneZeroEWSplitFn.cc new file mode 100644 --- /dev/null +++ b/Shower/QTilde/SplittingFunctions/OneOneZeroEWSplitFn.cc @@ -0,0 +1,217 @@ +// -*- C++ -*- +// +// This is the implementation of the non-inlined, non-templated member +// functions of the OneOneZeroEWSplitFn class. +// + +#include "OneOneZeroEWSplitFn.h" +#include "ThePEG/StandardModel/StandardModelBase.h" +#include "ThePEG/Repository/EventGenerator.h" +#include "ThePEG/Interface/ClassDocumentation.h" +#include "ThePEG/Utilities/DescribeClass.h" +#include "ThePEG/Persistency/PersistentOStream.h" +#include "ThePEG/Persistency/PersistentIStream.h" +#include "ThePEG/PDT/ParticleData.h" +#include "Herwig/Decay/TwoBodyDecayMatrixElement.h" +#include "Herwig/Models/StandardModel/SMFFHVertex.h" + +using namespace Herwig; + +IBPtr OneOneZeroEWSplitFn::clone() const { + return new_ptr(*this); +} + +IBPtr OneOneZeroEWSplitFn::fullclone() const { + return new_ptr(*this); +} + +void OneOneZeroEWSplitFn::persistentOutput(PersistentOStream & os) const { + os << gWWH_ << gZZH_ << _theSM; +} + +void OneOneZeroEWSplitFn::persistentInput(PersistentIStream & is, int) { + is >> gWWH_ >> gZZH_ >> _theSM; +} + +// The following static variable is needed for the type description system in ThePEG. +DescribeClass +describeHerwigOneOneZeroEWSplitFn("Herwig::OneOneZeroEWSplitFn", "HwShower.so"); + + +void OneOneZeroEWSplitFn::Init() { + + static ClassDocumentation documentation + ("The OneOneZeroEWSplitFn class implements the splittings W->WH and Z->ZH"); + +} + + +void OneOneZeroEWSplitFn::doinit() { + SplittingFunction::doinit(); + tcSMPtr sm = generator()->standardModel(); + double sw2 = sm->sin2ThetaW(); + // W -> W H coupling g = e/sin theta_W + gWWH_ = 1./sqrt(sw2); + // Z -> Z H coupling + gZZH_ = 1./(sqrt(sw2)*sqrt(1.-sw2)); + // to employ running masses, wherever needed + _theSM = dynamic_ptr_cast(generator()->standardModel()); +} + + +void OneOneZeroEWSplitFn::getCouplings(double & g, const IdList & ids) const { + if(abs(ids[0]->id())==ParticleID::Wplus){ + g = gWWH_; + } + else if(ids[0]->id()==ParticleID::Z0){ + g = gZZH_; + } + else + assert(false); +} + + +double OneOneZeroEWSplitFn::P(const double z, const Energy2 t, + const IdList &ids, const bool mass, const RhoDMatrix & rho) const { + double gvvh(0.); + getCouplings(gvvh,ids); + double rho00 = abs(rho(0,0)); + double rho11 = abs(rho(1,1)); + double rho22 = abs(rho(2,2)); + // the splitting in the massless limit + double val = ((1.-z)*(2.*rho11+sqr(z)*(rho00+rho22)))/(4.*z); + // the massive limit + if(mass){ + // get the running mass + double mBt = _theSM->mass(t,getParticleData(ids[0]->id()))/sqrt(t); + double mHt = _theSM->mass(t,getParticleData(ids[2]->id()))/sqrt(t); + //val += (2./sqr(z))*sqr(m0t)*(rho11+sqr(z)*(rho00+rho22)); + val += -(sqr(mHt)*(2.*rho11+sqr(z)*(rho00+rho22)))/(4.*z) + - (sqr(mBt)*(2.*rho11+z*(-4.*rho11+z*(2.*rho11+(-1.+(-2.+z)*z)*(rho00+rho22))))) + /(4.*sqr(z)); + } + return sqr(gvvh)*val; +} + + +double OneOneZeroEWSplitFn::overestimateP(const double z, + const IdList & ids) const { + double gvvh(0.); + getCouplings(gvvh,ids); + return sqr(gvvh)/(2.*z); +} + + +double OneOneZeroEWSplitFn::ratioP(const double z, const Energy2 t, + const IdList & ids, const bool mass, + const RhoDMatrix & rho) const { + double rho00 = abs(rho(0,0)); + double rho11 = abs(rho(1,1)); + double rho22 = abs(rho(2,2)); + // ratio in the massless limit + double val = ((1.-z)*(2.*rho11+sqr(z)*(rho00+rho22)))/2.; + // the massive limit + if(mass){ + // get the running mass + double mBt = _theSM->mass(t,getParticleData(ids[0]->id()))/sqrt(t); + double mHt = _theSM->mass(t,getParticleData(ids[2]->id()))/sqrt(t); + val += -(sqr(mHt)*(2.*rho11+ sqr(z)*(rho00+rho22)))/2. + - (sqr(mBt)*(2.*rho11+z*(-4.*rho11+2.*z*rho11+z*(-1.+(-2.+z)*z)*(rho00+rho22))))/(2.*z); + } + return val; +} + + +double OneOneZeroEWSplitFn::integOverP(const double z, + const IdList & ids, + unsigned int PDFfactor) const { + double gvvh(0.); + getCouplings(gvvh,ids); + double pre = sqr(gvvh); + switch (PDFfactor) { + case 0: + return pre*log(z)/2.; + case 1: + case 2: + case 3: + default: + throw Exception() << "OneOneZeroEWSplitFn::integOverP() invalid PDFfactor = " + << PDFfactor << Exception::runerror; + } +} + +double OneOneZeroEWSplitFn::invIntegOverP(const double r, const IdList & ids, + unsigned int PDFfactor) const { + double gvvh(0.); + getCouplings(gvvh,ids); + double pre = sqr(gvvh); + switch (PDFfactor) { + case 0: + return exp(2.*r/(pre)); + case 1: + case 2: + case 3: + default: + throw Exception() << "OneOneZeroEWSplitFn::invIntegOverP() invalid PDFfactor = " + << PDFfactor << Exception::runerror; + } +} + +bool OneOneZeroEWSplitFn::accept(const IdList &ids) const { + if(ids.size()!=3) + return false; + if(ids[0]->id()!=ids[1]->id()) + return false; + if(abs(ids[0]->id())==ParticleID::Wplus && ids[2]->id()==ParticleID::h0) + return true; + else if(ids[0]->id()==ParticleID::Z0 && ids[2]->id()==ParticleID::h0) + return true; + else + return false; +} + + +vector > +OneOneZeroEWSplitFn::generatePhiForward(const double, const Energy2, const IdList & , + const RhoDMatrix &) { + // no dependence on the spin density matrix, dependence on off-diagonal terms cancels + // and rest = splitting function for Tr(rho)=1 as required by defn + return vector >(1,make_pair(0,1.)); +} + + +vector > +OneOneZeroEWSplitFn::generatePhiBackward(const double, const Energy2, const IdList & , + const RhoDMatrix &) { + // no dependence on the spin density matrix, dependence on off-diagonal terms cancels + // and rest = splitting function for Tr(rho)=1 as required by defn + return vector >(1,make_pair(0,1.)); +} + + +DecayMEPtr OneOneZeroEWSplitFn::matrixElement(const double z, const Energy2 t, + const IdList & ids, const double phi, + bool) { + double gvvh(0.); + getCouplings(gvvh,ids); + // calculate the kernal + DecayMEPtr kernal(new_ptr(TwoBodyDecayMatrixElement(PDT::Spin1,PDT::Spin1,PDT::Spin0))); + Complex phase = exp(Complex(0.,1.)*phi); + Complex cphase = conj(phase); + double r2 = sqrt(2.); + double mBt = _theSM->mass(t,getParticleData(ids[0]->id()))/sqrt(t); + double mHt = _theSM->mass(t,getParticleData(ids[2]->id()))/sqrt(t); + double sqrtmass = sqrt(-(sqr(mBt)*sqr(1.-z))-sqr(mHt)*z+(1.-z)*z); + // assign kernel + (*kernal)(0,0,0) = -gvvh*mBt/r2; // 111 + (*kernal)(0,1,0) = -(cphase/2.)*sqrtmass; // 121 + (*kernal)(0,2,0) = 0.; // 131 + (*kernal)(1,0,0) = ( phase/2.*z)*sqrtmass; // 211 + (*kernal)(1,1,0) = 0.; // 221 > 441 + (*kernal)(1,2,0) = -(cphase/2.*z)*sqrtmass; // 231 + (*kernal)(2,0,0) = 0.; // 311 + (*kernal)(2,1,0) = ( phase/2.)*sqrtmass;; // 321 + (*kernal)(2,2,0) = -gvvh*mBt/r2; // 331 + // return the answer + return kernal; +} diff --git a/Shower/QTilde/SplittingFunctions/OneOneZeroEWSplitFn.h b/Shower/QTilde/SplittingFunctions/OneOneZeroEWSplitFn.h new file mode 100644 --- /dev/null +++ b/Shower/QTilde/SplittingFunctions/OneOneZeroEWSplitFn.h @@ -0,0 +1,219 @@ +// -*- C++ -*- +#ifndef Herwig_OneOneZeroEWSplitFn_H +#define Herwig_OneOneZeroEWSplitFn_H +// +// This is the declaration of the OneOneZeroEWSplitFn class. +// + +#include "SplittingFunction.h" +#include "Herwig/Models/StandardModel/StandardModel.h" + +namespace Herwig { + +using namespace ThePEG; + +/** + * The OneOneZeroEWSplitFn class implements the splitting function for + * \f$\1\to q\1 0\f$ where the spin-1 particles are the W / Z massive + * electroweak gauge bosons and the spin-0 particle is the massive Higgs + * boson. + * + * @see \ref OneOneZeroEWSplitFnInterfaces "The interfaces" + * defined for OneOneZeroEWSplitFn. + */ +class OneOneZeroEWSplitFn: public SplittingFunction { + +public: + + /** + * Concrete implementation of the method to determine whether this splitting + * function can be used for a given set of particles. + * @param ids The PDG codes for the particles in the splitting. + */ + virtual bool accept(const IdList & ids) const; + + /** + * Methods to return the splitting function. + */ + //@{ + /** + * The concrete implementation of the splitting function, \f$P(z,t)\f$. + * @param z The energy fraction. + * @param t The scale. + * @param ids The PDG codes for the particles in the splitting. + * @param mass Whether or not to include the mass dependent terms + * @param rho The spin density matrix + */ + virtual double P(const double z, const Energy2 t, const IdList & ids, + const bool mass, const RhoDMatrix & rho) const; + + /** + * The concrete implementation of the overestimate of the splitting function, + * \f$P_{\rm over}\f$. + * @param z The energy fraction. + * @param ids The PDG codes for the particles in the splitting. + */ + virtual double overestimateP(const double z, const IdList & ids) const; + + /** + * The concrete implementation of the + * the ratio of the splitting function to the overestimate, i.e. + * \f$P(z,t)/P_{\rm over}(z)\f$. + * @param z The energy fraction. + * @param t The scale. + * @param ids The PDG codes for the particles in the splitting. + * @param mass Whether or not to include the mass dependent terms + * @param rho The spin density matrix + */ + virtual double ratioP(const double z, const Energy2 t, const IdList & ids, + const bool mass, const RhoDMatrix & rho) const; + + /** + * The concrete implementation of the indefinite integral of the + * overestimated splitting function, \f$P_{\rm over}\f$. + * @param z The energy fraction. + * @param ids The PDG codes for the particles in the splitting. + * @param PDFfactor Which additional factor to include for the PDF + * 0 is no additional factor, + * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ + */ + virtual double integOverP(const double z, const IdList & ids, + unsigned int PDFfactor=0) const; + + /** + * The concrete implementation of the inverse of the indefinite integral. + * @param r Value of the splitting function to be inverted + * @param ids The PDG codes for the particles in the splitting. + * @param PDFfactor Which additional factor to include for the PDF + * 0 is no additional factor, + * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ + */ + virtual double invIntegOverP(const double r, const IdList & ids, + unsigned int PDFfactor=0) const; + //@} + + /** + * Method to calculate the azimuthal angle + * @param z The energy fraction + * @param t The scale \f$t=2p_j\cdot p_k\f$. + * @param ids The PDG codes for the particles in the splitting. + * @param The azimuthal angle, \f$\phi\f$. + * @return The weight + */ + virtual vector > + generatePhiForward(const double z, const Energy2 t, const IdList & ids, + const RhoDMatrix &); + + /** + * Method to calculate the azimuthal angle for backward evolution + * @param z The energy fraction + * @param t The scale \f$t=2p_j\cdot p_k\f$. + * @param ids The PDG codes for the particles in the splitting. + * @param The azimuthal angle, \f$\phi\f$. + * @return The weight + */ + virtual vector > + generatePhiBackward(const double z, const Energy2 t, const IdList & ids, + const RhoDMatrix &); + + /** + * Calculate the matrix element for the splitting + * @param z The energy fraction + * @param t The scale \f$t=2p_j\cdot p_k\f$. + * @param ids The PDG codes for the particles in the splitting. + * @param The azimuthal angle, \f$\phi\f$. + */ + virtual DecayMEPtr matrixElement(const double z, const Energy2 t, + const IdList & ids, const double phi, bool timeLike); + +protected: + + /** + * Get the couplings + */ + void getCouplings(double & g, const IdList & ids) const; + +public: + + /** @name Functions used by the persistent I/O system. */ + //@{ + /** + * Function used to write out object persistently. + * @param os the persistent output stream written to. + */ + void persistentOutput(PersistentOStream & os) const; + + /** + * Function used to read in object persistently. + * @param is the persistent input stream read from. + * @param version the version number of the object when written. + */ + void persistentInput(PersistentIStream & is, int version); + //@} + + /** + * The standard Init function used to initialize the interfaces. + * Called exactly once for each class by the class description system + * before the main function starts or + * when this class is dynamically loaded. + */ + static void Init(); + +protected: + + /** @name Clone Methods. */ + //@{ + /** + * Make a simple clone of this object. + * @return a pointer to the new object. + */ + virtual IBPtr clone() const; + + /** Make a clone of this object, possibly modifying the cloned object + * to make it sane. + * @return a pointer to the new object. + */ + virtual IBPtr fullclone() const; + //@} + +protected: + + /** @name Standard Interfaced functions. */ + //@{ + /** + * Initialize this object after the setup phase before saving an + * EventGenerator to disk. + * @throws InitException if object could not be initialized properly. + */ + virtual void doinit(); + //@} + +private: + + /** + * The assignment operator is private and must never be called. + * In fact, it should not even be implemented. + */ + OneOneZeroEWSplitFn & operator=(const OneOneZeroEWSplitFn &) = delete; + +private: + + /** + * W -> W H couplings + */ + double gWWH_; + + /** + * Z0 -> Z0 H couplings + */ + double gZZH_; + + /** + * Pointer to the SM object. + */ + tcHwSMPtr _theSM; +}; + +} + +#endif /* Herwig_OneOneZeroEWSplitFn_H */ diff --git a/Shower/QTilde/SplittingFunctions/SplittingFunction.cc b/Shower/QTilde/SplittingFunctions/SplittingFunction.cc --- a/Shower/QTilde/SplittingFunctions/SplittingFunction.cc +++ b/Shower/QTilde/SplittingFunctions/SplittingFunction.cc @@ -1,919 +1,1053 @@ // -*- C++ -*- // // SplittingFunction.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the SplittingFunction class. // #include "SplittingFunction.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/Utilities/EnumIO.h" #include "Herwig/Shower/QTilde/Base/ShowerParticle.h" #include "ThePEG/Utilities/DescribeClass.h" using namespace Herwig; DescribeAbstractClass describeSplittingFunction ("Herwig::SplittingFunction",""); void SplittingFunction::Init() { static ClassDocumentation documentation ("The SplittingFunction class is the based class for 1->2 splitting functions" " in Herwig"); static Switch interfaceColourStructure ("ColourStructure", "The colour structure for the splitting function", &SplittingFunction::_colourStructure, Undefined, false, false); static SwitchOption interfaceColourStructureTripletTripletOctet (interfaceColourStructure, "TripletTripletOctet", "3 -> 3 8", TripletTripletOctet); static SwitchOption interfaceColourStructureOctetOctetOctet (interfaceColourStructure, "OctetOctetOctet", "8 -> 8 8", OctetOctetOctet); static SwitchOption interfaceColourStructureOctetTripletTriplet (interfaceColourStructure, "OctetTripletTriplet", "8 -> 3 3bar", OctetTripletTriplet); static SwitchOption interfaceColourStructureTripletOctetTriplet (interfaceColourStructure, "TripletOctetTriplet", "3 -> 8 3", - TripletOctetTriplet); + TripletOctetTriplet); static SwitchOption interfaceColourStructureSextetSextetOctet (interfaceColourStructure, "SextetSextetOctet", "6 -> 6 8", SextetSextetOctet); - + static SwitchOption interfaceColourStructureChargedChargedNeutral (interfaceColourStructure, "ChargedChargedNeutral", "q -> q 0", ChargedChargedNeutral); static SwitchOption interfaceColourStructureNeutralChargedCharged (interfaceColourStructure, "NeutralChargedCharged", "0 -> q qbar", NeutralChargedCharged); static SwitchOption interfaceColourStructureChargedNeutralCharged (interfaceColourStructure, "ChargedNeutralCharged", "q -> 0 q", ChargedNeutralCharged); + static SwitchOption interfaceColourStructureEW + (interfaceColourStructure, + "EW", + "q -> q W/Z, q -> q h0, V -> V' V'', V -> V H", + EW); - static Switch + static Switch interfaceInteractionType ("InteractionType", "Type of the interaction", - &SplittingFunction::_interactionType, + &SplittingFunction::_interactionType, ShowerInteraction::UNDEFINED, false, false); static SwitchOption interfaceInteractionTypeQCD (interfaceInteractionType, "QCD","QCD",ShowerInteraction::QCD); static SwitchOption interfaceInteractionTypeQED (interfaceInteractionType, "QED","QED",ShowerInteraction::QED); + static SwitchOption interfaceInteractionTypeEW + (interfaceInteractionType, + "EW","EW",ShowerInteraction::EW); static Switch interfaceAngularOrdered ("AngularOrdered", "Whether or not this interaction is angular ordered, " "normally only g->q qbar and gamma-> f fbar are the only ones which aren't.", &SplittingFunction::angularOrdered_, true, false, false); static SwitchOption interfaceAngularOrderedYes (interfaceAngularOrdered, "Yes", "Interaction is angular ordered", true); static SwitchOption interfaceAngularOrderedNo (interfaceAngularOrdered, "No", "Interaction isn't angular ordered", false); static Switch interfaceScaleChoice ("ScaleChoice", "The scale choice to be used", &SplittingFunction::scaleChoice_, 2, false, false); static SwitchOption interfaceScaleChoicepT (interfaceScaleChoice, "pT", "pT of the branching", 0); static SwitchOption interfaceScaleChoiceQ2 (interfaceScaleChoice, "Q2", "Q2 of the branching", 1); static SwitchOption interfaceScaleChoiceFromAngularOrdering (interfaceScaleChoice, "FromAngularOrdering", "If angular order use pT, otherwise Q2", 2); static Switch interfaceStrictAO ("StrictAO", "Whether or not to apply strict angular-ordering," " i.e. for QED even in QCD emission, and vice versa", &SplittingFunction::strictAO_, true, false, false); static SwitchOption interfaceStrictAOYes (interfaceStrictAO, "Yes", "Apply strict ordering", true); static SwitchOption interfaceStrictAONo (interfaceStrictAO, "No", "Don't apply strict ordering", false); } void SplittingFunction::persistentOutput(PersistentOStream & os) const { os << oenum(_interactionType) << oenum(_colourStructure) << _colourFactor << angularOrdered_ << scaleChoice_ << strictAO_; } void SplittingFunction::persistentInput(PersistentIStream & is, int) { is >> ienum(_interactionType) >> ienum(_colourStructure) >> _colourFactor >> angularOrdered_ >> scaleChoice_ >> strictAO_; } void SplittingFunction::colourConnection(tShowerParticlePtr parent, tShowerParticlePtr first, tShowerParticlePtr second, - ShowerPartnerType partnerType, + ShowerPartnerType partnerType, const bool back) const { if(_colourStructure==TripletTripletOctet) { if(!back) { - ColinePair cparent = ColinePair(parent->colourLine(), + ColinePair cparent = ColinePair(parent->colourLine(), parent->antiColourLine()); // ensure input consistency - assert(( cparent.first && !cparent.second && - partnerType==ShowerPartnerType::QCDColourLine) || - ( !cparent.first && cparent.second && + assert(( cparent.first && !cparent.second && + partnerType==ShowerPartnerType::QCDColourLine) || + ( !cparent.first && cparent.second && partnerType==ShowerPartnerType::QCDAntiColourLine)); // q -> q g if(cparent.first) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(second); newline->addColoured ( first); newline->addAntiColoured (second); } // qbar -> qbar g else { ColinePtr newline=new_ptr(ColourLine()); cparent.second->addAntiColoured(second); newline->addColoured(second); newline->addAntiColoured(first); } // Set progenitor first->progenitor(parent->progenitor()); second->progenitor(parent->progenitor()); } else { - ColinePair cfirst = ColinePair(first->colourLine(), + ColinePair cfirst = ColinePair(first->colourLine(), first->antiColourLine()); // ensure input consistency - assert(( cfirst.first && !cfirst.second && - partnerType==ShowerPartnerType::QCDColourLine) || - ( !cfirst.first && cfirst.second && + assert(( cfirst.first && !cfirst.second && + partnerType==ShowerPartnerType::QCDColourLine) || + ( !cfirst.first && cfirst.second && partnerType==ShowerPartnerType::QCDAntiColourLine)); // q -> q g if(cfirst.first) { ColinePtr newline=new_ptr(ColourLine()); cfirst.first->addAntiColoured(second); newline->addColoured(second); newline->addColoured(parent); } // qbar -> qbar g else { ColinePtr newline=new_ptr(ColourLine()); cfirst.second->addColoured(second); newline->addAntiColoured(second); newline->addAntiColoured(parent); } // Set progenitor parent->progenitor(first->progenitor()); second->progenitor(first->progenitor()); } } else if(_colourStructure==OctetOctetOctet) { if(!back) { - ColinePair cparent = ColinePair(parent->colourLine(), + ColinePair cparent = ColinePair(parent->colourLine(), parent->antiColourLine()); // ensure input consistency assert(cparent.first&&cparent.second); // ensure first gluon is hardest - if( first->id()==second->id() && parent->showerKinematics()->z()<0.5 ) + if( first->id()==second->id() && parent->showerKinematics()->z()<0.5 ) swap(first,second); // colour line radiates if(partnerType==ShowerPartnerType::QCDColourLine) { // The colour line is radiating ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(second); cparent.second->addAntiColoured(first); newline->addColoured(first); newline->addAntiColoured(second); } // anti colour line radiates else if(partnerType==ShowerPartnerType::QCDAntiColourLine) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(first); cparent.second->addAntiColoured(second); newline->addColoured(second); newline->addAntiColoured(first); } else assert(false); } else { - ColinePair cfirst = ColinePair(first->colourLine(), + ColinePair cfirst = ColinePair(first->colourLine(), first->antiColourLine()); // ensure input consistency assert(cfirst.first&&cfirst.second); // The colour line is radiating if(partnerType==ShowerPartnerType::QCDColourLine) { ColinePtr newline=new_ptr(ColourLine()); cfirst.first->addAntiColoured(second); cfirst.second->addAntiColoured(parent); newline->addColoured(parent); newline->addColoured(second); } // anti colour line radiates else if(partnerType==ShowerPartnerType::QCDAntiColourLine) { ColinePtr newline=new_ptr(ColourLine()); cfirst.first->addColoured(parent); cfirst.second->addColoured(second); newline->addAntiColoured(second); newline->addAntiColoured(parent); } else assert(false); - } + } } else if(_colourStructure == OctetTripletTriplet) { if(!back) { - ColinePair cparent = ColinePair(parent->colourLine(), + ColinePair cparent = ColinePair(parent->colourLine(), parent->antiColourLine()); // ensure input consistency assert(cparent.first&&cparent.second); cparent.first ->addColoured ( first); cparent.second->addAntiColoured(second); // Set progenitor first->progenitor(parent->progenitor()); second->progenitor(parent->progenitor()); } else { - ColinePair cfirst = ColinePair(first->colourLine(), + ColinePair cfirst = ColinePair(first->colourLine(), first->antiColourLine()); // ensure input consistency assert(( cfirst.first && !cfirst.second) || (!cfirst.first && cfirst.second)); // g -> q qbar if(cfirst.first) { ColinePtr newline=new_ptr(ColourLine()); cfirst.first->addColoured(parent); newline->addAntiColoured(second); - newline->addAntiColoured(parent); + newline->addAntiColoured(parent); } // g -> qbar q else { ColinePtr newline=new_ptr(ColourLine()); cfirst.second->addAntiColoured(parent); newline->addColoured(second); newline->addColoured(parent); } // Set progenitor parent->progenitor(first->progenitor()); second->progenitor(first->progenitor()); } } else if(_colourStructure == TripletOctetTriplet) { if(!back) { - ColinePair cparent = ColinePair(parent->colourLine(), + ColinePair cparent = ColinePair(parent->colourLine(), parent->antiColourLine()); // ensure input consistency - assert(( cparent.first && !cparent.second) || + assert(( cparent.first && !cparent.second) || (!cparent.first && cparent.second)); // q -> g q if(cparent.first) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(first); newline->addColoured (second); newline->addAntiColoured( first); } // qbar -> g qbar else { ColinePtr newline=new_ptr(ColourLine()); cparent.second->addAntiColoured(first); newline->addColoured ( first); - newline->addAntiColoured(second); + newline->addAntiColoured(second); } // Set progenitor first->progenitor(parent->progenitor()); second->progenitor(parent->progenitor()); } else { - ColinePair cfirst = ColinePair(first->colourLine(), + ColinePair cfirst = ColinePair(first->colourLine(), first->antiColourLine()); // ensure input consistency assert(cfirst.first&&cfirst.second); // q -> g q if(parent->id()>0) { cfirst.first ->addColoured(parent); cfirst.second->addColoured(second); } else { cfirst.first ->addAntiColoured(second); cfirst.second->addAntiColoured(parent); } // Set progenitor parent->progenitor(first->progenitor()); second->progenitor(first->progenitor()); } } else if(_colourStructure==SextetSextetOctet) { //make sure we're not doing backward evolution assert(!back); //make sure something sensible assert(parent->colourLine() || parent->antiColourLine()); - + //get the colour lines or anti-colour lines bool isAntiColour=true; ColinePair cparent; if(parent->colourLine()) { - cparent = ColinePair(const_ptr_cast(parent->colourInfo()->colourLines()[0]), + cparent = ColinePair(const_ptr_cast(parent->colourInfo()->colourLines()[0]), const_ptr_cast(parent->colourInfo()->colourLines()[1])); isAntiColour=false; } else { - cparent = ColinePair(const_ptr_cast(parent->colourInfo()->antiColourLines()[0]), + cparent = ColinePair(const_ptr_cast(parent->colourInfo()->antiColourLines()[0]), const_ptr_cast(parent->colourInfo()->antiColourLines()[1])); } - + //check for sensible input // assert(cparent.first && cparent.second); // sextet has 2 colour lines if(!isAntiColour) { //pick at random which of the colour topolgies to take double topology = UseRandom::rnd(); if(topology < 0.25) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(second); cparent.second->addColoured(first); newline->addColoured(first); newline->addAntiColoured(second); } else if(topology >=0.25 && topology < 0.5) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(first); cparent.second->addColoured(second); newline->addColoured(first); - newline->addAntiColoured(second); + newline->addAntiColoured(second); } else if(topology >= 0.5 && topology < 0.75) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(second); - cparent.second->addColoured(first); - newline->addColoured(first); - newline->addAntiColoured(second); + cparent.second->addColoured(first); + newline->addColoured(first); + newline->addAntiColoured(second); } else { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(first); cparent.second->addColoured(second); newline->addColoured(first); newline->addAntiColoured(second); } } // sextet has 2 anti-colour lines else { double topology = UseRandom::rnd(); if(topology < 0.25){ ColinePtr newline=new_ptr(ColourLine()); cparent.first->addAntiColoured(second); cparent.second->addAntiColoured(first); newline->addAntiColoured(first); newline->addColoured(second); } else if(topology >=0.25 && topology < 0.5) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addAntiColoured(first); cparent.second->addAntiColoured(second); newline->addAntiColoured(first); - newline->addColoured(second); + newline->addColoured(second); } else if(topology >= 0.5 && topology < 0.75) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addAntiColoured(second); cparent.second->addAntiColoured(first); newline->addAntiColoured(first); - newline->addColoured(second); + newline->addColoured(second); } else { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addAntiColoured(first); cparent.second->addAntiColoured(second); newline->addAntiColoured(first); newline->addColoured(second); } - } + } } else if(_colourStructure == ChargedChargedNeutral) { if(!parent->data().coloured()) return; if(!back) { - ColinePair cparent = ColinePair(parent->colourLine(), + ColinePair cparent = ColinePair(parent->colourLine(), parent->antiColourLine()); // q -> q g if(cparent.first) { cparent.first->addColoured(first); } // qbar -> qbar g if(cparent.second) { cparent.second->addAntiColoured(first); } } else { - ColinePair cfirst = ColinePair(first->colourLine(), + ColinePair cfirst = ColinePair(first->colourLine(), first->antiColourLine()); // q -> q g if(cfirst.first) { cfirst.first->addColoured(parent); } // qbar -> qbar g if(cfirst.second) { cfirst.second->addAntiColoured(parent); } } } else if(_colourStructure == ChargedNeutralCharged) { if(!parent->data().coloured()) return; if(!back) { - ColinePair cparent = ColinePair(parent->colourLine(), + ColinePair cparent = ColinePair(parent->colourLine(), parent->antiColourLine()); // q -> q g if(cparent.first) { cparent.first->addColoured(second); } // qbar -> qbar g if(cparent.second) { cparent.second->addAntiColoured(second); } } else { if (second->dataPtr()->iColour()==PDT::Colour3 ) { ColinePtr newline=new_ptr(ColourLine()); newline->addColoured(second); newline->addColoured(parent); } else if (second->dataPtr()->iColour()==PDT::Colour3bar ) { ColinePtr newline=new_ptr(ColourLine()); newline->addAntiColoured(second); newline->addAntiColoured(parent); } } } else if(_colourStructure == NeutralChargedCharged ) { if(!back) { if(first->dataPtr()->coloured()) { ColinePtr newline=new_ptr(ColourLine()); if(first->dataPtr()->iColour()==PDT::Colour3) { newline->addColoured (first ); newline->addAntiColoured(second); } else if (first->dataPtr()->iColour()==PDT::Colour3bar) { newline->addColoured (second); newline->addAntiColoured(first ); } else if(parent->dataPtr()->coloured()|| first ->dataPtr()->coloured()|| second->dataPtr()->coloured()) assert(false); } } - else { - ColinePair cfirst = ColinePair(first->colourLine(), + else { + ColinePair cfirst = ColinePair(first->colourLine(), first->antiColourLine()); // gamma -> q qbar if(cfirst.first) { cfirst.first->addAntiColoured(second); } // gamma -> qbar q else if(cfirst.second) { cfirst.second->addColoured(second); } - else if(parent->dataPtr()->coloured()|| - first ->dataPtr()->coloured()|| - second->dataPtr()->coloured()) + else assert(false); } } + else if(_colourStructure == EW) { + if(!parent->data().coloured()) return; + if(!back) { + ColinePair cparent = ColinePair(parent->colourLine(), + parent->antiColourLine()); + // q -> q g + if(cparent.first) { + cparent.first->addColoured(first); + } + // qbar -> qbar g + if(cparent.second) { + cparent.second->addAntiColoured(first); + } + } + else { + ColinePair cfirst = ColinePair(first->colourLine(), + first->antiColourLine()); + // q -> q g + if(cfirst.first) { + cfirst.first->addColoured(parent); + } + // qbar -> qbar g + if(cfirst.second) { + cfirst.second->addAntiColoured(parent); + } + } + } else { assert(false); } } void SplittingFunction::doinit() { Interfaced::doinit(); assert(_interactionType!=ShowerInteraction::UNDEFINED); assert((_colourStructure>0&&_interactionType==ShowerInteraction::QCD) || - (_colourStructure<0&&_interactionType==ShowerInteraction::QED) ); + (_colourStructure<0&&(_interactionType==ShowerInteraction::QED || + _interactionType==ShowerInteraction::EW)) ); if(_colourFactor>0.) return; // compute the colour factors if need if(_colourStructure==TripletTripletOctet) { _colourFactor = 4./3.; } else if(_colourStructure==OctetOctetOctet) { _colourFactor = 3.; } else if(_colourStructure==OctetTripletTriplet) { _colourFactor = 0.5; } else if(_colourStructure==TripletOctetTriplet) { _colourFactor = 4./3.; } else if(_colourStructure==SextetSextetOctet) { _colourFactor = 10./3.; } else if(_colourStructure<0) { _colourFactor = 1.; } else { assert(false); } } bool SplittingFunction::checkColours(const IdList & ids) const { if(_colourStructure==TripletTripletOctet) { if(ids[0]!=ids[1]) return false; if((ids[0]->iColour()==PDT::Colour3||ids[0]->iColour()==PDT::Colour3bar) && ids[2]->iColour()==PDT::Colour8) return true; return false; } else if(_colourStructure==OctetOctetOctet) { for(unsigned int ix=0;ix<3;++ix) { if(ids[ix]->iColour()!=PDT::Colour8) return false; } return true; } else if(_colourStructure==OctetTripletTriplet) { if(ids[0]->iColour()!=PDT::Colour8) return false; if(ids[1]->iColour()==PDT::Colour3&&ids[2]->iColour()==PDT::Colour3bar) return true; if(ids[1]->iColour()==PDT::Colour3bar&&ids[2]->iColour()==PDT::Colour3) return true; return false; } else if(_colourStructure==TripletOctetTriplet) { if(ids[0]!=ids[2]) return false; if((ids[0]->iColour()==PDT::Colour3||ids[0]->iColour()==PDT::Colour3bar) && ids[1]->iColour()==PDT::Colour8) return true; return false; } else if(_colourStructure==SextetSextetOctet) { if(ids[0]!=ids[1]) return false; if((ids[0]->iColour()==PDT::Colour6 || ids[0]->iColour()==PDT::Colour6bar) && ids[2]->iColour()==PDT::Colour8) return true; return false; } else if(_colourStructure==ChargedChargedNeutral) { if(ids[0]!=ids[1]) return false; if(ids[2]->iCharge()!=0) return false; if(ids[0]->iCharge()==ids[1]->iCharge()) return true; return false; } else if(_colourStructure==ChargedNeutralCharged) { if(ids[0]!=ids[2]) return false; if(ids[1]->iCharge()!=0) return false; if(ids[0]->iCharge()==ids[2]->iCharge()) return true; return false; } else if(_colourStructure==NeutralChargedCharged) { if(ids[1]->id()!=-ids[2]->id()) return false; if(ids[0]->iCharge()!=0) return false; if(ids[1]->iCharge()==-ids[2]->iCharge()) return true; return false; } else { assert(false); } return false; } namespace { bool hasColour(tPPtr p) { PDT::Colour colour = p->dataPtr()->iColour(); return colour==PDT::Colour3 || colour==PDT::Colour8 || colour == PDT::Colour6; } bool hasAntiColour(tPPtr p) { PDT::Colour colour = p->dataPtr()->iColour(); return colour==PDT::Colour3bar || colour==PDT::Colour8 || colour == PDT::Colour6bar; } - + } void SplittingFunction::evaluateFinalStateScales(ShowerPartnerType partnerType, Energy scale, double z, tShowerParticlePtr parent, tShowerParticlePtr emitter, tShowerParticlePtr emitted) { // identify emitter and emitted double zEmitter = z, zEmitted = 1.-z; bool bosonSplitting(false); // special for g -> gg, particle highest z is emitter if(emitter->id() == emitted->id() && emitter->id() == parent->id() && zEmitted > zEmitter) { swap(zEmitted,zEmitter); swap( emitted, emitter); } // otherwise if particle ID same else if(emitted->id()==parent->id()) { swap(zEmitted,zEmitter); swap( emitted, emitter); } // no real emitter/emitted else if(emitter->id()!=parent->id()) { bosonSplitting = true; } // may need to add angularOrder flag here // now the various scales // QED if(partnerType==ShowerPartnerType::QED) { assert(colourStructure()==ChargedChargedNeutral || colourStructure()==ChargedNeutralCharged || - colourStructure()==NeutralChargedCharged ); + colourStructure()==NeutralChargedCharged || + colourStructure()==EW); // normal case if(!bosonSplitting) { - assert(colourStructure()==ChargedChargedNeutral || - colourStructure()==ChargedNeutralCharged ); + assert(colourStructure()==ChargedChargedNeutral); // set the scales // emitter emitter->scales().QED = zEmitter*scale; emitter->scales().QED_noAO = scale; if(strictAO_) emitter->scales().QCD_c = min(zEmitter*scale,parent->scales().QCD_c ); else emitter->scales().QCD_c = min( scale,parent->scales().QCD_c ); emitter->scales().QCD_c_noAO = min(scale,parent->scales().QCD_c_noAO ); if(strictAO_) emitter->scales().QCD_ac = min(zEmitter*scale,parent->scales().QCD_ac ); else emitter->scales().QCD_ac = min( scale,parent->scales().QCD_ac ); emitter->scales().QCD_ac_noAO = min(scale,parent->scales().QCD_ac_noAO); - // emitted + emitter->scales().EW = min(scale,parent->scales().EW ); + // emitted emitted->scales().QED = zEmitted*scale; emitted->scales().QED_noAO = scale; emitted->scales().QCD_c = ZERO; emitted->scales().QCD_c_noAO = ZERO; emitted->scales().QCD_ac = ZERO; emitted->scales().QCD_ac_noAO = ZERO; + emitted->scales().EW = min(scale,parent->scales().EW ); } // gamma -> f fbar else { - assert(colourStructure()==NeutralChargedCharged ); + if (parent->id()==22 && abs(emitter->id())==24 && emitter->id() == - emitted->id()) + ; + else + assert(colourStructure()==NeutralChargedCharged || colourStructure()==EW); // emitter - emitter->scales().QED = zEmitter*scale; - emitter->scales().QED_noAO = scale; + emitter->scales().QED = zEmitter*scale; + emitter->scales().QED_noAO = scale; if(hasColour(emitter)) { emitter->scales().QCD_c = zEmitter*scale; emitter->scales().QCD_c_noAO = scale; } if(hasAntiColour(emitter)) { emitter->scales().QCD_ac = zEmitter*scale; emitter->scales().QCD_ac_noAO = scale; } - // emitted - emitted->scales().QED = zEmitted*scale; - emitted->scales().QED_noAO = scale; + emitter->scales().EW = zEmitter*scale; + // emitted + emitted->scales().QED = zEmitted*scale; + emitted->scales().QED_noAO = scale; if(hasColour(emitted)) { emitted->scales().QCD_c = zEmitted*scale; emitted->scales().QCD_c_noAO = scale; } if(hasAntiColour(emitted)) { emitted->scales().QCD_ac = zEmitted*scale; emitted->scales().QCD_ac_noAO = scale; } + emitted->scales().EW = zEmitted*scale; } } // QCD - else { + else if (partnerType==ShowerPartnerType::QCDColourLine || + partnerType==ShowerPartnerType::QCDAntiColourLine) { // normal case eg q -> q g and g -> g g if(!bosonSplitting) { if(strictAO_) emitter->scales().QED = min(zEmitter*scale,parent->scales().QED ); else emitter->scales().QED = min( scale,parent->scales().QED ); - emitter->scales().QED_noAO = min(scale,parent->scales().QED_noAO); + emitter->scales().QED_noAO = min(scale,parent->scales().QED_noAO); + emitter->scales().EW = min(scale,parent->scales().EW ); if(partnerType==ShowerPartnerType::QCDColourLine) { emitter->scales().QCD_c = zEmitter*scale; emitter->scales().QCD_c_noAO = scale; emitter->scales().QCD_ac = min(zEmitter*scale,parent->scales().QCD_ac ); emitter->scales().QCD_ac_noAO = min( scale,parent->scales().QCD_ac_noAO); } else { emitter->scales().QCD_c = min(zEmitter*scale,parent->scales().QCD_c ); emitter->scales().QCD_c_noAO = min( scale,parent->scales().QCD_c_noAO ); emitter->scales().QCD_ac = zEmitter*scale; emitter->scales().QCD_ac_noAO = scale; } - // emitted + // emitted emitted->scales().QED = ZERO; emitted->scales().QED_noAO = ZERO; emitted->scales().QCD_c = zEmitted*scale; emitted->scales().QCD_c_noAO = scale; emitted->scales().QCD_ac = zEmitted*scale; emitted->scales().QCD_ac_noAO = scale; + emitted->scales().EW = min(scale,parent->scales().EW ); } // g -> q qbar else { // emitter if(emitter->dataPtr()->charged()) { emitter->scales().QED = zEmitter*scale; emitter->scales().QED_noAO = scale; } - emitter->scales().QCD_c = zEmitter*scale; - emitter->scales().QCD_c_noAO = scale; - emitter->scales().QCD_ac = zEmitter*scale; - emitter->scales().QCD_ac_noAO = scale; - // emitted + emitter->scales().EW = zEmitter*scale; + emitter->scales().QCD_c = zEmitter*scale; + emitter->scales().QCD_c_noAO = scale; + emitter->scales().QCD_ac = zEmitter*scale; + emitter->scales().QCD_ac_noAO = scale; + // emitted if(emitted->dataPtr()->charged()) { emitted->scales().QED = zEmitted*scale; emitted->scales().QED_noAO = scale; } - emitted->scales().QCD_c = zEmitted*scale; - emitted->scales().QCD_c_noAO = scale; - emitted->scales().QCD_ac = zEmitted*scale; - emitted->scales().QCD_ac_noAO = scale; + emitted->scales().EW = zEmitted*scale; + emitted->scales().QCD_c = zEmitted*scale; + emitted->scales().QCD_c_noAO = scale; + emitted->scales().QCD_ac = zEmitted*scale; + emitted->scales().QCD_ac_noAO = scale; } } + else if(partnerType==ShowerPartnerType::EW) { + // EW + emitter->scales().EW = zEmitter*scale; + emitted->scales().EW = zEmitted*scale; + // QED + // W radiation AO + if(emitted->dataPtr()->charged()) { + emitter->scales().QED = zEmitter*scale; + emitter->scales().QED_noAO = scale; + emitted->scales().QED = zEmitted*scale; + emitted->scales().QED_noAO = scale; + } + // Z don't + else { + emitter->scales().QED = min(scale,parent->scales().QED ); + emitter->scales().QED_noAO = min(scale,parent->scales().QED_noAO); + emitted->scales().QED = ZERO; + emitted->scales().QED_noAO = ZERO; + } + // QCD + emitter->scales().QCD_c = min(scale,parent->scales().QCD_c ); + emitter->scales().QCD_c_noAO = min(scale,parent->scales().QCD_c_noAO ); + emitter->scales().QCD_ac = min(scale,parent->scales().QCD_ac ); + emitter->scales().QCD_ac_noAO = min(scale,parent->scales().QCD_ac_noAO); + emitted->scales().QCD_c = ZERO; + emitted->scales().QCD_c_noAO = ZERO; + emitted->scales().QCD_ac = ZERO; + emitted->scales().QCD_ac_noAO = ZERO; + } + else + assert(false); } void SplittingFunction::evaluateInitialStateScales(ShowerPartnerType partnerType, Energy scale, double z, tShowerParticlePtr parent, tShowerParticlePtr spacelike, tShowerParticlePtr timelike) { // scale for time-like child Energy AOScale = (1.-z)*scale; // QED if(partnerType==ShowerPartnerType::QED) { if(parent->id()==spacelike->id()) { // parent parent ->scales().QED = scale; parent ->scales().QED_noAO = scale; parent ->scales().QCD_c = min(scale,spacelike->scales().QCD_c ); parent ->scales().QCD_c_noAO = min(scale,spacelike->scales().QCD_c_noAO ); parent ->scales().QCD_ac = min(scale,spacelike->scales().QCD_ac ); parent ->scales().QCD_ac_noAO = min(scale,spacelike->scales().QCD_ac_noAO); // timelike timelike->scales().QED = AOScale; timelike->scales().QED_noAO = scale; timelike->scales().QCD_c = ZERO; timelike->scales().QCD_c_noAO = ZERO; timelike->scales().QCD_ac = ZERO; timelike->scales().QCD_ac_noAO = ZERO; } else if(parent->id()==timelike->id()) { parent ->scales().QED = scale; parent ->scales().QED_noAO = scale; if(hasColour(parent)) { parent ->scales().QCD_c = scale; parent ->scales().QCD_c_noAO = scale; } if(hasAntiColour(parent)) { parent ->scales().QCD_ac = scale; parent ->scales().QCD_ac_noAO = scale; } - // timelike + // timelike timelike->scales().QED = AOScale; timelike->scales().QED_noAO = scale; if(hasColour(timelike)) { timelike->scales().QCD_c = AOScale; timelike->scales().QCD_c_noAO = scale; } if(hasAntiColour(timelike)) { timelike->scales().QCD_ac = AOScale; timelike->scales().QCD_ac_noAO = scale; } } else { parent ->scales().QED = scale; parent ->scales().QED_noAO = scale; parent ->scales().QCD_c = ZERO ; parent ->scales().QCD_c_noAO = ZERO ; parent ->scales().QCD_ac = ZERO ; parent ->scales().QCD_ac_noAO = ZERO ; - // timelike + // timelike timelike->scales().QED = AOScale; timelike->scales().QED_noAO = scale; if(hasColour(timelike)) { timelike->scales().QCD_c = min(AOScale,spacelike->scales().QCD_ac ); timelike->scales().QCD_c_noAO = min( scale,spacelike->scales().QCD_ac_noAO); } if(hasAntiColour(timelike)) { timelike->scales().QCD_ac = min(AOScale,spacelike->scales().QCD_c ); timelike->scales().QCD_ac_noAO = min( scale,spacelike->scales().QCD_c_noAO ); } } } // QCD - else { - // timelike + else if (partnerType==ShowerPartnerType::QCDColourLine || + partnerType==ShowerPartnerType::QCDAntiColourLine) { + // timelike if(timelike->dataPtr()->charged()) { timelike->scales().QED = AOScale; timelike->scales().QED_noAO = scale; } if(hasColour(timelike)) { timelike->scales().QCD_c = AOScale; timelike->scales().QCD_c_noAO = scale; } if(hasAntiColour(timelike)) { timelike->scales().QCD_ac = AOScale; timelike->scales().QCD_ac_noAO = scale; } if(parent->id()==spacelike->id()) { parent ->scales().QED = min(scale,spacelike->scales().QED ); parent ->scales().QED_noAO = min(scale,spacelike->scales().QED_noAO ); parent ->scales().QCD_c = min(scale,spacelike->scales().QCD_c ); parent ->scales().QCD_c_noAO = min(scale,spacelike->scales().QCD_c_noAO ); parent ->scales().QCD_ac = min(scale,spacelike->scales().QCD_ac ); parent ->scales().QCD_ac_noAO = min(scale,spacelike->scales().QCD_ac_noAO); } else { if(parent->dataPtr()->charged()) { parent ->scales().QED = scale; parent ->scales().QED_noAO = scale; } if(hasColour(parent)) { parent ->scales().QCD_c = scale; parent ->scales().QCD_c_noAO = scale; } if(hasAntiColour(parent)) { parent ->scales().QCD_ac = scale; parent ->scales().QCD_ac_noAO = scale; } } } + else if(partnerType==ShowerPartnerType::EW) { + if(abs(spacelike->id())!=ParticleID::Wplus && + spacelike->id() !=ParticleID::Z0 ) { + // QCD scales + parent ->scales().QCD_c = min(scale,spacelike->scales().QCD_c ); + parent ->scales().QCD_c_noAO = min(scale,spacelike->scales().QCD_c_noAO ); + parent ->scales().QCD_ac = min(scale,spacelike->scales().QCD_ac ); + parent ->scales().QCD_ac_noAO = min(scale,spacelike->scales().QCD_ac_noAO); + timelike->scales().QCD_c = ZERO; + timelike->scales().QCD_c_noAO = ZERO; + timelike->scales().QCD_ac = ZERO; + timelike->scales().QCD_ac_noAO = ZERO; + // QED scales + if(timelike->id()==ParticleID::Z0) { + parent ->scales().QED = min(scale,spacelike->scales().QED ); + parent ->scales().QED_noAO = min(scale,spacelike->scales().QED_noAO ); + timelike->scales().QED = ZERO; + timelike->scales().QED_noAO = ZERO; + } + else { + parent ->scales().QED = scale; + parent ->scales().QED_noAO = scale; + timelike->scales().QED = AOScale; + timelike->scales().QED_noAO = scale; + } + // EW scales + parent ->scales().EW = scale; + timelike->scales().EW = AOScale; + } + else assert(false); + } + else + assert(false); } void SplittingFunction::evaluateDecayScales(ShowerPartnerType partnerType, Energy scale, double z, tShowerParticlePtr parent, tShowerParticlePtr spacelike, tShowerParticlePtr timelike) { assert(parent->id()==spacelike->id()); // angular-ordered scale for 2nd child Energy AOScale = (1.-z)*scale; // QED if(partnerType==ShowerPartnerType::QED) { // timelike timelike->scales().QED = AOScale; timelike->scales().QED_noAO = scale; timelike->scales().QCD_c = ZERO; timelike->scales().QCD_c_noAO = ZERO; timelike->scales().QCD_ac = ZERO; timelike->scales().QCD_ac_noAO = ZERO; + timelike->scales().EW = ZERO; // spacelike spacelike->scales().QED = scale; spacelike->scales().QED_noAO = scale; + spacelike->scales().EW = max(scale,parent->scales().EW ); } // QCD - else { - // timelike + else if(partnerType==ShowerPartnerType::QCDColourLine || + partnerType==ShowerPartnerType::QCDAntiColourLine) { + // timelike timelike->scales().QED = ZERO; timelike->scales().QED_noAO = ZERO; timelike->scales().QCD_c = AOScale; timelike->scales().QCD_c_noAO = scale; timelike->scales().QCD_ac = AOScale; timelike->scales().QCD_ac_noAO = scale; + timelike->scales().EW = ZERO; // spacelike spacelike->scales().QED = max(scale,parent->scales().QED ); spacelike->scales().QED_noAO = max(scale,parent->scales().QED_noAO ); + spacelike->scales().EW = max(scale,parent->scales().EW ); } + else if(partnerType==ShowerPartnerType::EW) { + // EW + timelike->scales().EW = AOScale; + spacelike->scales().EW = max(scale,parent->scales().EW ); + // QCD + timelike->scales().QCD_c = ZERO; + timelike->scales().QCD_c_noAO = ZERO; + timelike->scales().QCD_ac = ZERO; + timelike->scales().QCD_ac_noAO = ZERO; + timelike->scales().EW = ZERO; + // QED + timelike->scales().QED = ZERO; + timelike->scales().QED_noAO = ZERO; + spacelike->scales().QED = max(scale,parent->scales().QED ); + spacelike->scales().QED_noAO = max(scale,parent->scales().QED_noAO ); + } + else + assert(false); spacelike->scales().QCD_c = max(scale,parent->scales().QCD_c ); spacelike->scales().QCD_c_noAO = max(scale,parent->scales().QCD_c_noAO ); spacelike->scales().QCD_ac = max(scale,parent->scales().QCD_ac ); spacelike->scales().QCD_ac_noAO = max(scale,parent->scales().QCD_ac_noAO); } diff --git a/Shower/QTilde/SplittingFunctions/SplittingFunction.h b/Shower/QTilde/SplittingFunctions/SplittingFunction.h --- a/Shower/QTilde/SplittingFunctions/SplittingFunction.h +++ b/Shower/QTilde/SplittingFunctions/SplittingFunction.h @@ -1,386 +1,391 @@ // -*- C++ -*- // // SplittingFunction.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_SplittingFunction_H #define HERWIG_SplittingFunction_H // // This is the declaration of the SplittingFunction class. // #include "ThePEG/Interface/Interfaced.h" #include "Herwig/Shower/QTilde/ShowerConfig.h" #include "ThePEG/EventRecord/RhoDMatrix.h" #include "Herwig/Decay/DecayMatrixElement.h" #include "Herwig/Shower/QTilde/Kinematics/ShowerKinematics.fh" #include "ThePEG/EventRecord/ColourLine.h" #include "ThePEG/PDT/ParticleData.h" #include "SplittingFunction.fh" namespace Herwig { using namespace ThePEG; /** \ingroup Shower * Enum to define the possible types of colour structure which can occur in * the branching. */ enum ColourStructure {Undefined=0, TripletTripletOctet = 1,OctetOctetOctet =2, OctetTripletTriplet = 3,TripletOctetTriplet=4, SextetSextetOctet = 5, ChargedChargedNeutral=-1,ChargedNeutralCharged=-2, - NeutralChargedCharged=-3}; + NeutralChargedCharged=-3,EW=-4}; /** \ingroup Shower * * This is an abstract class which defines the common interface * for all \f$1\to2\f$ splitting functions, for both initial-state * and final-state radiation. * * The SplittingFunction class contains a number of purely virtual members * which must be implemented in the inheriting classes. The class also stores * the interaction type of the spltting function. * * The inheriting classes need to specific the splitting function * \f$P(z,2p_j\cdot p_k)\f$, in terms of the energy fraction \f$z\f$ and * the evolution scale. In order to allow the splitting functions to be used * with different choices of evolution functions the scale is given by * \f[2p_j\cdot p_k=(p_j+p_k)^2-m_{jk}^2=Q^2-(p_j+p_k)^2=z(1-z)\tilde{q}^2= * \frac{p_T^2}{z(1-z)}-m_{jk}^2+\frac{m_j^2}{z}+\frac{m_k^2}{1-z},\f] * where \f$Q^2\f$ is the virtuality of the branching particle, * $p_T$ is the relative transverse momentum of the branching products and * \f$\tilde{q}^2\f$ is the angular variable described in hep-ph/0310083. * * In addition an overestimate of the * splitting function, \f$P_{\rm over}(z)\f$ which only depends upon \f$z\f$, * the integral, inverse of the integral for this overestimate and * ratio of the true splitting function to the overestimate must be provided * as they are necessary for the veto alogrithm used to implement the evolution. * * @see \ref SplittingFunctionInterfaces "The interfaces" * defined for SplittingFunction. */ class SplittingFunction: public Interfaced { public: /** * The default constructor. * @param b All splitting functions must have an interaction order */ SplittingFunction() : Interfaced(), _interactionType(ShowerInteraction::UNDEFINED), _colourStructure(Undefined), _colourFactor(-1.), angularOrdered_(true), scaleChoice_(2), strictAO_(true) {} public: /** * Methods to return the interaction type and order for the splitting function */ //@{ /** * Return the type of the interaction */ ShowerInteraction interactionType() const {return _interactionType;} /** * Return the colour structure */ ColourStructure colourStructure() const {return _colourStructure;} /** * Return the colour factor */ double colourFactor(const IdList &ids) const { if(_colourStructure>0) return _colourFactor; else if(_colourStructure<0) { if(_colourStructure==ChargedChargedNeutral || _colourStructure==ChargedNeutralCharged) { return sqr(double(ids[0]->iCharge())/3.); } else if(_colourStructure==NeutralChargedCharged) { double fact = sqr(double(ids[1]->iCharge())/3.); if(ids[1]->coloured()) fact *= abs(double(ids[1]->iColour())); return fact; } + else if(_colourStructure==EW) { + return 1.; + } else { assert(false); return 0.; } } else { assert(false); return 0.; } } //@} /** * Purely virtual method which should determine whether this splitting * function can be used for a given set of particles. * @param ids The PDG codes for the particles in the splitting. */ virtual bool accept(const IdList & ids) const = 0; /** * Method to check the colours are correct */ virtual bool checkColours(const IdList & ids) const; /** * Methods to return the splitting function. */ //@{ /** * Purely virtual method which should return the exact value of the splitting function, * \f$P\f$ evaluated in terms of the energy fraction, \f$z\f$, and the evolution scale \f$\tilde{q}^2\f$. * @param z The energy fraction. * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param mass Whether or not to include the mass dependent terms + * @param rho The spin density matrix */ virtual double P(const double z, const Energy2 t, const IdList & ids, const bool mass, const RhoDMatrix & rho) const = 0; /** * Purely virtual method which should return * an overestimate of the splitting function, * \f$P_{\rm over}\f$ such that the result \f$P_{\rm over}\geq P\f$. This function * should be simple enough that it does not depend on the evolution scale. * @param z The energy fraction. * @param ids The PDG codes for the particles in the splitting. */ virtual double overestimateP(const double z, const IdList & ids) const = 0; /** * Purely virtual method which should return * the ratio of the splitting function to the overestimate, i.e. * \f$P(z,\tilde{q}^2)/P_{\rm over}(z)\f$. * @param z The energy fraction. * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param mass Whether or not to include the mass dependent terms + * @param rho The spin density matrix */ virtual double ratioP(const double z, const Energy2 t, const IdList & ids, const bool mass, const RhoDMatrix & rho) const = 0; /** * Purely virtual method which should return the indefinite integral of the * overestimated splitting function, \f$P_{\rm over}\f$. * @param z The energy fraction. * @param ids The PDG codes for the particles in the splitting. * @param PDFfactor Which additional factor to include for the PDF * 0 is no additional factor, * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ * */ virtual double integOverP(const double z, const IdList & ids, unsigned int PDFfactor=0) const = 0; /** * Purely virtual method which should return the inverse of the * indefinite integral of the * overestimated splitting function, \f$P_{\rm over}\f$ which is used to * generate the value of \f$z\f$. * @param r Value of the splitting function to be inverted * @param ids The PDG codes for the particles in the splitting. * @param PDFfactor Which additional factor to include for the PDF * 0 is no additional factor, * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ */ virtual double invIntegOverP(const double r, const IdList & ids, unsigned int PDFfactor=0) const = 0; //@} /** * Purely virtual method which should make the proper colour connection * between the emitting parent and the branching products. * @param parent The parent for the branching * @param first The first branching product * @param second The second branching product * @param partnerType The type of evolution partner * @param back Whether this is foward or backward evolution. */ virtual void colourConnection(tShowerParticlePtr parent, tShowerParticlePtr first, tShowerParticlePtr second, ShowerPartnerType partnerType, const bool back) const; /** * Method to calculate the azimuthal angle for forward evolution * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. * @return The weight */ virtual vector > generatePhiForward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix &) = 0; /** * Method to calculate the azimuthal angle for backward evolution * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @return The weight */ virtual vector > generatePhiBackward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix &) = 0; /** * Calculate the matrix element for the splitting * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param phi The azimuthal angle, \f$\phi\f$. * @param timeLike Whether timelike or spacelike, affects inclusive of mass terms */ virtual DecayMEPtr matrixElement(const double z, const Energy2 t, const IdList & ids, const double phi, bool timeLike) = 0; /** * Whether or not the interaction is angular ordered */ bool angularOrdered() const {return angularOrdered_;} /** * Scale choice */ bool pTScale() const { return scaleChoice_ == 2 ? angularOrdered_ : scaleChoice_ == 0; } /** * Functions to state scales after branching happens */ //@{ /** * Sort out scales for final-state emission */ void evaluateFinalStateScales(ShowerPartnerType type, Energy scale, double z, tShowerParticlePtr parent, tShowerParticlePtr first, tShowerParticlePtr second); /** * Sort out scales for initial-state emission */ void evaluateInitialStateScales(ShowerPartnerType type, Energy scale, double z, tShowerParticlePtr parent, tShowerParticlePtr first, tShowerParticlePtr second); /** * Sort out scales for decay emission */ void evaluateDecayScales(ShowerPartnerType type, Energy scale, double z, tShowerParticlePtr parent, tShowerParticlePtr first, tShowerParticlePtr second); //@} public: /** @name Functions used by the persistent I/O system. */ //@{ /** * Function used to write out object persistently. * @param os the persistent output stream written to. */ void persistentOutput(PersistentOStream & os) const; /** * Function used to read in object persistently. * @param is the persistent input stream read from. * @param version the version number of the object when written. */ void persistentInput(PersistentIStream & is, int version); //@} /** * The standard Init function used to initialize the interfaces. * Called exactly once for each class by the class description system * before the main function starts or * when this class is dynamically loaded. */ static void Init(); protected: /** @name Standard Interfaced functions. */ //@{ /** * Initialize this object after the setup phase before saving an * EventGenerator to disk. * @throws InitException if object could not be initialized properly. */ virtual void doinit(); //@} protected: /** * Set the colour factor */ void colourFactor(double in) {_colourFactor=in;} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ SplittingFunction & operator=(const SplittingFunction &) = delete; private: /** * The interaction type for the splitting function. */ ShowerInteraction _interactionType; /** * The colour structure */ ColourStructure _colourStructure; /** * The colour factor */ double _colourFactor; /** * Whether or not this interaction is angular-ordered */ bool angularOrdered_; /** * The choice of scale */ unsigned int scaleChoice_; /** * Enforce strict AO */ bool strictAO_; }; } #endif /* HERWIG_SplittingFunction_H */ diff --git a/Shower/QTilde/SplittingFunctions/SplittingGenerator.cc b/Shower/QTilde/SplittingFunctions/SplittingGenerator.cc --- a/Shower/QTilde/SplittingFunctions/SplittingGenerator.cc +++ b/Shower/QTilde/SplittingFunctions/SplittingGenerator.cc @@ -1,615 +1,646 @@ // -*- C++ -*- // // SplittingGenerator.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the SplittingGenerator class. // #include "SplittingGenerator.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Command.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Utilities/StringUtils.h" #include "ThePEG/Repository/Repository.h" #include "Herwig/Shower/QTilde/Base/ShowerParticle.h" #include "Herwig/Shower/ShowerHandler.h" #include "ThePEG/Utilities/Rebinder.h" #include #include "ThePEG/Utilities/DescribeClass.h" using namespace Herwig; namespace { bool checkInteraction(ShowerInteraction allowed, ShowerInteraction splitting) { - if(allowed==ShowerInteraction::Both) + if(allowed==ShowerInteraction::ALL) + return true; + else if(allowed==ShowerInteraction::QEDQCD && + (splitting==ShowerInteraction::QED || + splitting==ShowerInteraction::QCD )) return true; else if(allowed == splitting) return true; else return false; } } DescribeClass describeSplittingGenerator ("Herwig::SplittingGenerator",""); IBPtr SplittingGenerator::clone() const { return new_ptr(*this); } IBPtr SplittingGenerator::fullclone() const { return new_ptr(*this); } - void SplittingGenerator::persistentOutput(PersistentOStream & os) const { os << _bbranchings << _fbranchings << _deTuning; } void SplittingGenerator::persistentInput(PersistentIStream & is, int) { is >> _bbranchings >> _fbranchings >> _deTuning; } void SplittingGenerator::Init() { static ClassDocumentation documentation ("There class is responsible for initializing the Sudakov form factors ", "and generating splittings."); static Command interfaceAddSplitting ("AddFinalSplitting", "Adds another splitting to the list of splittings considered " "in the shower. Command is a->b,c; Sudakov", &SplittingGenerator::addFinalSplitting); static Command interfaceAddInitialSplitting ("AddInitialSplitting", "Adds another splitting to the list of initial splittings to consider " "in the shower. Command is a->b,c; Sudakov. Here the particle a is the " "particle that is PRODUCED by the splitting. b is the initial state " "particle that is splitting in the shower.", &SplittingGenerator::addInitialSplitting); static Command interfaceDeleteSplitting ("DeleteFinalSplitting", "Deletes a splitting from the list of splittings considered " "in the shower. Command is a->b,c; Sudakov", &SplittingGenerator::deleteFinalSplitting); static Command interfaceDeleteInitialSplitting ("DeleteInitialSplitting", "Deletes a splitting from the list of initial splittings to consider " "in the shower. Command is a->b,c; Sudakov. Here the particle a is the " "particle that is PRODUCED by the splitting. b is the initial state " "particle that is splitting in the shower.", &SplittingGenerator::deleteInitialSplitting); static Parameter interfaceDetuning ("Detuning", "The Detuning parameter to make the veto algorithm less efficient to improve the weight variations", &SplittingGenerator::_deTuning, 1.0, 1.0, 10.0, false, false, Interface::limited); } string SplittingGenerator::addSplitting(string arg, bool final) { string partons = StringUtils::car(arg); string sudakov = StringUtils::cdr(arg); vector products; string::size_type next = partons.find("->"); if(next == string::npos) return "Error: Invalid string for splitting " + arg; if(partons.find(';') == string::npos) return "Error: Invalid string for splitting " + arg; tPDPtr parent = Repository::findParticle(partons.substr(0,next)); partons = partons.substr(next+2); do { next = min(partons.find(','), partons.find(';')); tPDPtr pdp = Repository::findParticle(partons.substr(0,next)); partons = partons.substr(next+1); if(pdp) products.push_back(pdp); else return "Error: Could not create splitting from " + arg; } while(partons[0] != ';' && partons.size()); SudakovPtr s; s = dynamic_ptr_cast(Repository::TraceObject(sudakov)); if(!s) return "Error: Could not load Sudakov " + sudakov + '\n'; IdList ids; ids.push_back(parent); for(vector::iterator it = products.begin(); it!=products.end(); ++it) ids.push_back(*it); // check splitting can handle this if(!s->splittingFn()->accept(ids)) return "Error: Sudakov " + sudakov + " SplittingFunction can't handle particles\n"; // add to map addToMap(ids,s,final); return ""; } string SplittingGenerator::deleteSplitting(string arg, bool final) { string partons = StringUtils::car(arg); string sudakov = StringUtils::cdr(arg); vector products; string::size_type next = partons.find("->"); if(next == string::npos) return "Error: Invalid string for splitting " + arg; if(partons.find(';') == string::npos) return "Error: Invalid string for splitting " + arg; tPDPtr parent = Repository::findParticle(partons.substr(0,next)); partons = partons.substr(next+2); do { next = min(partons.find(','), partons.find(';')); tPDPtr pdp = Repository::findParticle(partons.substr(0,next)); partons = partons.substr(next+1); if(pdp) products.push_back(pdp); else return "Error: Could not create splitting from " + arg; } while(partons[0] != ';' && partons.size()); SudakovPtr s; s = dynamic_ptr_cast(Repository::TraceObject(sudakov)); if(!s) return "Error: Could not load Sudakov " + sudakov + '\n'; IdList ids; ids.push_back(parent); for(vector::iterator it = products.begin(); it!=products.end(); ++it) ids.push_back(*it); // check splitting can handle this if(!s->splittingFn()->accept(ids)) - return "Error: Sudakov " + sudakov + " Splitting Function can't handle particles\n"; + return "Error: Sudakov " + sudakov + " SplittingFunction can't handle particles\n"; // delete from map deleteFromMap(ids,s,final); return ""; } void SplittingGenerator::addToMap(const IdList &ids, const SudakovPtr &s, bool final) { if(!final) { // search if the branching was already included. auto binsert =BranchingInsert(abs(ids[1]->id()),BranchingElement(s,ids)); // get the range of already inserted splittings. auto eqrange=_bbranchings.equal_range(binsert.first); for(auto it = eqrange.first; it != eqrange.second; ++it){ if((*it).second == binsert.second) throw Exception()<<"SplittingGenerator: Trying to insert existing splitting.\n" << Exception::setuperror; } _bbranchings.insert(binsert); s->addSplitting(ids); } else { // search if the branching was already included. auto binsert =BranchingInsert(abs(ids[0]->id()),BranchingElement(s,ids)); // get the range of already inserted splittings. auto eqrange=_fbranchings.equal_range(binsert.first); for(auto it = eqrange.first; it != eqrange.second; ++it){ if((*it).second ==binsert.second) throw Exception()<<"SplittingGenerator: Trying to insert existing splitting.\n" << Exception::setuperror; } _fbranchings.insert(binsert); s->addSplitting(ids); } } void SplittingGenerator::deleteFromMap(const IdList &ids, const SudakovPtr &s, bool final) { bool didRemove=false; if(!final) { pair range = _bbranchings.equal_range(abs(ids[1]->id())); for(BranchingList::iterator it=range.first; it!=range.second&&it!=_bbranchings.end();++it) { if(it->second.sudakov==s&&it->second.particles==ids) { BranchingList::iterator it2=it; --it; _bbranchings.erase(it2); didRemove=true; } } s->removeSplitting(ids); } else { pair range = _fbranchings.equal_range(abs(ids[0]->id())); for(BranchingList::iterator it=range.first; it!=range.second&&it!=_fbranchings.end();++it) { if(it->second.sudakov==s&&it->second.particles==ids) { BranchingList::iterator it2 = it; --it; _fbranchings.erase(it2); didRemove=true; } } s->removeSplitting(ids); } if (!didRemove) throw Exception()<<"SplittingGenerator: Try to remove non existing splitting.\n" << Exception::setuperror; } Branching SplittingGenerator::chooseForwardBranching(ShowerParticle &particle, double enhance, ShowerInteraction type) const { RhoDMatrix rho; bool rhoCalc(false); Energy newQ = ZERO; ShoKinPtr kinematics = ShoKinPtr(); ShowerPartnerType partnerType(ShowerPartnerType::Undefined); SudakovPtr sudakov = SudakovPtr(); IdList ids; // First, find the eventual branching, corresponding to the highest scale. long index = abs(particle.data().id()); // if no branchings return empty branching struct if( _fbranchings.find(index) == _fbranchings.end() ) return Branching(ShoKinPtr(), IdList(),SudakovPtr(),ShowerPartnerType::Undefined); // otherwise select branching for(BranchingList::const_iterator cit = _fbranchings.lower_bound(index); cit != _fbranchings.upper_bound(index); ++cit) { // check either right interaction or doing both if(!checkInteraction(type,cit->second.sudakov->interactionType())) continue; if(!rhoCalc && particle.dataPtr()->iSpin()!=PDT::Spin0) { rho = particle.extractRhoMatrix(true); rhoCalc = true; } // whether or not this interaction should be angular ordered bool angularOrdered = cit->second.sudakov->splittingFn()->angularOrdered(); ShoKinPtr newKin; ShowerPartnerType type; IdList particles = particle.id()!=cit->first ? cit->second.conjugateParticles : cit->second.particles; // work out which starting scale we need if(cit->second.sudakov->interactionType()==ShowerInteraction::QED) { type = ShowerPartnerType::QED; Energy startingScale = angularOrdered ? particle.scales().QED : particle.scales().QED_noAO; newKin = cit->second.sudakov-> generateNextTimeBranching(startingScale,particles,rho,enhance, _deTuning); } else if(cit->second.sudakov->interactionType()==ShowerInteraction::QCD) { // special for octets if(particle.dataPtr()->iColour()==PDT::Colour8) { // octet -> octet octet if(cit->second.sudakov->splittingFn()->colourStructure()==OctetOctetOctet) { type = ShowerPartnerType::QCDColourLine; Energy startingScale = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO; newKin= cit->second.sudakov-> generateNextTimeBranching(startingScale,particles,rho,0.5*enhance, _deTuning); startingScale = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO; ShoKinPtr newKin2 = cit->second.sudakov-> generateNextTimeBranching(startingScale,particles,rho,0.5*enhance, _deTuning); // pick the one with the highest scale if( ( newKin && newKin2 && newKin2->scale() > newKin->scale()) || (!newKin && newKin2) ) { newKin = newKin2; type = ShowerPartnerType::QCDAntiColourLine; } } // other g -> q qbar else { Energy startingScale = angularOrdered ? max(particle.scales().QCD_c , particle.scales().QCD_ac ) : max(particle.scales().QCD_c_noAO, particle.scales().QCD_ac_noAO); newKin= cit->second.sudakov-> generateNextTimeBranching(startingScale,particles,rho,enhance, _deTuning); type = UseRandom::rndbool() ? ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine; } } // everything else q-> qg etc else { Energy startingScale; if(particle.hasColour()) { type = ShowerPartnerType::QCDColourLine; startingScale = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO; } else { type = ShowerPartnerType::QCDAntiColourLine; startingScale = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO; } newKin= cit->second.sudakov-> generateNextTimeBranching(startingScale,particles,rho,enhance, _deTuning); } } + else if(cit->second.sudakov->interactionType()==ShowerInteraction::EW) { + type = ShowerPartnerType::EW; + Energy startingScale = particle.scales().EW; + newKin = cit->second.sudakov-> + generateNextTimeBranching(startingScale,particles,rho,enhance,_deTuning); + } // shouldn't be anything else else assert(false); // if no kinematics contine if(!newKin) continue; // select highest scale if( newKin->scale() > newQ ) { kinematics = newKin; newQ = newKin->scale(); ids = particles; sudakov = cit->second.sudakov; partnerType = type; } } // return empty branching if nothing happened if(!kinematics) { if ( particle.spinInfo() ) particle.spinInfo()->undecay(); return Branching(ShoKinPtr(), IdList(),SudakovPtr(), ShowerPartnerType::Undefined); } // if not hard generate phi kinematics->phi(sudakov->generatePhiForward(particle,ids,kinematics,rho)); // and return it return Branching(kinematics, ids,sudakov,partnerType); } Branching SplittingGenerator:: chooseDecayBranching(ShowerParticle &particle, const ShowerParticle::EvolutionScales & stoppingScales, Energy minmass, double enhance, ShowerInteraction interaction) const { RhoDMatrix rho(particle.dataPtr()->iSpin()); Energy newQ = Constants::MaxEnergy; ShoKinPtr kinematics; SudakovPtr sudakov; ShowerPartnerType partnerType(ShowerPartnerType::Undefined); IdList ids; // First, find the eventual branching, corresponding to the lowest scale. long index = abs(particle.data().id()); // if no branchings return empty branching struct if(_fbranchings.find(index) == _fbranchings.end()) return Branching(ShoKinPtr(), IdList(),SudakovPtr(),ShowerPartnerType::Undefined); // otherwise select branching for(BranchingList::const_iterator cit = _fbranchings.lower_bound(index); cit != _fbranchings.upper_bound(index); ++cit) { // check interaction doesn't change flavour if(cit->second.particles[1]->id()!=index&&cit->second.particles[2]->id()!=index) continue; // check either right interaction or doing both if(!checkInteraction(interaction,cit->second.sudakov->interactionType())) continue; // whether or not this interaction should be angular ordered bool angularOrdered = cit->second.sudakov->splittingFn()->angularOrdered(); ShoKinPtr newKin; IdList particles = particle.id()!=cit->first ? cit->second.conjugateParticles : cit->second.particles; ShowerPartnerType type; // work out which starting scale we need if(cit->second.sudakov->interactionType()==ShowerInteraction::QED) { type = ShowerPartnerType::QED; Energy stoppingScale = angularOrdered ? stoppingScales.QED : stoppingScales.QED_noAO; Energy startingScale = angularOrdered ? particle.scales().QED : particle.scales().QED_noAO; if(startingScale < stoppingScale ) { newKin = cit->second.sudakov-> - generateNextDecayBranching(startingScale,stoppingScale,minmass,particles,rho,enhance,_deTuning); + generateNextDecayBranching(startingScale,stoppingScale,minmass,particles,rho, + enhance,_deTuning); } } else if(cit->second.sudakov->interactionType()==ShowerInteraction::QCD) { // special for octets if(particle.dataPtr()->iColour()==PDT::Colour8) { // octet -> octet octet if(cit->second.sudakov->splittingFn()->colourStructure()==OctetOctetOctet) { Energy stoppingColour = angularOrdered ? stoppingScales.QCD_c : stoppingScales.QCD_c_noAO; Energy stoppingAnti = angularOrdered ? stoppingScales.QCD_ac : stoppingScales.QCD_ac_noAO; Energy startingColour = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO; Energy startingAnti = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO; type = ShowerPartnerType::QCDColourLine; if(startingColoursecond.sudakov-> generateNextDecayBranching(startingColour,stoppingColour,minmass, particles,rho,0.5*enhance,_deTuning); } ShoKinPtr newKin2; if(startingAntisecond.sudakov-> - generateNextDecayBranching(startingAnti,stoppingAnti,minmass,particles,rho,0.5*enhance,_deTuning); + generateNextDecayBranching(startingAnti,stoppingAnti,minmass, + particles,rho,0.5*enhance,_deTuning); } // pick the one with the lowest scale if( (newKin&&newKin2&&newKin2->scale()scale()) || (!newKin&&newKin2) ) { newKin = newKin2; type = ShowerPartnerType::QCDAntiColourLine; } } // other else { assert(false); } } // everything else else { Energy startingScale,stoppingScale; if(particle.hasColour()) { type = ShowerPartnerType::QCDColourLine; stoppingScale = angularOrdered ? stoppingScales.QCD_c : stoppingScales.QCD_c_noAO; startingScale = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO; } else { type = ShowerPartnerType::QCDAntiColourLine; stoppingScale = angularOrdered ? stoppingScales.QCD_ac : stoppingScales.QCD_ac_noAO; startingScale = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO; } - if(startingScale < stoppingScale ) { + if(startingScale < stoppingScale ) { newKin = cit->second.sudakov-> - generateNextDecayBranching(startingScale,stoppingScale,minmass,particles,rho,enhance,_deTuning); + generateNextDecayBranching(startingScale,stoppingScale,minmass,particles,rho, + enhance,_deTuning); } } } + else if(cit->second.sudakov->interactionType()==ShowerInteraction::EW) { + type = ShowerPartnerType::EW; + Energy stoppingScale, startingScale; + stoppingScale = stoppingScales.EW; + startingScale = particle.scales().EW; + if(startingScale < stoppingScale ) { + newKin = cit->second.sudakov-> + generateNextDecayBranching(startingScale,stoppingScale,minmass,particles,rho,enhance,_deTuning); + } + } // shouldn't be anything else else assert(false); if(!newKin) continue; // select highest scale if(newKin->scale() < newQ ) { newQ = newKin->scale(); ids = particles; kinematics=newKin; sudakov=cit->second.sudakov; partnerType = type; } } // return empty branching if nothing happened if(!kinematics) return Branching(ShoKinPtr(), IdList(),SudakovPtr(), ShowerPartnerType::Undefined); // and generate phi kinematics->phi(sudakov->generatePhiDecay(particle,ids,kinematics,rho)); // and return it return Branching(kinematics, ids,sudakov,partnerType); } Branching SplittingGenerator:: -chooseBackwardBranching(ShowerParticle &particle,PPtr , +chooseBackwardBranching(ShowerParticle &particle,PPtr, double enhance, Ptr::transient_const_pointer beam, ShowerInteraction type, tcPDFPtr pdf, Energy freeze) const { RhoDMatrix rho; bool rhoCalc(false); Energy newQ=ZERO; ShoKinPtr kinematics=ShoKinPtr(); ShowerPartnerType partnerType(ShowerPartnerType::Undefined); SudakovPtr sudakov; IdList ids; // First, find the eventual branching, corresponding to the highest scale. long index = abs(particle.id()); // if no possible branching return if(_bbranchings.find(index) == _bbranchings.end()) return Branching(ShoKinPtr(), IdList(),SudakovPtr(),ShowerPartnerType::Undefined); // otherwise select branching for(BranchingList::const_iterator cit = _bbranchings.lower_bound(index); cit != _bbranchings.upper_bound(index); ++cit ) { // check either right interaction or doing both if(!checkInteraction(type,cit->second.sudakov->interactionType())) continue; // setup the PDF cit->second.sudakov->setPDF(pdf,freeze); //calc rho as needed if(!rhoCalc && particle.dataPtr()->iSpin()!=PDT::Spin0) { rho = particle.extractRhoMatrix(false); rhoCalc = true; } // whether or not this interaction should be angular ordered bool angularOrdered = cit->second.sudakov->splittingFn()->angularOrdered(); ShoKinPtr newKin; IdList particles = particle.id()!=cit->first ? cit->second.conjugateParticles : cit->second.particles; ShowerPartnerType type; if(cit->second.sudakov->interactionType()==ShowerInteraction::QED) { type = ShowerPartnerType::QED; Energy startingScale = angularOrdered ? particle.scales().QED : particle.scales().QED_noAO; newKin=cit->second.sudakov-> - generateNextSpaceBranching(startingScale,particles,particle.x(),rho,enhance,beam,_deTuning); + generateNextSpaceBranching(startingScale,particles, particle.x(),rho,enhance, + beam,_deTuning); } else if(cit->second.sudakov->interactionType()==ShowerInteraction::QCD) { // special for octets if(particle.dataPtr()->iColour()==PDT::Colour8) { // octet -> octet octet if(cit->second.sudakov->splittingFn()->colourStructure()==OctetOctetOctet) { type = ShowerPartnerType::QCDColourLine; Energy startingScale = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO; newKin = cit->second.sudakov-> - generateNextSpaceBranching(startingScale,particles, particle.x(),rho,0.5*enhance,beam,_deTuning); + generateNextSpaceBranching(startingScale,particles, particle.x(),rho,0.5*enhance, + beam,_deTuning); startingScale = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO; ShoKinPtr newKin2 = cit->second.sudakov-> - generateNextSpaceBranching(startingScale,particles, particle.x(),rho,0.5*enhance,beam,_deTuning); + generateNextSpaceBranching(startingScale,particles, particle.x(),rho, + 0.5*enhance,beam,_deTuning); // pick the one with the highest scale if( (newKin&&newKin2&&newKin2->scale()>newKin->scale()) || (!newKin&&newKin2) ) { newKin = newKin2; type = ShowerPartnerType::QCDAntiColourLine; } } else { Energy startingScale = angularOrdered ? max(particle.scales().QCD_c , particle.scales().QCD_ac ) : max(particle.scales().QCD_c_noAO, particle.scales().QCD_ac_noAO); type = UseRandom::rndbool() ? ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine; newKin=cit->second.sudakov-> generateNextSpaceBranching(startingScale,particles, particle.x(),rho,enhance,beam,_deTuning); } } // everything else else { Energy startingScale; if(particle.hasColour()) { type = ShowerPartnerType::QCDColourLine; startingScale = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO; } else { type = ShowerPartnerType::QCDAntiColourLine; startingScale = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO; } newKin=cit->second.sudakov-> - generateNextSpaceBranching(startingScale,particles, particle.x(),rho,enhance,beam,_deTuning); + generateNextSpaceBranching(startingScale,particles,particle.x(),rho,enhance,beam,_deTuning); } } + else if(cit->second.sudakov->interactionType()==ShowerInteraction::EW) { + type = ShowerPartnerType::EW; + Energy startingScale = particle.scales().EW; + newKin=cit->second.sudakov-> + generateNextSpaceBranching(startingScale,particles,particle.x(),rho,enhance,beam,_deTuning); + } // shouldn't be anything else else assert(false); // if no kinematics contine if(!newKin) continue; // select highest scale if(newKin->scale() > newQ) { newQ = newKin->scale(); kinematics=newKin; ids = particles; sudakov=cit->second.sudakov; partnerType = type; } } // return empty branching if nothing happened if(!kinematics) { if ( particle.spinInfo() ) particle.spinInfo()->undecay(); return Branching(ShoKinPtr(), IdList(),SudakovPtr(), ShowerPartnerType::Undefined); } // initialize the ShowerKinematics // and generate phi kinematics->phi(sudakov->generatePhiBackward(particle,ids,kinematics,rho)); // return the answer return Branching(kinematics, ids,sudakov,partnerType); } void SplittingGenerator::rebind(const TranslationMap & trans) { BranchingList::iterator cit; for(cit=_fbranchings.begin();cit!=_fbranchings.end();++cit) { (cit->second).sudakov=trans.translate((cit->second).sudakov); for(unsigned int ix=0;ix<(cit->second).particles.size();++ix) { (cit->second).particles[ix]=trans.translate((cit->second).particles[ix]); } for(unsigned int ix=0;ix<(cit->second).conjugateParticles.size();++ix) { (cit->second).conjugateParticles[ix]=trans.translate((cit->second).conjugateParticles[ix]); } } for(cit=_bbranchings.begin();cit!=_bbranchings.end();++cit) { (cit->second).sudakov=trans.translate((cit->second).sudakov); for(unsigned int ix=0;ix<(cit->second).particles.size();++ix) { (cit->second).particles[ix]=trans.translate((cit->second).particles[ix]); } for(unsigned int ix=0;ix<(cit->second).conjugateParticles.size();++ix) { (cit->second).conjugateParticles[ix]=trans.translate((cit->second).conjugateParticles[ix]); } } Interfaced::rebind(trans); } IVector SplittingGenerator::getReferences() { IVector ret = Interfaced::getReferences(); BranchingList::iterator cit; for(cit=_fbranchings.begin();cit!=_fbranchings.end();++cit) { ret.push_back((cit->second).sudakov); for(unsigned int ix=0;ix<(cit->second).particles.size();++ix) ret.push_back(const_ptr_cast((cit->second).particles[ix])); for(unsigned int ix=0;ix<(cit->second).conjugateParticles.size();++ix) ret.push_back(const_ptr_cast((cit->second).conjugateParticles[ix])); } for(cit=_bbranchings.begin();cit!=_bbranchings.end();++cit) { ret.push_back((cit->second).sudakov); for(unsigned int ix=0;ix<(cit->second).particles.size();++ix) ret.push_back(const_ptr_cast((cit->second).particles[ix])); for(unsigned int ix=0;ix<(cit->second).conjugateParticles.size();++ix) ret.push_back(const_ptr_cast((cit->second).conjugateParticles[ix])); } return ret; } diff --git a/Shower/QTilde/SplittingFunctions/SudakovFormFactor.h b/Shower/QTilde/SplittingFunctions/SudakovFormFactor.h --- a/Shower/QTilde/SplittingFunctions/SudakovFormFactor.h +++ b/Shower/QTilde/SplittingFunctions/SudakovFormFactor.h @@ -1,626 +1,626 @@ // -*- C++ -*- // // SudakovFormFactor.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_SudakovFormFactor_H #define HERWIG_SudakovFormFactor_H // // This is the declaration of the SudakovFormFactor class. // #include "ThePEG/Interface/Interfaced.h" #include "Herwig/Shower/QTilde/SplittingFunctions/SplittingFunction.h" #include "Herwig/Shower/ShowerAlpha.h" #include "Herwig/Shower/QTilde/SplittingFunctions/SplittingGenerator.fh" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/PDF/BeamParticleData.h" #include "ThePEG/EventRecord/RhoDMatrix.h" #include "ThePEG/EventRecord/SpinInfo.h" #include "Herwig/Shower/QTilde/Kinematics/ShowerKinematics.fh" #include "SudakovFormFactor.fh" #include "SudakovCutOff.h" namespace Herwig { using namespace ThePEG; /** * A typedef for the BeamParticleData */ typedef Ptr::transient_const_pointer tcBeamPtr; /** \ingroup Shower * * This is the definition of the Sudakov form factor class. In general this * is the base class for the implementation of Sudakov form factors in Herwig. * The methods generateNextTimeBranching(), generateNextDecayBranching() and * generateNextSpaceBranching need to be implemented in classes inheriting from this * one. * * In addition a number of methods are implemented to assist with the calculation * of the form factor using the veto algorithm in classes inheriting from this one. * * In general the Sudakov form-factor, for final-state radiation, is given * by * \f[\Delta_{ba}(\tilde{q}_{i+1},\tilde{q}_i)= * \exp\left\{ * -\int^{\tilde{q}^2_i}_{\tilde{q}^2_{i+1}} * \frac{{\rm d}\tilde{q}^2}{\tilde{q}^2} * \int\frac{\alpha_S(z,\tilde{q})}{2\pi} * P_{ba}(z,\tilde{q})\Theta(p_T) * \right\}. * \f] * We can solve this to obtain the next value of the scale \f$\tilde{q}_{i+1}\f$ * given the previous value \f$\tilde{q}_i\f$ * in the following way. First we obtain a simplified form of the integrand * which is greater than or equal to the true integrand for all values of * \f$\tilde{q}\f$. * * In practice it is easiest to obtain this over estimate in pieces. The ShowerAlpha * object contains an over estimate for \f$\alpha_S\f$, the splitting function * contains both an over estimate of the spltting function and its integral * which is needed to compute the over estimate of the \f$\tilde{q}\f$ integrand, * together with an over estimate of the limit of the \f$z\f$ integral. * * This gives an overestimate of the integrand * \f[g(\tilde{q}^2) = \frac{c}{\tilde{q}^2}, \f] * where because the over estimates are chosen to be independent of \f$\tilde{q}\f$ the * parameter * \f[c = \frac{\alpha_{\rm over}}{2\pi}\int^{z_1}_{z_0}P_{\rm over}(z),\f] * is a constant independent of \f$\tilde{q}\f$. * * The guesstz() member can then be used to generate generate the value of * \f$\tilde{q}^2\f$ according to this result. This is done by solving the Sudakov * form factor, with the over estimates, is equal to a random number * \f$r\f$ in the interval \f$[0,1]\f$. This gives * \f[\tilde{q}^2_{i+1}=G^{-1}\left[G(\tilde{q}^2_i)+\ln r\right],\f] * where \f$G(\tilde{q}^2)=c\ln(\tilde{q}^2)\f$ is the infinite integral * of \f$g(\tilde{q}^2)\f$ and \f$G^{-1}(x)=\exp\left(\frac{x}c\right)\f$ * is its inverse. * It this case we therefore obtain * \f[\tilde{q}^2_{i+1}=\tilde{q}^2_ir^{\frac1c}.\f] * The value of \f$z\f$ can then be calculated in a similar way * \f[z = I^{-1}\left[I(z_0)+r\left(I(z_1)-I(z_0)\right)\right],\f] * using the guesstz() member, * where \f$I=\int P(z){\rm d}z\f$ and \f$I^{-1}\f$ is its inverse. * * The veto algorithm then uses rejection using the ratio of the * true value to the overestimated one to obtain the original distribution. * This is accomplished using the * - alphaSVeto() member for the \f$\alpha_S\f$ veto * - SplittingFnVeto() member for the veto on the value of the splitting function. * in general there must also be a chech that the emission is in the allowed * phase space but this is left to the inheriting classes as it will depend * on the ordering variable. * * The Sudakov form factor for the initial-scale shower is different because * it must include the PDF which guides the backward evolution. * It is given by * \f[\Delta_{ba}(\tilde{q}_{i+1},\tilde{q}_i)= * \exp\left\{ * -\int^{\tilde{q}^2_i}_{\tilde{q}^2_{i+1}} * \frac{{\rm d}\tilde{q}^2}{\tilde{q}^2} * \int\frac{\alpha_S(z,\tilde{q})}{2\pi} * P_{ba}(z,\tilde{q})\frac{x'f_a(\frac{x}z,\tilde{q}^2)}{xf_b(x,\tilde{q^2})} * \right\}, * \f] * where \f$x\f$ is the fraction of the beam momentum the parton \f$b\f$ had before * the backward evolution. * This can be solve in the same way as for the final-state branching but the constant * becomes * \f[c = \frac{\alpha_{\rm over}}{2\pi}\int^{z_1}_{z_0}P_{\rm over}(z)PDF_{\rm max},\f] * where * \f[PDF_{\rm max}=\max\frac{x'f_a(\frac{x}z,\tilde{q}^2)}{xf_b(x,\tilde{q^2})},\f] * which can be set using an interface. * In addition the PDFVeto() member then is needed to implement the relevant veto. * * @see SplittingGenerator * @see SplittingFunction * @see ShowerAlpha * @see \ref SudakovFormFactorInterfaces "The interfaces" * defined for SudakovFormFactor. */ class SudakovFormFactor: public Interfaced { /** * The SplittingGenerator is a friend to insert the particles in the * branchings at initialisation */ friend class SplittingGenerator; public: /** * The default constructor. */ SudakovFormFactor() : pdfmax_(35.0), pdffactor_(0), z_( 0.0 ),phi_(0.0), pT_(){} /** * Members to generate the scale of the next branching */ //@{ /** * Return the scale of the next time-like branching. If there is no * branching then it returns ZERO. * @param startingScale starting scale for the evolution * @param ids The PDG codes of the particles in the splitting * @param enhance The radiation enhancement factor * defined. */ virtual ShoKinPtr generateNextTimeBranching(const Energy startingScale, const IdList &ids, const RhoDMatrix & rho, double enhance, double detuning); /** * Return the scale of the next space-like decay branching. If there is no * branching then it returns ZERO. * @param startingScale starting scale for the evolution * @param stoppingScale stopping scale for the evolution * @param minmass The minimum mass allowed for the spake-like particle. * @param ids The PDG codes of the particles in the splitting * defined. * @param enhance The radiation enhancement factor */ virtual ShoKinPtr generateNextDecayBranching(const Energy startingScale, const Energy stoppingScale, const Energy minmass, const IdList &ids, const RhoDMatrix & rho, double enhance, double detuning); /** * Return the scale of the next space-like branching. If there is no * branching then it returns ZERO. * @param startingScale starting scale for the evolution * @param ids The PDG codes of the particles in the splitting * @param x The fraction of the beam momentum * defined. * @param beam The beam particle * @param enhance The radiation enhancement factor */ virtual ShoKinPtr generateNextSpaceBranching(const Energy startingScale, const IdList &ids,double x, const RhoDMatrix & rho, double enhance, tcBeamPtr beam, double detuning); //@} /** * Generate the azimuthal angle of the branching for forward evolution * @param particle The branching particle * @param ids The PDG codes of the particles in the branchings * @param The Shower kinematics */ virtual double generatePhiForward(ShowerParticle & particle,const IdList & ids, ShoKinPtr kinematics, const RhoDMatrix & rho); /** * Generate the azimuthal angle of the branching for backward evolution * @param particle The branching particle * @param ids The PDG codes of the particles in the branchings * @param The Shower kinematics */ virtual double generatePhiBackward(ShowerParticle & particle,const IdList & ids, ShoKinPtr kinematics, const RhoDMatrix & rho); /** * Generate the azimuthal angle of the branching for ISR in decays * @param particle The branching particle * @param ids The PDG codes of the particles in the branchings * @param The Shower kinematics */ virtual double generatePhiDecay(ShowerParticle & particle,const IdList & ids, ShoKinPtr kinematics, const RhoDMatrix & rho); /** * Methods to provide public access to the private member variables */ //@{ /** * Return the pointer to the SplittingFunction object. */ tSplittingFnPtr splittingFn() const { return splittingFn_; } /** * Return the pointer to the ShowerAlpha object. */ tShowerAlphaPtr alpha() const { return alpha_; } /** * The type of interaction */ inline ShowerInteraction interactionType() const {return splittingFn_->interactionType();} //@} public: /** * Methods to access the kinematic variables for the branching */ //@{ /** * The energy fraction */ double z() const { return z_; } /** * The azimuthal angle */ double phi() const { return phi_; } /** * The transverse momentum */ Energy pT() const { return pT_; } //@} /** * Access the maximum weight for the PDF veto */ double pdfMax() const { return pdfmax_;} /** * Method to return the evolution scale given the * transverse momentum, \f$p_T\f$ and \f$z\f$. */ virtual Energy calculateScale(double z, Energy pt, IdList ids,unsigned int iopt); public: /** @name Functions used by the persistent I/O system. */ //@{ /** * Function used to write out object persistently. * @param os the persistent output stream written to. */ void persistentOutput(PersistentOStream & os) const; /** * Function used to read in object persistently. * @param is the persistent input stream read from. * @param version the version number of the object when written. */ void persistentInput(PersistentIStream & is, int version); //@} /** * The standard Init function used to initialize the interfaces. * Called exactly once for each class by the class description system * before the main function starts or * when this class is dynamically loaded. */ static void Init(); protected: /** * Methods to provide the next value of the scale before the vetos * are applied. */ //@{ /** * Value of the energy fraction and scale for time-like branching * @param t The scale * @param tmin The minimum scale * @param enhance The radiation enhancement factor * @return False if scale less than minimum, true otherwise */ bool guessTimeLike(Energy2 &t, Energy2 tmin, double enhance, double detune); /** * Value of the energy fraction and scale for time-like branching * @param t The scale * @param tmax The maximum scale * @param minmass The minimum mass of the particle after the branching * @param enhance The radiation enhancement factor */ bool guessDecay(Energy2 &t, Energy2 tmax,Energy minmass, double enhance, double detune); /** * Value of the energy fraction and scale for space-like branching * @param t The scale * @param tmin The minimum scale * @param x Fraction of the beam momentum. * @param enhance The radiation enhancement factor */ bool guessSpaceLike(Energy2 &t, Energy2 tmin, const double x, double enhance, double detune); //@} /** * Initialize the values of the cut-offs and scales * @param tmin The minimum scale * @param ids The ids of the partics in the branching */ void initialize(const IdList & ids,Energy2 &tmin); /** * Phase Space veto member to implement the \f$\Theta\f$ function as a veto * so that the emission is within the allowed phase space. * @param t The scale * @param maxQ2 The maximum virtuality * @return true if vetoed */ bool PSVeto(const Energy2 t); /** * Compute the limits on \f$z\f$ for time-like branching * @param scale The scale of the particle * @return True if lower limit less than upper, otherwise false */ bool computeTimeLikeLimits(Energy2 & scale); /** * Compute the limits on \f$z\f$ for space-like branching * @param scale The scale of the particle * @param x The energy fraction of the parton * @return True if lower limit less than upper, otherwise false */ bool computeSpaceLikeLimits(Energy2 & scale, double x); protected: /** * Methods to implement the veto algorithm to generate the scale of * the next branching */ //@{ /** * Value of the energy fraction and value of the scale for the veto algorithm * @param iopt The option for calculating z * @param ids The PDG codes of the particles in the splitting * - 0 is final-state * - 1 is initial-state for the hard process * - 2 is initial-state for particle decays * @param t1 The starting valoe of the scale * @param enhance The radiation enhancement factor * @param identical Whether or not the outgoing particles are identical * @param t_main rerurns the value of the energy fraction for the veto algorithm * @param z_main returns the value of the scale for the veto algorithm */ void guesstz(Energy2 t1,unsigned int iopt, const IdList &ids, double enhance,bool ident, double detune, Energy2 &t_main, double &z_main); /** * Veto on the PDF for the initial-state shower * @param t The scale * @param x The fraction of the beam momentum * @param parton0 Pointer to the particleData for the * new parent (this is the particle we evolved back to) * @param parton1 Pointer to the particleData for the * original particle * @param beam The BeamParticleData object */ bool PDFVeto(const Energy2 t, const double x, const tcPDPtr parton0, const tcPDPtr parton1, tcBeamPtr beam) const; /** * The PDF veto ratio */ double PDFVetoRatio(const Energy2 t, const double x, const tcPDPtr parton0, const tcPDPtr parton1, tcBeamPtr beam,double factor) const; /** * The veto on the splitting function. * @param t The scale * @param ids The PDG codes of the particles in the splitting * @param mass Whether or not to use the massive splitting functions * @return true if vetoed */ bool SplittingFnVeto(const Energy2 t, const IdList &ids, const bool mass, const RhoDMatrix & rho, - double detune) const { + const double & detune) const { return UseRandom::rnd()>SplittingFnVetoRatio(t,ids,mass,rho,detune); } /** * The Splitting function veto ratio */ double SplittingFnVetoRatio(const Energy2 t, const IdList &ids, const bool mass, const RhoDMatrix & rho, - double detune) const { + const double & detune) const { return splittingFn_->ratioP(z_, t, ids,mass,rho)/detune; } /** * The veto on the coupling constant * @param pt2 The value of ther transverse momentum squared, \f$p_T^2\f$. * @return true if vetoed */ bool alphaSVeto(Energy2 pt2) const; /** * The alpha S veto ratio */ double alphaSVetoRatio(Energy2 pt2,double factor) const; //@} /** * Set the particles in the splittings */ void addSplitting(const IdList &); /** * Delete the particles in the splittings */ void removeSplitting(const IdList &); /** * Access the potential branchings */ const vector & particles() const { return particles_; } public: /** * Set the PDF */ void setPDF(tcPDFPtr pdf, Energy scale) { pdf_ = pdf; freeze_ = scale; } public: /** * Calculate the virtual masses for a branchings */ const vector & virtualMasses(const IdList & ids) { return cutoff_->virtualMasses(ids); } /** * The minimum pT2 */ Energy2 pT2min() { return cutoff_->pT2min(); } protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const {return new_ptr(*this);} /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const {return new_ptr(*this);} //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ SudakovFormFactor & operator=(const SudakovFormFactor &) = delete; private: /** * Pointer to the splitting function for this Sudakov form factor */ SplittingFnPtr splittingFn_; /** * Pointer to the coupling for this Sudakov form factor */ ShowerAlphaPtr alpha_; /** * Pointer to the coupling for this Sudakov form factor */ SudakovCutOffPtr cutoff_; /** * Maximum value of the PDF weight */ double pdfmax_; /** * List of the particles this Sudakov is used for to aid in setting up * interpolation tables if needed */ vector particles_; /** * Option for the inclusion of a factor \f$1/(1-z)\f$ in the PDF estimate */ unsigned pdffactor_; private: /** * Member variables to keep the shower kinematics information * generated by a call to generateNextTimeBranching or generateNextSpaceBranching */ //@{ /** * The energy fraction */ double z_; /** * The azimuthal angle */ double phi_; /** * The transverse momentum */ Energy pT_; //@} /** * The limits of \f$z\f$ in the splitting */ pair zlimits_; /** * Stuff for the PDFs */ //@{ /** * PDf */ tcPDFPtr pdf_; /** * Freezing scale */ Energy freeze_; //@} private: /** * The evolution scale, \f$\tilde{q}\f$. */ Energy q_; /** * The Ids of the particles in the current branching */ IdList ids_; /** * The masses of the particles in the current branching */ vector masses_; /** * The mass squared of the particles in the current branching */ vector masssquared_; }; } #endif /* HERWIG_SudakovFormFactor_H */ diff --git a/Shower/QTilde/SplittingFunctions/ZeroZeroOneSplitFn.h b/Shower/QTilde/SplittingFunctions/ZeroZeroOneSplitFn.h --- a/Shower/QTilde/SplittingFunctions/ZeroZeroOneSplitFn.h +++ b/Shower/QTilde/SplittingFunctions/ZeroZeroOneSplitFn.h @@ -1,186 +1,188 @@ // -*- C++ -*- // // ZeroZeroOneSplitFn.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_ZeroZeroOneSplitFn_H #define HERWIG_ZeroZeroOneSplitFn_H // // This is the declaration of the ZeroZeroOneSplitFn class. // #include "Herwig/Shower/QTilde/SplittingFunctions/SplittingFunction.h" namespace Herwig { using namespace ThePEG; /** \ingroup Shower * This class provides the concrete implementation of the exact leading-order * splitting function for \f$\phi\to \phi g\f$. * * In this case the splitting function is given by * \f[P(z,t) = 2C\left(\frac{z}{1-z}-\frac{m^2_\phi}{t}\right),\f] * where \f$C\f$ is the corresponding colour factor. * Our choice for the overestimate is * \f[P_{\rm over}(z) = \frac{2C}{1-z},\f] * therefore the integral is * \f[\int P_{\rm over}(z) {\rm d}z = -2C\ln(1-z),\f] * and its inverse is * \f[1-\exp\left(\frac{r}{2C}\right).\f] * * @see \ref ZeroZeroOneSplitFnInterfaces "The interfaces" * defined for ZeroZeroOneSplitFn. */ class ZeroZeroOneSplitFn: public SplittingFunction { public: /** * Concrete implementation of the method to determine whether this splitting * function can be used for a given set of particles. * @param ids The PDG codes for the particles in the splitting. */ virtual bool accept(const IdList & ids) const; /** * Methods to return the splitting function. */ //@{ /** * The concrete implementation of the splitting function, \f$P\f$. * @param z The energy fraction. * @param t The scale. * @param ids The PDG codes for the particles in the splitting. * @param mass Whether or not to include the mass dependent terms + * @param rho The spin density matrix */ virtual double P(const double z, const Energy2 t, const IdList & ids, bool mass, const RhoDMatrix & rho) const; /** * The concrete implementation of the overestimate of the splitting function, * \f$P_{\rm over}\f$. * @param z The energy fraction. * @param ids The PDG codes for the particles in the splitting. */ virtual double overestimateP(const double z, const IdList & ids) const; /** * The concrete implementation of the * the ratio of the splitting function to the overestimate, i.e. * \f$P(z,\tilde{q}^2)/P_{\rm over}(z)\f$. * @param z The energy fraction. * @param t The scale. * @param ids The PDG codes for the particles in the splitting. * @param mass Whether or not to include the mass dependent terms + * @param rho The spin density matrix */ virtual double ratioP(const double z, const Energy2 t, const IdList & ids, bool mass, const RhoDMatrix & rho) const; /** * The concrete implementation of the indefinite integral of the * overestimated splitting function, \f$P_{\rm over}\f$. * @param z The energy fraction. * @param ids The PDG codes for the particles in the splitting. * @param PDFfactor Which additional factor to include for the PDF * 0 is no additional factor, * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ */ virtual double integOverP(const double z, const IdList & ids, unsigned int PDFfactor=0) const; /** * The concrete implementation of the inverse of the indefinite integral. * @param r Value of the splitting function to be inverted * @param ids The PDG codes for the particles in the splitting. * @param PDFfactor Which additional factor to include for the PDF * 0 is no additional factor, * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ */ virtual double invIntegOverP(const double r, const IdList & ids, unsigned int PDFfactor=0) const; //@} /** * Method to calculate the azimuthal angle for forward evolution * @param particle The particle which is branching * @param showerkin The ShowerKinematics object * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. * @return The weight */ virtual vector > generatePhiForward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix &); /** * Method to calculate the azimuthal angle for backward * Shouldn't be needed and NOT IMPLEMENTED * @param particle The particle which is branching * @param showerkin The ShowerKinematics object * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. * @return The weight */ virtual vector > generatePhiBackward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix &); /** * Calculate the matrix element for the splitting * @param particle The particle which is branching * @param showerkin The ShowerKinematics object * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. */ virtual DecayMEPtr matrixElement(const double z, const Energy2 t, const IdList & ids, const double phi, bool timeLike); public: /** * The standard Init function used to initialize the interfaces. * Called exactly once for each class by the class description system * before the main function starts or * when this class is dynamically loaded. */ static void Init(); protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const {return new_ptr(*this);} /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const {return new_ptr(*this);} //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ ZeroZeroOneSplitFn & operator=(const ZeroZeroOneSplitFn &) = delete; }; } #endif /* HERWIG_ZeroZeroOneSplitFn_H */ diff --git a/Shower/ShowerConfig.cc b/Shower/ShowerConfig.cc new file mode 100644 --- /dev/null +++ b/Shower/ShowerConfig.cc @@ -0,0 +1,47 @@ +// -*- C++ -*- +// +// ShowerConfig.cc is a part of Herwig - A multi-purpose Monte Carlo event generator +// Copyright (C) 2002-2011 The Herwig Collaboration +// +// Herwig is licenced under version 2 of the GPL, see COPYING for details. +// Please respect the MCnet academic guidelines, see GUIDELINES for details. +// +// +// This is the implementation of the non-inlined, non-templated member +// functions of the ShowerConfig class. +// +#include "ShowerConfig.h" +#include "Base/SudakovFormFactor.h" + +using namespace Herwig; + +BranchingElement::~BranchingElement() {} + +BranchingElement::BranchingElement() {} + +BranchingElement::BranchingElement(SudakovPtr sud, IdList part) : sudakov(sud), particles(part) { + for(unsigned int ix=0;ixCC() ? tcPDPtr(part[ix]->CC()) : part[ix]); +} + +namespace ThePEG { + +/** + * Output operator to allow the structure + */ +PersistentOStream & operator << (PersistentOStream & os, + const Herwig::BranchingElement & x) { + os << x.sudakov << x.particles << x.conjugateParticles; + return os; +} + +/** + * Input operator to allow the structure + */ +PersistentIStream & operator >> (PersistentIStream & is, + Herwig::BranchingElement & x) { + is >> x.sudakov >> x.particles >> x.conjugateParticles; + return is; +} + +} diff --git a/Shower/ShowerInteraction.h b/Shower/ShowerInteraction.h --- a/Shower/ShowerInteraction.h +++ b/Shower/ShowerInteraction.h @@ -1,41 +1,44 @@ // -*- C++ -*- // // ShowerInteraction.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_ShowerInteraction_H #define HERWIG_ShowerInteraction_H namespace Herwig { /** \ingroup Shower * * Handy header file to be included in all Shower classes. * It contains only some useful enums. */ /** * Enum for the type of interaction */ enum class ShowerInteraction { UNDEFINED=-1, QCD, QED, - Both + QEDQCD, + EW, + ALL }; /** * Enum for the type of shower partner */ enum class ShowerPartnerType { Undefined, QCDColourLine, QCDAntiColourLine, - QED + QED, + EW }; } #endif // HERWIG_ShowerInteraction_H diff --git a/Utilities/Maths.cc b/Utilities/Maths.cc --- a/Utilities/Maths.cc +++ b/Utilities/Maths.cc @@ -1,108 +1,96 @@ // -*- C++ -*- // // Maths.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #include #include "Maths.h" +#include "ThePEG/Config/Constants.h" + namespace Herwig { namespace Math { using ThePEG::Complex; using std::cout; using std::endl; namespace { inline Complex Li2Prod(Complex y,Complex y2) { static const double a1 =-0.250000000000000e0,a2 =-0.111111111111111e0; static const double a3 =-0.010000000000000e0,a4 =-0.017006802721088e0; static const double a5 =-0.019444444444444e0,a6 =-0.020661157024793e0; static const double a7 =-0.021417300648069e0,a8 =-0.021948866377231e0; static const double a9 =-0.022349233811171e0,a10 =-0.022663689135191e0; return y*(1.+a1*y*(1.+a2*y*(1.+a3*y2*(1.+a4*y2*(1.+a5*y2* (1.+a6*y2*(1.+a7*y2*(1.+a8*y2*(1.+a9*y2*(1.+a10*y2)))))))))); } inline long double Li2Prod(long double y,long double y2) { static const long double a1 =-0.250000000000000e0,a2 =-0.111111111111111e0; static const long double a3 =-0.010000000000000e0,a4 =-0.017006802721088e0; static const long double a5 =-0.019444444444444e0,a6 =-0.020661157024793e0; static const long double a7 =-0.021417300648069e0,a8 =-0.021948866377231e0; static const long double a9 =-0.022349233811171e0,a10 =-0.022663689135191e0; return y*(1.+a1*y*(1.+a2*y*(1.+a3*y2*(1.+a4*y2*(1.+a5*y2* (1.+a6*y2*(1.+a7*y2*(1.+a8*y2*(1.+a9*y2*(1.+a10*y2)))))))))); } } - -Complex Li2(Complex x) -{ +Complex Li2(Complex x) { + using ThePEG::Constants::zeta2; Complex z; - static double zeta2= 1.644934066848226e0; double xr(real(x)),xi(imag(x)),r2(xr*xr+xi*xi); - if(r2>1.&&xr/r2>0.5) - { - z=-log(1./x); - return Li2Prod(z,z*z)+zeta2-log(x)*log(1.-x)+0.5*log(x)*log(x); - } - else if (r2>1.&&(xr/r2)<=0.5) - { - z=-log(1.-1./x); + if(r2>1.&&xr/r2>0.5) { + z=-log(1./x); + return Li2Prod(z,z*z)+zeta2-log(x)*log(1.-x)+0.5*log(x)*log(x); + } + else if (r2>1.&&(xr/r2)<=0.5) { + z=-log(1.-1./x); return -Li2Prod(z,z*z)-zeta2-0.5*pow(log(-x),2); - } - else if(r2==1.&&xi==0.) - { - if(xr>0){return zeta2;} - else{return -0.5*zeta2;} - } - else if(r2<=1.&&xr>0.5) - { - z=-log(x); - return -Li2Prod(z,z*z)+zeta2-log(x)*log(1.-x); - } - else - { - z=-log(1.-x); - return Li2Prod(z,z*z); - } + } + else if(r2==1.&&xi==0.) { + if(xr>0){return zeta2;} + else{return -0.5*zeta2;} + } + else if(r2<=1.&&xr>0.5) { + z=-log(x); + return -Li2Prod(z,z*z)+zeta2-log(x)*log(1.-x); + } + else { + z=-log(1.-x); + return Li2Prod(z,z*z); + } } -long double ReLi2(long double x) -{ +long double ReLi2(long double x) { + using ThePEG::Constants::zeta2; long double z; - static long double zeta2= 1.644934066848226e0; long double output; - if(x>1.&&x<2.) - { - z=-log(1./x); - output= Li2Prod(z,z*z)+zeta2-log(x)*log(x-1.)+0.5*log(x)*log(x); - } - else if (x>1.||x<-1.) - { - z=-log(1.-1./x); - if(x<-1){output= -Li2Prod(z,z*z)-zeta2-0.5*pow(log(-x),2);} - else{output= -Li2Prod(z,z*z)-0.5*pow(log(x),2)+2.*zeta2;} - } + if(x>1.&&x<2.) { + z=-log(1./x); + output= Li2Prod(z,z*z)+zeta2-log(x)*log(x-1.)+0.5*log(x)*log(x); + } + else if (x>1.||x<-1.) { + z=-log(1.-1./x); + if(x<-1){output= -Li2Prod(z,z*z)-zeta2-0.5*pow(log(-x),2);} + else{output= -Li2Prod(z,z*z)-0.5*pow(log(x),2)+2.*zeta2;} + } else if(x== 1.){output= zeta2;} else if(x==-1.){output= -0.5*zeta2;} - else if(x>0.5) - { - z=-log(x); - output= -Li2Prod(z,z*z)+zeta2-log(x)*log(1.-x); - } - else - { - z=-log(1.-x); - output= Li2Prod(z,z*z); - } + else if(x>0.5) { + z=-log(x); + output= -Li2Prod(z,z*z)+zeta2-log(x)*log(1.-x); + } + else { + z=-log(1.-x); + output= Li2Prod(z,z*z); + } return output; } - - } } diff --git a/Utilities/Maths.h b/Utilities/Maths.h --- a/Utilities/Maths.h +++ b/Utilities/Maths.h @@ -1,69 +1,70 @@ // -*- C++ -*- // // Maths.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_Math_H #define HERWIG_Math_H #include #include #include "ThePEG/Config/Complex.h" #include "ThePEG/Utilities/Maths.h" +#include "ThePEG/Config/TemplateTools.h" namespace Herwig { using ThePEG::Complex; using std::complex; /** The Math namespace includes the declaration of some useful * mathematical functions. */ namespace Math { /** * The dilog function taken from FORTRAN Herwig */ Complex Li2(Complex); /** * The real part of the dilog function taken from FORTRAN Herwig */ long double ReLi2(long double); /** * Fold angles into the range (0,2 Pi) */ inline double angleZeroTo2Pi(double angle) { double ret = fmod(angle, 2 * M_PI); if (ret < 0) ret += 2 * M_PI; return ret; } /** * Fold angles into the range (-Pi,Pi) */ inline double angleMinusPiToPi(double angle) { double ret = angleZeroTo2Pi(angle); if (ret > M_PI) ret -= 2 * M_PI; return ret; } /** * Calculates the (lower) median of a vector of T objects. T has to be * comparable, i.e. T::operator< must be defined. */ template inline T median(std::vector v) { if (v.empty()) return T(); sort ( v.begin(), v.end() ); const size_t N = v.size(); return (N % 2) ? v.at((N+1)/2 - 1) : v.at(N/2 - 1); } } } #endif /* HERWIG_Math_H */ diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -1,262 +1,263 @@ dnl Process this file with autoconf to produce a configure script. AC_PREREQ([2.63]) AC_INIT([Herwig],[devel],[herwig@projects.hepforge.org],[Herwig]) AC_CONFIG_SRCDIR([Utilities/HerwigStrategy.cc]) AC_CONFIG_AUX_DIR([Config]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_HEADERS([Config/config.h]) dnl AC_PRESERVE_HELP_ORDER AC_CANONICAL_HOST dnl === disable debug symbols by default ===== if test "x$CXXFLAGS" = "x"; then CXXFLAGS="-O2 -DBOOST_UBLAS_NDEBUG" fi if test "x$CFLAGS" = "x"; then CFLAGS=-O2 fi AC_LANG([C++]) AM_INIT_AUTOMAKE([1.11 subdir-objects gnu dist-bzip2 no-dist-gzip -Wall -Wno-portability]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) dnl Checks for C++ compiler. Handle C++11 flags. AC_PROG_CXX AX_CXX_COMPILE_STDCXX([11],[noext],[mandatory]) dnl check for POSIX AC_CHECK_HEADER([unistd.h],[], [AC_MSG_ERROR([Herwig needs "unistd.h". Non-POSIX systems are not supported.])]) AC_CHECK_HEADER([sys/stat.h],[], [AC_MSG_ERROR([Herwig needs "sys/stat.h". Non-POSIX systems are not supported.])]) dnl Checks for programs. AC_PROG_INSTALL AC_PROG_MAKE_SET AC_PROG_LN_S dnl modified search order AC_PROG_FC([gfortran g95 g77]) dnl xlf95 f95 fort ifort ifc efc pgf95 lf95 ftn xlf90 f90 pgf90 pghpf epcf90 xlf f77 frt pgf77 cf77 fort77 fl32 af77]) AC_LANG_PUSH([Fortran]) AC_MSG_CHECKING([if the Fortran compiler ($FC) works]) AC_COMPILE_IFELSE( AC_LANG_PROGRAM([],[ print *[,]"Hello"]), [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) AC_MSG_ERROR([A Fortran compiler is required to build Herwig.]) ] ) AC_LANG_POP([Fortran]) AC_FC_WRAPPERS LT_PREREQ([2.2.6]) LT_INIT([disable-static dlopen pic-only]) dnl #################################### dnl #################################### dnl for Doc/fixinterfaces.pl AC_PATH_PROG(PERL, perl) dnl for Models/Feynrules AM_PATH_PYTHON([2.6],, [:]) AM_CONDITIONAL([HAVE_PYTHON], [test "x$PYTHON" != "x:"]) HERWIG_CHECK_GSL HERWIG_CHECK_THEPEG BOOST_REQUIRE([1.41]) BOOST_FIND_HEADER([boost/numeric/ublas/io.hpp]) dnl Boost 1.64 is missing a required header to make these work dnl we just assume they're there if io.hpp has been found OK above dnl BOOST_FIND_HEADER([boost/numeric/ublas/matrix.hpp]) dnl BOOST_FIND_HEADER([boost/numeric/ublas/matrix_proxy.hpp]) dnl BOOST_FIND_HEADER([boost/numeric/ublas/matrix_sparse.hpp]) dnl BOOST_FIND_HEADER([boost/numeric/ublas/symmetric.hpp]) dnl BOOST_FIND_HEADER([boost/numeric/ublas/vector.hpp]) BOOST_FIND_HEADER([boost/operators.hpp]) BOOST_TEST() HERWIG_CHECK_VBFNLO HERWIG_CHECK_NJET HERWIG_CHECK_GOSAM HERWIG_CHECK_GOSAM_CONTRIB HERWIG_CHECK_OPENLOOPS HERWIG_CHECK_MADGRAPH HERWIG_CHECK_EVTGEN HERWIG_CHECK_PYTHIA HERWIG_COMPILERFLAGS HERWIG_LOOPTOOLS FASTJET_CHECK_FASTJET HERWIG_ENABLE_MODELS SHARED_FLAG=-shared AM_CONDITIONAL(NEED_APPLE_FIXES, [test "xx${host/darwin/foundit}xx" != "xx${host}xx"]) if test "xx${host/darwin/foundit}xx" != "xx${host}xx"; then APPLE_DSO_FLAGS=-Wl,-undefined,dynamic_lookup SHARED_FLAG=-bundle fi AC_SUBST([APPLE_DSO_FLAGS]) AC_SUBST([SHARED_FLAG]) AC_CONFIG_FILES([UnderlyingEvent/Makefile Models/Makefile Models/StandardModel/Makefile Models/RSModel/Makefile Models/General/Makefile Models/Susy/Makefile Models/Susy/NMSSM/Makefile Models/Susy/RPV/Makefile Models/UED/Makefile Models/LH/Makefile Models/DarkMatter/Makefile Models/LHTP/Makefile Models/Transplanckian/Makefile Models/Leptoquarks/Makefile Models/Zprime/Makefile Models/TTbAsymm/Makefile Models/Feynrules/Makefile Models/Feynrules/python/Makefile-FR Models/ADD/Makefile Models/Sextet/Makefile Decay/Makefile Decay/FormFactors/Makefile Decay/Tau/Makefile Decay/Baryon/Makefile Decay/VectorMeson/Makefile Decay/Perturbative/Makefile Decay/ScalarMeson/Makefile Decay/TensorMeson/Makefile Decay/WeakCurrents/Makefile Decay/Partonic/Makefile Decay/General/Makefile Decay/Radiation/Makefile Decay/EvtGen/Makefile Doc/refman.conf Doc/refman.h PDT/Makefile PDF/Makefile MatrixElement/Makefile MatrixElement/General/Makefile MatrixElement/Lepton/Makefile MatrixElement/Hadron/Makefile MatrixElement/DIS/Makefile MatrixElement/Powheg/Makefile MatrixElement/Gamma/Makefile MatrixElement/Reweighters/Makefile + MatrixElement/EW/Makefile MatrixElement/Matchbox/Makefile MatrixElement/Matchbox/Base/Makefile MatrixElement/Matchbox/Utility/Makefile MatrixElement/Matchbox/Phasespace/Makefile MatrixElement/Matchbox/Dipoles/Makefile MatrixElement/Matchbox/InsertionOperators/Makefile MatrixElement/Matchbox/Matching/Makefile MatrixElement/Matchbox/Cuts/Makefile MatrixElement/Matchbox/Scales/Makefile MatrixElement/Matchbox/ColorFull/Makefile MatrixElement/Matchbox/CVolver/Makefile MatrixElement/Matchbox/Builtin/Makefile MatrixElement/Matchbox/Builtin/Amplitudes/Makefile MatrixElement/Matchbox/Tests/Makefile MatrixElement/Matchbox/External/Makefile MatrixElement/Matchbox/External/BLHAGeneric/Makefile MatrixElement/Matchbox/External/VBFNLO/Makefile MatrixElement/Matchbox/External/NJet/Makefile MatrixElement/Matchbox/External/GoSam/Makefile MatrixElement/Matchbox/External/OpenLoops/Makefile MatrixElement/Matchbox/External/MadGraph/Makefile MatrixElement/Matchbox/External/MadGraph/mg2herwig MatrixElement/FxFx/Makefile Sampling/Makefile Sampling/CellGrids/Makefile Shower/Makefile Shower/QTilde/Makefile Shower/QTilde/Matching/Makefile Shower/Dipole/Makefile Shower/Dipole/Base/Makefile Shower/Dipole/Kernels/Makefile Shower/Dipole/Kinematics/Makefile Shower/Dipole/Utility/Makefile Shower/Dipole/AlphaS/Makefile Shower/Dipole/SpinCorrelations/Makefile Utilities/Makefile Utilities/XML/Makefile Utilities/Statistics/Makefile Hadronization/Makefile lib/Makefile include/Makefile src/Makefile src/defaults/Makefile src/snippets/Makefile src/Matchbox/Makefile src/herwig-config Doc/Makefile Doc/HerwigDefaults.in Looptools/Makefile Analysis/Makefile API/Makefile src/Makefile-UserModules src/defaults/Analysis.in src/defaults/MatchboxDefaults.in src/defaults/Decays.in src/defaults/decayers.in src/defaults/setup.gosam.in src/Matchbox/LO-DefaultShower.in src/Matchbox/LO-DipoleShower.in src/Matchbox/MCatLO-DefaultShower.in src/Matchbox/MCatLO-DipoleShower.in src/Matchbox/LO-NoShower.in src/Matchbox/MCatNLO-DefaultShower.in src/Matchbox/MCatNLO-DipoleShower.in src/Matchbox/NLO-NoShower.in src/Matchbox/Powheg-DefaultShower.in src/Matchbox/Powheg-DipoleShower.in src/Merging/Makefile Shower/Dipole/Merging/Makefile src/defaults/MatchboxMergingDefaults.in Contrib/Makefile Contrib/make_makefiles.sh Tests/Makefile Makefile]) AC_CONFIG_FILES([Tests/python/rivet_check ],[chmod +x Tests/python/rivet_check ]) AC_CONFIG_FILES([Tests/python/LowEnergy.py ],[chmod +x Tests/python/LowEnergy.py ]) AC_CONFIG_FILES([Tests/python/make_input_files.py],[chmod +x Tests/python/make_input_files.py]) AC_CONFIG_FILES([Tests/python/merge-DIS ],[chmod +x Tests/python/merge-DIS ]) AC_CONFIG_FILES([Tests/python/merge-EE ],[chmod +x Tests/python/merge-EE ]) AC_CONFIG_FILES([Tests/python/merge-EE-Gamma ],[chmod +x Tests/python/merge-EE-Gamma ]) AC_CONFIG_FILES([Tests/python/merge-Fixed ],[chmod +x Tests/python/merge-Fixed ]) AC_CONFIG_FILES([Tests/python/merge-GammaGamma ],[chmod +x Tests/python/merge-GammaGamma ]) AC_CONFIG_FILES([Tests/python/merge-LHC-EW ],[chmod +x Tests/python/merge-LHC-EW ]) AC_CONFIG_FILES([Tests/python/merge-LHC-Jets ],[chmod +x Tests/python/merge-LHC-Jets ]) AC_CONFIG_FILES([Tests/python/merge-LHC-Photon ],[chmod +x Tests/python/merge-LHC-Photon ]) AC_CONFIG_FILES([Tests/python/mergeLowEnergy.py ],[chmod +x Tests/python/mergeLowEnergy.py ]) AC_CONFIG_FILES([Tests/python/merge-TVT-EW ],[chmod +x Tests/python/merge-TVT-EW ]) AC_CONFIG_FILES([Tests/python/merge-TVT-Jets ],[chmod +x Tests/python/merge-TVT-Jets ]) AC_CONFIG_FILES([Tests/python/merge-TVT-Photon ],[chmod +x Tests/python/merge-TVT-Photon ]) AC_CONFIG_FILES([Tests/python/plot-EE ],[chmod +x Tests/python/plot-EE ]) AC_CONFIG_FILES([Tests/python/R.py ],[chmod +x Tests/python/R.py ]) AC_CONFIG_LINKS([Doc/BSMlibs.in:Doc/BSMlibs.in]) AC_CONFIG_FILES([Doc/fixinterfaces.pl],[chmod +x Doc/fixinterfaces.pl]) AC_CONFIG_HEADERS([PDF/SaSPhotonPDF.cc]) HERWIG_OVERVIEW AC_CONFIG_COMMANDS([summary],[cat config.herwig]) AC_OUTPUT diff --git a/src/Matchbox/PQCDLevel.in b/src/Matchbox/PQCDLevel.in --- a/src/Matchbox/PQCDLevel.in +++ b/src/Matchbox/PQCDLevel.in @@ -1,13 +1,13 @@ # -*- ThePEG-repository -*- set /Herwig/DipoleShower/DipoleShowerHandler:MPIHandler NULL set /Herwig/Shower/ShowerHandler:MPIHandler NULL set /Herwig/Shower/PowhegShowerHandler:MPIHandler NULL -set /Herwig/Shower/ShowerHandler:Interactions QCD +set /Herwig/Shower/ShowerHandler:Interaction QCD cd /Herwig/EventHandlers set EventHandler:HadronizationHandler NULL set EventHandler:DecayHandler NULL set /Herwig/Analysis/Basics:CheckQuark No diff --git a/src/defaults/MatrixElements.in b/src/defaults/MatrixElements.in --- a/src/defaults/MatrixElements.in +++ b/src/defaults/MatrixElements.in @@ -1,324 +1,328 @@ # -*- ThePEG-repository -*- ############################################################################## # Setup of default matrix elements. # # Only one ME is activated by default, but this file lists # some alternatives. All available MEs can be found in the # 'include/Herwig/MatrixElements' subdirectory of your Herwig # installation. # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Instead of editing this file directly, you should reset # the matrix elements in your own input files: # # - create your custom SubProcessHandler # - insert the MEs you need # - set your SubProcessHandler instead of the default (see HerwigDefaults.in) ############################################################################## mkdir /Herwig/MatrixElements cd /Herwig/MatrixElements library HwMELepton.so library HwMEHadron.so library HwMEDIS.so ############################################################ # e+e- matrix elements ############################################################ # e+e- > q qbar create Herwig::MEee2gZ2qq MEee2gZ2qq newdef MEee2gZ2qq:MinimumFlavour 1 newdef MEee2gZ2qq:MaximumFlavour 5 newdef MEee2gZ2qq:AlphaQCD /Herwig/Shower/AlphaQCD newdef MEee2gZ2qq:AlphaQED /Herwig/Shower/AlphaQED # e+e- -> l+l- create Herwig::MEee2gZ2ll MEee2gZ2ll newdef MEee2gZ2ll:Allowed Charged set MEee2gZ2ll:AlphaQED /Herwig/Shower/AlphaQED +# e+e- -> l+l- +create Herwig::MEee2ff MEee2ff +set MEee2ff:AlphaQED /Herwig/Shower/AlphaQED + # e+e- -> W+W- ZZ create Herwig::MEee2VV MEee2VV # e+e- -> ZH create Herwig::MEee2ZH MEee2ZH newdef MEee2ZH:Coupling /Herwig/Shower/AlphaQCD # e+e- -> e+e-H/nu_enu_ebarH create Herwig::MEee2HiggsVBF MEee2HiggsVBF ############################################################ # Low energy matrix elements ############################################################ # e+ e- -> pi+pi- create Herwig::MEee2Mesons MEee2Pions HwMELeptonLowEnergy.so create Herwig::TwoPionCzyzCurrent /Herwig/Decays/TwoPionCzyzCurrent HwWeakCurrents.so set MEee2Pions:WeakCurrent /Herwig/Decays/TwoPionCzyzCurrent # e+ e- -> K+K-/ K0K0 create Herwig::MEee2Mesons MEee2Kaons HwMELeptonLowEnergy.so create Herwig::TwoKaonCzyzCurrent /Herwig/Decays/TwoKaonCzyzCurrent set MEee2Kaons:WeakCurrent /Herwig/Decays/TwoKaonCzyzCurrent # e+ e- -> pi+ pi- pi0 create Herwig::MEee2Mesons MEee3Pions HwMELeptonLowEnergy.so create Herwig::ThreePionCzyzCurrent /Herwig/Decays/ThreePionCzyzCurrent set MEee3Pions:WeakCurrent /Herwig/Decays/ThreePionCzyzCurrent # e+ e- -> 2pi+ 2pi-, 2pi0, pi+ pi- create Herwig::MEee2Mesons MEee4Pions HwMELeptonLowEnergy.so create Herwig::FourPionCzyzCurrent /Herwig/Decays/FourPionCzyzCurrent set MEee4Pions:WeakCurrent /Herwig/Decays/FourPionCzyzCurrent # e+ e- -> eta pi+ pi- create Herwig::MEee2Mesons MEee2EtaPiPi HwMELeptonLowEnergy.so create Herwig::EtaPiPiCurrent /Herwig/Decays/EtaPiPiCurrent set MEee2EtaPiPi:WeakCurrent /Herwig/Decays/EtaPiPiCurrent # e+ e- -> eta' pi+ pi- create Herwig::MEee2Mesons MEee2EtaPrimePiPi HwMELeptonLowEnergy.so create Herwig::EtaPrimePiPiCurrent /Herwig/Decays/EtaPrimePiPiCurrent set MEee2EtaPrimePiPi:WeakCurrent /Herwig/Decays/EtaPrimePiPiCurrent # e+ e- -> omega pi (omega -> pi0 gamma) create Herwig::MEee2Mesons MEee2OmegaPi HwMELeptonLowEnergy.so create Herwig::TwoPionPhotonSNDCurrent /Herwig/Decays/OmegaPiCurrent set MEee2OmegaPi:WeakCurrent /Herwig/Decays/OmegaPiCurrent # e+ e- > pi0 gamma create Herwig::MEee2Mesons MEee2PiGamma HwMELeptonLowEnergy.so create Herwig::PionPhotonCurrent /Herwig/Decays/PiGammaCurrent set MEee2PiGamma:WeakCurrent /Herwig/Decays/PiGammaCurrent # e+e- -> eta gamma create Herwig::MEee2Mesons MEee2EtaGamma HwMELeptonLowEnergy.so create Herwig::EtaPhotonCurrent /Herwig/Decays/EtaGammaCurrent set MEee2EtaGamma:WeakCurrent /Herwig/Decays/EtaGammaCurrent # e+e- -> eta phi create Herwig::MEee2Mesons MEee2EtaPhi HwMELeptonLowEnergy.so create Herwig::EtaPhiCurrent /Herwig/Decays/EtaPhiCurrent set MEee2EtaPhi:WeakCurrent /Herwig/Decays/EtaPhiCurrent # e+e- -> eta omega create Herwig::MEee2Mesons MEee2EtaOmega HwMELeptonLowEnergy.so create Herwig::EtaOmegaCurrent /Herwig/Decays/EtaOmegaCurrent set MEee2EtaOmega:WeakCurrent /Herwig/Decays/EtaOmegaCurrent # e+e- > p pbar create Herwig::MEee2Mesons MEee2PPbar HwMELeptonLowEnergy.so create Herwig::WeakBaryonCurrent /Herwig/Decays/CzyzCurrent create Herwig::CzyzNucleonFormFactor /Herwig/Decays/CzyzFormFactor HwFormFactors.so set /Herwig/Decays/CzyzCurrent:FormFactor /Herwig/Decays/CzyzFormFactor set MEee2PPbar:WeakCurrent /Herwig/Decays/CzyzCurrent # e+e- > hyperons create Herwig::MEee2Mesons MEee2LL HwMELeptonLowEnergy.so create Herwig::WeakBaryonCurrent /Herwig/Decays/KornerKurodaCurrent create Herwig::KornerKurodaFormFactor /Herwig/Decays/KornerKurodaFormFactor set /Herwig/Decays/KornerKurodaFormFactor:IncludeNucleon No set /Herwig/Decays/KornerKurodaCurrent:FormFactor /Herwig/Decays/KornerKurodaFormFactor set MEee2LL:WeakCurrent /Herwig/Decays/KornerKurodaCurrent # e+e- -> KKpi create Herwig::MEee2Mesons MEee2KKPi HwMELeptonLowEnergy.so create Herwig::KKPiCurrent /Herwig/Decays/KKPiCurrent set MEee2KKPi:WeakCurrent /Herwig/Decays/KKPiCurrent # e+e- -> phi pi create Herwig::MEee2Mesons MEee2PhiPi HwMELeptonLowEnergy.so create Herwig::PhiPiCurrent /Herwig/Decays/PhiPiCurrent set MEee2PhiPi:WeakCurrent /Herwig/Decays/PhiPiCurrent # e+ e- -> omega pi pi create Herwig::MEee2Mesons MEee2OmegaPiPi HwMELeptonLowEnergy.so create Herwig::OmegaPiPiCurrent /Herwig/Decays/OmegaPiPiCurrent set MEee2OmegaPiPi:WeakCurrent /Herwig/Decays/OmegaPiPiCurrent ############################################################ # NLO (POWHEG e+e- matrix elements ############################################################ library HwPowhegMELepton.so create Herwig::MEee2gZ2qqPowheg PowhegMEee2gZ2qq newdef PowhegMEee2gZ2qq:MinimumFlavour 1 newdef PowhegMEee2gZ2qq:MaximumFlavour 5 newdef PowhegMEee2gZ2qq:AlphaQCD /Herwig/Shower/AlphaQCD newdef PowhegMEee2gZ2qq:AlphaQED /Herwig/Shower/AlphaQED create Herwig::MEee2gZ2llPowheg PowhegMEee2gZ2ll newdef PowhegMEee2gZ2ll:Allowed Charged set PowhegMEee2gZ2ll:AlphaQED /Herwig/Shower/AlphaQED ############################################################ # hadron-hadron matrix elements ############################################################ ################################### # Electroweak processes ################################### # q qbar -> gamma/Z -> l+l- create Herwig::MEqq2gZ2ff MEqq2gZ2ff newdef MEqq2gZ2ff:Process 3 newdef MEqq2gZ2ff:Coupling /Herwig/Shower/AlphaQCD # q qbar to W -> l nu create Herwig::MEqq2W2ff MEqq2W2ff newdef MEqq2W2ff:Process 2 newdef MEqq2W2ff:Coupling /Herwig/Shower/AlphaQCD # W+jet create Herwig::MEPP2WJet MEWJet newdef MEWJet:WDecay Leptons # Z+jet create Herwig::MEPP2ZJet MEZJet newdef MEZJet:ZDecay ChargedLeptons # PP->WW/WZ/ZZ create Herwig::MEPP2VV MEPP2VV # PP->WZ gamma create Herwig::MEPP2VGamma MEPP2VGamma ################################### # Photon and jet processes ################################### # qqbar/gg -> gamma gamma create Herwig::MEPP2GammaGamma MEGammaGamma # hadron-hadron to gamma+jet create Herwig::MEPP2GammaJet MEGammaJet # QCD 2-to-2 create Herwig::MEQCD2to2 MEQCD2to2 # MinBias create Herwig::MEMinBias MEMinBias newdef MEMinBias:csNorm 0.01 newdef MEMinBias:Scale 2.0 ################################### # Heavy Quark ################################### # qqbar/gg -> t tbar create Herwig::MEPP2QQ MEHeavyQuark create Herwig::MEPP2SingleTop MESingleTopTChannel set MESingleTopTChannel:Process tChannel create Herwig::MEPP2SingleTop MESingleTopSChannel set MESingleTopSChannel:Process sChannel create Herwig::MEPP2SingleTop MESingleTopTW set MESingleTopTW:Process tW ################################### # Higgs processes ################################### # hadron-hadron to higgs create Herwig::MEPP2Higgs MEHiggs newdef MEHiggs:ShapeScheme MassGenerator newdef MEHiggs:Process gg newdef MEHiggs:Coupling /Herwig/Shower/AlphaQCD # hadron-hadron to higgs+jet create Herwig::MEPP2HiggsJet MEHiggsJet # PP->ZH create Herwig::MEPP2ZH MEPP2ZH newdef MEPP2ZH:Coupling /Herwig/Shower/AlphaQCD # PP->WH create Herwig::MEPP2WH MEPP2WH newdef MEPP2WH:Coupling /Herwig/Shower/AlphaQCD # PP -> Higgs via VBF create Herwig::MEPP2HiggsVBF MEPP2HiggsVBF newdef MEPP2HiggsVBF:ShowerAlphaQCD /Herwig/Shower/AlphaQCD # PP -> t tbar Higgs create Herwig::MEPP2QQHiggs MEPP2ttbarH newdef MEPP2ttbarH:QuarkType Top # PP -> b bbar Higgs create Herwig::MEPP2QQHiggs MEPP2bbbarH newdef MEPP2bbbarH:QuarkType Bottom ########################################################## # Hadron-Hadron NLO matrix elements in the Powheg scheme ########################################################## library HwPowhegMEHadron.so # q qbar -> gamma/Z -> l+l- create Herwig::MEqq2gZ2ffPowheg PowhegMEqq2gZ2ff newdef PowhegMEqq2gZ2ff:Process 3 newdef PowhegMEqq2gZ2ff:Coupling /Herwig/Shower/AlphaQCD # q qbar to W -> l nu create Herwig::MEqq2W2ffPowheg PowhegMEqq2W2ff newdef PowhegMEqq2W2ff:Process 2 newdef PowhegMEqq2W2ff:Coupling /Herwig/Shower/AlphaQCD # PP->ZH create Herwig::MEPP2ZHPowheg PowhegMEPP2ZH newdef PowhegMEPP2ZH:Coupling /Herwig/Shower/AlphaQCD # PP->WH create Herwig::MEPP2WHPowheg PowhegMEPP2WH newdef PowhegMEPP2WH:Coupling /Herwig/Shower/AlphaQCD # hadron-hadron to higgs create Herwig::MEPP2HiggsPowheg PowhegMEHiggs newdef PowhegMEHiggs:ShapeScheme MassGenerator newdef PowhegMEHiggs:Process gg newdef PowhegMEHiggs:Coupling /Herwig/Shower/AlphaQCD # PP->VV create Herwig::MEPP2VVPowheg PowhegMEPP2VV newdef PowhegMEPP2VV:Coupling /Herwig/Shower/AlphaQCD # PP -> Higgs via VBF create Herwig::MEPP2HiggsVBFPowheg PowhegMEPP2HiggsVBF newdef PowhegMEPP2HiggsVBF:ShowerAlphaQCD /Herwig/Shower/AlphaQCD # PP -> diphoton NLO create Herwig::MEPP2GammaGammaPowheg MEGammaGammaPowheg set MEGammaGammaPowheg:Process 0 set MEGammaGammaPowheg:Contribution 1 set MEGammaGammaPowheg:ShowerAlphaQCD /Herwig/Shower/AlphaQCD set MEGammaGammaPowheg:ShowerAlphaQED /Herwig/Shower/AlphaQED ########################################################## # DIS matrix elements ########################################################## # neutral current create Herwig::MENeutralCurrentDIS MEDISNC newdef MEDISNC:Coupling /Herwig/Shower/AlphaQCD newdef MEDISNC:Contribution 0 # charged current create Herwig::MEChargedCurrentDIS MEDISCC newdef MEDISCC:Coupling /Herwig/Shower/AlphaQCD newdef MEDISCC:Contribution 0 # neutral current (POWHEG) create Herwig::MENeutralCurrentDIS PowhegMEDISNC newdef PowhegMEDISNC:Coupling /Herwig/Shower/AlphaQCD newdef PowhegMEDISNC:Contribution 1 # charged current (POWHEG) create Herwig::MEChargedCurrentDIS PowhegMEDISCC newdef PowhegMEDISCC:Coupling /Herwig/Shower/AlphaQCD newdef PowhegMEDISCC:Contribution 1 ########################################################## # Gamma-Gamma matrix elements ########################################################## # fermion-antiferimon create Herwig::MEGammaGamma2ff MEgg2ff HwMEGammaGamma.so # W+ W- create Herwig::MEGammaGamma2WW MEgg2WW HwMEGammaGamma.so ########################################################## # Gamma-Hadron matrix elements ########################################################## # gamma parton -> 2 jets create Herwig::MEGammaP2Jets MEGammaP2Jets HwMEGammaHadron.so ########################################################## # Set up the Subprocesses # # Generic for all colliders ########################################################## create ThePEG::SubProcessHandler SubProcess newdef SubProcess:PartonExtractor /Herwig/Partons/PPExtractor diff --git a/src/defaults/Shower.in b/src/defaults/Shower.in --- a/src/defaults/Shower.in +++ b/src/defaults/Shower.in @@ -1,325 +1,442 @@ # -*- ThePEG-repository -*- ############################################################ # Setup of default parton shower # -# Useful switches for users are marked near the top of +# Useful switches for users are marked near the top of # this file. # # Don't edit this file directly, but reset the switches # in your own input files! ############################################################ library HwMPI.so library HwShower.so library HwMatching.so mkdir /Herwig/Shower cd /Herwig/Shower create Herwig::QTildeShowerHandler ShowerHandler newdef ShowerHandler:MPIHandler /Herwig/UnderlyingEvent/MPIHandler newdef ShowerHandler:RemDecayer /Herwig/Partons/RemnantDecayer # use LO PDFs for Shower, can be changed later newdef ShowerHandler:PDFA /Herwig/Partons/ShowerLOPDF newdef ShowerHandler:PDFB /Herwig/Partons/ShowerLOPDF newdef ShowerHandler:PDFARemnant /Herwig/Partons/RemnantPDF newdef ShowerHandler:PDFBRemnant /Herwig/Partons/RemnantPDF ##################################### # initial setup, don't change these! ##################################### create Herwig::SplittingGenerator SplittingGenerator create Herwig::ShowerAlphaQCD AlphaQCD create Herwig::ShowerAlphaQED AlphaQED +set AlphaQED:CouplingSource Thompson +create Herwig::ShowerAlphaQED AlphaEW +set AlphaEW:CouplingSource MZ create Herwig::PartnerFinder PartnerFinder newdef PartnerFinder:PartnerMethod 0 newdef PartnerFinder:ScaleChoice 0 create Herwig::KinematicsReconstructor KinematicsReconstructor newdef KinematicsReconstructor:ReconstructionOption Colour3 newdef KinematicsReconstructor:InitialStateReconOption SofterFraction newdef KinematicsReconstructor:InitialInitialBoostOption LongTransBoost newdef KinematicsReconstructor:FinalFinalWeight Yes newdef /Herwig/Partons/RemnantDecayer:AlphaS AlphaQCD newdef /Herwig/Partons/RemnantDecayer:AlphaEM AlphaQED newdef ShowerHandler:PartnerFinder PartnerFinder newdef ShowerHandler:KinematicsReconstructor KinematicsReconstructor newdef ShowerHandler:SplittingGenerator SplittingGenerator +newdef ShowerHandler:Interactions QEDQCD newdef ShowerHandler:SpinCorrelations Yes newdef ShowerHandler:SoftCorrelations Singular ################################################################## # Intrinsic pT # -# Recommended: +# Recommended: # 1.9 GeV for Tevatron W/Z production. # 2.1 GeV for LHC W/Z production at 10 TeV # 2.2 GeV for LHC W/Z production at 14 TeV # # Set all parameters to 0 to disable ################################################################## newdef ShowerHandler:IntrinsicPtGaussian 2.2*GeV newdef ShowerHandler:IntrinsicPtBeta 0 newdef ShowerHandler:IntrinsicPtGamma 0*GeV newdef ShowerHandler:IntrinsicPtIptmax 0*GeV ############################################################# # Set up truncated shower handler. ############################################################# create Herwig::PowhegShowerHandler PowhegShowerHandler set PowhegShowerHandler:MPIHandler /Herwig/UnderlyingEvent/MPIHandler set PowhegShowerHandler:RemDecayer /Herwig/Partons/RemnantDecayer newdef PowhegShowerHandler:PDFA /Herwig/Partons/ShowerLOPDF newdef PowhegShowerHandler:PDFB /Herwig/Partons/ShowerLOPDF newdef PowhegShowerHandler:PDFARemnant /Herwig/Partons/RemnantPDF newdef PowhegShowerHandler:PDFBRemnant /Herwig/Partons/RemnantPDF newdef PowhegShowerHandler:MPIHandler /Herwig/UnderlyingEvent/MPIHandler newdef PowhegShowerHandler:RemDecayer /Herwig/Partons/RemnantDecayer newdef PowhegShowerHandler:PDFA /Herwig/Partons/ShowerLOPDF newdef PowhegShowerHandler:PDFB /Herwig/Partons/ShowerLOPDF newdef PowhegShowerHandler:PDFARemnant /Herwig/Partons/RemnantPDF newdef PowhegShowerHandler:PDFBRemnant /Herwig/Partons/RemnantPDF newdef PowhegShowerHandler:PartnerFinder PartnerFinder newdef PowhegShowerHandler:KinematicsReconstructor KinematicsReconstructor newdef PowhegShowerHandler:SplittingGenerator SplittingGenerator -newdef PowhegShowerHandler:Interactions QCDandQED +newdef PowhegShowerHandler:Interactions QEDQCD newdef PowhegShowerHandler:SpinCorrelations Yes newdef PowhegShowerHandler:SoftCorrelations Singular newdef PowhegShowerHandler:IntrinsicPtGaussian 2.2*GeV newdef PowhegShowerHandler:IntrinsicPtBeta 0 newdef PowhegShowerHandler:IntrinsicPtGamma 0*GeV newdef PowhegShowerHandler:IntrinsicPtIptmax 0*GeV newdef PowhegShowerHandler:EvolutionScheme DotProduct ############################################################# # End of interesting user servicable section. # -# Anything that follows below should only be touched if you -# know what you're doing. +# Anything that follows below should only be touched if you +# know what you're doing. # # Really. ############################################################# # # a few default values newdef ShowerHandler:MECorrMode 1 newdef ShowerHandler:EvolutionScheme DotProduct newdef AlphaQCD:ScaleFactor 1.0 newdef AlphaQCD:NPAlphaS 2 newdef AlphaQCD:Qmin 0.935 newdef AlphaQCD:NumberOfLoops 2 newdef AlphaQCD:AlphaIn 0.1186 # # # Lets set up all the splittings create Herwig::HalfHalfOneSplitFn QtoQGammaSplitFn set QtoQGammaSplitFn:InteractionType QED set QtoQGammaSplitFn:ColourStructure ChargedChargedNeutral set QtoQGammaSplitFn:AngularOrdered Yes set QtoQGammaSplitFn:StrictAO Yes create Herwig::HalfHalfOneSplitFn QtoQGSplitFn newdef QtoQGSplitFn:InteractionType QCD newdef QtoQGSplitFn:ColourStructure TripletTripletOctet set QtoQGSplitFn:AngularOrdered Yes set QtoQGSplitFn:StrictAO Yes create Herwig::OneOneOneSplitFn GtoGGSplitFn newdef GtoGGSplitFn:InteractionType QCD newdef GtoGGSplitFn:ColourStructure OctetOctetOctet set GtoGGSplitFn:AngularOrdered Yes set GtoGGSplitFn:StrictAO Yes create Herwig::OneOneOneMassiveSplitFn WtoWGammaSplitFn newdef WtoWGammaSplitFn:InteractionType QED newdef WtoWGammaSplitFn:ColourStructure ChargedChargedNeutral set WtoWGammaSplitFn:AngularOrdered Yes set WtoWGammaSplitFn:StrictAO Yes create Herwig::OneHalfHalfSplitFn GtoQQbarSplitFn newdef GtoQQbarSplitFn:InteractionType QCD newdef GtoQQbarSplitFn:ColourStructure OctetTripletTriplet set GtoQQbarSplitFn:AngularOrdered Yes set GtoQQbarSplitFn:StrictAO Yes create Herwig::OneHalfHalfSplitFn GammatoQQbarSplitFn newdef GammatoQQbarSplitFn:InteractionType QED newdef GammatoQQbarSplitFn:ColourStructure NeutralChargedCharged set GammatoQQbarSplitFn:AngularOrdered Yes set GammatoQQbarSplitFn:StrictAO Yes create Herwig::HalfOneHalfSplitFn QtoGQSplitFn newdef QtoGQSplitFn:InteractionType QCD newdef QtoGQSplitFn:ColourStructure TripletOctetTriplet set QtoGQSplitFn:AngularOrdered Yes set QtoGQSplitFn:StrictAO Yes create Herwig::HalfOneHalfSplitFn QtoGammaQSplitFn newdef QtoGammaQSplitFn:InteractionType QED newdef QtoGammaQSplitFn:ColourStructure ChargedNeutralCharged set QtoGammaQSplitFn:AngularOrdered Yes set QtoGammaQSplitFn:StrictAO Yes + +create Herwig::HalfHalfOneEWSplitFn QtoQWZSplitFn +newdef QtoQWZSplitFn:InteractionType EW +newdef QtoQWZSplitFn:ColourStructure EW + +create Herwig::HalfHalfOneEWSplitFn LtoLWZSplitFn +newdef LtoLWZSplitFn:InteractionType EW +newdef LtoLWZSplitFn:ColourStructure EW + +create Herwig::HalfHalfZeroEWSplitFn QtoQHSplitFn +newdef QtoQHSplitFn:InteractionType EW +newdef QtoQHSplitFn:ColourStructure EW + +create Herwig::OneOneOneEWSplitFn VtoVVSplitFn +newdef VtoVVSplitFn:InteractionType EW +newdef VtoVVSplitFn:ColourStructure EW + +create Herwig::OneOneOneQEDSplitFn GammatoWWSplitFn +newdef GammatoWWSplitFn:InteractionType QED +newdef GammatoWWSplitFn:ColourStructure ChargedNeutralCharged + +create Herwig::OneOneZeroEWSplitFn VtoVHSplitFn +newdef VtoVHSplitFn:InteractionType EW +newdef VtoVHSplitFn:ColourStructure EW + # # Now the Sudakovs create Herwig::PTCutOff PTCutOff newdef PTCutOff:pTmin 0.958*GeV create Herwig::SudakovFormFactor SudakovCommon newdef SudakovCommon:Alpha AlphaQCD newdef SudakovCommon:Cutoff PTCutOff newdef SudakovCommon:PDFmax 1.0 cp SudakovCommon QtoQGSudakov newdef QtoQGSudakov:SplittingFunction QtoQGSplitFn newdef QtoQGSudakov:PDFmax 1.9 cp SudakovCommon QtoQGammaSudakov set QtoQGammaSudakov:SplittingFunction QtoQGammaSplitFn set QtoQGammaSudakov:Alpha AlphaQED set QtoQGammaSudakov:PDFmax 1.9 cp QtoQGammaSudakov LtoLGammaSudakov cp PTCutOff LtoLGammaPTCutOff # Technical parameter to stop evolution. set LtoLGammaPTCutOff:pTmin 0.000001 set LtoLGammaSudakov:Cutoff LtoLGammaPTCutOff +cp SudakovCommon QtoQWZSudakov +set QtoQWZSudakov:SplittingFunction QtoQWZSplitFn +set QtoQWZSudakov:Alpha AlphaEW +set QtoQWZSudakov:PDFmax 1.9 + +cp SudakovCommon LtoLWZSudakov +set LtoLWZSudakov:SplittingFunction LtoLWZSplitFn +set LtoLWZSudakov:Alpha AlphaEW +set LtoLWZSudakov:PDFmax 1.9 + +cp SudakovCommon QtoQHSudakov +set QtoQHSudakov:SplittingFunction QtoQHSplitFn +set QtoQHSudakov:Alpha AlphaEW +set QtoQHSudakov:PDFmax 1.9 + +cp QtoQHSudakov LtoLHSudakov + +cp SudakovCommon VtoVVSudakov +set VtoVVSudakov:SplittingFunction VtoVVSplitFn +set VtoVVSudakov:Alpha AlphaQED + +cp SudakovCommon GammatoWWSudakov +set GammatoWWSudakov:SplittingFunction GammatoWWSplitFn +set GammatoWWSudakov:Alpha AlphaEW +set GammatoWWSudakov:PDFmax 1.9 + + + +cp SudakovCommon VtoVHSudakov +set VtoVHSudakov:SplittingFunction VtoVHSplitFn +set VtoVHSudakov:Alpha AlphaEW +set VtoVHSudakov:PDFmax 1.9 + cp SudakovCommon GtoGGSudakov newdef GtoGGSudakov:SplittingFunction GtoGGSplitFn newdef GtoGGSudakov:PDFmax 2.0 cp SudakovCommon WtoWGammaSudakov newdef WtoWGammaSudakov:SplittingFunction WtoWGammaSplitFn set WtoWGammaSudakov:Alpha AlphaQED cp SudakovCommon GtoQQbarSudakov newdef GtoQQbarSudakov:SplittingFunction GtoQQbarSplitFn newdef GtoQQbarSudakov:PDFmax 120.0 cp SudakovCommon GammatoQQbarSudakov newdef GammatoQQbarSudakov:SplittingFunction GammatoQQbarSplitFn set GammatoQQbarSudakov:Alpha AlphaQED newdef GammatoQQbarSudakov:PDFmax 10000.0 cp SudakovCommon GtobbbarSudakov newdef GtobbbarSudakov:SplittingFunction GtoQQbarSplitFn newdef GtobbbarSudakov:PDFmax 40000.0 cp SudakovCommon GtoccbarSudakov newdef GtoccbarSudakov:SplittingFunction GtoQQbarSplitFn newdef GtoccbarSudakov:PDFmax 2000.0 cp SudakovCommon QtoGQSudakov newdef QtoGQSudakov:SplittingFunction QtoGQSplitFn cp SudakovCommon QtoGammaQSudakov newdef QtoGammaQSudakov:SplittingFunction QtoGammaQSplitFn set QtoGammaQSudakov:Alpha AlphaQED newdef QtoGammaQSudakov:PDFmax 2000.0 cp SudakovCommon utoGuSudakov newdef utoGuSudakov:SplittingFunction QtoGQSplitFn newdef utoGuSudakov:PDFFactor OverOneMinusZ newdef utoGuSudakov:PDFmax 5.0 cp SudakovCommon dtoGdSudakov newdef dtoGdSudakov:SplittingFunction QtoGQSplitFn newdef dtoGdSudakov:PDFFactor OverOneMinusZ # # Now add the final splittings # do SplittingGenerator:AddFinalSplitting u->u,g; QtoQGSudakov do SplittingGenerator:AddFinalSplitting d->d,g; QtoQGSudakov do SplittingGenerator:AddFinalSplitting s->s,g; QtoQGSudakov do SplittingGenerator:AddFinalSplitting c->c,g; QtoQGSudakov do SplittingGenerator:AddFinalSplitting b->b,g; QtoQGSudakov do SplittingGenerator:AddFinalSplitting t->t,g; QtoQGSudakov # do SplittingGenerator:AddFinalSplitting g->g,g; GtoGGSudakov # do SplittingGenerator:AddFinalSplitting g->u,ubar; GtoQQbarSudakov do SplittingGenerator:AddFinalSplitting g->d,dbar; GtoQQbarSudakov do SplittingGenerator:AddFinalSplitting g->s,sbar; GtoQQbarSudakov do SplittingGenerator:AddFinalSplitting g->c,cbar; GtoccbarSudakov do SplittingGenerator:AddFinalSplitting g->b,bbar; GtobbbarSudakov do SplittingGenerator:AddFinalSplitting g->t,tbar; GtoQQbarSudakov # do SplittingGenerator:AddFinalSplitting gamma->u,ubar; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->d,dbar; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->s,sbar; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->c,cbar; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->b,bbar; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->t,tbar; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->e-,e+; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->mu-,mu+; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->tau-,tau+; GammatoQQbarSudakov # do SplittingGenerator:AddFinalSplitting u->u,gamma; QtoQGammaSudakov do SplittingGenerator:AddFinalSplitting d->d,gamma; QtoQGammaSudakov do SplittingGenerator:AddFinalSplitting s->s,gamma; QtoQGammaSudakov do SplittingGenerator:AddFinalSplitting c->c,gamma; QtoQGammaSudakov do SplittingGenerator:AddFinalSplitting b->b,gamma; QtoQGammaSudakov do SplittingGenerator:AddFinalSplitting t->t,gamma; QtoQGammaSudakov do SplittingGenerator:AddFinalSplitting e-->e-,gamma; LtoLGammaSudakov do SplittingGenerator:AddFinalSplitting mu-->mu-,gamma; LtoLGammaSudakov do SplittingGenerator:AddFinalSplitting tau-->tau-,gamma; LtoLGammaSudakov do SplittingGenerator:AddFinalSplitting W+->W+,gamma; WtoWGammaSudakov # # Now lets add the initial splittings. Remember the form a->b,c; means # that the current particle b is given and we backward branch to new # particle a which is initial state and new particle c which is final state # do SplittingGenerator:AddInitialSplitting u->u,g; QtoQGSudakov do SplittingGenerator:AddInitialSplitting d->d,g; QtoQGSudakov do SplittingGenerator:AddInitialSplitting s->s,g; QtoQGSudakov do SplittingGenerator:AddInitialSplitting c->c,g; QtoQGSudakov do SplittingGenerator:AddInitialSplitting b->b,g; QtoQGSudakov do SplittingGenerator:AddInitialSplitting u->u,gamma; QtoQGammaSudakov do SplittingGenerator:AddInitialSplitting d->d,gamma; QtoQGammaSudakov do SplittingGenerator:AddInitialSplitting s->s,gamma; QtoQGammaSudakov do SplittingGenerator:AddInitialSplitting c->c,gamma; QtoQGammaSudakov do SplittingGenerator:AddInitialSplitting b->b,gamma; QtoQGammaSudakov do SplittingGenerator:AddInitialSplitting t->t,gamma; QtoQGammaSudakov do SplittingGenerator:AddInitialSplitting g->g,g; GtoGGSudakov # do SplittingGenerator:AddInitialSplitting g->d,dbar; GtoQQbarSudakov do SplittingGenerator:AddInitialSplitting g->u,ubar; GtoQQbarSudakov do SplittingGenerator:AddInitialSplitting g->s,sbar; GtoQQbarSudakov do SplittingGenerator:AddInitialSplitting g->c,cbar; GtoccbarSudakov do SplittingGenerator:AddInitialSplitting g->b,bbar; GtobbbarSudakov # #do SplittingGenerator:AddInitialSplitting gamma->d,dbar; GammatoQQbarSudakov #do SplittingGenerator:AddInitialSplitting gamma->u,ubar; GammatoQQbarSudakov #do SplittingGenerator:AddInitialSplitting gamma->s,sbar; GammatoQQbarSudakov #do SplittingGenerator:AddInitialSplitting gamma->c,cbar; GammatoQQbarSudakov #do SplittingGenerator:AddInitialSplitting gamma->b,bbar; GammatoQQbarSudakov do SplittingGenerator:AddInitialSplitting gamma->e-,e+; GammatoQQbarSudakov do SplittingGenerator:AddInitialSplitting gamma->mu-,mu+; GammatoQQbarSudakov do SplittingGenerator:AddInitialSplitting gamma->tau-,tau+; GammatoQQbarSudakov # do SplittingGenerator:AddInitialSplitting d->g,d; dtoGdSudakov do SplittingGenerator:AddInitialSplitting u->g,u; utoGuSudakov do SplittingGenerator:AddInitialSplitting s->g,s; QtoGQSudakov do SplittingGenerator:AddInitialSplitting c->g,c; QtoGQSudakov do SplittingGenerator:AddInitialSplitting b->g,b; QtoGQSudakov do SplittingGenerator:AddInitialSplitting dbar->g,dbar; dtoGdSudakov do SplittingGenerator:AddInitialSplitting ubar->g,ubar; utoGuSudakov do SplittingGenerator:AddInitialSplitting sbar->g,sbar; QtoGQSudakov do SplittingGenerator:AddInitialSplitting cbar->g,cbar; QtoGQSudakov do SplittingGenerator:AddInitialSplitting bbar->g,bbar; QtoGQSudakov # do SplittingGenerator:AddInitialSplitting d->gamma,d; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting u->gamma,u; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting s->gamma,s; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting c->gamma,c; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting b->gamma,b; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting dbar->gamma,dbar; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting ubar->gamma,ubar; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting sbar->gamma,sbar; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting cbar->gamma,cbar; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting bbar->gamma,bbar; QtoGammaQSudakov + +# +# Electroweak +# +do SplittingGenerator:AddFinalSplitting u->u,Z0; QtoQWZSudakov +do SplittingGenerator:AddFinalSplitting d->d,Z0; QtoQWZSudakov +do SplittingGenerator:AddFinalSplitting s->s,Z0; QtoQWZSudakov +do SplittingGenerator:AddFinalSplitting c->c,Z0; QtoQWZSudakov +do SplittingGenerator:AddFinalSplitting b->b,Z0; QtoQWZSudakov +do SplittingGenerator:AddFinalSplitting t->t,Z0; QtoQWZSudakov +do SplittingGenerator:AddInitialSplitting u->u,Z0; QtoQWZSudakov +do SplittingGenerator:AddInitialSplitting d->d,Z0; QtoQWZSudakov +do SplittingGenerator:AddInitialSplitting s->s,Z0; QtoQWZSudakov +do SplittingGenerator:AddInitialSplitting c->c,Z0; QtoQWZSudakov +do SplittingGenerator:AddInitialSplitting b->b,Z0; QtoQWZSudakov +do SplittingGenerator:AddInitialSplitting t->t,Z0; QtoQWZSudakov + +do SplittingGenerator:AddFinalSplitting u->d,W+; QtoQWZSudakov +do SplittingGenerator:AddFinalSplitting c->s,W+; QtoQWZSudakov +do SplittingGenerator:AddFinalSplitting d->u,W-; QtoQWZSudakov +do SplittingGenerator:AddFinalSplitting s->c,W-; QtoQWZSudakov +do SplittingGenerator:AddInitialSplitting u->d,W+; QtoQWZSudakov +do SplittingGenerator:AddInitialSplitting c->s,W+; QtoQWZSudakov +do SplittingGenerator:AddInitialSplitting d->u,W-; QtoQWZSudakov +do SplittingGenerator:AddInitialSplitting s->c,W-; QtoQWZSudakov + +do SplittingGenerator:AddFinalSplitting e-->e-,Z0; LtoLWZSudakov +do SplittingGenerator:AddFinalSplitting mu-->mu-,Z0; LtoLWZSudakov +do SplittingGenerator:AddFinalSplitting tau-->tau-,Z0; LtoLWZSudakov +do SplittingGenerator:AddFinalSplitting nu_e->nu_e,Z0; LtoLWZSudakov +do SplittingGenerator:AddFinalSplitting nu_mu->nu_mu,Z0; LtoLWZSudakov +do SplittingGenerator:AddFinalSplitting nu_tau->nu_tau,Z0; LtoLWZSudakov + +do SplittingGenerator:AddFinalSplitting e-->nu_e,W-; LtoLWZSudakov +do SplittingGenerator:AddFinalSplitting mu-->nu_mu,W-; LtoLWZSudakov +do SplittingGenerator:AddFinalSplitting tau-->nu_tau,W-; LtoLWZSudakov +do SplittingGenerator:AddFinalSplitting nu_e->e-,W+; LtoLWZSudakov +do SplittingGenerator:AddFinalSplitting nu_mu->mu-,W+; LtoLWZSudakov +do SplittingGenerator:AddFinalSplitting nu_tau->tau-,W+; LtoLWZSudakov + +do SplittingGenerator:AddFinalSplitting c->c,h0; QtoQHSudakov +do SplittingGenerator:AddFinalSplitting b->b,h0; QtoQHSudakov +do SplittingGenerator:AddFinalSplitting t->t,h0; QtoQHSudakov +do SplittingGenerator:AddInitialSplitting c->c,h0; QtoQHSudakov +do SplittingGenerator:AddInitialSplitting b->b,h0; QtoQHSudakov +do SplittingGenerator:AddInitialSplitting t->t,h0; QtoQHSudakov + +do SplittingGenerator:AddFinalSplitting gamma->W+,W-; GammatoWWSudakov + +do SplittingGenerator:AddFinalSplitting Z0->W+,W-; VtoVVSudakov +do SplittingGenerator:AddFinalSplitting W+->W+,gamma; VtoVVSudakov +do SplittingGenerator:AddFinalSplitting W+->W+,Z0; VtoVVSudakov + +do SplittingGenerator:AddFinalSplitting W+->W+,h0; VtoVHSudakov +do SplittingGenerator:AddFinalSplitting Z0->Z0,h0; VtoVHSudakov