Page MenuHomeHEPForge

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/Analysis/LeptonDalitzAnalysis.cc b/Analysis/LeptonDalitzAnalysis.cc
--- a/Analysis/LeptonDalitzAnalysis.cc
+++ b/Analysis/LeptonDalitzAnalysis.cc
@@ -1,224 +1,198 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LeptonDalitzAnalysis class.
//
#include "LeptonDalitzAnalysis.h"
#include "ThePEG/EventRecord/Event.h"
+#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "Herwig++/Shower/Base/ShowerParticle.h"
-#include "ThePEG/Repository/CurrentGenerator.h"
-
-#ifdef ThePEG_TEMPLATES_IN_CC_FILE
-// #include "LeptonDalitzAnalysis.tcc"
-#endif
-
using namespace Herwig;
-LeptonDalitzAnalysis::~LeptonDalitzAnalysis() {}
-
void LeptonDalitzAnalysis::analyze(tEventPtr event, long ieve, int loop, int state) {
// Rotate to CMS, extract final state particles and call analyze(particles).
AnalysisHandler::analyze(event, ieve, loop, state);
if(_nout>50000) return;
tPVector final=event->primaryCollision()->step(1)->getFinalState();
tPVector quark,anti,gluon;
- for(unsigned int ix=0;ix<final.size();++ix)
- {
- tPPtr part=final[ix],last=part->parents()[0];
- do
- {
- part=last;
- if(part->parents().empty()) last=tPPtr();
- else last=part->parents()[0];
- }
- while(!part->parents().empty()&&
- dynamic_ptr_cast<ShowerParticlePtr>(last));
- if(part->id()==22||part->id()==23&&final[ix]->previous())
- part=final[ix];
- if(part->id()>0&&part->id()<=6) quark.push_back(final[ix]);
- else if(part->id()<0&&part->id()>=-6) anti.push_back(final[ix]);
- else if(part->id()==21) gluon.push_back(final[ix]);
+ for(unsigned int ix=0;ix<final.size();++ix) {
+ tPPtr part=final[ix],last=part->parents()[0];
+ do {
+ part=last;
+ last = part->parents().empty() ? last=tPPtr() : part->parents()[0];
}
+ while(!part->parents().empty()&&
+ dynamic_ptr_cast<ShowerParticlePtr>(last));
+ if(part->id()==22||part->id()==23&&final[ix]->previous())
+ part=final[ix];
+ if(part->id()>0&&part->id()<=6) quark.push_back(final[ix]);
+ else if(part->id()<0&&part->id()>=-6) anti.push_back(final[ix]);
+ else if(part->id()==21) gluon.push_back(final[ix]);
+ }
// quark jets
Lorentz5Momentum pquark[2],panti[2];
double ycut[2]={0.,0.};
- if(gluon.size()!=0)
- {
- Energy eq(0.*MeV),eg(0.*MeV),ea(0.*MeV);
- for(unsigned int ix=0;ix<quark.size();++ix)
- eq+=quark[ix]->momentum().e();
- for(unsigned int ix=0;ix<anti.size();++ix)
- ea+=anti[ix]->momentum().e();
- for(unsigned int ix=0;ix<gluon.size();++ix)
- eg+=gluon[ix]->momentum().e();
- ++_nout;
- eg+=eq+ea;
- _output[1].push_back(make_pair(2.*eq/eg,2.*ea/eg));
- return;
+ if(gluon.size()!=0) {
+ Energy eq(0.*MeV),eg(0.*MeV),ea(0.*MeV);
+ for(unsigned int ix=0;ix<quark.size();++ix)
+ eq+=quark[ix]->momentum().e();
+ for(unsigned int ix=0;ix<anti.size();++ix)
+ ea+=anti[ix]->momentum().e();
+ for(unsigned int ix=0;ix<gluon.size();++ix)
+ eg+=gluon[ix]->momentum().e();
+ ++_nout;
+ eg+=eq+ea;
+ _output[1].push_back(make_pair(2.*eq/eg,2.*ea/eg));
+ return;
+ }
+ else if(quark.size()>1) {
+ _kint.clearMap();
+ KtJet::KtEvent ev = KtJet::KtEvent(_kint.convert(quark), 1, 1, 1);
+ ev.findJetsN(2);
+ vector<KtJet::KtLorentzVector> ktjets=ev.getJetsPt();
+ ycut[0]=ev.getDMerge(1);
+ int nquark[2]={0,0},iq;
+ for(int ix=0;ix<ev.getNConstituents();++ix) {
+ // find jet
+ iq=ktjets[1].contains(*ev.getConstituents()[ix]);
+ if(quark[ix]->id()<0) --nquark[iq];
+ else if(quark[ix]->id()<=6) ++nquark[iq];
}
- else if(quark.size()>1)
- {
- _kint.clearMap();
- KtJet::KtEvent ev = KtJet::KtEvent(_kint.convert(quark), 1, 1, 1);
- ev.findJetsN(2);
- vector<KtJet::KtLorentzVector> ktjets=ev.getJetsPt();
- ycut[0]=ev.getDMerge(1);
- int nquark[2]={0,0},iq;
- for(int ix=0;ix<ev.getNConstituents();++ix)
- {
- // find jet
- iq=ktjets[1].contains(*ev.getConstituents()[ix]);
- if(quark[ix]->id()<0) --nquark[iq];
- else if(quark[ix]->id()<=6) ++nquark[iq];
- }
- if(nquark[0]>nquark[1])
- {
- pquark[0] = KtJetInterface::convert(ktjets[0]);
- pquark[1] = KtJetInterface::convert(ktjets[1]);
- }
- else
- {
- pquark[1] = KtJetInterface::convert(ktjets[0]);
- pquark[0] = KtJetInterface::convert(ktjets[1]);
- }
+ pquark[0] = KtJetInterface::convert(ktjets[0]);
+ pquark[1] = KtJetInterface::convert(ktjets[1]);
+ if(nquark[0]<=nquark[1]) swap(pquark[0],pquark[1]);
+ }
+ // antiquark jets
+ if(anti.size()>1) {
+ _kint.clearMap();
+ KtJet::KtEvent ev = KtJet::KtEvent(_kint.convert(anti), 1, 1, 1);
+ ev.findJetsN(2);
+ vector<KtJet::KtLorentzVector> ktjets=ev.getJetsPt();
+ ycut[1]=ev.getDMerge(1);
+ int nanti[2]={0,0},iq;
+ for(int ix=0;ix<ev.getNConstituents();++ix) {
+ // find jet
+ iq=ktjets[1].contains(*ev.getConstituents()[ix]);
+ if(anti[ix]->id()<0) --nanti[iq];
+ else if(anti[ix]->id()<=6) ++nanti[iq];
}
- // antiquark jets
- if(anti.size()>1)
- {
- _kint.clearMap();
- KtJet::KtEvent ev = KtJet::KtEvent(_kint.convert(anti), 1, 1, 1);
- ev.findJetsN(2);
- vector<KtJet::KtLorentzVector> ktjets=ev.getJetsPt();
- ycut[1]=ev.getDMerge(1);
- int nanti[2]={0,0},iq;
- for(int ix=0;ix<ev.getNConstituents();++ix)
- {
- // find jet
- iq=ktjets[1].contains(*ev.getConstituents()[ix]);
- if(anti[ix]->id()<0) --nanti[iq];
- else if(anti[ix]->id()<=6) ++nanti[iq];
- }
- if(nanti[0]<nanti[1])
- {
- panti[0] = KtJetInterface::convert(ktjets[0]);
- panti[1] = KtJetInterface::convert(ktjets[1]);
- }
- else
- {
- panti[1] = KtJetInterface::convert(ktjets[0]);
- panti[0] = KtJetInterface::convert(ktjets[1]);
- }
- }
+ if(nanti[0]<nanti[1])
+ {
+ panti[0] = KtJetInterface::convert(ktjets[0]);
+ panti[1] = KtJetInterface::convert(ktjets[1]);
+ }
+ else
+ {
+ panti[1] = KtJetInterface::convert(ktjets[0]);
+ panti[0] = KtJetInterface::convert(ktjets[1]);
+ }
+ }
double x[2];
- if(quark.size()==1&&anti.size()==1)
- {
- x[0]=1.0;
- x[1]=1.0;
- }
- else if(quark.size()==1&&anti.size()>1)
- {
- Energy x0 = quark[0]->momentum().e();
- Energy x1 = panti[0].e();
- Energy sum = x0+x1+panti[1].e();
- x[0] = x0 * 2./sum;
- x[1] = x1 * 2./sum;
- }
- else if(quark.size()>1&&anti.size()==1)
- {
- Energy x0=pquark[0].e();
- Energy x1=anti[0]->momentum().e();
- Energy sum=x0+x1+pquark[1].e();
- x[0] = x0 * 2./sum;
- x[1] = x1 * 2./sum;
- }
- else if(quark.size()>1&&anti.size()>1)
- {
+ if(quark.size()==1&&anti.size()==1) {
+ x[0]=1.0;
+ x[1]=1.0;
+ }
+ else if(quark.size()==1&&anti.size()>1) {
+ Energy x0 = quark[0]->momentum().e();
+ Energy x1 = panti[0].e();
+ Energy sum = x0 + x1 + panti[1].e();
+ x[0] = x0 * 2./sum;
+ x[1] = x1 * 2./sum;
+ }
+ else if(quark.size()>1&&anti.size()==1) {
+ Energy x0 = pquark[0].e();
+ Energy x1 = anti[0]->momentum().e();
+ Energy sum = x0 + x1 + pquark[1].e();
+ x[0] = x0 * 2./sum;
+ x[1] = x1 * 2./sum;
+ }
+ else if(quark.size()>1&&anti.size()>1) {
Energy x0, x1, sum;
if(ycut[0]>ycut[1])
{
x0=pquark[0].e();
x1=panti[0].e()+panti[1].e();
sum=x0+x1+pquark[1].e();
}
else
{
x0=pquark[0].e()+pquark[1].e();
x1=panti[0].e();
sum=x0+x1+panti[1].e();
}
x[0] = x0 * 2./sum;
x[1] = x1 * 2./sum;
}
else
{
x[0]=1.;
x[1]=1.;
cerr << "testing fails ?? " << quark.size() << " " << anti.size() << endl;
}
++_nout;
_output[0].push_back(make_pair(x[0],x[1]));
}
LorentzRotation LeptonDalitzAnalysis::transform(tEventPtr ) const {
return LorentzRotation();
// Return the Rotation to the frame in which you want to perform the analysis.
}
void LeptonDalitzAnalysis::analyze(const tPVector & ) {
}
void LeptonDalitzAnalysis::analyze(tPPtr) {}
NoPIOClassDescription<LeptonDalitzAnalysis> LeptonDalitzAnalysis::initLeptonDalitzAnalysis;
// Definition of the static class description member.
void LeptonDalitzAnalysis::Init() {
static ClassDocumentation<LeptonDalitzAnalysis> documentation
("There is no documentation for the LeptonDalitzAnalysis class");
}
void LeptonDalitzAnalysis::dofinish() {
AnalysisHandler::dofinish();
ofstream file;
string fname = generator()->filename() + string("-") + name() + string(".top");
file.open(fname.c_str());
file << "SET WINDOW X 2 9 Y 2 9\n";
file << "SET FONT DUPLEX\n";
file << "SET LIMITS X 0 1 Y 0 1\n";
file << "TITLE BOTTOM \"X011\"\n";
file << "CASE \" X X\"\n";
file << "TITLE LEFT \"X021\"\n";
file << "CASE \" X X\"\n";
for(unsigned int ix=0;ix<_output[0].size();++ix)
{file << _output[0][ix].first << " " << _output[0][ix].second << "\n";}
file << "PLOT\n";
for(unsigned int ix=0;ix<_output[1].size();++ix)
{file << _output[1][ix].first << " " << _output[1][ix].second << "\n";}
file << "PLOT RED\n";
// plot the limits
double kb=1.;
double xc,xb;
for(double z=0.0;z<=1.0;z+=0.001)
{
xc=1.-z*(1.-z)*kb;
xb=(2.-xc)*0.5+(z-0.5)*xc;
file << xb << " " << xc << "\n";
}
file << "join red" << "\n";
for(double z=0.0;z<=1.0;z+=0.001)
{
xc=1.-z*(1.-z)*kb;
xb=(2.-xc)*0.5+(z-0.5)*xc;
file << xc << " " << xb << "\n";
}
file << "join red\n";
file << 0. << " " << 1. << "\n" << 1. << " " << 0. << "\n" << "join\n";
file.close();
}
diff --git a/Analysis/LeptonDalitzAnalysis.h b/Analysis/LeptonDalitzAnalysis.h
--- a/Analysis/LeptonDalitzAnalysis.h
+++ b/Analysis/LeptonDalitzAnalysis.h
@@ -1,213 +1,190 @@
// -*- C++ -*-
#ifndef HERWIG_LeptonDalitzAnalysis_H
#define HERWIG_LeptonDalitzAnalysis_H
//
// This is the declaration of the LeptonDalitzAnalysis class.
//
#include "ThePEG/Handlers/AnalysisHandler.h"
#include "LeptonDalitzAnalysis.fh"
#include "ThePEG/Vectors/Lorentz5Vector.h"
#include "Herwig++/Interfaces/KtJetInterface.h"
#include "KtJet/KtJet.h"
#include "KtJet/KtLorentzVector.h"
namespace Herwig {
using namespace ThePEG;
/**
* Here is the documentation of the LeptonDalitzAnalysis class.
*
* @see \ref LeptonDalitzAnalysisInterfaces "The interfaces"
* defined for LeptonDalitzAnalysis.
*/
class LeptonDalitzAnalysis: public AnalysisHandler {
public:
- /** @name Standard constructors and destructors. */
- //@{
- /**
- * The default constructor.
- */
- inline LeptonDalitzAnalysis();
-
- /**
- * The copy constructor.
- */
- inline LeptonDalitzAnalysis(const LeptonDalitzAnalysis &);
-
- /**
- * The destructor.
- */
- virtual ~LeptonDalitzAnalysis();
- //@}
-
-public:
-
/** @name Virtual functions required by the AnalysisHandler class. */
//@{
/**
* Analyze a given Event. Note that a fully generated event
* may be presented several times, if it has been manipulated in
* between. The default version of this function will call transform
* to make a lorentz transformation of the whole event, then extract
* all final state particles and call analyze(tPVector) of this
* analysis object and those of all associated analysis objects. The
* default version will not, however, do anything on events which
* have not been fully generated, or have been manipulated in any
* way.
* @param event pointer to the Event to be analyzed.
* @param ieve the event number.
* @param loop the number of times this event has been presented.
* If negative the event is now fully generated.
* @param state a number different from zero if the event has been
* manipulated in some way since it was last presented.
*/
virtual void analyze(tEventPtr event, long ieve, int loop, int state);
/**
* Transform the event to the desired Lorentz frame and return the
* corresponding LorentzRotation.
* @param event a pointer to the Event to be transformed.
* @return the LorentzRotation used in the transformation.
*/
virtual LorentzRotation transform(tEventPtr event) const;
/**
* Analyze the given vector of particles. The default version calls
* analyze(tPPtr) for each of the particles.
* @param particles the vector of pointers to particles to be analyzed
*/
virtual void analyze(const tPVector & particles);
/**
* Analyze the given particle.
* @param particle pointer to the particle to be analyzed.
*/
virtual void analyze(tPPtr particle);
//@}
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.
*/
inline 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.
*/
inline virtual IBPtr fullclone() const;
//@}
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object. Called in the run phase just before
* a run begins.
*/
inline virtual void doinitrun();
/**
* Finalize this object. Called in the run phase just after a
* run has ended. Used eg. to write out statistics.
*/
inline virtual void dofinish();
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is an concrete class without persistent data.
*/
static NoPIOClassDescription<LeptonDalitzAnalysis> initLeptonDalitzAnalysis;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
LeptonDalitzAnalysis & operator=(const LeptonDalitzAnalysis &);
private:
/**
* Vectors to store the output
*/
vector<pair<double,double> > _output[2];
/**
* Total number of points
*/
unsigned int _nout;
/**
* The interface between Herwig++ and KtJet
*/
Herwig::KtJetInterface _kint;
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of LeptonDalitzAnalysis. */
template <>
struct BaseClassTrait<Herwig::LeptonDalitzAnalysis,1> {
/** Typedef of the first base class of LeptonDalitzAnalysis. */
typedef AnalysisHandler NthBase;
};
/** This template specialization informs ThePEG about the name of
* the LeptonDalitzAnalysis class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::LeptonDalitzAnalysis>
: public ClassTraitsBase<Herwig::LeptonDalitzAnalysis> {
/** Return a platform-independent class name */
static string className() { return "Herwig::LeptonDalitzAnalysis"; }
/**
* The name of a file containing the dynamic library where the class
* LeptonDalitzAnalysis is implemented. It may also include several, space-separated,
* libraries if the class LeptonDalitzAnalysis depends on other classes (base classes
* excepted). In this case the listed libraries will be dynamically
* linked in the order they are specified.
*/
static string library() { return "HwKtJet.so HwLEPJetAnalysis.so"; }
};
/** @endcond */
}
#include "LeptonDalitzAnalysis.icc"
-#ifndef ThePEG_TEMPLATES_IN_CC_FILE
-// #include "LeptonDalitzAnalysis.tcc"
-#endif
#endif /* HERWIG_LeptonDalitzAnalysis_H */
diff --git a/Analysis/LeptonDalitzAnalysis.icc b/Analysis/LeptonDalitzAnalysis.icc
--- a/Analysis/LeptonDalitzAnalysis.icc
+++ b/Analysis/LeptonDalitzAnalysis.icc
@@ -1,29 +1,24 @@
// -*- C++ -*-
//
// This is the implementation of the inlined member functions of
// the LeptonDalitzAnalysis class.
//
namespace Herwig {
-inline LeptonDalitzAnalysis::LeptonDalitzAnalysis() {}
-
-inline LeptonDalitzAnalysis::LeptonDalitzAnalysis(const LeptonDalitzAnalysis & x)
- : AnalysisHandler(x) {}
-
inline IBPtr LeptonDalitzAnalysis::clone() const {
return new_ptr(*this);
}
inline IBPtr LeptonDalitzAnalysis::fullclone() const {
return new_ptr(*this);
}
inline void LeptonDalitzAnalysis::doinitrun() {
AnalysisHandler::doinitrun();
_nout=0;
}
}
diff --git a/Models/UED/UEDF1F1Z0Vertex.cc b/Models/UED/UEDF1F1Z0Vertex.cc
--- a/Models/UED/UEDF1F1Z0Vertex.cc
+++ b/Models/UED/UEDF1F1Z0Vertex.cc
@@ -1,173 +1,173 @@
// -*- C++ -*-
//
// UEDF1F1Z0Vertex.cc is a part of Herwig++ - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2007 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 UEDF1F1Z0Vertex class.
//
#include "UEDF1F1Z0Vertex.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
-UEDF1F1Z0Vertex::UEDF1F1Z0Vertex() : theSin2ThW(0.0), theRadius(),
+UEDF1F1Z0Vertex::UEDF1F1Z0Vertex() : theSin2ThW(0.0), theCosThW(0.0), theRadius(),
theID1Last(0), theID2Last(0) ,
theq2Last(0.*GeV2), theCoupLast(0.),
theLeftLast(0.), theRightLast(0.) {
vector<long> anti, ferm, boson(25, 23);
//QQ, uu, dd
for(long i = 5100001; i < 6100007; ++i) {
if(i == 5100007) i += 999994;
anti.push_back(-i);
ferm.push_back(i);
}
//top/bottom quark l/r mixing
anti.push_back(-5100006); ferm.push_back(6100006);
anti.push_back(-6100006); ferm.push_back(5100006);
anti.push_back(-5100005); ferm.push_back(6100005);
anti.push_back(-6100005); ferm.push_back(5100005);
//leptons
for(long i = 5100011; i < 5100017; ++i) {
anti.push_back(-i);
ferm.push_back(i);
}
for(long i = 6100011; i < 6100017; i +=2) {
anti.push_back(-i);
ferm.push_back(i);
}
setList(anti, ferm, boson);
}
void UEDF1F1Z0Vertex::doinit() throw(InitException) {
FFVVertex::doinit();
UEDBasePtr model = dynamic_ptr_cast<tUEDBasePtr>(generator()->standardModel());
if(!model)
throw InitException() << "UEDF1F1Z0Vertex::doinit() - The pointer to "
<< "the UEDBase object is null!"
<< Exception::runerror;
theSin2ThW = model->sin2ThetaW();
theCosThW = sqrt(1. - theSin2ThW);
theRadius = model->compactRadius();
orderInGs(0);
orderInGem(1);
}
void UEDF1F1Z0Vertex::persistentOutput(PersistentOStream & os) const {
os << theSin2ThW << theCosThW << ounit(theRadius,1/GeV);
}
void UEDF1F1Z0Vertex::persistentInput(PersistentIStream & is, int) {
is >> theSin2ThW >> theCosThW >> iunit(theRadius,1/GeV);
}
ClassDescription<UEDF1F1Z0Vertex> UEDF1F1Z0Vertex::initUEDF1F1Z0Vertex;
// Definition of the static class description member.
void UEDF1F1Z0Vertex::Init() {
static ClassDocumentation<UEDF1F1Z0Vertex> documentation
("This is the implementation of the level-1 fermion pair Z_0 boson "
"coupling.");
}
void UEDF1F1Z0Vertex::setCoupling(Energy2 q2, tcPDPtr part1, tcPDPtr part2,
tcPDPtr part3) {
long iferm(0), ianti(0);
if(part1->id() == ParticleID::Z0) {
iferm = part2->id();
ianti = part3->id();
if(iferm < 0) swap(iferm, ianti);
}
else if(part2->id() == ParticleID::Z0) {
iferm = part1->id();
ianti = part3->id();
if(iferm < 0) swap(iferm, ianti);
}
else if(part3->id() == ParticleID::Z0) {
iferm = part2->id();
ianti = part1->id();
if(iferm < 0) swap(iferm, ianti);
}
else
throw HelicityConsistencyError() << "UEDFFZ0Vertex::setCoupling - "
<< "There is no Z boson in this vertex!"
<< Exception::runerror;
ianti = abs(ianti);
bool ferma = (iferm >= 5100001 && iferm <= 5100006) ||
(iferm >= 6100001 && iferm <= 6100006) ||
(iferm >= 5100011 && iferm <= 5100016) ||
(iferm >= 6100011 && iferm <= 6100016);
bool fermb = (ianti >= 5100001 && ianti <= 5100006) ||
(ianti >= 6100001 && ianti <= 6100006) ||
(ianti >= 5100011 && ianti <= 5100016) ||
(ianti >= 6100011 && ianti <= 6100016);
if( ferma && fermb ) {
if(q2 != theq2Last) {
theq2Last = q2;
theCoupLast = 0.5*weakCoupling(q2)/theCosThW;
}
if( ianti != theID1Last || iferm != theID2Last) {
theID1Last = ianti;
theID2Last = iferm;
int stateA = ianti/1000000;
int stateB = iferm/1000000;
long smID = (stateA == 6) ? ianti - 6100000 : ianti - 5100000;
// L/R mixing
double beta = getParticleData(smID)->mass()*theRadius;
double gamma = beta*beta/(1. + beta*beta);
double sin2al = 0.5 - 0.5*sqrt(1. - gamma);
double cos2al = 1. - sin2al;
if(stateA == 5 && stateB == 5) {
if(smID >= 11 && smID <= 16)
theLeftLast = -cos2al + 2.*theSin2ThW;
else if(smID <= 6 && smID % 2 == 0)
theLeftLast = cos2al - 4.*theSin2ThW/3.;
else
theLeftLast = -cos2al + 2.*theSin2ThW/3.;
theRightLast = theLeftLast;
}
else if(stateA == 6 && stateB == 6) {
if(smID >= 11 && smID <= 16)
theLeftLast = -sin2al + 2.*theSin2ThW;
else if(smID <=6 && smID % 2 == 0)
theLeftLast = sin2al - 4.*theSin2ThW/3.;
else
theLeftLast = -sin2al + 2.*theSin2ThW/3.;
theRightLast = theLeftLast;
}
else {
theLeftLast = sqrt(sin2al*cos2al);
if(smID % 2 == 0) theLeftLast *= -1.;
theRightLast = -theLeftLast;
}
}
setNorm(theCoupLast);
setLeft(theLeftLast);
setRight(theRightLast);
}
else {
throw HelicityLogicalError() << "UEDF1F1Z0Vertex::setCoupling - "
<< "There is an unknown particle(s) in the "
<< "UED F^(1) F^(1) Z^(0) vertex. ID: "
<< ianti << " " << iferm
<< Exception::warning;
setNorm(0.0);
setLeft(0.0);
setRight(0.0);
}
}
diff --git a/PDF/ForcedSplitting.cc b/PDF/ForcedSplitting.cc
deleted file mode 100644
--- a/PDF/ForcedSplitting.cc
+++ /dev/null
@@ -1,220 +0,0 @@
-// -*- C++ -*-
-//
-// ForcedSplitting.cc is a part of Herwig++ - A multi-purpose Monte Carlo event generator
-// Copyright (C) 2002-2007 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 ForcedSplitting class.
-//
-
-#include "ForcedSplitting.h"
-#include "ThePEG/Interface/ClassDocumentation.h"
-#include <ThePEG/Interface/Reference.h>
-#include <ThePEG/Interface/Parameter.h>
-#include <ThePEG/PDT/EnumParticles.h>
-#include "ThePEG/Persistency/PersistentOStream.h"
-#include "ThePEG/Persistency/PersistentIStream.h"
-#include "ThePEG/Repository/EventGenerator.h"
-#include "ThePEG/Handlers/EventHandler.h"
-#include "Herwig++/Utilities/EnumParticles.h"
-#include "Herwig++/Shower/ShowerHandler.h"
-#include <cassert>
-
-using namespace Herwig;
-
-void ForcedSplitting::persistentOutput(PersistentOStream & os) const {
- os << ounit(_kinCutoff, GeV) << _range
- << _zbin << _ybin << _nbinmax << _alpha;
-}
-
-void ForcedSplitting::persistentInput(PersistentIStream & is, int) {
- is >> iunit(_kinCutoff, GeV) >> _range
- >> _zbin >> _ybin >> _nbinmax >> _alpha;
-}
-
-ClassDescription<ForcedSplitting> ForcedSplitting::initForcedSplitting;
-// Definition of the static class description member.
-
-void ForcedSplitting::Init() {
-
- static ClassDocumentation<ForcedSplitting> documentation
- ("This class is responsible for correctly tying the parton shower to "
- "the remaining flavours in the hadron and producing the correct remnant");
-
- static Parameter<ForcedSplitting,Energy> interfaceKinCutoff
- ("KinCutoff",
- "Parameter kinCutoff used to constrain qtilde",
- &ForcedSplitting::_kinCutoff, GeV, 0.75*GeV, 0.5*GeV, 10.0*GeV,
- false, false, Interface::limited);
-
- static Parameter<ForcedSplitting,double> interfaceEmissionRange
- ("EmissionRange",
- "Factor above the minimum possible value in which the forced splitting is allowed.",
- &ForcedSplitting::_range, 1.1, 1.0, 10.0,
- false, false, Interface::limited);
-
- static Parameter<ForcedSplitting,double> interfaceZBinSize
- ("ZBinSize",
- "The size of the vbins in z for the interpolation of the splitting function.",
- &ForcedSplitting::_zbin, 0.05, 0.001, 0.1,
- false, false, Interface::limited);
-
- static Parameter<ForcedSplitting,int> interfaceMaxBin
- ("MaxBin",
- "Maximum number of z bins",
- &ForcedSplitting::_nbinmax, 100, 10, 1000,
- false, false, Interface::limited);
-
- static Reference<ForcedSplitting,ShowerAlpha> interfaceAlphaS
- ("AlphaS",
- "Pointer to object to calculate the strong coupling",
- &ForcedSplitting::_alpha, false, false, true, false, false);
-
-}
-
-
-// This creates the parton to split and sets it momentum and parent/child
-// relationships
-PPtr ForcedSplitting::forceSplit(const tRemPPtr rem, long child, Energy &oldQ,
- double &oldx, Lorentz5Momentum &pf,
- Lorentz5Momentum &p,
- const unsigned int iopt,
- const tStepPtr step) const {
- Lorentz5Momentum beam = _beam->momentum();
- PPtr parton = new_ptr(Particle(getParticleData(child)));
- Lorentz5Momentum partonp = emit(beam,oldQ,oldx,parton,pf,iopt);
- p += partonp;
- parton->set5Momentum(partonp);
- step->addDecayProduct(rem,parton,false);
- return parton;
-}
-
-// This forces the final output of the remnant ((di)quark) and sets the
-// momentum and parent/child relationships
-PPtr ForcedSplitting::finalSplit(const tRemPPtr rem, long remID,
- Lorentz5Momentum usedMomentum,
- const tStepPtr step) const {
- // Create the remnant and set its momentum, also reset all of the decay
- // products from the hadron
- PPtr remnant = new_ptr(Particle(getParticleData(remID)));
- Lorentz5Momentum prem(rem->momentum()-usedMomentum);
- prem.setMass(getParticleData(remID)->constituentMass());
- prem.rescaleEnergy();
- remnant->set5Momentum(prem);
- // Add the remnant to the step, but don't do colour connections
- step->addDecayProduct(rem,remnant,false);
- return remnant;
-}
-
-// This defines the momentum for an emitted parton, currently no pt is
-// given to the produced partons, z is generated uniformly.
-Lorentz5Momentum ForcedSplitting::emit(const Lorentz5Momentum &par,
- Energy &lastQ, double &lastx,
- PPtr parton,
- Lorentz5Momentum &pf,
- const unsigned int iopt) const {
- assert(iopt==1||iopt==2);
- Ptr<BeamParticleData>::const_pointer beam =
- dynamic_ptr_cast<Ptr<BeamParticleData>::const_pointer>(_beam->dataPtr());
-
- if(!_pdf)
- throw Exception() << "No PDF object present in "
- << "ForcedSplitting::emit(...)"
- << Exception::runerror;
-
- // the last scale is minimum of last value and upper limit
- Energy minQ=_range*_kinCutoff*sqrt(lastx)/(1-lastx);
- if(minQ>lastQ) lastQ=minQ;
- // generate the new value of qtilde
- // weighted towards the lower value: dP/dQ = 1/Q -> Q(R) =
- // Q0 (Qmax/Q0)^R
- Energy q;
- double zmin,zmax,yy;
- do {
- q = minQ*pow(lastQ/minQ,UseRandom::rnd());
- zmin = lastx;
- yy = 1.+0.5*sqr(_kinCutoff/q);
- zmax = yy - sqrt(sqr(yy)-1.);
- }
- while(zmax<zmin);
- // now generate z as in FORTRAN HERWIG
- // use y = ln(z/(1-z)) as integration variable
- double ymin=log(zmin/(1.-zmin));
- double ymax=log(zmax/(1.-zmax));
- double dely=ymax-ymin;
- // unsigned int nz=std::min(int(_ybin*dely+1),_nbinmax);
- unsigned int nz=_nbinmax;
- dely/=nz;
- yy=ymin+0.5*dely;
- double psum(0.);
- tcPDPtr gluon=getParticleData(ParticleID::g);
- vector<double> prob;
- for(unsigned int iz=0;iz<nz;++iz) {
- double ez=exp(yy);
- double wr=1.+ez;
- double zr=wr/ez;
- double wz=1./wr;
- double zz=wz*ez;
- double az=wz*zz*_alpha->value(sqr(max(wz*q,_kinCutoff)));
- // g -> q qbar
- if(iopt==1) {
- // calculate splitting function
- double pdfval(0.0);
- // SG modified this, should be x/z rather than x/(1-z)!
- // SP as q is always less than forcedSplitScale, the pdf scale is fixed
- // pdfval=_pdf->xfx(beam,gluon,sqr(q),lastx*zr);
- pdfval=_pdf->xfx(beam,gluon,sqr(_forcedSplitScale),lastx*zr);
- // SG: this is symmetric in z <-> 1-z
- psum+=pdfval*az*0.5*(sqr(zz)+sqr(wz));
- }
- // q -> q g
- else {
- // calculate splitting function
- double pdfval(0.0);
- // SG modified this, should be x/z rather than x/(1-z)!
- // SP as q is always less than forcedSplitScale, the pdf scale is fixed
- // pdfval=_pdf->xfx(beam,parton->dataPtr(),sqr(q),lastx*zr);
- pdfval=_pdf->xfx(beam,parton->dataPtr(),sqr(_forcedSplitScale),lastx*zr);
- // SG this splitting function has to have a 1/z pole!
- psum+=pdfval*az*4./3.*(1.+sqr(wz))*zr;
- }
- prob.push_back(psum);
- yy+=dely;
- }
- // choose z
- double pval=psum*UseRandom::rnd();
- unsigned int iz=0;
- for(;iz<prob.size();++iz) {
- if(prob[iz]>pval) break;
- }
- if(iz==prob.size()) --iz;
- double ey=exp(ymin+dely*(float(iz+1)-UseRandom::rnd()));
- double z=ey/(1.+ey);
- Energy2 pt2=sqr((1.-z)*q)- z*sqr(_kinCutoff);
- Energy2 emittedm2 = sqr(parton->dataPtr()->constituentMass());
- // Now boost pcm and pf to z only frame
- Lorentz5Momentum p = Lorentz5Momentum(0.0*MeV, par.vect());
- Lorentz5Momentum n = Lorentz5Momentum(0.0*MeV, -par.vect());
- // generate phi and compute pt of branching
- double phi = Constants::twopi*UseRandom::rnd();
- Energy pt=sqrt(pt2);
- Lorentz5Momentum qt = LorentzMomentum(pt*cos(phi), pt*sin(phi), 0.0*MeV, 0.0*MeV);
- // compute alpha for previous particle
- Energy2 p_dot_n = p*n;
- double lastalpha = pf*n/p_dot_n;
- Lorentz5Momentum qtout=qt;
- Energy2 qtout2=-qt*qt;
- double alphaout=(1.-z)/z*lastalpha;
- double betaout=0.5*(emittedm2+qtout2)/alphaout/p_dot_n;
- Lorentz5Momentum k=alphaout*p+betaout*n+qtout;
- k.rescaleMass();
- pf+=k;
- lastQ=q;
- lastx/=z;
- return k;
-}
-
diff --git a/PDF/ForcedSplitting.fh b/PDF/ForcedSplitting.fh
deleted file mode 100644
--- a/PDF/ForcedSplitting.fh
+++ /dev/null
@@ -1,22 +0,0 @@
-// -*- C++ -*-
-//
-// This is the forward declaration of the ForcedSplitting class.
-//
-#ifndef HERWIG_ForcedSplitting_FH
-#define HERWIG_ForcedSplitting_FH
-
-#include "ThePEG/Config/Pointers.h"
-
-namespace Herwig {
-
-class ForcedSplitting;
-
-}
-
-namespace ThePEG {
-
-ThePEG_DECLARE_POINTERS(Herwig::ForcedSplitting,ForcedSplittingPtr);
-
-}
-
-#endif
diff --git a/PDF/ForcedSplitting.h b/PDF/ForcedSplitting.h
deleted file mode 100644
--- a/PDF/ForcedSplitting.h
+++ /dev/null
@@ -1,276 +0,0 @@
-// -*- C++ -*-
-//
-// ForcedSplitting.h is a part of Herwig++ - A multi-purpose Monte Carlo event generator
-// Copyright (C) 2002-2007 The Herwig Collaboration
-//
-// Herwig++ is licenced under version 2 of the GPL, see COPYING for details.
-// Please respect the MCnet academic guidelines, see GUIDELINES for details.
-//
-#ifndef HERWIG_ForcedSplitting_H
-#define HERWIG_ForcedSplitting_H
-//
-// This is the declaration of the ForcedSplitting class.
-//
-
-#include "ThePEG/Interface/Interfaced.h"
-#include "Herwig++/Shower/Couplings/ShowerAlpha.h"
-#include "ThePEG/PDF/BeamParticleData.h"
-#include "ThePEG/EventRecord/RemnantParticle.h"
-#include "ThePEG/PDT/RemnantData.h"
-#include "ThePEG/PDT/RemnantDecayer.h"
-
-#include "ForcedSplitting.fh"
-
-namespace Herwig {
-
-using namespace ThePEG;
-
-/** \ingroup Hadronization
- *
- * This is the definition of a simple forced splitting algorithm.
- * This takes the Remnant object produced from the PDF and backward
- * evolution (hadron - parton) and produce partons with the remaining
- * flavours and with the correct colour connections.
- *
- * The algorithim operates by starting with the parton which enters the hard process.
- * If this is from the sea there is a forced branching to produce the antiparticle
- * from a gluon branching. If the parton entering the hard process was a gluon, or
- * a gluon was produced from the first step of the algorithm, there is then a further
- * branching back to a valence parton. After these partons have been produced a quark or
- * diquark is produced to give the remaining valence content of the incoming hadron.
- *
- * The forced branching are generated using a scale between _forcedSplitScale as set by the
- * HwRemDecayer object and EmissionRange times
- * the minimum scale. The energy fractions are then distributed using
- * \f[\frac{\alpha_S}{2\pi}\frac{P(z)}{z}f(x/z,\tilde{q})\f]
- * with the massless splitting functions.
- *
- * @see \ref ForcedSplittingInterfaces "The interfaces"
- * defined for ForcedSplitting.
- */
-class ForcedSplitting: public Interfaced {
-
-public:
-
- /**
- * The default constructor.
- */
- inline ForcedSplitting()
- : _kinCutoff(0.75*GeV), _forcedSplitScale(2.5*GeV), _range(1.1),
- _zbin(0.05), _ybin(0.), _nbinmax(100) {}
-
- /** @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();
-
-public:
-
-
- /**
- * This takes the particle and find a splitting for np -> p + child and
- * creates the correct kinematics and connects for such a split. This
- * Splitting has an upper bound on qtilde given by the energy argument
- * @param rem The Remnant
- * @param child The PDG code for the outgoing particle
- * @param oldQ The maximum scale for the evolution
- * @param oldx The fraction of the hadron's momentum carried by the last parton
- * @param pf The momentum of the last parton at input and after branching at output
- * @param p The total emitted momentum
- * @param iopt Whether to use the \f$q\to gq\f$ or \f$g\to q\bar{q}\f$ splitting function.
- * @param step The step into which the new particles are inserted
- */
- PPtr forceSplit(const tRemPPtr rem, long child, Energy &oldQ, double &oldx,
- Lorentz5Momentum &pf, Lorentz5Momentum &p,const unsigned int iopt,
- const tStepPtr step) const;
-
- /**
- * This computes the momentum of the emitted parton.
- * @param par Momentum of the beam particle
- * @param lastQ The maximum scale for the branching
- * @param lastx \f$x\f$ after the last emission
- * @param parton The parton in the last emission
- * @param pf at input is the momentum of the last parton and the emitted momentum on output
- * @param iopt Whether to use the \f$q\to gq\f$ or \f$g\to q\bar{q}\f$ splitting function.
- */
- Lorentz5Momentum emit(const Lorentz5Momentum &par, Energy &lastQ,
- double &lastx, PPtr parton, Lorentz5Momentum &pf,
- const unsigned int iopt) const;
-
- /**
- * This creates a parton from the remaining flavours of the hadron. The
- * last parton used was a valance parton, so only 2 (or 1, if meson) flavours
- * remain to be used.
- */
- PPtr finalSplit(const tRemPPtr rem, long remID, Lorentz5Momentum,
- const tStepPtr ) const;
-
- /**
- * Set the beam particle.
- */
- inline void setBeam(tcPPtr beam) const {
- _beam = beam;
- }
-
- /**
- * Set the PDF to use.
- */
- inline void setPDF(tcPDFPtr pdf, const Energy forcedSplitScale) const {
- _pdf = pdf;
- _forcedSplitScale = forcedSplitScale;
- }
-
-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:
-
- /**
- * Initialize this object after the setup phase before saving an
- * EventGenerator to disk.
- * @throws InitException if object could not be initialized properly.
- */
- inline virtual void doinit() throw(InitException) {
- Interfaced::doinit();
- _ybin=0.25/_zbin;
- }
-
-
-private:
-
- /**
- * The static object used to initialize the description of this class.
- * Indicates that this is a concrete class with persistent data.
- */
- static ClassDescription<ForcedSplitting> initForcedSplitting;
-
- /**
- * The assignment operator is private and must never be called.
- * In fact, it should not even be implemented.
- */
- ForcedSplitting & operator=(const ForcedSplitting &);
-
-private:
-
- /**
- * The kinematic cut-off
- */
- Energy _kinCutoff;
-
- /**
- * Start of evolution
- */
- mutable Energy _forcedSplitScale;
-
- /**
- * Range for emission
- */
- double _range;
-
- /**
- * Size of the bins in z for the interpolation
- */
- double _zbin;
-
- /**
- * Size of the bins in y for the interpolation
- */
- double _ybin;
-
- /**
- * Maximum number of bins for the z interpolation
- */
- int _nbinmax;
-
- /**
- * Pointer to the object calculating the QCD coupling
- */
- ShowerAlphaPtr _alpha;
-
- /**
- * The beam particle data for the current initial-state shower
- */
- mutable tcPPtr _beam;
-
- /**
- * The PDF for the current initial-state shower
- */
- mutable tcPDFPtr _pdf;
-
-};
-
-}
-
-#include "ThePEG/Utilities/ClassTraits.h"
-
-namespace ThePEG {
-
-/** @cond TRAITSPECIALIZATIONS */
-
-/** This template specialization informs ThePEG about the
- * base classes of ForcedSplitting. */
-template <>
-struct BaseClassTrait<Herwig::ForcedSplitting,1> {
- /** Typedef of the first base class of ForcedSplitting. */
- typedef Interfaced NthBase;
-};
-
-/** This template specialization informs ThePEG about the name of
- * the ForcedSplitting class and the shared object where it is defined. */
-template <>
-struct ClassTraits<Herwig::ForcedSplitting>
- : public ClassTraitsBase<Herwig::ForcedSplitting> {
- /** Return a platform-independent class name */
- static string className() { return "Herwig::ForcedSplitting"; }
- /**
- * The name of a file containing the dynamic library where the class
- * ForcedSplitting is implemented. It may also include several, space-separated,
- * libraries if the class ForcedSplitting depends on other classes (base classes
- * excepted). In this case the listed libraries will be dynamically
- * linked in the order they are specified.
- */
- static string library() { return "HwRemDecayer.so"; }
-};
-
-/** @endcond */
-
-}
-
-#endif /* HERWIG_ForcedSplitting_H */
diff --git a/PDF/HwRemDecayer.cc b/PDF/HwRemDecayer.cc
--- a/PDF/HwRemDecayer.cc
+++ b/PDF/HwRemDecayer.cc
@@ -1,516 +1,784 @@
// -*- C++ -*-
//
// HwRemDecayer.cc is a part of Herwig++ - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2007 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 HwRemDecayer class.
//
#include "HwRemDecayer.h"
#include "ThePEG/Interface/ClassDocumentation.h"
+#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include <ThePEG/Interface/Reference.h>
-#include <ThePEG/Interface/Switch.h>
-#include "Herwig++/PDT/StandardMatchers.h"
-#include "ThePEG/PDT/StandardMatchers.h"
+#include <ThePEG/Interface/Reference.h>
+#include <ThePEG/Interface/Switch.h>
#include "Herwig++/Shower/ShowerHandler.h"
+#include "ThePEG/Utilities/UtilityBase.h"
+#include "ThePEG/Utilities/SimplePhaseSpace.h"
+#include "ThePEG/Utilities/Throw.h"
using namespace Herwig;
-using namespace ThePEG;
-int HwRemDecayer::HadronContent::getValence() {
- if(extracted != -1)
- throw Exception() << "Try to extract second valence quark in "
- << "HwRemDecayer::GetValence()"
- << Exception::runerror;
- int index( UseRandom::irnd( flav.size() ) );
- extracted = index;
- return sign*flav[index];
+void HwRemDecayer::persistentOutput(PersistentOStream & os) const {
+ os << ounit(_kinCutoff, GeV) << _range
+ << _zbin << _ybin << _nbinmax << _alpha << DISRemnantOpt_;
}
-void HwRemDecayer::HadronContent::extract(int id) {
- for(unsigned int i=0; i<flav.size(); i++)
- if(id == sign*flav[i]){
- extracted = i;
- break;
- }
+void HwRemDecayer::persistentInput(PersistentIStream & is, int) {
+ is >> iunit(_kinCutoff, GeV) >> _range
+ >> _zbin >> _ybin >> _nbinmax >> _alpha >> DISRemnantOpt_;
}
-bool HwRemDecayer::HadronContent::isSeaQuark(tcPPtr parton) const{
- return ((parton->id() != ParticleID::g) &&
- ( !isValenceQuark(parton) ) );
+ClassDescription<HwRemDecayer> HwRemDecayer::initHwRemDecayer;
+// Definition of the static class description member.
+
+void HwRemDecayer::Init() {
+
+ static ClassDocumentation<HwRemDecayer> documentation
+ ("The HwRemDecayer class decays the remnant for Herwig++");
+
+ static Parameter<HwRemDecayer,double> interfaceZBinSize
+ ("ZBinSize",
+ "The size of the vbins in z for the interpolation of the splitting function.",
+ &HwRemDecayer::_zbin, 0.05, 0.001, 0.1,
+ false, false, Interface::limited);
+
+ static Parameter<HwRemDecayer,int> interfaceMaxBin
+ ("MaxBin",
+ "Maximum number of z bins",
+ &HwRemDecayer::_nbinmax, 100, 10, 1000,
+ false, false, Interface::limited);
+
+ static Reference<HwRemDecayer,ShowerAlpha> interfaceAlphaS
+ ("AlphaS",
+ "Pointer to object to calculate the strong coupling",
+ &HwRemDecayer::_alpha, false, false, true, false, false);
+
+ static Parameter<HwRemDecayer,Energy> interfaceKinCutoff
+ ("KinCutoff",
+ "Parameter kinCutoff used to constrain qtilde",
+ &HwRemDecayer::_kinCutoff, GeV, 0.75*GeV, 0.5*GeV, 10.0*GeV,
+ false, false, Interface::limited);
+
+ static Parameter<HwRemDecayer,double> interfaceEmissionRange
+ ("EmissionRange",
+ "Factor above the minimum possible value in which the forced splitting is allowed.",
+ &HwRemDecayer::_range, 1.1, 1.0, 10.0,
+ false, false, Interface::limited);
+
+
+ static Switch<HwRemDecayer,unsigned int> interfaceDISRemnantOption
+ ("DISRemnantOption",
+ "Options for the treatment of the remnant in DIS",
+ &HwRemDecayer::DISRemnantOpt_, 0, false, false);
+ static SwitchOption interfaceDISRemnantOptionDefault
+ (interfaceDISRemnantOption,
+ "Default",
+ "Use the minimum number of particles needed to take the recoil"
+ " and allow the lepton to be used if needed",
+ 0);
+ static SwitchOption interfaceDISRemnantOptionNoLepton
+ (interfaceDISRemnantOption,
+ "NoLepton",
+ "Use the minimum number of particles needed to take the recoil but"
+ " veto events where the lepton kinematics would need to be altered",
+ 1);
+ static SwitchOption interfaceDISRemnantOptionAllParticles
+ (interfaceDISRemnantOption,
+ "AllParticles",
+ "Use all particles in the colour connected system to take the recoil"
+ " and use the lepton if needed.",
+ 2);
+ static SwitchOption interfaceDISRemnantOptionAllParticlesNoLepton
+ (interfaceDISRemnantOption,
+ "AllParticlesNoLepton",
+ "Use all the particles in the colour connected system to take the"
+ " recoil but don't use the lepton.",
+ 3);
+
}
-bool HwRemDecayer::HadronContent::isValenceQuark(tcPPtr parton) const{
- int id(parton->id());
- for(unsigned int i=0; i<flav.size(); i++)
- if(id == sign*flav[i])
- return true;
-
- return false;
+ParticleVector HwRemDecayer::decay(const DecayMode &,
+ const Particle &, Step &) const {
+ throw Exception() << "HwRemDecayer::decay(...) "
+ << "must not be called explicitely."
+ << Exception::runerror;
}
-long HwRemDecayer::HadronContent::RemID() const{
- if(extracted == -1)
- throw Exception() << "Try to build a Diquark id without "
- << "having extracted something in "
- << "HwRemDecayer::RemID(...)"
- << Exception::runerror;
- if(flav.size()==2)//the hadron was a meson
- return sign*flav[(extracted+1)%2];
-
- long remId;
- int id1(sign*flav[(extracted+1)%3]),
- id2(sign*flav[(extracted+2)%3]),
- sign(0), spin(0);
-
- if (abs(id1) > abs(id2)) swap(id1, id2);
- sign = (id1 < 0) ? -1 : 1; // Needed for the spin 0/1 part
- remId = id2*1000+id1*100;
-
- // Now decide if we have spin 0 diquark or spin 1 diquark
- if(id1 == id2) spin = 3; // spin 1
- else spin = 1; // otherwise spin 0
-
- remId += sign*spin;
- return remId;
-}
-
-HwRemDecayer::HadronContent
-HwRemDecayer::getHadronContent(tcPPtr hadron) const {
- HadronContent hc;
- long id(hadron->id());
- if(HadronMatcher::Check(hadron->data())) {
- hc.sign = id < 0? -1: 1;
- hc.flav.push_back((id = abs(id)/10)%10);
- hc.flav.push_back((id /= 10)%10);
- hc.flav.push_back((id /= 10)%10);
- hc.extracted = -1;
- }
- return hc;
-}
-
-bool HwRemDecayer::accept(const DecayMode &) const {
- return true;
-}
-
-bool HwRemDecayer::multiCapable() const {
- return true;
-}
-
-bool HwRemDecayer::
-canHandle(tcPDPtr particle, tcPDPtr parton) const {
- return ( HadronMatcher::Check(*particle) &&
- (StandardQCDPartonMatcher::Check(*parton)||
- parton->id()==ParticleID::gamma ));
-}
-
-void HwRemDecayer::initialize(pair<tRemPPtr, tRemPPtr> rems, Step & step, Energy forcedSplitScale) {
- if(!theForcedSplitter) return;
- tcPPair beam(generator()->currentEventHandler()->currentCollision()->incoming());
-
+void HwRemDecayer::initialize(pair<tRemPPtr, tRemPPtr> rems, tPPair beam, Step & step,
+ Energy forcedSplitScale) {
+ // the step
thestep = &step;
+ // valence content of the hadrons
theContent.first = getHadronContent(beam.first);
theContent.second = getHadronContent(beam.second);
+ // momentum extracted from the hadrons
theUsed.first = Lorentz5Momentum();
theUsed.second = Lorentz5Momentum();
theMaps.first.clear();
theMaps.second.clear();
theX.first = 0.0;
theX.second = 0.0;
theRems = rems;
_forcedSplitScale = forcedSplitScale;
-
+ // check remnants attached to the right hadrons
if( (theRems.first && parent(theRems.first ) != beam.first ) ||
(theRems.second && parent(theRems.second) != beam.second) )
throw Exception() << "Remnant order wrong in "
<< "HwRemDecayer::initialize(...)"
<< Exception::runerror;
return;
}
+void HwRemDecayer::doSplit(pair<tPPtr, tPPtr> partons, pair<tcPDFPtr, tcPDFPtr> pdfs,
+ bool first) {
+ if(theRems.first) {
+ ParticleVector children=theRems.first->children();
+ for(unsigned int ix=0;ix<children.size();++ix) {
+ if(children[ix]->dataPtr()==theRems.first->dataPtr())
+ theRems.first = dynamic_ptr_cast<RemPPtr>(children[ix]);
+ }
+ }
+ if(theRems.second) {
+ ParticleVector children=theRems.second->children();
+ for(unsigned int ix=0;ix<children.size();++ix) {
+ if(children[ix]->dataPtr()==theRems.second->dataPtr())
+ theRems.second = dynamic_ptr_cast<RemPPtr>(children[ix]);
+ }
+ }
+ // forced splitting for first parton
+ if(partons.first->data().coloured()) {
+ try {
+ split(partons.first, theContent.first, theRems.first,
+ theUsed.first, theMaps.first, pdfs.first, first);
+ }
+ catch(ShowerHandler::ExtraScatterVeto) {
+ theX.first -= partons.first->momentum().rho()/
+ parent(theRems.first)->momentum().rho();
+ throw ShowerHandler::ExtraScatterVeto();
+ }
+ }
+ // forced splitting for second parton
+ if(partons.second->data().coloured()) {
+ try{
+ split(partons.second, theContent.second, theRems.second,
+ theUsed.second, theMaps.second, pdfs.second, first);
+ // additional check for the remnants
+ // if can't do the rescale veto the emission
+ if(!first&&partons.first->data().coloured()&&
+ partons.second->data().coloured()) {
+ Lorentz5Momentum pnew[2]=
+ {theRems.first->momentum() - theUsed.first - partons.first->momentum(),
+ theRems.second->momentum() - theUsed.second - partons.second->momentum()};
+
+ pnew[0].setMass(getParticleData(theContent.first.RemID())->constituentMass());
+ pnew[0].rescaleEnergy();
+ pnew[1].setMass(getParticleData(theContent.second.RemID())->constituentMass());
+ pnew[1].rescaleEnergy();
+
+ for(unsigned int iy=0; iy<theRems.first->children().size(); ++iy)
+ pnew[0] += theRems.first->children()[iy]->momentum();
+
+ for(unsigned int iy=0; iy<theRems.second->children().size(); ++iy)
+ pnew[1] += theRems.second->children()[iy]->momentum();
+
+ Lorentz5Momentum ptotal=
+ theRems.first ->momentum()-partons.first ->momentum()+
+ theRems.second->momentum()-partons.second->momentum();
+
+ if(ptotal.m() < (pnew[0].m() + pnew[1].m()) ) {
+ if(partons.second->id() != ParticleID::g){
+ if(partons.second==theMaps.second.back().first)
+ theUsed.second -= theMaps.second.back().second->momentum();
+ else
+ theUsed.second -= theMaps.second.back().first->momentum();
+
+ thestep->removeParticle(theMaps.second.back().first);
+ thestep->removeParticle(theMaps.second.back().second);
+ }
+ theMaps.second.pop_back();
+ throw ShowerHandler::ExtraScatterVeto();
+ }
+ }
+ }
+ catch(ShowerHandler::ExtraScatterVeto){
+ if(!partons.first||!partons.second||
+ !theRems.first||!theRems.second)
+ throw ShowerHandler::ExtraScatterVeto();
+ //case of the first forcedSplitting worked fine
+ theX.first -= partons.first->momentum().rho()/
+ parent(theRems.first)->momentum().rho();
+ theX.second -= partons.second->momentum().rho()/
+ parent(theRems.second)->momentum().rho();
+
+ //case of the first interaction
+ //throw veto immediately, because event get rejected anyway.
+ if(first) throw ShowerHandler::ExtraScatterVeto();
+
+ //secondary interactions have to end on a gluon, if parton
+ //was NOT a gluon, the forced splitting particles must be removed
+ if(partons.first->id() != ParticleID::g){
+ if(partons.first==theMaps.first.back().first)
+ theUsed.first -= theMaps.first.back().second->momentum();
+ else
+ theUsed.first -= theMaps.first.back().first->momentum();
+
+ thestep->removeParticle(theMaps.first.back().first);
+ thestep->removeParticle(theMaps.first.back().second);
+ }
+ theMaps.first.pop_back();
+ throw ShowerHandler::ExtraScatterVeto();
+ }
+ }
+}
+
+void HwRemDecayer::finalize() {
+ PPtr diquark;
+ //Do the final Rem->Diquark or Rem->quark "decay"
+ if(theRems.first) {
+ diquark = finalSplit(theRems.first, theContent.first.RemID(),
+ theUsed.first);
+ theMaps.first.push_back(make_pair(diquark, tPPtr()));
+ }
+ if(theRems.second) {
+ diquark = finalSplit(theRems.second, theContent.second.RemID(),
+ theUsed.second);
+ theMaps.second.push_back(make_pair(diquark, tPPtr()));
+ }
+ setRemMasses();
+ if(theRems.first) fixColours(theMaps.first , theanti.first );
+ if(theRems.second) fixColours(theMaps.second, theanti.second);
+}
+
+HwRemDecayer::HadronContent
+HwRemDecayer::getHadronContent(tcPPtr hadron) const {
+ HadronContent hc;
+ hc.hadron = hadron->dataPtr();
+ long id(hadron->id());
+ // baryon
+ if(BaryonMatcher::Check(hadron->data())) {
+ hc.sign = id < 0? -1: 1;
+ hc.flav.push_back((id = abs(id)/10)%10);
+ hc.flav.push_back((id /= 10)%10);
+ hc.flav.push_back((id /= 10)%10);
+ hc.extracted = -1;
+ }
+ else if(hadron->data().id()==ParticleID::gamma) {
+ hc.sign = 1;
+ for(int ix=1;ix<6;++ix) {
+ hc.flav.push_back( ix);
+ hc.flav.push_back(-ix);
+ }
+ }
+ return hc;
+}
+
+long HwRemDecayer::HadronContent::RemID() const{
+ if(extracted == -1)
+ throw Exception() << "Try to build a Diquark id without "
+ << "having extracted something in "
+ << "HwRemDecayer::RemID(...)"
+ << Exception::runerror;
+ //the hadron was a meson or photon
+ if(flav.size()==2) return sign*flav[(extracted+1)%2];
+
+ long remId;
+ int id1(sign*flav[(extracted+1)%3]),
+ id2(sign*flav[(extracted+2)%3]),
+ sign(0), spin(0);
+
+ if (abs(id1) > abs(id2)) swap(id1, id2);
+ sign = (id1 < 0) ? -1 : 1; // Needed for the spin 0/1 part
+ remId = id2*1000+id1*100;
+ // Now decide if we have spin 0 diquark or spin 1 diquark
+ if(id1 == id2) spin = 3; // spin 1
+ else spin = 1; // otherwise spin 0
+ remId += sign*spin;
+ return remId;
+}
+
void HwRemDecayer::split(tPPtr parton, HadronContent & content,
tRemPPtr rem, Lorentz5Momentum & used,
PartnerMap &partners, tcPDFPtr pdf, bool first) {
- tcPPtr beam(parent(rem));
+ theBeam = parent(rem);
+ theBeamData = dynamic_ptr_cast<Ptr<BeamParticleData>::const_pointer>
+ (theBeam->dataPtr());
if(rem==theRems.first)
- theX.first += parton->momentum().rho()/beam->momentum().rho();
+ theX.first += parton->momentum().rho()/theBeam->momentum().rho();
else
- theX.second += parton->momentum().rho()/beam->momentum().rho();
+ theX.second += parton->momentum().rho()/theBeam->momentum().rho();
double check = rem==theRems.first ? theX.first : theX.second;
if(1.0-check < 1e-3) throw ShowerHandler::ExtraScatterVeto();
bool anti;
Lorentz5Momentum lastp(parton->momentum());
int lastID(parton->id());
- PPtr newSea, newValence;
ColinePtr cl;
- //set the beam object to access its momentum.
- theForcedSplitter->setBeam(beam);
- theForcedSplitter->setPDF(pdf,_forcedSplitScale);
-
Energy oldQ(_forcedSplitScale);
-
+ _pdf = pdf;
//do nothing if already valence quark
- if(first && content.isValenceQuark(parton)){
+ if(first && content.isValenceQuark(parton)) {
//set the extracted value, because otherwise no RemID could be generated.
content.extract(lastID);
- //add the particle to the colour partners
+ // add the particle to the colour partners
partners.push_back(make_pair(parton, tPPtr()));
//set the sign
anti = parton->hasAntiColour();
- if(rem==theRems.first)
- theanti.first = anti;
- else
- theanti.second = anti;
+ if(rem==theRems.first) theanti.first = anti;
+ else theanti.second = anti;
return;
}
//or gluon for secondaries
- if(!first && lastID == ParticleID::g){
+ else if(!first && lastID == ParticleID::g){
partners.push_back(make_pair(parton, tPPtr()));
return;
}
- if( lastID != ParticleID::g ){
- //do the gluon splitting
- // Create the new parton with its momentum and parent/child relationship set
- if(rem==theRems.first)
- newSea = theForcedSplitter->
- forceSplit(rem, -lastID, oldQ, theX.first,
- lastp, used,1, thestep);
- else
- newSea = theForcedSplitter->
- forceSplit(rem, -lastID, oldQ, theX.second,
- lastp, used,1, thestep);
-
+ // if a sea quark.antiquark forced splitting to a gluon
+ // Create the new parton with its momentum and parent/child relationship set
+ PPtr newSea;
+ if( lastID != ParticleID::g ) {
+ newSea = forceSplit(rem, -lastID, oldQ,
+ rem==theRems.first ? theX.first : theX.second,
+ lastp, used,content);
cl = new_ptr(ColourLine());
if(newSea->id() > 0) cl->addColoured(newSea);
else cl->addAntiColoured(newSea);
-
+ // if a secondard scatter finished so return
+ if(!first){
+ partners.push_back(make_pair(parton, newSea));
+ return;
+ }
}
-
- if(!first){
- partners.push_back(make_pair(parton, newSea));
- return;
- }
- if( !content.isValenceQuark(parton) ){
- //final valence splitting
-
- //This was in the old code, but probably accidental:
- //oldQ = theForcedSplitter->getQspac();
- if(rem==theRems.first)
- newValence = theForcedSplitter->
- forceSplit(rem, content.getValence(),
- oldQ, theX.first, lastp, used, 2, thestep);
- else
- newValence = theForcedSplitter->
- forceSplit(rem, content.getValence(),
- oldQ, theX.second, lastp, used, 2, thestep);
-
- //case of a gluon going into the hard subprocess
- if( lastID == ParticleID::g ){
+ // otherwise evolve back to valence
+ if( !content.isValenceQuark(parton) ) {
+ // final valence splitting
+ PPtr newValence = forceSplit(rem, 0, oldQ,
+ rem==theRems.first ? theX.first : theX.second,
+ lastp, used, content);
+ // extract from the hadron to allow remnant to be determined
+ content.extract(newValence->id());
+ // case of a gluon going into the hard subprocess
+ if( lastID == ParticleID::g ) {
partners.push_back(make_pair(parton, tPPtr()));
-
anti = newValence->hasAntiColour();
- if(rem==theRems.first)
- theanti.first = anti;
- else
- theanti.second = anti;
-
+ if(rem==theRems.first) theanti.first = anti;
+ else theanti.second = anti;
parton->colourLine(!anti)->addColoured(newValence, anti);
return;
}
//The valence quark will always be connected to the sea quark with opposite sign
tcPPtr particle;
if(lastID*newValence->id() < 0){
particle = parton;
partners.push_back(make_pair(newSea, tPPtr()));
- }else{
+ }
+ else {
particle = newSea;
partners.push_back(make_pair(parton, tPPtr()));
}
anti = newValence->hasAntiColour();
- if(rem==theRems.first)
- theanti.first = anti;
- else
- theanti.second = anti;
-
- if(particle->colourLine()) particle->colourLine()->addAntiColoured(newValence);
- if(particle->antiColourLine()) particle->antiColourLine()->addColoured(newValence);
+ if(rem==theRems.first) theanti.first = anti;
+ else theanti.second = anti;
+ if(particle->colourLine())
+ particle->colourLine()->addAntiColoured(newValence);
+ if(particle->antiColourLine())
+ particle->antiColourLine()->addColoured(newValence);
}
return;
}
-void HwRemDecayer::setRemMasses() const {
- // get the masses of the remnants
- Energy mrem[2];
- Lorentz5Momentum ptotal,pnew[2];
- vector<tRemPPtr> theprocessed;
- theprocessed.push_back(theRems.first);
- theprocessed.push_back(theRems.second);
-
- for(unsigned int ix=0;ix<2;++ix) {
- if(!theprocessed[ix]) continue;
- pnew[ix]=Lorentz5Momentum();
- for(unsigned int iy=0;iy<theprocessed[ix]->children().size();++iy) {
- pnew[ix]+=theprocessed[ix]->children()[iy]->momentum();
- }
- mrem[ix]=sqrt(pnew[ix].m2());
- }
- // now find the remnant remnant cmf frame
- if(!theprocessed[0]||!theprocessed[1]) return;
- Lorentz5Momentum prem[2]={theprocessed[0]->momentum(),
- theprocessed[1]->momentum()};
- ptotal=prem[0]+prem[1];
- ptotal.rescaleMass();
- // boost momenta to this frame
- if(ptotal.m()< (pnew[0].m()+pnew[1].m()))
- throw Exception() << "Not enough energy in both remnants in "
- << "HwRemDecayer::setRemMasses() "
- << Exception::eventerror;
-
- Boost boostv(-ptotal.boostVector());
- ptotal.boost(boostv);
- for(unsigned int ix=0;ix<2;++ix) {
- prem[ix].boost(boostv);
- // set the masses and energies,
- prem[ix].setMass(mrem[ix]);
- prem[ix].setE(0.5/ptotal.m()*(sqr(ptotal.m())+sqr(mrem[ix])-sqr(mrem[1-ix])));
- prem[ix].rescaleRho();
- // boost back to the lab
- prem[ix].boost(-boostv);
- // set the momenta of the remnants
- theprocessed[ix]->set5Momentum(prem[ix]);
- }
-
- // boost the decay products
- Lorentz5Momentum ptemp;
- for(unsigned int ix=0;ix<2;++ix) {
- Boost btorest(-pnew[ix].boostVector());
- Boost bfmrest( prem[ix].boostVector());
- for(unsigned int iy=0;iy<theprocessed[ix]->children().size();++iy) {
- ptemp=theprocessed[ix]->children()[iy]->momentum();
- ptemp.boost(btorest);
- ptemp.boost(bfmrest);
- theprocessed[ix]->children()[iy]->set5Momentum(ptemp);
- }
- }
-}
-
void HwRemDecayer::fixColours(PartnerMap partners, bool anti) const {
PartnerMap::const_iterator prev;
tPPtr pnew, pold;
ColinePtr clnew, clold;
assert(partners.size()>=2);
for(PartnerMap::iterator it=partners.begin();
it!=partners.end(); it++){
if(it==partners.begin()) continue;
prev = it - 1;
//determine the particles to work with
pold = prev->first;
if(prev->second){
if(pold->hasAntiColour() != anti)
pold = prev->second;
}
assert(pold);
pnew = it->first;
if(it->second){
if(it->second->colourLine(!anti)) //look for the opposite colour
pnew = it->second;
}
assert(pnew);
//save the corresponding colour lines
clold = pold->colourLine(anti);
clnew = pnew->colourLine(!anti);
assert(clold);
if(clnew){//there is already a colour line (not the final diquark)
if( (clnew->coloured().size() + clnew->antiColoured().size()) > 1 ){
if( (clold->coloured().size() + clold->antiColoured().size()) > 1 ){
//join the colour lines
//I don't use the join method, because potentially only (anti)coloured
//particles belong to one colour line
if(clold!=clnew){//procs are not already connected
while ( !clnew->coloured().empty() ) {
tPPtr p = clnew->coloured()[0];
clnew->removeColoured(p);
clold->addColoured(p);
}
while ( !clnew->antiColoured().empty() ) {
tPPtr p = clnew->antiColoured()[0];
clnew->removeAntiColoured(p);
clold->addAntiColoured(p);
}
}
}else{
//if pold is the only member on it's
//colour line, remove it.
clold->removeColoured(pold, anti);
//and add it to clnew
clnew->addColoured(pold, anti);
}
}else{//pnnew is the only member on it's colour line.
clnew->removeColoured(pnew, !anti);
clold->addColoured(pnew, !anti);
}
}else{//there is no coline at all for pnew
clold->addColoured(pnew, !anti);
}
//end of loop
}
return;
}
-void HwRemDecayer::doSplit(pair<tPPtr, tPPtr> partons, pair<tcPDFPtr, tcPDFPtr> pdfs,
- bool first) {
- if(!theForcedSplitter) return;
- // forced splitting for first parton
- if(partons.first->data().coloured()) {
- try {
- split(partons.first, theContent.first, theRems.first,
- theUsed.first, theMaps.first, pdfs.first, first);
+PPtr HwRemDecayer::forceSplit(const tRemPPtr rem, long child, Energy &lastQ,
+ double &lastx, Lorentz5Momentum &pf,
+ Lorentz5Momentum &p, HadronContent & content) const {
+ // beam momentum
+ Lorentz5Momentum beam = theBeam->momentum();
+ // the last scale is minimum of last value and upper limit
+ Energy minQ=_range*_kinCutoff*sqrt(lastx)/(1-lastx);
+ if(minQ>lastQ) lastQ=minQ;
+ // generate the new value of qtilde
+ // weighted towards the lower value: dP/dQ = 1/Q -> Q(R) =
+ // Q0 (Qmax/Q0)^R
+ Energy q;
+ double zmin,zmax,yy;
+ do {
+ q = minQ*pow(lastQ/minQ,UseRandom::rnd());
+ zmin = lastx;
+ yy = 1.+0.5*sqr(_kinCutoff/q);
+ zmax = yy - sqrt(sqr(yy)-1.);
+ }
+ while(zmax<zmin);
+ // now generate z as in FORTRAN HERWIG
+ // use y = ln(z/(1-z)) as integration variable
+ double ymin=log(zmin/(1.-zmin));
+ double ymax=log(zmax/(1.-zmax));
+ double dely=ymax-ymin;
+ unsigned int nz=_nbinmax;
+ dely/=nz;
+ yy=ymin+0.5*dely;
+ vector<int> ids;
+ if(child!=0) ids.push_back(ParticleID::g);
+ else {
+ ids=content.flav;
+ for(unsigned int ix=0;ix<ids.size();++ix) ids[ix] *= content.sign;
+ }
+ // probabilities of the different types of possible splitting
+ map<long,pair<double,vector<double> > > partonprob;
+ double ptotal(0.);
+ for(unsigned int iflav=0;iflav<ids.size();++iflav) {
+ // only do each parton once
+ if(partonprob.find(ids[iflav])!=partonprob.end()) continue;
+ // particle data object
+ tcPDPtr in = getParticleData(ids[iflav]);
+ double psum(0.);
+ vector<double> prob;
+ for(unsigned int iz=0;iz<nz;++iz) {
+ double ez=exp(yy);
+ double wr=1.+ez;
+ double zr=wr/ez;
+ double wz=1./wr;
+ double zz=wz*ez;
+ double az=wz*zz*_alpha->value(sqr(max(wz*q,_kinCutoff)));
+ // g -> q qbar
+ if(ids[iflav]==ParticleID::g) {
+ // calculate splitting function
+ // SP as q is always less than forcedSplitScale, the pdf scale is fixed
+ // pdfval = _pdf->xfx(theBeamData,in,sqr(q),lastx*zr);
+ double pdfval=_pdf->xfx(theBeamData,in,sqr(_forcedSplitScale),lastx*zr);
+ psum += pdfval*az*0.5*(sqr(zz)+sqr(wz));
+ }
+ // q -> q g
+ else {
+ // calculate splitting function
+ // SP as q is always less than forcedSplitScale, the pdf scale is fixed
+ // pdfval = _pdf->xfx(theBeamData,in,sqr(q),lastx*zr);
+ double pdfval=_pdf->xfx(theBeamData,in,sqr(_forcedSplitScale),lastx*zr);
+ psum += pdfval*az*4./3.*(1.+sqr(wz))*zr;
+ }
+ prob.push_back(psum);
+ yy+=dely;
}
- catch(ShowerHandler::ExtraScatterVeto) {
- theX.first -= partons.first->momentum().rho()/parent(theRems.first)->momentum().rho();
- throw ShowerHandler::ExtraScatterVeto();
+ partonprob[ids[iflav]] = make_pair(psum,prob);
+ ptotal+=psum;
+ }
+ // select the flavour
+ ptotal *= UseRandom::rnd();
+ map<long,pair<double,vector<double> > >::const_iterator pit;
+ for(pit=partonprob.begin();pit!=partonprob.end();++pit) {
+ if(pit->second.first>=ptotal) break;
+ else ptotal -= pit->second.first;
+ }
+ if(pit==partonprob.end())
+ throw Exception() << "Can't select parton for forced backward evolution in "
+ << "HwRemDecayer::forceSplit" << Exception::eventerror;
+ // select z
+ unsigned int iz=0;
+ for(;iz<pit->second.second.size();++iz) {
+ if(pit->second.second[iz]>ptotal) break;
+ }
+ if(iz==pit->second.second.size()) --iz;
+ double ey=exp(ymin+dely*(float(iz+1)-UseRandom::rnd()));
+ double z=ey/(1.+ey);
+ Energy2 pt2=sqr((1.-z)*q)- z*sqr(_kinCutoff);
+ // create the particle
+ if(pit->first!=ParticleID::g) child=pit->first;
+ PPtr parton = getParticleData(child)->produceParticle();
+ Energy2 emittedm2 = sqr(parton->dataPtr()->constituentMass());
+ // Now boost pcm and pf to z only frame
+ Lorentz5Momentum p_ref = Lorentz5Momentum(0.0*MeV, beam.vect());
+ Lorentz5Momentum n_ref = Lorentz5Momentum(0.0*MeV, -beam.vect());
+ // generate phi and compute pt of branching
+ double phi = Constants::twopi*UseRandom::rnd();
+ Energy pt=sqrt(pt2);
+ Lorentz5Momentum qt = LorentzMomentum(pt*cos(phi), pt*sin(phi), 0.0*MeV, 0.0*MeV);
+ // compute alpha for previous particle
+ Energy2 p_dot_n = p_ref*n_ref;
+ double lastalpha = pf*n_ref/p_dot_n;
+ Lorentz5Momentum qtout=qt;
+ Energy2 qtout2=-qt*qt;
+ double alphaout=(1.-z)/z*lastalpha;
+ double betaout=0.5*(emittedm2+qtout2)/alphaout/p_dot_n;
+ Lorentz5Momentum k=alphaout*p_ref+betaout*n_ref+qtout;
+ k.rescaleMass();
+ parton->set5Momentum(k);
+ pf+=k;
+ lastQ=q;
+ lastx/=z;
+ p += parton->momentum();
+ thestep->addDecayProduct(rem,parton,false);
+ return parton;
+}
+
+void HwRemDecayer::setRemMasses() const {
+ // get the masses of the remnants
+ Energy mrem[2];
+ Lorentz5Momentum ptotal,pnew[2];
+ vector<tRemPPtr> theprocessed;
+ theprocessed.push_back(theRems.first);
+ theprocessed.push_back(theRems.second);
+ // one remnant in e.g. DIS
+ if(!theprocessed[0]||!theprocessed[1]) {
+ tRemPPtr rem = theprocessed[0] ? theprocessed[0] : theprocessed[1];
+ Lorentz5Momentum deltap(rem->momentum());
+ // find the diquark and momentum we still need in the energy
+ tPPtr diquark;
+ vector<PPtr> progenitors;
+ for(unsigned int ix=0;ix<rem->children().size();++ix) {
+ if(!DiquarkMatcher::Check(rem->children()[ix]->data())) {
+ progenitors.push_back(rem->children()[ix]);
+ deltap -= rem->children()[ix]->momentum();
+ }
+ else
+ diquark = rem->children()[ix];
}
- }
- // forced splitting for second parton
- if(partons.second->data().coloured()) {
- try{
- split(partons.second, theContent.second, theRems.second,
- theUsed.second, theMaps.second, pdfs.second, first);
- // additional check for the remnants
- // if can't do the rescale veto the emission
- if(!first&&partons.first->data().coloured()&&
- partons.second->data().coloured()) {
- Lorentz5Momentum pnew[2]=
- {theRems.first->momentum() - theUsed.first - partons.first->momentum(),
- theRems.second->momentum() - theUsed.second - partons.second->momentum()};
-
- pnew[0].setMass(getParticleData(theContent.first.RemID())->constituentMass());
- pnew[0].rescaleEnergy();
- pnew[1].setMass(getParticleData(theContent.second.RemID())->constituentMass());
- pnew[1].rescaleEnergy();
-
- for(unsigned int iy=0; iy<theRems.first->children().size(); ++iy)
- pnew[0] += theRems.first->children()[iy]->momentum();
-
- for(unsigned int iy=0; iy<theRems.second->children().size(); ++iy)
- pnew[1] += theRems.second->children()[iy]->momentum();
-
- Lorentz5Momentum ptotal=
- theRems.first ->momentum()-partons.first ->momentum()+
- theRems.second->momentum()-partons.second->momentum();
-
- if(ptotal.m() < (pnew[0].m() + pnew[1].m()) ) {
- if(partons.second->id() != ParticleID::g){
- if(partons.second==theMaps.second.back().first)
- theUsed.second -= theMaps.second.back().second->momentum();
- else
- theUsed.second -= theMaps.second.back().first->momentum();
-
- thestep->removeParticle(theMaps.second.back().first);
- thestep->removeParticle(theMaps.second.back().second);
- }
- theMaps.second.pop_back();
- throw ShowerHandler::ExtraScatterVeto();
- }
+ // now find the total momentum of the hadronic final-state to
+ // reshuffle against
+ // find the hadron for this remnant
+ tPPtr hadron=rem;
+ do hadron=hadron->parents()[0];
+ while(!hadron->parents().empty());
+ // find incoming parton to hard process from this hadron
+ tPPtr hardin =
+ generator()->currentEvent()->primaryCollision()->incoming().first==hadron ?
+ generator()->currentEvent()->primarySubProcess()->incoming().first :
+ generator()->currentEvent()->primarySubProcess()->incoming().second;
+ tPPtr parent=hardin;
+ vector<PPtr> tempprog;
+ // find the outgoing particles emitted from the backward shower
+ do {
+ assert(!parent->parents().empty());
+ tPPtr newparent=parent->parents()[0];
+ if(newparent==hadron) break;
+ for(unsigned int ix=0;ix<newparent->children().size();++ix) {
+ if(newparent->children()[ix]!=parent)
+ findChildren(newparent->children()[ix],tempprog);
+ }
+ parent=newparent;
+ }
+ while(parent!=hadron);
+ // add to list of potential particles to reshuffle against in right order
+ for(unsigned int ix=tempprog.size();ix>0;--ix) progenitors.push_back(tempprog[ix-1]);
+ // final-state particles which are colour connected
+ tColinePair lines = make_pair(hardin->colourLine(),hardin->antiColourLine());
+ vector<PPtr> others;
+ for(ParticleVector::const_iterator
+ cit = generator()->currentEvent()->primarySubProcess()->outgoing().begin();
+ cit!= generator()->currentEvent()->primarySubProcess()->outgoing().end();++cit) {
+ // colour connected
+ if(lines.first&&lines.first==(**cit).colourLine()) {
+ findChildren(*cit,progenitors);
+ continue;
+ }
+ // anticolour connected
+ if(lines.second&&lines.second==(**cit).antiColourLine()) {
+ findChildren(*cit,progenitors);
+ continue;
+ }
+ // not connected
+ for(unsigned int ix=0;ix<(**cit).children().size();++ix)
+ others.push_back((**cit).children()[ix]);
+ }
+ // work out how much of the system needed for rescaling
+ unsigned int iloc=0;
+ Lorentz5Momentum psystem,ptotal;
+ do {
+ psystem+=progenitors[iloc]->momentum();
+ ptotal = psystem + deltap;
+ ptotal.rescaleMass();
+ psystem.rescaleMass();
+ ++iloc;
+ if(ptotal.mass() > psystem.mass() + diquark->mass() &&
+ DISRemnantOpt_<2) break;
+ }
+ while(iloc<progenitors.size());
+ if(ptotal.mass() > psystem.mass() + diquark->mass()) --iloc;
+ if(iloc==progenitors.size()) {
+ // try touching the lepton in dis as a last restort
+ for(unsigned int ix=0;ix<others.size();++ix) {
+ progenitors.push_back(others[ix]);
+ psystem+=progenitors[iloc]->momentum();
+ ptotal = psystem + deltap;
+ ptotal.rescaleMass();
+ psystem.rescaleMass();
+ ++iloc;
+ }
+ --iloc;
+ if(ptotal.mass() > psystem.mass() + diquark->mass()) {
+ if(DISRemnantOpt_==0||DISRemnantOpt_==2)
+ Throw<Exception>() << "Warning had to adjust the momentum of the"
+ << " non-colour connected"
+ << " final-state, e.g. the scattered lepton in DIS"
+ << Exception::warning;
+ else
+ throw Exception() << "Can't set remnant momentum without adjusting "
+ << "the momentum of the"
+ << " non-colour connected"
+ << " final-state, e.g. the scattered lepton in DIS"
+ << " vetoing event"
+ << Exception::eventerror;
+ }
+ else {
+ throw Exception() << "Can't put the remnant on-shell in HwRemDecayer::setRemMasses()"
+ << Exception::eventerror;
}
}
- catch(ShowerHandler::ExtraScatterVeto){
- //case of the first forcedSplitting worked fine
- theX.first -= partons.first->momentum().rho()/parent(theRems.first)->momentum().rho();
- theX.second -= partons.second->momentum().rho()/parent(theRems.second)->momentum().rho();
-
- //case of the first interaction
- //throw veto immediately, because event get rejected anyway.
- if(first) throw ShowerHandler::ExtraScatterVeto();
-
- //secondary interactions have to end on a gluon, if parton
- //was NOT a gluon, the forced splitting particles must be removed
- if(partons.first->id() != ParticleID::g){
- if(partons.first==theMaps.first.back().first)
- theUsed.first -= theMaps.first.back().second->momentum();
- else
- theUsed.first -= theMaps.first.back().first->momentum();
-
- thestep->removeParticle(theMaps.first.back().first);
- thestep->removeParticle(theMaps.first.back().second);
+ psystem.rescaleMass();
+ LorentzRotation R = Utilities::getBoostToCM(make_pair(psystem, deltap));
+ Energy pz = SimplePhaseSpace::getMagnitude(sqr(ptotal.mass()),
+ psystem.mass(), diquark->mass());
+ LorentzRotation Rs(-(R*psystem).boostVector());
+ Rs.boost(0.0, 0.0, pz/sqrt(sqr(pz) + sqr(psystem.mass())));
+ Rs = Rs*R;
+ // put remnant on shell
+ deltap.transform(R);
+ deltap.setMass(diquark->mass());
+ deltap.setE(sqrt(sqr(diquark->mass())+sqr(pz)));
+ deltap.rescaleRho();
+ R.invert();
+ deltap.transform(R);
+ Rs = R*Rs;
+ // apply transformation to required particles to absorb recoil
+ for(unsigned int ix=0;ix<=iloc;++ix) {
+ progenitors[ix]->deepTransform(Rs);
+ }
+ diquark->set5Momentum(deltap);
+ }
+ // two remnants
+ else {
+ for(unsigned int ix=0;ix<2;++ix) {
+ if(!theprocessed[ix]) continue;
+ pnew[ix]=Lorentz5Momentum();
+ for(unsigned int iy=0;iy<theprocessed[ix]->children().size();++iy) {
+ pnew[ix]+=theprocessed[ix]->children()[iy]->momentum();
}
- theMaps.first.pop_back();
- throw ShowerHandler::ExtraScatterVeto();
+ mrem[ix]=sqrt(pnew[ix].m2());
+ }
+ // now find the remnant remnant cmf frame
+ Lorentz5Momentum prem[2]={theprocessed[0]->momentum(),
+ theprocessed[1]->momentum()};
+ ptotal=prem[0]+prem[1];
+ ptotal.rescaleMass();
+ // boost momenta to this frame
+ if(ptotal.m()< (pnew[0].m()+pnew[1].m()))
+ throw Exception() << "Not enough energy in both remnants in "
+ << "HwRemDecayer::setRemMasses() "
+ << Exception::eventerror;
+
+ Boost boostv(-ptotal.boostVector());
+ ptotal.boost(boostv);
+ for(unsigned int ix=0;ix<2;++ix) {
+ prem[ix].boost(boostv);
+ // set the masses and energies,
+ prem[ix].setMass(mrem[ix]);
+ prem[ix].setE(0.5/ptotal.m()*(sqr(ptotal.m())+sqr(mrem[ix])-sqr(mrem[1-ix])));
+ prem[ix].rescaleRho();
+ // boost back to the lab
+ prem[ix].boost(-boostv);
+ // set the momenta of the remnants
+ theprocessed[ix]->set5Momentum(prem[ix]);
+ }
+ // boost the decay products
+ Lorentz5Momentum ptemp;
+ for(unsigned int ix=0;ix<2;++ix) {
+ Boost btorest(-pnew[ix].boostVector());
+ Boost bfmrest( prem[ix].boostVector());
+ for(unsigned int iy=0;iy<theprocessed[ix]->children().size();++iy) {
+ ptemp=theprocessed[ix]->children()[iy]->momentum();
+ ptemp.boost(btorest);
+ ptemp.boost(bfmrest);
+ theprocessed[ix]->children()[iy]->set5Momentum(ptemp);
+ }
}
}
}
-void HwRemDecayer::finalize(){
- if(!theForcedSplitter) return;
- PPtr diquark;
- //Do the final Rem->Diquark or Rem->quark "decay"
- if(theRems.first) {
- diquark = theForcedSplitter->
- finalSplit(theRems.first, theContent.first.RemID(),
- theUsed.first, thestep);
- theMaps.first.push_back(make_pair(diquark, tPPtr()));
+void HwRemDecayer::findChildren(tPPtr part,vector<PPtr> & particles) const {
+ if(part->children().empty()) particles.push_back(part);
+ else {
+ for(unsigned int ix=0;ix<part->children().size();++ix)
+ findChildren(part->children()[ix],particles);
}
- if(theRems.second) {
- diquark = theForcedSplitter->
- finalSplit(theRems.second, theContent.second.RemID(),
- theUsed.second, thestep);
- theMaps.second.push_back(make_pair(diquark, tPPtr()));
- }
- setRemMasses();
- if(theRems.first) fixColours(theMaps.first, theanti.first);
- if(theRems.second) fixColours(theMaps.second, theanti.second);
}
-
-ParticleVector HwRemDecayer::decay(const DecayMode &,
- const Particle &, Step &) const {
- throw Exception() << "HwRemDecayer::decay(...) "
- << "must not be called explicitely."
- << Exception::runerror;
- return PVector();
-}
-
-
-void HwRemDecayer::persistentOutput(PersistentOStream & os) const {
- os << theForcedSplitter;
-}
-
-void HwRemDecayer::persistentInput(PersistentIStream & is, int) {
- is >> theForcedSplitter;
-}
-
-ClassDescription<HwRemDecayer> HwRemDecayer::initHwRemDecayer;
-// Definition of the static class description member.
-
-void HwRemDecayer::Init() {
-
- static ClassDocumentation<HwRemDecayer> documentation
- ("There is no documentation for the HwRemDecayer class");
-
- static Reference<HwRemDecayer,ForcedSplitting> interfaceForcedSplitting
- ("ForcedSplitter",
- "Object used for the forced splitting of the Remnant. "
- "Set NULL to turn off forced splitting.",
- &HwRemDecayer::theForcedSplitter, false, false, true, true, false);
-}
diff --git a/PDF/HwRemDecayer.h b/PDF/HwRemDecayer.h
--- a/PDF/HwRemDecayer.h
+++ b/PDF/HwRemDecayer.h
@@ -1,322 +1,426 @@
// -*- C++ -*-
//
// HwRemDecayer.h is a part of Herwig++ - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2007 The Herwig Collaboration
//
// Herwig++ is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_HwRemDecayer_H
#define HERWIG_HwRemDecayer_H
//
// This is the declaration of the HwRemDecayer class.
//
#include "ThePEG/PDT/RemnantDecayer.h"
#include "ThePEG/Handlers/EventHandler.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/EventRecord/SubProcess.h"
-#include "ForcedSplitting.h"
+#include "ThePEG/PDF/BeamParticleData.h"
+#include "Herwig++/Shower/Couplings/ShowerAlpha.h"
#include "HwRemDecayer.fh"
namespace Herwig {
using namespace ThePEG;
/**
- * Here is the documentation of the HwRemDecayer class. This
- * class is responsible for the decay of the remnants. Additional
- * secondary scatter have to be evolved backwards to a gluon, the
+ * The HwRemDecayer class is responsible for the decay of the remnants. Additional
+ * secondary scatters have to be evolved backwards to a gluon, the
* first/hard interaction has to be evolved back to a valence quark.
- * This is necessary because the Cluster Hadronization can only cope
- * with diquarks as remnants. All this is generated inside this class,
- * which main methods are then called by the ShowerHandler. The kinematics
- * of the splittings is calculated inside ForcedSplitting.
+ * This is all generated inside this class,
+ * which main methods are then called by the ShowerHandler.
+ *
+ * A simple forced splitting algorithm is used.
+ * This takes the Remnant object produced from the PDF and backward
+ * evolution (hadron - parton) and produce partons with the remaining
+ * flavours and with the correct colour connections.
+ *
+ * The algorithim operates by starting with the parton which enters the hard process.
+ * If this is from the sea there is a forced branching to produce the antiparticle
+ * from a gluon branching. If the parton entering the hard process was a gluon, or
+ * a gluon was produced from the first step of the algorithm, there is then a further
+ * branching back to a valence parton. After these partons have been produced a quark or
+ * diquark is produced to give the remaining valence content of the incoming hadron.
+ *
+ * The forced branching are generated using a scale between QSpac and EmissionRange times
+ * the minimum scale. The energy fractions are then distributed using
+ * \f[\frac{\alpha_S}{2\pi}\frac{P(z)}{z}f(x/z,\tilde{q})\f]
+ * with the massless splitting functions.
*
* \author Manuel B\"ahr
*
* @see \ref HwRemDecayerInterfaces "The interfaces"
* defined for HwRemDecayer.
*/
class HwRemDecayer: public RemnantDecayer {
public:
/** Typedef to store information about colour partners */
typedef vector<pair<tPPtr, tPPtr> > PartnerMap;
public:
+ /**
+ * The default constructor.
+ */
+ inline HwRemDecayer();
+
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* Check if this decayer can perfom the decay specified by the
* given decay mode.
* @param dm the DecayMode describing the decay.
* @return true if this decayer can handle the given mode, otherwise false.
*/
- virtual bool accept(const DecayMode & dm) const;
+ inline virtual bool accept(const DecayMode & dm) const;
/**
* Return true if this decayer can handle the extraction of the \a
* extracted parton from the given \a particle.
*/
- virtual bool canHandle(tcPDPtr parent, tcPDPtr extracted) const;
+ inline virtual bool canHandle(tcPDPtr parent, tcPDPtr extracted) const;
/**
* Return true if this decayed can extract more than one parton from
* a particle.
*/
- virtual bool multiCapable() const;
+ inline virtual bool multiCapable() const;
/**
* Perform a decay for a given DecayMode and a given Particle instance.
* @param dm the DecayMode describing the decay.
* @param p the Particle instance to be decayed.
* @param step the step we are working on.
* @return a ParticleVector containing the decay products.
*/
virtual ParticleVector decay(const DecayMode & dm, const Particle & p, Step & step) 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();
/**
* Do several checks and initialization, for remnantdecay inside ShowerHandler.
*/
- void initialize(pair<tRemPPtr, tRemPPtr> rems, Step & step, Energy forcedSplitScale);
+ void initialize(pair<tRemPPtr, tRemPPtr> rems, tPPair beam, Step & step,
+ Energy forcedSplitScale);
/**
* Perform the acual forced splitting.
* @param partons is a pair of ThePEG::Particle pointers which store the final
* partons on which the shower ends.
* @param pdfs are pointers to the pdf objects for both beams
* @param first is a flage wether or not this is the first or a secondary interation
*/
void doSplit(pair<tPPtr, tPPtr> partons, pair<tcPDFPtr, tcPDFPtr> pdfs, bool first);
/**
* Perform the final creation of the diquarks. Set the remnant masses and do
* all colour connections.
*/
void finalize();
+ /**
+ * Find the children
+ */
+ void findChildren(tPPtr,vector<PPtr> &) const;
+
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
- inline virtual IBPtr clone() const {
- return new_ptr(*this);
- }
+ inline 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.
*/
- inline virtual IBPtr fullclone() const {
- return new_ptr(*this);
- }
+ inline 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.
+ */
+ inline virtual void doinit() throw(InitException);
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<HwRemDecayer> initHwRemDecayer;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
HwRemDecayer & operator=(const HwRemDecayer &);
private:
/**
* Simple struct to store info about baryon quark and di-quark
* constituents.
*/
- struct HadronContent {
- /**
- * Randomly choose a valence flavour from \a flav.
- */
- int getValence();
+ struct HadronContent {
/**
* manually extract the valence flavour \a id.
*/
- void extract(int id);
+ inline void extract(int id);
/**
* Return a proper particle ID assuming that \a id has been removed
* from the hadron.
*/
long RemID() const;
/**
* Method to determine whether \a parton is a quark from the sea.
* @return TRUE if \a parton is neither a valence quark nor a gluon.
*/
- bool isSeaQuark(tcPPtr parton) const;
+ inline bool isSeaQuark(tcPPtr parton) const;
/**
* Method to determine whether \a parton is a valence quark.
*/
- bool isValenceQuark(tcPPtr parton) const;
+ inline bool isValenceQuark(tcPPtr parton) const;
/** The valence flavours of the corresponding baryon. */
vector<int> flav;
/** The array index of the extracted particle. */
int extracted;
/** -1 if the particle is an anti-particle. +1 otherwise. */
- int sign;
+ int sign;
+
+ /** The ParticleData objects of the hadron */
+ tcPDPtr hadron;
};
/**
* Return a HadronContent struct from a PPtr to a hadron.
*/
HadronContent getHadronContent(tcPPtr hadron) const;
/**
* Do the forced Splitting of the Remnant with respect to the
* extracted parton \a parton.
* @param parton = PPtr to the parton going into the subprocess.
* @param content = HadronContent struct to keep track of flavours.
* @param rem = Pointer to the ThePEG::RemnantParticle.
* @param used = Momentum vector to keep track of remaining momenta.
* @param partners = Vector of pairs filled with tPPtr to the particles
* which should be colour connected.
* @param pdf pointer to the PDF Object which is used for this particle
* @param first = Flag for the first interaction.
*/
void split(tPPtr parton, HadronContent & content, tRemPPtr rem,
Lorentz5Momentum & used, PartnerMap & partners, tcPDFPtr pdf, bool first);
/**
* Do all colour connections.
* @param partners = Object that holds the information which particles to connect.
* @param anti = flag to indicate, if (anti)colour was extracted as first parton.
*/
void fixColours(PartnerMap partners, bool anti) const;
/**
* Set the momenta of the Remnants properly and boost the decay particles.
*/
void setRemMasses() const;
/**
- * This is a pointer to the Herwig::ForcedSplitting object
+ * This creates a parton from the remaining flavours of the hadron. The
+ * last parton used was a valance parton, so only 2 (or 1, if meson) flavours
+ * remain to be used.
*/
- ForcedSplittingPtr theForcedSplitter;
+ inline PPtr finalSplit(const tRemPPtr rem, long remID, Lorentz5Momentum) const;
+
+ /**
+ * This takes the particle and find a splitting for np -> p + child and
+ * creates the correct kinematics and connects for such a split. This
+ * Splitting has an upper bound on qtilde given by the energy argument
+ * @param rem The Remnant
+ * @param child The PDG code for the outgoing particle
+ * @param oldQ The maximum scale for the evolution
+ * @param oldx The fraction of the hadron's momentum carried by the last parton
+ * @param pf The momentum of the last parton at input and after branching at output
+ * @param p The total emitted momentum
+ */
+ PPtr forceSplit(const tRemPPtr rem, long child, Energy &oldQ, double &oldx,
+ Lorentz5Momentum &pf, Lorentz5Momentum &p,
+ HadronContent & content) const;
/**
* A flag which indicates, whether the extracted valence quark was a
* anti particle.
*/
pair<bool, bool> theanti;
/**
* variable to sum up the x values of the extracted particles
*/
pair<double, double> theX;
/**Pair of HadronContent structs to know about the quark content of the beams*/
pair<HadronContent, HadronContent> theContent;
/**Pair of Lorentz5Momentum to keep track of the forced splitting product momenta*/
pair<Lorentz5Momentum, Lorentz5Momentum> theUsed;
/**
* Pair of PartnerMap's to store the particles, which will be colour
* connected in the end.
*/
pair<PartnerMap, PartnerMap> theMaps;
/**
* Variable to hold a pointer to the current step. The variable is used to
* determine, wether decay(const DecayMode & dm, const Particle & p, Step & step)
* has been called in this event or not.
*/
StepPtr thestep;
/**
* Pair of Remnant pointers. This is needed to boost
* in the Remnant-Remnant CMF after all have been decayed.
*/
pair<RemPPtr, RemPPtr> theRems;
/**
+ * The beam particle data for the current incoming hadron
+ */
+ mutable tcPPtr theBeam;
+
+ /**
+ * the beam data
+ */
+ mutable Ptr<BeamParticleData>::const_pointer theBeamData;
+
+ /**
+ * The PDF for the current initial-state shower
+ */
+ mutable tcPDFPtr _pdf;
+
+private:
+
+ /**
+ * The kinematic cut-off
+ */
+ Energy _kinCutoff;
+
+ /**
* The PDF freezing scale as set in ShowerHandler
*/
Energy _forcedSplitScale;
+ /**
+ * Range for emission
+ */
+ double _range;
+
+ /**
+ * Size of the bins in z for the interpolation
+ */
+ double _zbin;
+
+ /**
+ * Size of the bins in y for the interpolation
+ */
+ double _ybin;
+
+ /**
+ * Maximum number of bins for the z interpolation
+ */
+ int _nbinmax;
+
+ /**
+ * Pointer to the object calculating the QCD coupling
+ */
+ ShowerAlphaPtr _alpha;
+
+ /**
+ * Option for the DIS remnant
+ */
+ unsigned int DISRemnantOpt_;
};
+
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of HwRemDecayer. */
template <>
struct BaseClassTrait<Herwig::HwRemDecayer,1> {
/** Typedef of the first base class of HwRemDecayer. */
typedef RemnantDecayer NthBase;
};
/** This template specialization informs ThePEG about the name of
* the HwRemDecayer class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::HwRemDecayer>
: public ClassTraitsBase<Herwig::HwRemDecayer> {
/** Return a platform-independent class name */
static string className() { return "Herwig::HwRemDecayer"; }
/**
* The name of a file containing the dynamic library where the class
* HwRemDecayer is implemented. It may also include several, space-separated,
* libraries if the class HwRemDecayer depends on other classes (base classes
* excepted). In this case the listed libraries will be dynamically
* linked in the order they are specified.
*/
static string library() { return "HwRemDecayer.so"; }
};
/** @endcond */
}
+#include "HwRemDecayer.icc"
+
#endif /* HERWIG_HwRemDecayer_H */
diff --git a/PDF/HwRemDecayer.icc b/PDF/HwRemDecayer.icc
new file mode 100644
--- /dev/null
+++ b/PDF/HwRemDecayer.icc
@@ -0,0 +1,93 @@
+// -*- C++ -*-
+//
+// HwRemDecayer.icc is a part of Herwig++ - A multi-purpose Monte Carlo event generator
+// Copyright (C) 2002-2007 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 inlined member functions of
+// the HwRemDecayer class.
+//
+#include "Herwig++/PDT/StandardMatchers.h"
+#include "ThePEG/PDT/StandardMatchers.h"
+
+namespace Herwig {
+
+inline HwRemDecayer::HwRemDecayer() : _kinCutoff(0.75*GeV),
+ _forcedSplitScale(2.5*GeV),
+ _range(1.1),
+ _zbin(0.05),_ybin(0.),
+ _nbinmax(100),
+ DISRemnantOpt_(0)
+{}
+
+inline IBPtr HwRemDecayer::clone() const {
+ return new_ptr(*this);
+}
+
+inline IBPtr HwRemDecayer::fullclone() const {
+ return new_ptr(*this);
+}
+
+inline bool HwRemDecayer::HadronContent::isSeaQuark(tcPPtr parton) const{
+ return ((parton->id() != ParticleID::g) && ( !isValenceQuark(parton) ) );
+}
+
+inline bool HwRemDecayer::HadronContent::isValenceQuark(tcPPtr parton) const{
+ int id(sign*parton->id());
+ return find(flav.begin(),flav.end(),id) != flav.end();
+}
+
+inline bool HwRemDecayer::accept(const DecayMode &) const {
+ return true;
+}
+
+inline bool HwRemDecayer::multiCapable() const {
+ return true;
+}
+
+inline bool HwRemDecayer::
+canHandle(tcPDPtr particle, tcPDPtr parton) const {
+ if(!StandardQCDPartonMatcher::Check(*parton)) return false;
+ return HadronMatcher::Check(*particle) || particle->id()==ParticleID::gamma;
+}
+
+inline PPtr HwRemDecayer::finalSplit(const tRemPPtr rem, long remID,
+ Lorentz5Momentum usedMomentum) const {
+ // Create the remnant and set its momentum, also reset all of the decay
+ // products from the hadron
+ PPtr remnant = new_ptr(Particle(getParticleData(remID)));
+ Lorentz5Momentum prem(rem->momentum()-usedMomentum);
+ prem.setMass(getParticleData(remID)->constituentMass());
+ prem.rescaleEnergy();
+ remnant->set5Momentum(prem);
+ // Add the remnant to the step, but don't do colour connections
+ thestep->addDecayProduct(rem,remnant,false);
+ return remnant;
+}
+
+inline void HwRemDecayer::HadronContent::extract(int id) {
+ for(unsigned int i=0; i<flav.size(); i++) {
+ if(id == sign*flav[i]){
+ if(hadron->id() == ParticleID::gamma) {
+ flav[0] = id;
+ flav[1] = -id;
+ extracted = 0;
+ flav.resize(2);
+ }
+ else {
+ extracted = i;
+ }
+ break;
+ }
+ }
+}
+
+inline void HwRemDecayer::doinit() throw(InitException) {
+ Interfaced::doinit();
+ _ybin=0.25/_zbin;
+}
+
+}
diff --git a/PDF/LeptonRemnant.cc b/PDF/LeptonRemnant.cc
new file mode 100644
--- /dev/null
+++ b/PDF/LeptonRemnant.cc
@@ -0,0 +1,164 @@
+// -*- C++ -*-
+//
+// This is the implementation of the non-inlined, non-templated member
+// functions of the LeptonRemnant class.
+//
+
+#include "LeptonRemnant.h"
+#include "ThePEG/PDT/EnumParticles.h"
+#include "ThePEG/Interface/Parameter.h"
+#include "ThePEG/Interface/ClassDocumentation.h"
+#include "ThePEG/Persistency/PersistentOStream.h"
+#include "ThePEG/Persistency/PersistentIStream.h"
+#include "ThePEG/Repository/UseRandom.h"
+
+using namespace Herwig;
+
+void LeptonRemnant::doinit() throw(InitException) {
+ photon = getParticleData(ParticleID::gamma);
+ RemnantHandler::doinit();
+}
+
+void LeptonRemnant::persistentOutput(PersistentOStream & os) const {
+ os << photon << minX;
+}
+
+void LeptonRemnant::persistentInput(PersistentIStream & is, int) {
+ is >> photon >> minX;
+}
+
+ClassDescription<LeptonRemnant> LeptonRemnant::initLeptonRemnant;
+// Definition of the static class description member.
+
+void LeptonRemnant::Init() {
+
+ static ClassDocumentation<LeptonRemnant> documentation
+ ("The LeptonRemnant class is design to generate the remnant in leptonic collisions");
+
+ static Parameter<LeptonRemnant,double> interfaceMinX
+ ("MinX",
+ "The minimum energy fraction allowed for a photon remnant. "
+ "If less than this no remnant will be emitted.",
+ &LeptonRemnant::minX, 1.0e-10, 0.0, 1.0,
+ true, false, true);
+}
+
+bool LeptonRemnant::
+canHandle(tcPDPtr particle, const cPDVector & partons) const {
+ // check that we have an incoming lepton beam
+ int id = abs(particle->id());
+ if( id != ParticleID::eminus && id != ParticleID::muminus) return false;
+ for ( cPDVector::const_iterator it = partons.begin(); it != partons.end(); ++it ) {
+ if ( (**it).id() != particle->id() &&
+ (**it).id() != ParticleID::gamma ) return false;
+ }
+ return true;
+}
+
+Lorentz5Momentum LeptonRemnant::
+generate(PartonBinInstance & pb, const double *,
+ Energy2 scale, const LorentzMomentum & parent) const {
+ // photon into hard process and lepton remnant
+ if ( pb.particleData() != pb.partonData() &&
+ pb.partonData()->id() == ParticleID::gamma) {
+ cerr << "testing in generate A\n";
+ exit(0);
+// if ( pb.eps() < minX ) {
+// pb.remnants(PVector());
+// return parent;
+// }
+// LorentzMomentum p(0.0*GeV, 0.0*GeV, parent.rho(), parent.e());
+// TransverseMomentum qt;
+// Energy2 qt2 = 0.0*GeV2;
+// if ( scale >= 0.0*GeV2 ) {
+// qt2 = pb.eps()*(pb.xi()*parent.m2() + scale);
+// double phi = rnd(2.0*Constants::pi);
+// qt = TransverseMomentum(sqrt(qt2)*cos(phi), sqrt(qt2)*sin(phi));
+// }
+// Energy pl = p.plus()*pb.eps();
+// LorentzMomentum prem = lightCone(pl, qt2/pl, qt);
+// prem.rotateY(parent.theta());
+// prem.rotateZ(parent.phi());
+// PPtr rem = photon->produceParticle(prem, 0.0*GeV);
+// pb.remnants(PVector(1, rem));
+// return parent - rem->momentum();
+ }
+ else if( pb.particleData() == pb.partonData() ) {
+ if ( pb.eps() < minX ) {
+ pb.remnants(PVector());
+ return parent;
+ }
+ LorentzMomentum p(0.0*GeV, 0.0*GeV, parent.rho(), parent.e());
+ TransverseMomentum qt;
+ Energy2 qt2 = 0.0*GeV2;
+ if ( scale >= 0.0*GeV2 ) {
+ qt2 = pb.eps()*(pb.xi()*parent.m2() + scale);
+ double phi = rnd(2.0*Constants::pi);
+ qt = TransverseMomentum(sqrt(qt2)*cos(phi), sqrt(qt2)*sin(phi));
+ }
+ Energy pl = p.plus()*pb.eps();
+ LorentzMomentum prem = lightCone(pl, qt2/pl, qt);
+ prem.rotateY(parent.theta());
+ prem.rotateZ(parent.phi());
+ PPtr rem = photon->produceParticle(prem, 0.0*GeV);
+ pb.remnants(PVector(1, rem));
+ return parent - rem->momentum();
+ }
+ else {
+ throw RemnantHandlerException
+ (pb.particleData()->name(), pb.partonData()->name(), name(),
+ "The remnant handler can only extract leptons of the"
+ " same type and photons from leptons.");
+ }
+}
+
+Lorentz5Momentum LeptonRemnant::
+generate(PartonBinInstance & pb, const double *, Energy2 scale, Energy2,
+ const LorentzMomentum & parent) const {
+ // photon into hard process and lepton remnant
+ if ( pb.particleData() != pb.partonData() &&
+ pb.partonData()->id() == ParticleID::gamma) {
+ LorentzMomentum p(0.0*GeV, 0.0*GeV, parent.rho(), parent.e());
+ TransverseMomentum qt;
+ Energy2 qt2 = 0.0*GeV2;
+ if ( scale >= 0.0*GeV2 ) {
+ qt2 = pb.eps()*(pb.xi()*parent.m2() + scale);
+ double phi = rnd(2.0*Constants::pi);
+ qt = TransverseMomentum(sqrt(qt2)*cos(phi), sqrt(qt2)*sin(phi));
+ }
+ Energy pl = p.plus()*pb.eps();
+ LorentzMomentum prem = lightCone(pl, qt2/pl, qt);
+ prem.rotateY(parent.theta());
+ prem.rotateZ(parent.phi());
+ PPtr rem = pb.particleData()->produceParticle(prem, pb.particleData()->mass());
+ pb.remnants(PVector(1, rem));
+ return parent - rem->momentum();
+ }
+ else if ( pb.particleData() == pb.partonData() ) {
+ if ( pb.eps() < minX ) {
+ pb.remnants(PVector());
+ return parent;
+ }
+ LorentzMomentum p(0.0*GeV, 0.0*GeV, parent.rho(), parent.e());
+ TransverseMomentum qt;
+ Energy2 qt2 = 0.0*GeV2;
+ if ( scale >= 0.0*GeV2 ) {
+ qt2 = pb.eps()*(pb.xi()*parent.m2() + scale);
+ double phi = rnd(2.0*Constants::pi);
+ qt = TransverseMomentum(sqrt(qt2)*cos(phi), sqrt(qt2)*sin(phi));
+ }
+ Energy pl = p.plus()*pb.eps();
+ LorentzMomentum prem = lightCone(pl, qt2/pl, qt);
+ prem.rotateY(parent.theta());
+ prem.rotateZ(parent.phi());
+ PPtr rem = photon->produceParticle(prem, 0.0*GeV);
+ pb.remnants(PVector(1, rem));
+ return parent - rem->momentum();
+ }
+ else {
+ throw RemnantHandlerException
+ (pb.particleData()->name(), pb.partonData()->name(), name(),
+ "The remnant handler can only extract leptons of the"
+ " same type and photons from leptons.");
+ }
+}
diff --git a/PDF/LeptonRemnant.fh b/PDF/LeptonRemnant.fh
new file mode 100644
--- /dev/null
+++ b/PDF/LeptonRemnant.fh
@@ -0,0 +1,22 @@
+// -*- C++ -*-
+//
+// This is the forward declaration of the LeptonRemnant class.
+//
+#ifndef HERWIG_LeptonRemnant_FH
+#define HERWIG_LeptonRemnant_FH
+
+#include "ThePEG/Config/Pointers.h"
+
+namespace Herwig {
+
+class LeptonRemnant;
+
+}
+
+namespace ThePEG {
+
+ThePEG_DECLARE_POINTERS(Herwig::LeptonRemnant,LeptonRemnantPtr);
+
+}
+
+#endif
diff --git a/PDF/LeptonRemnant.h b/PDF/LeptonRemnant.h
new file mode 100644
--- /dev/null
+++ b/PDF/LeptonRemnant.h
@@ -0,0 +1,197 @@
+// -*- C++ -*-
+#ifndef HERWIG_LeptonRemnant_H
+#define HERWIG_LeptonRemnant_H
+//
+// This is the declaration of the LeptonRemnant class.
+//
+
+#include "ThePEG/PDF/RemnantHandler.h"
+#include "LeptonRemnant.fh"
+
+namespace Herwig {
+
+using namespace ThePEG;
+
+/**
+ * Here is the documentation of the LeptonRemnant class.
+ *
+ * @see \ref LeptonRemnantInterfaces "The interfaces"
+ * defined for LeptonRemnant.
+ */
+class LeptonRemnant: public RemnantHandler {
+
+public:
+
+ /**
+ * The default constructor.
+ */
+ inline LeptonRemnant();
+
+
+ /** @name Virtual functions mandated by the RemnantHandler base class. */
+ //@{
+ /**
+ * Return true if this remnant handler can handle extracting all
+ * specified \a partons form the given \a particle.
+ */
+ virtual bool canHandle(tcPDPtr particle, const cPDVector & partons) const;
+
+ /**
+ * Generate momenta. Generates the momenta of the extracted parton
+ * in the particle cms (but with the parton \f$x\f$ still the
+ * positive light-cone fraction) as given by the last argument, \a
+ * p. If the particle is space-like the positive and negative
+ * light-cone momenta are \f$\sqrt{-m^2}\f$ and \f$-sqrt{-m^2}\f$
+ * respectively. If the \a scale is negative, it means that the \a
+ * doScale in the previous call to nDim() was true, otherwise the
+ * given scale should be the virtuality of the extracted
+ * parton. Generated quantities which are not returned in the
+ * momentum may be saved in the PartonBin, \a pb, for later use. In
+ * particular, if the nDim() random numbers, \a r, are not enough to
+ * generate with weight one, the resulting weight should be stored
+ * with the remnantWeight() method of the parton bin.
+ */
+ virtual Lorentz5Momentum generate(PartonBinInstance & pb, const double * r,
+ Energy2 scale,
+ const LorentzMomentum & p) const;
+
+ /**
+ * Generate the momentum of the extracted parton with the \a parent
+ * momentum given by the last argument. If the \a scale is negative,
+ * it means that the doScale in the previous call to nDim() was
+ * true, otherwise the given \a scale should be the virtuality of
+ * the extracted parton. \a shat is the total invariant mass squared
+ * of the hard sub-system produced by the extracted parton and the
+ * primary parton entering from the other side. Generated quantities
+ * which are not returned in the momentum may be saved in the
+ * PartonBinInstance, \a pb, for later use. In particular, if the
+ * nDim() random numbers, \a r, are not enough to generate with
+ * weight one, the resulting weight should be stored with the
+ * remnantWeight() method of the parton bin.
+ */
+ virtual Lorentz5Momentum generate(PartonBinInstance & pb, const double * r,
+ Energy2 scale, Energy2 shat,
+ const LorentzMomentum & parent) 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.
+ */
+ inline 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.
+ */
+ inline virtual IBPtr fullclone() const;
+ //@}
+
+ /** @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() throw(InitException);
+ //@}
+
+private:
+
+ /**
+ * The minimum energy fraction allowed for a photon remnant.
+ */
+ double minX;
+
+ /**
+ * Easy access to a proton data object.
+ */
+ tPDPtr photon;
+
+private:
+
+ /**
+ * The static object used to initialize the description of this class.
+ * Indicates that this is a concrete class with persistent data.
+ */
+ static ClassDescription<LeptonRemnant> initLeptonRemnant;
+
+ /**
+ * The assignment operator is private and must never be called.
+ * In fact, it should not even be implemented.
+ */
+ LeptonRemnant & operator=(const LeptonRemnant &);
+
+};
+
+}
+
+#include "ThePEG/Utilities/ClassTraits.h"
+
+namespace ThePEG {
+
+/** @cond TRAITSPECIALIZATIONS */
+
+/** This template specialization informs ThePEG about the
+ * base classes of LeptonRemnant. */
+template <>
+struct BaseClassTrait<Herwig::LeptonRemnant,1> {
+ /** Typedef of the first base class of LeptonRemnant. */
+ typedef RemnantHandler NthBase;
+};
+
+/** This template specialization informs ThePEG about the name of
+ * the LeptonRemnant class and the shared object where it is defined. */
+template <>
+struct ClassTraits<Herwig::LeptonRemnant>
+ : public ClassTraitsBase<Herwig::LeptonRemnant> {
+ /** Return a platform-independent class name */
+ static string className() { return "Herwig::LeptonRemnant"; }
+ /**
+ * The name of a file containing the dynamic library where the class
+ * LeptonRemnant is implemented. It may also include several, space-separated,
+ * libraries if the class LeptonRemnant depends on other classes (base classes
+ * excepted). In this case the listed libraries will be dynamically
+ * linked in the order they are specified.
+ */
+ static string library() { return "HwLeptonPDF.so"; }
+};
+
+/** @endcond */
+
+}
+
+#include "LeptonRemnant.icc"
+
+#endif /* HERWIG_LeptonRemnant_H */
diff --git a/PDF/LeptonRemnant.icc b/PDF/LeptonRemnant.icc
new file mode 100644
--- /dev/null
+++ b/PDF/LeptonRemnant.icc
@@ -0,0 +1,19 @@
+// -*- C++ -*-
+//
+// This is the implementation of the inlined member functions of
+// the LeptonRemnant class.
+//
+
+namespace Herwig {
+
+inline LeptonRemnant::LeptonRemnant()
+ : minX(1.0e-10) {}
+
+inline IBPtr LeptonRemnant::clone() const {
+ return new_ptr(*this);
+}
+
+inline IBPtr LeptonRemnant::fullclone() const {
+ return new_ptr(*this);
+}
+}
diff --git a/PDF/Makefile.am b/PDF/Makefile.am
--- a/PDF/Makefile.am
+++ b/PDF/Makefile.am
@@ -1,44 +1,55 @@
-pkglib_LTLIBRARIES =
+pkglib_LTLIBRARIES =
+
+noinst_LTLIBRARIES = libHwPDF.la
+libHwPDF_la_SOURCES = \
+PartonExtractor.cc PartonExtractor.h \
+PartonExtractor.icc PartonExtractor.fh
+
pkglib_LTLIBRARIES += HwMRST.la
HwMRST_la_SOURCES = \
MRST.cc MRST.h MRST.icc
-
## add this to produce tests of the PDFs
## HwMRST_la_CPPFLAGS=$(AM_CPPFLAGS) -DMRST_TESTING
+HwMRST_la_LDFLAGS = -module -version-info 4:0:0
-HwMRST_la_LDFLAGS = -module -version-info 4:0:0
+pkglib_LTLIBRARIES += HwLeptonPDF.la
+HwLeptonPDF_la_SOURCES = \
+WeiszackerWilliamsPDF.cc WeiszackerWilliamsPDF.h \
+WeiszackerWilliamsPDF.icc WeiszackerWilliamsPDF.fh\
+LeptonRemnant.cc LeptonRemnant.h LeptonRemnant.icc LeptonRemnant.fh
+HwLeptonPDF_la_LDFLAGS = -module -version-info 3:0:0
+
EXTRA_DIST = mrst
pkglib_LTLIBRARIES += HwRemDecayer.la
HwRemDecayer_la_SOURCES = \
-HwRemDecayer.h HwRemDecayer.cc HwRemDecayer.fh \
-ForcedSplitting.h ForcedSplitting.cc ForcedSplitting.fh
+HwRemDecayer.h HwRemDecayer.icc HwRemDecayer.cc HwRemDecayer.fh
HwRemDecayer_la_LDFLAGS = -module -version-info 4:0:0
pkglib_LTLIBRARIES += HwMPIPDF.la
HwMPIPDF_la_SOURCES = \
MPIPDF.h MPIPDF.icc MPIPDF.cc MPIPDF.fh
HwMPIPDF_la_LDFLAGS = -module -version-info 3:0:0
pkglib_LTLIBRARIES += HwSatPDF.la
HwSatPDF_la_SOURCES = \
SatPDF.h SatPDF.cc SatPDF.fh
HwSatPDF_la_LDFLAGS = -module -version-info 1:0:0
if WANT_LOCAL_PDF
install-data-local:
for i in `find $(srcdir)/mrst -name '*.dat'`; \
do \
$(install_sh_DATA) $$i $(DESTDIR)$(pkgdatadir)/PDF/$${i#$(srcdir)/}; \
done
uninstall-local:
rm -rf $(DESTDIR)$(pkgdatadir)/PDF
endif
dist-hook:
rm -rf `find $(distdir)/mrst -name '.svn' -or -name '.cvsignore' -or -name 'CVS'`
diff --git a/PDF/PartonExtractor.cc b/PDF/PartonExtractor.cc
new file mode 100644
--- /dev/null
+++ b/PDF/PartonExtractor.cc
@@ -0,0 +1,46 @@
+// -*- C++ -*-
+//
+// This is the implementation of the non-inlined, non-templated member
+// functions of the PartonExtractor class.
+//
+
+#include "PartonExtractor.h"
+#include "ThePEG/Interface/ClassDocumentation.h"
+#include "ThePEG/Persistency/PersistentOStream.h"
+#include "ThePEG/Persistency/PersistentIStream.h"
+#include "ThePEG/PDT/EnumParticles.h"
+
+using namespace Herwig;
+
+void PartonExtractor::persistentOutput(ThePEG::PersistentOStream & os) const {
+}
+
+void PartonExtractor::persistentInput(ThePEG::PersistentIStream & is, int) {
+}
+
+ThePEG::ClassDescription<PartonExtractor> PartonExtractor::initPartonExtractor;
+// Definition of the static class description member.
+
+void PartonExtractor::Init() {
+
+ static ThePEG::ClassDocumentation<PartonExtractor> documentation
+ ("The PartonExtractor class of Herwig++ uses all the functionality from ThePEG"
+ " with the only change being we integrate over the off-shell mass of the "
+ " photon in processes where a photon entering the hard process is emitted"
+ "from an incoming lepton beam");
+
+}
+
+ThePEG::pair<int,int> PartonExtractor::nDims(const ThePEG::PBPair & pbins) {
+ // if photon from a lepton generate scale
+ bool genscale[2]={false,false};
+ for(unsigned int ix=0;ix<2;++ix) {
+ ThePEG::PBPtr bin = ix==0 ? pbins.first : pbins.second;
+ int id = abs(bin->particle()->id());
+ if( ( id==ThePEG::ParticleID::eminus || id==ThePEG::ParticleID::muminus ) &&
+ bin->parton()->id()==ThePEG::ParticleID::gamma )
+ genscale[ix]=true;
+ }
+ return ThePEG::make_pair(pbins.first ->nDim(genscale[0]),
+ pbins.second->nDim(genscale[1]));
+}
diff --git a/PDF/PartonExtractor.fh b/PDF/PartonExtractor.fh
new file mode 100644
--- /dev/null
+++ b/PDF/PartonExtractor.fh
@@ -0,0 +1,22 @@
+// -*- C++ -*-
+//
+// This is the forward declaration of the PartonExtractor class.
+//
+#ifndef HERWIG_PartonExtractor_FH
+#define HERWIG_PartonExtractor_FH
+
+#include "ThePEG/Config/Pointers.h"
+
+namespace Herwig {
+
+class PartonExtractor;
+
+}
+
+namespace ThePEG {
+
+ThePEG_DECLARE_POINTERS(Herwig::PartonExtractor,PartonExtractorPtr);
+
+}
+
+#endif
diff --git a/PDF/PartonExtractor.h b/PDF/PartonExtractor.h
new file mode 100644
--- /dev/null
+++ b/PDF/PartonExtractor.h
@@ -0,0 +1,137 @@
+// -*- C++ -*-
+#ifndef HERWIG_PartonExtractor_H
+#define HERWIG_PartonExtractor_H
+//
+// This is the declaration of the PartonExtractor class.
+//
+
+#include "ThePEG/PDF/PartonExtractor.h"
+#include "PartonExtractor.fh"
+
+namespace Herwig {
+
+/**
+ * Here is the documentation of the PartonExtractor class.
+ *
+ * @see \ref PartonExtractorInterfaces "The interfaces"
+ * defined for PartonExtractor.
+ */
+class PartonExtractor: public ThePEG::PartonExtractor {
+
+public:
+
+ /**
+ * The default constructor.
+ */
+ inline PartonExtractor();
+
+public:
+
+ /**
+ * Determine the number of random numbers needed to calculate
+ * \f$\hat{s}\f$ and the product of all densitiy functions.
+ */
+ virtual ThePEG::pair<int,int> nDims(const ThePEG::PBPair & pbins);
+
+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(ThePEG::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(ThePEG::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 ThePEG::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.
+ */
+ inline virtual ThePEG::IBPtr 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 ThePEG::ClassDescription<PartonExtractor> initPartonExtractor;
+
+ /**
+ * The assignment operator is private and must never be called.
+ * In fact, it should not even be implemented.
+ */
+ PartonExtractor & operator=(const PartonExtractor &);
+
+};
+
+}
+
+#include "ThePEG/Utilities/ClassTraits.h"
+
+namespace ThePEG {
+
+/** @cond TRAITSPECIALIZATIONS */
+
+/** This template specialization informs ThePEG about the
+ * base classes of PartonExtractor. */
+template <>
+struct BaseClassTrait<Herwig::PartonExtractor,1> {
+ /** Typedef of the first base class of PartonExtractor. */
+ typedef ThePEG::PartonExtractor NthBase;
+};
+
+/** This template specialization informs ThePEG about the name of
+ * the PartonExtractor class and the shared object where it is defined. */
+template <>
+struct ClassTraits<Herwig::PartonExtractor>
+ : public ClassTraitsBase<Herwig::PartonExtractor> {
+ /** Return a platform-independent class name */
+ static string className() { return "Herwig::PartonExtractor"; }
+ /**
+ * The name of a file containing the dynamic library where the class
+ * PartonExtractor is implemented. It may also include several, space-separated,
+ * libraries if the class PartonExtractor depends on other classes (base classes
+ * excepted). In this case the listed libraries will be dynamically
+ * linked in the order they are specified.
+ */
+ static string library() { return "PartonExtractor.so"; }
+};
+
+/** @endcond */
+
+}
+
+#include "PartonExtractor.icc"
+#ifndef ThePEG_TEMPLATES_IN_CC_FILE
+// #include "PartonExtractor.tcc"
+#endif
+
+#endif /* HERWIG_PartonExtractor_H */
diff --git a/PDF/PartonExtractor.icc b/PDF/PartonExtractor.icc
new file mode 100644
--- /dev/null
+++ b/PDF/PartonExtractor.icc
@@ -0,0 +1,19 @@
+// -*- C++ -*-
+//
+// This is the implementation of the inlined member functions of
+// the PartonExtractor class.
+//
+
+namespace Herwig {
+
+inline PartonExtractor::PartonExtractor() {}
+
+inline ThePEG::IBPtr PartonExtractor::clone() const {
+ return new_ptr(*this);
+}
+
+inline ThePEG::IBPtr PartonExtractor::fullclone() const {
+ return new_ptr(*this);
+}
+
+}
diff --git a/PDF/WeiszackerWilliamsPDF.cc b/PDF/WeiszackerWilliamsPDF.cc
new file mode 100644
--- /dev/null
+++ b/PDF/WeiszackerWilliamsPDF.cc
@@ -0,0 +1,85 @@
+// -*- C++ -*-
+//
+// This is the implementation of the non-inlined, non-templated member
+// functions of the WeiszackerWilliamsPDF class.
+//
+
+#include "WeiszackerWilliamsPDF.h"
+#include "ThePEG/Interface/ClassDocumentation.h"
+#include "ThePEG/Interface/Parameter.h"
+#include "ThePEG/PDT/ParticleData.h"
+#include "ThePEG/PDT/EnumParticles.h"
+#include "ThePEG/StandardModel/StandardModelBase.h"
+#include "ThePEG/Repository/EventGenerator.h"
+
+using namespace Herwig;
+
+bool WeiszackerWilliamsPDF::canHandleParticle(tcPDPtr particle) const {
+ return ( abs(particle->id()) == ParticleID::eminus ||
+ abs(particle->id()) == ParticleID::muminus );
+}
+
+cPDVector WeiszackerWilliamsPDF::partons(tcPDPtr) const {
+ // only photon
+ return cPDVector(1,getParticleData(ParticleID::gamma));
+}
+
+double WeiszackerWilliamsPDF::xfl(tcPDPtr particle, tcPDPtr parton, Energy2 partonScale,
+ double l, Energy2 ) const {
+ if(parton->id()!=ParticleID::gamma) return 0.;
+ double x(exp(-l));
+ return 0.5*SM().alphaEM()/Constants::pi*(1.+sqr(1.-x))/x
+ *log(partonScale/sqr(particle->mass()));
+}
+
+double WeiszackerWilliamsPDF::xfvl(tcPDPtr, tcPDPtr, Energy2, double,
+ Energy2) const {
+ // valence density is zero
+ return 0.0;
+}
+
+
+NoPIOClassDescription<WeiszackerWilliamsPDF>
+WeiszackerWilliamsPDF::initWeiszackerWilliamsPDF;
+// Definition of the static class description member.
+
+void WeiszackerWilliamsPDF::Init() {
+
+ static ClassDocumentation<WeiszackerWilliamsPDF> documentation
+ ("The WeiszackerWilliamsPDF provides the PDF for a photon inside"
+ " an incoming lepton in the Weisszacker-Williams approximation");
+
+ static Parameter<WeiszackerWilliamsPDF,Energy2> interfaceQ2Min
+ ("Q2Min",
+ "Minimum value of the magnitude of Q^2 for the photon",
+ &WeiszackerWilliamsPDF::_q2min, GeV2, 0.0*GeV2, 0.0*GeV2, 100.0*GeV2,
+ false, false, Interface::limited);
+
+ static Parameter<WeiszackerWilliamsPDF,Energy2> interfaceQ2Max
+ ("Q2Max",
+ "Maximum value of the magnitude of Q^2 for the photon",
+ &WeiszackerWilliamsPDF::_q2max, GeV2, 4.0*GeV2, 0.0*GeV2, 100.0*GeV2,
+ false, false, Interface::limited);
+
+}
+
+double WeiszackerWilliamsPDF::
+flattenScale(tcPDPtr a, tcPDPtr b, const PDFCuts & c,
+ double l, double z, double & jacobian) const {
+ double x = exp(-l);
+ Energy2 qqmax = min(_q2max,sqr(x)*c.sMax());
+ Energy2 qqmin = max(_q2min,sqr(x)*sqr(a->mass())/(1.-x));
+ if(qqmin>=qqmax) {
+ jacobian = 0.;
+ return 0.;
+ }
+ double low(log(qqmin/c.sMax())),upp(log(qqmax/c.sMax()));
+ jacobian *= upp-low;
+ return exp(low+z*(upp-low));
+}
+
+double WeiszackerWilliamsPDF::flattenL(tcPDPtr, tcPDPtr, const PDFCuts & c,
+ double z, double & jacobian) const {
+ jacobian *= c.lMax() - c.lMin();
+ return c.lMin() + z*jacobian;
+}
diff --git a/PDF/WeiszackerWilliamsPDF.fh b/PDF/WeiszackerWilliamsPDF.fh
new file mode 100644
--- /dev/null
+++ b/PDF/WeiszackerWilliamsPDF.fh
@@ -0,0 +1,22 @@
+// -*- C++ -*-
+//
+// This is the forward declaration of the WeiszackerWilliamsPDF class.
+//
+#ifndef HERWIG_WeiszackerWilliamsPDF_FH
+#define HERWIG_WeiszackerWilliamsPDF_FH
+
+#include "ThePEG/Config/Pointers.h"
+
+namespace Herwig {
+
+class WeiszackerWilliamsPDF;
+
+}
+
+namespace ThePEG {
+
+ThePEG_DECLARE_POINTERS(Herwig::WeiszackerWilliamsPDF,WeiszackerWilliamsPDFPtr);
+
+}
+
+#endif
diff --git a/PDF/WeiszackerWilliamsPDF.h b/PDF/WeiszackerWilliamsPDF.h
new file mode 100644
--- /dev/null
+++ b/PDF/WeiszackerWilliamsPDF.h
@@ -0,0 +1,189 @@
+// -*- C++ -*-
+#ifndef HERWIG_WeiszackerWilliamsPDF_H
+#define HERWIG_WeiszackerWilliamsPDF_H
+//
+// This is the declaration of the WeiszackerWilliamsPDF class.
+//
+
+#include "ThePEG/PDF/PDFBase.h"
+#include "WeiszackerWilliamsPDF.fh"
+
+namespace Herwig {
+
+using namespace ThePEG;
+
+/**
+ * Here is the documentation of the WeiszackerWilliamsPDF class.
+ *
+ * @see \ref WeiszackerWilliamsPDFInterfaces "The interfaces"
+ * defined for WeiszackerWilliamsPDF.
+ */
+class WeiszackerWilliamsPDF: public PDFBase {
+
+public:
+
+ /**
+ * Default constructor
+ */
+ inline WeiszackerWilliamsPDF();
+
+ /** @name Virtual functions to be overridden by sub-classes. */
+ //@{
+ /**
+ * Return true if this PDF can handle the extraction of partons from
+ * the given \a particle.
+ */
+ virtual bool canHandleParticle(tcPDPtr particle) const;
+
+ /**
+ * Return the partons which this PDF may extract from the given
+ * \a particle.
+ */
+ virtual cPDVector partons(tcPDPtr particle) const;
+
+ /**
+ * The density. Return the pdf for the given \a parton inside the
+ * given \a particle for the virtuality \a partonScale and
+ * logarithmic momentum fraction \a l \f$(l=\log(1/x)\$f. The \a
+ * particle is assumed to have a virtuality \a particleScale.
+ */
+ virtual double xfl(tcPDPtr particle, tcPDPtr parton, Energy2 partonScale,
+ double l, Energy2 particleScale = 0.0*GeV2) const;
+
+ /**
+ * The valence density. Return the pdf for the given cvalence \a
+ * parton inside the given \a particle for the virtuality \a
+ * partonScale and logarithmic momentum fraction \a l
+ * \f$(l=\log(1/x)\$f. The \a particle is assumed to have a
+ * virtuality \a particleScale. If not overidden by a sub class this
+ * will return zero.
+ */
+ virtual double xfvl(tcPDPtr particle, tcPDPtr parton, Energy2 partonScale,
+ double l, Energy2 particleScale = 0.0*GeV2) const;
+
+ /**
+ * Generate scale (as a fraction of the maximum scale). If the PDF
+ * contains strange peaks which can be difficult to handle, this
+ * function may be overwritten to return an appropriate scale
+ * \f$Q^2/Q^2_{\max}\f$ for a \a z uniformly distributed in
+ * ]0,1[. Also the jacobobian of the \f$Q^2/Q^2_{\max}\rightarrow
+ * z\f$ variable transformation must multiply the \a jacobian
+ * argument. The default version will simply use the function
+ * \f$Q^2/Q^2_{\max} = (Q^2_{\max}/Q^2_{\min})^(z-1)\f$ or, if
+ * \f$Q^2_{\min}\f$ is zero, \f$Q^2/Q^2_{\max} = z\f$ (where the
+ * limits are set by \a cut).
+ */
+ virtual double flattenScale(tcPDPtr particle, tcPDPtr parton,
+ const PDFCuts & cut, double l, double z,
+ double & jacobian) const;
+
+ /**
+ * Generate a momentum fraction. If the PDF contains strange peaks
+ * which can be difficult to handle, this function may be
+ * overwritten to return an appropriate \f$l=\log(1/x)\f$ for a \a z
+ * uniformly distributed in ]0,1[. Also the jacobobian of the
+ * \f$l\rightarrow z\f$ variable transformation must in the function
+ * multiply the \a jacobian argument. The default version will
+ * simply use the function \f$l(z) = l_{\min} +
+ * z*(l_{\max}-l_{\min})\f$ (where the limits are set by \a cut).
+ */
+ virtual double flattenL(tcPDPtr particle, tcPDPtr parton, const PDFCuts &cut,
+ double z, double & jacobian) const;
+ //@}
+
+
+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.
+ */
+ inline 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.
+ */
+ inline virtual IBPtr fullclone() const;
+ //@}
+
+private:
+
+ /**
+ * The static object used to initialize the description of this class.
+ * Indicates that this is an concrete class without persistent data.
+ */
+ static NoPIOClassDescription<WeiszackerWilliamsPDF> initWeiszackerWilliamsPDF;
+
+ /**
+ * The assignment operator is private and must never be called.
+ * In fact, it should not even be implemented.
+ */
+ WeiszackerWilliamsPDF & operator=(const WeiszackerWilliamsPDF &);
+
+private:
+
+ /**
+ * Minimum \f$Q^2\f$ for the photon
+ */
+ Energy2 _q2min;
+
+ /**
+ * Maximum \f$Q^2\f$ for the photon
+ */
+ Energy2 _q2max;
+
+};
+
+}
+
+#include "ThePEG/Utilities/ClassTraits.h"
+
+namespace ThePEG {
+
+/** @cond TRAITSPECIALIZATIONS */
+
+/** This template specialization informs ThePEG about the
+ * base classes of WeiszackerWilliamsPDF. */
+template <>
+struct BaseClassTrait<Herwig::WeiszackerWilliamsPDF,1> {
+ /** Typedef of the first base class of WeiszackerWilliamsPDF. */
+ typedef PDFBase NthBase;
+};
+
+/** This template specialization informs ThePEG about the name of
+ * the WeiszackerWilliamsPDF class and the shared object where it is defined. */
+template <>
+struct ClassTraits<Herwig::WeiszackerWilliamsPDF>
+ : public ClassTraitsBase<Herwig::WeiszackerWilliamsPDF> {
+ /** Return a platform-independent class name */
+ static string className() { return "Herwig::WeiszackerWilliamsPDF"; }
+ /**
+ * The name of a file containing the dynamic library where the class
+ * WeiszackerWilliamsPDF is implemented. It may also include several, space-separated,
+ * libraries if the class WeiszackerWilliamsPDF depends on other classes (base classes
+ * excepted). In this case the listed libraries will be dynamically
+ * linked in the order they are specified.
+ */
+ static string library() { return "HwLeptonPDF.so"; }
+};
+
+/** @endcond */
+
+}
+
+#include "WeiszackerWilliamsPDF.icc"
+
+#endif /* HERWIG_WeiszackerWilliamsPDF_H */
diff --git a/PDF/WeiszackerWilliamsPDF.icc b/PDF/WeiszackerWilliamsPDF.icc
new file mode 100644
--- /dev/null
+++ b/PDF/WeiszackerWilliamsPDF.icc
@@ -0,0 +1,21 @@
+// -*- C++ -*-
+//
+// This is the implementation of the inlined member functions of
+// the WeiszackerWilliamsPDF class.
+//
+
+namespace Herwig {
+
+inline WeiszackerWilliamsPDF::WeiszackerWilliamsPDF()
+ : _q2min(0.*GeV2), _q2max(4.*GeV2)
+{}
+
+inline IBPtr WeiszackerWilliamsPDF::clone() const {
+ return new_ptr(*this);
+}
+
+inline IBPtr WeiszackerWilliamsPDF::fullclone() const {
+ return new_ptr(*this);
+}
+
+}
diff --git a/PDT/StandardMatchers.h b/PDT/StandardMatchers.h
--- a/PDT/StandardMatchers.h
+++ b/PDT/StandardMatchers.h
@@ -1,137 +1,157 @@
// -*- C++ -*-
//
// StandardMatchers.h is a part of Herwig++ - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2007 The Herwig Collaboration
//
// Herwig++ is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef Herwig_StandardMatchers_H
#define Herwig_StandardMatchers_H
// This is the declaration of the AnyMatcher,
#include "ThePEG/PDT/Matcher.h"
+#include "ThePEG/Repository/CurrentGenerator.h"
+#include "ThePEG/PDF/BeamParticleData.h"
#include "ThePEG/PDT/EnumParticles.h"
namespace Herwig {
using namespace ThePEG;
/** \file Herwig++/PDT/StandardMatchers.h
*
* This file declare a set of standard matcher classes in addition to those
* defined in ThePEG. The classes can be used by themselves (with
* their static functions) or together with the Matcher class to
* define Interfaced objects of the MatcherBase type to be used in the
* Repository. Suitable typedefs are declared for the latter.
*
* @see Matcher
* @see MatcherBase
*/
/**
* A Matcher class which matches photons
*/
struct PhotonMatcher: public MatcherType {
/** Typedef the class matching the complex conjugate particles. */
typedef PhotonMatcher CC;
/** The main static function to check if a given particle type \a pd
matches. */
static bool Check(const ParticleData & pd) {
return pd.id()==ParticleID::gamma;
}
/** A simplified but unique class name. */
static string className() { return "Photon"; }
};
/**
* Gives a MatcherBase class based on PhotonMatcher.
*/
typedef Matcher<PhotonMatcher> MatchPhoton;
/**
* A Matcher class which matches top quarks
*/
struct TopMatcher: public MatcherType {
/** Typedef the class matching the complex conjugate particles. */
typedef TopMatcher CC;
/** The main static function to check if a given particle type \a pd
matches. */
static bool Check(const ParticleData & pd) {
return abs(pd.id())==ParticleID::t;
}
/** A simplified but unique class name. */
static string className() { return "Top"; }
};
/**
* Gives a MatcherBase class based on TopMatcher.
*/
typedef Matcher<TopMatcher> MatchTop;
/**
* A Matcher class which matches any hadron.
*/
struct HadronMatcher: public MatcherType {
/** Typedef the class matching the complex conjugate particles. */
typedef HadronMatcher CC;
/** The main static function to check if a given particle type \a pd
matches. */
- static bool Check(const ParticleData & pd) { return Check(pd.id()); }
+ static bool Check(const ParticleData & pd) {
+ if(pd.id()!=ParticleID::gamma) return Check(pd.id());
+ else {
+ Ptr<BeamParticleData>::const_pointer beam =
+ dynamic_ptr_cast< Ptr<BeamParticleData>::const_pointer>(&pd);
+ if(!beam) return false;
+ if(!beam->pdf()) return false;
+ return true;
+ }
+ }
/** The main static function to check if a given particle with type
\a id matches. */
static bool Check(long id) {
- return
+ bool hadron =
((id/10)%10 && (id/100)%10 && (id/1000)%10 == 0) ||
((id/10)%10 && (id/100)%10 && (id/1000)%10);
+ if(hadron) return true;
+ // special for gamma when acting like a hadron
+ if(id!=ParticleID::gamma) return false;
+ tcPDPtr gamma = CurrentGenerator::current().getParticleData(ParticleID::gamma);
+ Ptr<BeamParticleData>::const_pointer beam =
+ dynamic_ptr_cast< Ptr<BeamParticleData>::const_pointer>(gamma);
+ if(!beam) return false;
+ if(!beam->pdf()) return false;
+ return true;
}
/** A simplified but unique class name. */
static string className() { return "Hadron"; }
};
/** Gives a MatcherBase class based on HadronMatcher. */
typedef Matcher<HadronMatcher> MatchHadron;
/**
* A Matcher class which matches W bosons quarks
*/
struct WBosonMatcher: public MatcherType {
/** Typedef the class matching the complex conjugate particles. */
typedef WBosonMatcher CC;
/** The main static function to check if a given particle type \a pd
matches. */
static bool Check(const ParticleData & pd) {
return abs(pd.id())==ParticleID::Wplus;
}
/** A simplified but unique class name. */
static string className() { return "WBoson"; }
};
/**
* Gives a MatcherBase class based on WBosonMatcher.
*/
typedef Matcher<WBosonMatcher> MatchWBoson;
/**
* A Matcher class which matches W bosons quarks
*/
struct ZBosonMatcher: public MatcherType {
/** Typedef the class matching the complex conjugate particles. */
typedef ZBosonMatcher CC;
/** The main static function to check if a given particle type \a pd
matches. */
static bool Check(const ParticleData & pd) {
return abs(pd.id())==ParticleID::Z0;
}
/** A simplified but unique class name. */
static string className() { return "ZBoson"; }
};
/**
* Gives a MatcherBase class based on ZBosonMatcher.
*/
typedef Matcher<ZBosonMatcher> MatchZBoson;
}
#endif /* Herwig_StandardMatchers_H */
diff --git a/Shower/Base/Evolver.cc b/Shower/Base/Evolver.cc
--- a/Shower/Base/Evolver.cc
+++ b/Shower/Base/Evolver.cc
@@ -1,868 +1,922 @@
// -*- C++ -*-
//
// Evolver.cc is a part of Herwig++ - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2007 The Herwig Collaboration
//
// Herwig++ is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the Evolver class.
//
#include "Evolver.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/RefVector.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig++/Shower/Base/ShowerParticle.h"
#include "ShowerKinematics.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Handlers/EventHandler.h"
#include "ThePEG/Utilities/Throw.h"
#include "ShowerTree.h"
#include "ShowerProgenitor.h"
#include "KinematicsReconstructor.h"
#include "PartnerFinder.h"
#include "MECorrectionBase.h"
#include "ThePEG/Handlers/XComb.h"
#include "Herwig++/Shower/CKKW/Clustering/CascadeReconstructor.h"
#include "Herwig++/Shower/CKKW/Reweighting/DefaultReweighter.h"
#include "Herwig++/Shower/CKKW/Reweighting/DefaultCKKWVeto.h"
using namespace Herwig;
void Evolver::persistentOutput(PersistentOStream & os) const {
os << _model << _splittingGenerator << _maxtry
- << _meCorrMode << _hardVetoMode << _hardVetoRead
+ << _meCorrMode << _hardVetoMode << _hardVetoRead << _limitEmissions
<< ounit(_iptrms,GeV) << _beta << ounit(_gamma,GeV) << ounit(_iptmax,GeV) << _vetoes
<< _reconstructor << _reweighter << _ckkwVeto << _useCKKW;
}
void Evolver::persistentInput(PersistentIStream & is, int) {
is >> _model >> _splittingGenerator >> _maxtry
- >> _meCorrMode >> _hardVetoMode >> _hardVetoRead
+ >> _meCorrMode >> _hardVetoMode >> _hardVetoRead >> _limitEmissions
>> iunit(_iptrms,GeV) >> _beta >> iunit(_gamma,GeV) >> iunit(_iptmax,GeV) >> _vetoes
>> _reconstructor >> _reweighter >> _ckkwVeto >> _useCKKW;
}
void Evolver::doinitrun() {
Interfaced::doinitrun();
for(unsigned int ix=0;ix<_model->meCorrections().size();++ix) {
_model->meCorrections()[ix]->evolver(this);
}
#ifdef HERWIG_CHECK_VETOES
_vetoed_points.timelike.open("vetoed_timelike.dat");
_vetoed_points.spacelike.open("vetoed_spacelike.dat");
_vetoed_points.spacelike_decay.open("vetoed_spacelike_decay.dat");
#endif
}
ClassDescription<Evolver> Evolver::initEvolver;
// Definition of the static class description member.
void Evolver::Init() {
static ClassDocumentation<Evolver> documentation
("This class is responsible for carrying out the showering,",
"including the kinematics reconstruction, in a given scale range.");
static Reference<Evolver,SplittingGenerator>
interfaceSplitGen("SplittingGenerator",
"A reference to the SplittingGenerator object",
&Herwig::Evolver::_splittingGenerator,
false, false, true, false);
static Reference<Evolver,ShowerModel> interfaceShowerModel
("ShowerModel",
"The pointer to the object which defines the shower evolution model.",
&Evolver::_model, false, false, true, false, false);
static Parameter<Evolver,unsigned int> interfaceMaxTry
("MaxTry",
"The maximum number of attempts to generate the shower from a"
" particular ShowerTree",
&Evolver::_maxtry, 100, 1, 1000,
false, false, Interface::limited);
static Switch<Evolver, unsigned int> ifaceMECorrMode
("MECorrMode",
"Choice of the ME Correction Mode",
&Evolver::_meCorrMode, 1, false, false);
static SwitchOption off
(ifaceMECorrMode,"No","MECorrections off", 0);
static SwitchOption on
(ifaceMECorrMode,"Yes","hard+soft on", 1);
static SwitchOption hard
(ifaceMECorrMode,"Hard","only hard on", 2);
static SwitchOption soft
(ifaceMECorrMode,"Soft","only soft on", 3);
static Switch<Evolver, unsigned int> ifaceHardVetoMode
("HardVetoMode",
"Choice of the Hard Veto Mode",
&Evolver::_hardVetoMode, 1, false, false);
static SwitchOption HVoff
(ifaceHardVetoMode,"No","hard vetos off", 0);
static SwitchOption HVon
(ifaceHardVetoMode,"Yes","hard vetos on", 1);
static SwitchOption HVIS
(ifaceHardVetoMode,"Initial", "only IS emissions vetoed", 2);
static SwitchOption HVFS
(ifaceHardVetoMode,"Final","only FS emissions vetoed", 3);
static Switch<Evolver, unsigned int> ifaceHardVetoRead
("HardVetoScaleSource",
"If hard veto scale is to be read",
&Evolver::_hardVetoRead, 0, false, false);
static SwitchOption HVRcalc
(ifaceHardVetoRead,"Calculate","Calculate from hard process", 0);
static SwitchOption HVRread
(ifaceHardVetoRead,"Read","Read from XComb->lastScale", 1);
static Parameter<Evolver, Energy> ifaceiptrms
("IntrinsicPtGaussian",
"RMS of intrinsic pT of Gaussian distribution:\n"
"2*(1-Beta)*exp(-sqr(intrinsicpT/RMS))/sqr(RMS)",
&Evolver::_iptrms, GeV, 0*GeV, 0*GeV, 1000000.0*GeV,
false, false, Interface::limited);
static Parameter<Evolver, double> ifacebeta
("IntrinsicPtBeta",
"Proportion of inverse quadratic distribution in generating intrinsic pT.\n"
"(1-Beta) is the proportion of Gaussian distribution",
&Evolver::_beta, 0, 0, 1,
false, false, Interface::limited);
static Parameter<Evolver, Energy> ifacegamma
("IntrinsicPtGamma",
"Parameter for inverse quadratic:\n"
"2*Beta*Gamma/(sqr(Gamma)+sqr(intrinsicpT))",
&Evolver::_gamma,GeV, 0*GeV, 0*GeV, 100000.0*GeV,
false, false, Interface::limited);
static Parameter<Evolver, Energy> ifaceiptmax
("IntrinsicPtIptmax",
"Upper bound on intrinsic pT for inverse quadratic",
&Evolver::_iptmax,GeV, 0*GeV, 0*GeV, 100000.0*GeV,
false, false, Interface::limited);
static RefVector<Evolver,ShowerVeto> ifaceVetoes
("Vetoes",
"The vetoes to be checked during showering",
&Evolver::_vetoes, -1,
false,false,true,true,false);
+ static Switch<Evolver,unsigned int> interfaceLimitEmissions
+ ("LimitEmissions",
+ "Limit the number and type of emissions for testing",
+ &Evolver::_limitEmissions, 0, false, false);
+ static SwitchOption interfaceLimitEmissionsNoLimit
+ (interfaceLimitEmissions,
+ "NoLimit",
+ "Allow an arbitrary number of emissions",
+ 0);
+ static SwitchOption interfaceLimitEmissionsOneInitialStateEmission
+ (interfaceLimitEmissions,
+ "OneInitialStateEmission",
+ "Allow one emission in the initial state and none in the final state",
+ 1);
+ static SwitchOption interfaceLimitEmissionsOneFinalStateEmission
+ (interfaceLimitEmissions,
+ "OneFinalStateEmission",
+ "Allow one emission in the final state and none in the initial state",
+ 2);
}
void Evolver::useCKKW (CascadeReconstructorPtr cr, ReweighterPtr rew) {
DefaultReweighterPtr drew = dynamic_ptr_cast<DefaultReweighterPtr>(rew);
if (!drew) Throw<InitException>()
<< "Shower : Evolver::useCKKW : DefaultReweighter needed by Evolver, found Reweighter.";
_reconstructor = cr;
_reweighter = drew;
// alpha_s
// alpha_s is set as a reference in Reweighter
// now register the splitting functions with
// the reweighter
if (!_splittingGenerator->isISRadiationON(ShowerIndex::QCD) &&
!_splittingGenerator->isFSRadiationON(ShowerIndex::QCD))
Throw<InitException>() << "Shower : Evolver::useCKKW : Attempt to use CKKW with QCD radiation switched off.";
if(_splittingGenerator->isISRadiationON(ShowerIndex::QCD)) {
BranchingList bb = _splittingGenerator->bbList();
for(BranchingList::iterator b = bb.begin(); b != bb.end(); ++b) {
if (b->second.first->interactionType() == ShowerIndex::QCD)
_reweighter->insertSplitting(b->second.second,
b->second.first->splittingFn(),
true);
}
}
if(_splittingGenerator->isFSRadiationON(ShowerIndex::QCD)) {
BranchingList fb = _splittingGenerator->fbList();
for(BranchingList::iterator b = fb.begin(); b != fb.end(); ++b) {
if (b->second.first->interactionType() == ShowerIndex::QCD)
_reweighter->insertSplitting(b->second.second,
b->second.first->splittingFn(),
false);
}
}
// setup the reweighter
_reweighter->setup(_reconstructor);
// and insert an appropriate veto
if (!dynamic_ptr_cast<DefaultJetMeasurePtr>(_reweighter->resolution()))
Throw<InitException>() << "Shower : Evolver::useCKKW : DefaultJetMeasure needed by Evolver, found JetMeasure.";
_ckkwVeto =
new_ptr(DefaultCKKWVeto(dynamic_ptr_cast<DefaultJetMeasurePtr>(_reweighter->resolution())));
_ckkwVeto->enable();
addVeto(_ckkwVeto);
// indicate that we are doing CKKW
_useCKKW = true;
}
void Evolver::initCKKWShower (const CascadeHistory& hist, unsigned int currentMult, unsigned int maxMult) {
_ckkwVeto->eventGenerator(generator());
// disable the veto for maximum multiplicity,
// if wanted.
if(!_reweighter->vetoHighest() && currentMult == maxMult) {
_ckkwVeto->disable();
}
else {
if (_reweighter->highestNotHarder() && currentMult == maxMult)
_ckkwVeto->enable(hist.softestMEScale);
else
_ckkwVeto->enable();
}
}
void Evolver::generateIntrinsicpT(vector<ShowerProgenitorPtr> particlesToShower) {
_intrinsic.clear();
if ( !ipTon() || !isISRadiationON() ) return;
//dont do anything for the moment for secondary scatters
if( !ShowerHandler::currentHandler()->FirstInt() ) return;
// generate intrinsic pT
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
// only consider initial-state particles
if(particlesToShower[ix]->progenitor()->isFinalState()) continue;
if(!particlesToShower[ix]->progenitor()->dataPtr()->coloured()) continue;
Energy ipt;
if(UseRandom::rnd() > _beta) {
ipt=_iptrms*sqrt(-log(UseRandom::rnd()));
}
else {
ipt=_gamma*sqrt(pow(1.+sqr(_iptmax/_gamma), UseRandom::rnd())-1.);
}
pair<Energy,double> pt = make_pair(ipt,UseRandom::rnd()*Constants::twopi);
_intrinsic[particlesToShower[ix]] = pt;
}
}
void Evolver::setupMaximumScales(ShowerTreePtr hard,
vector<ShowerProgenitorPtr> p) {
// find out if hard partonic subprocess.
bool isPartonic(false);
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cit;
cit = _currenttree->incomingLines().begin();
Lorentz5Momentum pcm;
for(; cit!=hard->incomingLines().end(); ++cit) {
pcm += cit->first->progenitor()->momentum();
if (isPartonic || cit->first->progenitor()->coloured()) {
isPartonic = true;
}
}
// find maximum 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 = -1.0*GeV, ptest = 0.0*GeV;
if (hardVetoXComb()) {
// hepeup.SCALUP is written into the lastXComb by the
// LesHouchesReader itself - use this by user's choice.
// Can be more general than this.
ptmax = sqrt( ShowerHandler::currentHandler()
->lastXCombPtr()->lastScale() );
} else {
if (isPartonic) {
if (hard->isHard()) {
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cjt;
cjt = hard->outgoingLines().begin();
for(; cjt!=hard->outgoingLines().end(); ++cjt) {
if (cjt->first->progenitor()->coloured()) {
ptest = cjt->first->progenitor()->momentum().mt();
if (ptest > ptmax) {
ptmax = ptest;
}
}
}
// if there are no coloured FS particles, use shat as maximum
if (ptmax < 0.0*GeV) {
ptmax = pcm.m();
}
} else {
// must be a decay, incoming() is the decaying particle.
ptmax = hard->incomingLines().begin()->first
->progenitor()->momentum().m();
}
} else {
if (hard->isHard()) {
// if no coloured IS use shat as well
ptmax = pcm.m();
} else {
// must be a decay, incoming() is the decaying particle. Use its
// mass as maximum scale.
ptmax = hard->incomingLines().begin()->first
->progenitor()->momentum().m();
}
}
}
// set maxHardPt for all progenitors. For partonic processes this
// is now the max pt in the FS, for non-partonic processes or
// processes with no coloured FS the invariant mass of the IS
vector<ShowerProgenitorPtr>::const_iterator ckt = p.begin();
for (; ckt != p.end(); ckt++) {
(*ckt)->maxHardPt(ptmax);
}
}
void Evolver::showerHardProcess(ShowerTreePtr hard) {
// set the current tree
_currenttree=hard;
+ _nis = 0;
+ _nfs = 0;
vector<ShowerProgenitorPtr> particlesToShower=setupShower(true);
// setup the maximum scales for the shower, given by the hard process
if (hardVetoOn()) {
setupMaximumScales(_currenttree, particlesToShower);
}
// generate the intrinsic p_T once and for all
generateIntrinsicpT(particlesToShower);
unsigned int ntry(0);
do {
// clear results of last attempt
if(ntry!=0) {
_currenttree->clear();
setColourPartners(true);
+ _nis = 0;
+ _nfs = 0;
}
// initial-state radiation
if(_splittingGenerator->isISRadiationON()) {
- for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
+ unsigned int istart=UseRandom::irnd(particlesToShower.size());
+ unsigned int istop = particlesToShower.size();
+ for(unsigned int ix=istart;ix<=istop;++ix) {
+ if(ix==particlesToShower.size()) {
+ if(istart!=0) {
+ istop = istart-1;
+ ix=0;
+ }
+ else break;
+ }
// only consider initial-state particles
if(particlesToShower[ix]->progenitor()->isFinalState()) continue;
// get the PDF
_beam=particlesToShower[ix]->beam();
if(!_beam) throw Exception() << "The Beam particle does not have"
<< " BeamParticleData in Evolver::"
<< "showerhardProcess()"
<< Exception::runerror;
// perform the shower
_progenitor=particlesToShower[ix];
tPPtr beamparticle;
if ( particlesToShower[ix]->original()->parents().empty() ) {
beamparticle=particlesToShower[ix]->original();
}
else {
beamparticle=particlesToShower[ix]->original()->parents()[0];
}
_progenitor->hasEmitted(spaceLikeShower(particlesToShower[ix]->progenitor(),
beamparticle));
}
}
// final-state radiation
if(_splittingGenerator->isFSRadiationON()) {
- for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
+ unsigned int istart=UseRandom::irnd(particlesToShower.size());
+ unsigned int istop = particlesToShower.size();
+ for(unsigned int ix=istart;ix<=istop;++ix) {
+ if(ix==particlesToShower.size()) {
+ if(istart!=0) {
+ istop = istart-1;
+ ix=0;
+ }
+ else break;
+ }
// only consider final-state particles
if(!particlesToShower[ix]->progenitor()->isFinalState()) continue;
// perform shower
_progenitor=particlesToShower[ix];
_progenitor->hasEmitted(timeLikeShower(particlesToShower[ix]->progenitor()));
}
}
}
while(!_model->kinematicsReconstructor()->reconstructHardJets(hard,_intrinsic)&&
_maxtry>++ntry);
if(_maxtry==ntry) throw ShowerHandler::ShowerTriesVeto(ntry);
_currenttree->hasShowered(true);
}
void Evolver::hardMatrixElementCorrection() {
// set me correction to null pointer
_currentme=MECorrectionPtr();
// set the initial enhancement factors for the soft correction
_initialenhance=1.;
_finalenhance =1.;
// if hard matrix element switched off return
if(!MECOn()) return;
// see if there is an appropraite matrix element correction
for(unsigned int ix=0;ix<_model->meCorrections().size();++ix) {
double initial,final;
if(!_model->meCorrections()[ix]->canHandle(_currenttree,
initial,final,this)) continue;
if(_currentme) {
ostringstream output;
output << "There is more than one possible matrix"
<< "element which could be applied for ";
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cit;
for(cit=_currenttree->incomingLines().begin();
cit!=_currenttree->incomingLines().end();++cit)
{output << cit->first->progenitor()->PDGName() << " ";}
output << " -> ";
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cjt;
for(cjt=_currenttree->outgoingLines().begin();
cjt!=_currenttree->outgoingLines().end();++cjt)
{output << cjt->first->progenitor()->PDGName() << " ";}
output << "in Evolver::hardMatrixElementCorrection()\n";
throw Exception() << output << Exception::runerror;
}
else {
_currentme=_model->meCorrections()[ix];
_initialenhance = initial;
_finalenhance = final;
}
}
// if no suitable me correction
if(!_currentme) return;
// now apply the hard correction
if(hardMEC()) _currentme->applyHardMatrixElementCorrection(_currenttree);
}
bool Evolver::timeLikeShower(tShowerParticlePtr particle) {
+ // don't do anything if not needed
+ if(_limitEmissions == 1 || ( _limitEmissions == 2 && _nfs != 0) ) return false;
bool vetoed = true;
Branching fb;
while (vetoed) {
vetoed = false;
fb=_splittingGenerator->chooseForwardBranching(*particle,_finalenhance);
// check whether emission was harder than largest pt of hard subprocess
if (hardVetoFS() && fb.kinematics
&& fb.kinematics->pT() > _progenitor->maxHardPt()) {
vetoed = true;
particle->setEvolutionScale(ShowerIndex::QCD, fb.kinematics->scale());
continue;
}
// apply vetos if needed
if(fb.kinematics && _currentme && softMEC() && !_theUseCKKW) {
vetoed=_currentme->softMatrixElementVeto(_progenitor,particle,fb);
if (vetoed) continue;
}
if (fb.kinematics && _vetoes.size()) {
for (vector<ShowerVetoPtr>::iterator v = _vetoes.begin();
v != _vetoes.end(); ++v) {
if ((**v).vetoType() == ShowerVetoType::Emission) {
vetoed |= (**v).vetoTimeLike(_progenitor,particle,fb);
}
if ((**v).vetoType() == ShowerVetoType::Shower && (**v).vetoTimeLike(_progenitor,particle,fb)) {
throw VetoShower ();
}
if ((**v).vetoType() == ShowerVetoType::Event && (**v).vetoTimeLike(_progenitor,particle,fb))
throw Veto ();
}
if (vetoed) {
#ifdef HERWIG_CHECK_VETOES
_vetoed_points.timelike << fb.kinematics->scale()/GeV << "\t"
<< fb.kinematics->z() << endl;
#endif
particle->setEvolutionScale(ShowerIndex::QCD, fb.kinematics->scale());
continue;
}
}
}
// if no branching set decay matrix and return
if(!fb.kinematics) {
//
// add decay matrix stuff here
//
return false;
}
// has emitted
// Assign the shower kinematics to the emitting particle.
particle->setShowerKinematics(fb.kinematics);
// Assign the splitting function to the emitting particle.
// For the time being we are considering only 1->2 branching
// Create the ShowerParticle objects for the two children of
// the emitting particle; set the parent/child relationship
// if same as definition create particles, otherwise create cc
tcPDPtr pdata[2];
for(unsigned int ix=0;ix<2;++ix) pdata[ix]=getParticleData(fb.ids[ix+1]);
if(particle->id()!=fb.ids[0]) {
for(unsigned int ix=0;ix<2;++ix) {
tPDPtr cc(pdata[ix]->CC());
if(cc) pdata[ix]=cc;
}
}
ShowerParticleVector theChildren;
theChildren.push_back(new_ptr(ShowerParticle(pdata[0],true)));
theChildren.push_back(new_ptr(ShowerParticle(pdata[1],true)));
// some code moved to updateChildren
particle->showerKinematics()->updateChildren(particle, theChildren);
// update the history if needed
if(particle==_currenttree->getFinalStateShowerProduct(_progenitor))
_currenttree->updateFinalStateShowerProduct(_progenitor,
particle,theChildren);
_currenttree->addFinalStateBranching(particle,theChildren);
+ // update number of emissions
+ ++_nfs;
+ if(_limitEmissions!=0) return true;
// shower the first particle
//
// need to set rho here
//
timeLikeShower(theChildren[0]);
// shower the second particle
//
// need to set rho here
//
timeLikeShower(theChildren[1]);
// branching has happened
return true;
}
bool Evolver::spaceLikeShower(tShowerParticlePtr particle, PPtr beam) {
+ // don't do anything if not needed
+ if(_limitEmissions == 2 || ( _limitEmissions == 1 && _nis != 0 ) ) return false;
bool vetoed(true);
Branching bb;
// generate branching
while (vetoed) {
vetoed=false;
bb=_splittingGenerator->chooseBackwardBranching(*particle,beam,
_initialenhance,_beam);
// check whether emission was harder than largest pt of hard subprocess
if (hardVetoIS() && bb.kinematics
&& bb.kinematics->pT() > _progenitor->maxHardPt()) {
vetoed = true;
particle->setEvolutionScale(ShowerIndex::QCD, bb.kinematics->scale());
continue;
}
// apply the soft correction
if(bb.kinematics && _currentme && softMEC() && !_theUseCKKW) {
vetoed=_currentme->softMatrixElementVeto(_progenitor,particle,bb);
if (vetoed) continue;
}
if (bb.kinematics && _vetoes.size()) {
for (vector<ShowerVetoPtr>::iterator v = _vetoes.begin();
v != _vetoes.end(); ++v) {
if ((**v).vetoType() == ShowerVetoType::Emission) {
vetoed |= (**v).vetoSpaceLike(_progenitor,particle,bb);
}
if ((**v).vetoType() == ShowerVetoType::Shower && (**v).vetoSpaceLike(_progenitor,particle,bb))
throw VetoShower ();
if ((**v).vetoType() == ShowerVetoType::Event && (**v).vetoSpaceLike(_progenitor,particle,bb))
throw Veto ();
}
if (vetoed) {
#ifdef HERWIG_CHECK_VETOES
_vetoed_points.spacelike << bb.kinematics->scale()/GeV << "\t"
<< bb.kinematics->z() << endl;
#endif
particle->setEvolutionScale(ShowerIndex::QCD, bb.kinematics->scale());
continue;
}
}
}
if(!bb.kinematics) return false;
// assign the splitting function and shower kinematics
particle->setShowerKinematics(bb.kinematics);
// For the time being we are considering only 1->2 branching
// particles as in Sudakov form factor
tcPDPtr part[2]={getParticleData(bb.ids[0]),
getParticleData(bb.ids[2])};
if(particle->id()!=bb.ids[1]) {
if(part[0]->CC()) part[0]=part[0]->CC();
if(part[1]->CC()) part[1]=part[1]->CC();
}
// Now create the actual particles, make the otherChild a final state
// particle, while the newParent is not
ShowerParticlePtr newParent=new_ptr(ShowerParticle(part[0],false));
ShowerParticlePtr otherChild = new_ptr(ShowerParticle(part[1],true,true));
ShowerParticleVector theChildren;
theChildren.push_back(particle);
theChildren.push_back(otherChild);
particle->showerKinematics()->updateParent(newParent, theChildren);
// 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=spaceLikeShower(newParent,beam);
+ bool emitted = _limitEmissions==0 ? spaceLikeShower(newParent,beam) : false;
// now reconstruct the momentum
if(!emitted) {
if(_intrinsic.find(_progenitor)==_intrinsic.end()) {
bb.kinematics->updateLast(newParent,0.*MeV,0.*MeV);
}
else {
pair<Energy,double> kt=_intrinsic[_progenitor];
bb.kinematics->updateLast(newParent,
kt.first*cos(kt.second),
kt.first*sin(kt.second));
}
}
particle->showerKinematics()->updateChildren(newParent, theChildren);
+ if(_limitEmissions!=0) return true;
// perform the shower of the final-state particle
timeLikeShower(otherChild);
// return the emitted
return true;
}
void Evolver::showerDecay(ShowerTreePtr decay) {
// set the ShowerTree to be showered
_currenttree=decay;
// extract particles to be shower, set scales and perform hard matrix element
// correction
vector<ShowerProgenitorPtr> particlesToShower=setupShower(false);
setupMaximumScales(_currenttree, particlesToShower);
// main showering loop
unsigned int ntry(0);
do {
// clear results of last attempt
if(ntry!=0) {
_currenttree->clear();
setColourPartners(false);
}
// initial-state radiation
if(_splittingGenerator->isISRadiationON()) {
// compute the minimum mass of the final-state
Energy minmass(0.*MeV);
for(unsigned int ix=0;ix<particlesToShower.size();++ix)
{if(particlesToShower[ix]->progenitor()->isFinalState())
minmass+=particlesToShower[ix]->progenitor()->mass();}
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
// only consider initial-state particles
if(particlesToShower[ix]->progenitor()->isFinalState()) continue;
// perform shower
_progenitor=particlesToShower[ix];
// set the scales correctly. The current scale is the maximum scale for
// emission not the starting scale
vector<Energy> maxscale=_progenitor->progenitor()->evolutionScales();
Energy startScale=_progenitor->progenitor()->mass();
_progenitor->progenitor()->setEvolutionScale(ShowerIndex::QCD,startScale);
_progenitor->progenitor()->setEvolutionScale(ShowerIndex::QED,startScale);
_progenitor->progenitor()->setEvolutionScale(ShowerIndex::EWK,startScale);
// perform the shower
_progenitor->hasEmitted(spaceLikeDecayShower(_progenitor->progenitor(),
maxscale,minmass));
}
}
// final-state radiation
if(_splittingGenerator->isFSRadiationON()) {
- for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
- // only consider final-state particles
- if(!particlesToShower[ix]->progenitor()->isFinalState()) continue;
+ vector<unsigned int> iloc;
+ for(unsigned int ix=0;ix<particlesToShower.size();++ix)
+ if(particlesToShower[ix]->progenitor()->isFinalState()) iloc.push_back(ix);
+ if(iloc.empty()) break;
+ unsigned int istart=UseRandom::irnd(iloc.size()),ix=istart;
+ while (true) {
// perform shower
- _progenitor=particlesToShower[ix];
- _progenitor->hasEmitted(timeLikeShower(particlesToShower[ix]->progenitor()));
+ _progenitor=particlesToShower[iloc[ix]];
+ _progenitor->hasEmitted(timeLikeShower(_progenitor->progenitor()));
+ ++ix;
+ if(ix==iloc.size()) ix=0;
+ if(ix==istart) break;
}
}
}
while(!_model->kinematicsReconstructor()->reconstructDecayJets(decay)&&_maxtry>++ntry);
if(_maxtry==ntry) throw Exception() << "Failed to generate the shower after "
<< ntry << " attempts in Evolver::showerDecay()"
<< Exception::eventerror;
_currenttree->hasShowered(true);
}
bool Evolver::spaceLikeDecayShower(tShowerParticlePtr particle,vector<Energy> maxscale,
Energy minmass) {
bool vetoed = true;
Branching fb;
while (vetoed) {
vetoed = false;
fb=_splittingGenerator->chooseDecayBranching(*particle,maxscale,minmass,
_initialenhance);
// SG: here could be the veto of too hard radiation. I think the
// initial conditions don't allow this anyway.
// apply the soft correction
if(fb.kinematics && _currentme && softMEC() && !_theUseCKKW) {
vetoed=_currentme->softMatrixElementVeto(_progenitor,particle,fb);
if (vetoed) continue;
}
if (fb.kinematics && _vetoes.size()) {
for (vector<ShowerVetoPtr>::iterator v = _vetoes.begin();
v != _vetoes.end(); ++v) {
if ((**v).vetoType() == ShowerVetoType::Emission) {
vetoed |= (**v).vetoSpaceLike(_progenitor,particle,fb);
}
if ((**v).vetoType() == ShowerVetoType::Shower && (**v).vetoSpaceLike(_progenitor,particle,fb))
throw VetoShower ();
if ((**v).vetoType() == ShowerVetoType::Event && (**v).vetoSpaceLike(_progenitor,particle,fb))
throw Veto ();
}
if (vetoed) {
#ifdef HERWIG_CHECK_VETOES
_vetoed_points.spacelike_decay << fb.kinematics->scale()/GeV << "\t"
<< fb.kinematics->z() << endl;
#endif
particle->setEvolutionScale(ShowerIndex::QCD, fb.kinematics->scale());
continue;
}
}
}
// if no branching set decay matrix and return
if(!fb.kinematics) {
//
// add decay matrix stuff here
//
return false;
}
// has emitted
// Assign the shower kinematics to the emitting particle.
particle->setShowerKinematics(fb.kinematics);
// For the time being we are considering only 1->2 branching
// Create the ShowerParticle objects for the two children of
// the emitting particle; set the parent/child relationship
// if same as definition create particles, otherwise create cc
tcPDPtr pdata[2];
for(unsigned int ix=0;ix<2;++ix) pdata[ix]=getParticleData(fb.ids[ix+1]);
if(particle->id()!=fb.ids[0]) {
for(unsigned int ix=0;ix<2;++ix) {
tPDPtr cc(pdata[ix]->CC());
if(cc) pdata[ix]=cc;
}
}
ShowerParticleVector theChildren;
theChildren.push_back(new_ptr(ShowerParticle(pdata[0],true)));
theChildren.push_back(new_ptr(ShowerParticle(pdata[1],true)));
// some code moved to updateChildren
particle->showerKinematics()->updateChildren(particle, theChildren);
// In the case of splittings which involves coloured particles,
// set properly the colour flow of the branching.
// update the history if needed
_currenttree->updateInitialStateShowerProduct(_progenitor,theChildren[0]);
_currenttree->addInitialStateBranching(particle,theChildren[0],theChildren[1]);
// shower the first particle
//
// need to set rho here
//
spaceLikeDecayShower(theChildren[0],maxscale,minmass);
// shower the second particle
//
// need to set rho here
//
timeLikeShower(theChildren[1]);
// branching has happened
return true;
}
vector<ShowerProgenitorPtr> Evolver::setupShower(bool hard) {
// put all the particles into a data structure which has the particles
// and the maximum pt for emission from the particle
// set the initial colour partners
setColourPartners(hard);
map<ShowerProgenitorPtr, ShowerParticlePtr>::const_iterator cit;
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cjt;
// If we use CKKW and there is information available from
// the last parton shower history for each coloured line
// in the current tree, we reset scales and apply vetoes
_theUseCKKW = false;
if (_useCKKW) {
_theUseCKKW = true;
for(cit=_currenttree->incomingLines().begin();
cit!=_currenttree->incomingLines().end();++cit) {
if ((*cit).first->original()->coloured())
if (!_reconstructor->clusteringParticle((*cit).first->original())) {
_theUseCKKW = false;
break;
}
}
if(_theUseCKKW)
for(cjt=_currenttree->outgoingLines().begin();
cjt!=_currenttree->outgoingLines().end();++cjt) {
if ((*cjt).first->original()->coloured())
if (!_reconstructor->clusteringParticle((*cjt).first->original())) {
_theUseCKKW = false;
break;
}
}
// if we failed here, disable the veto
if(!_theUseCKKW) _ckkwVeto->disable();
}
// generate the hard matrix element correction if needed
// don't do this if we are doing CKKW
- if (!_theUseCKKW)
- hardMatrixElementCorrection();
+ if (!_theUseCKKW) hardMatrixElementCorrection();
// get the particles to be showered
vector<ShowerProgenitorPtr> particlesToShower;
// incoming particles
for(cit=_currenttree->incomingLines().begin();
cit!=_currenttree->incomingLines().end();++cit)
particlesToShower.push_back(((*cit).first));
- assert((particlesToShower.size()==1&&!hard)
- ||(particlesToShower.size()==2&&hard));
+ assert( (particlesToShower.size()==1 && !hard ) ||
+ (particlesToShower.size()==2 && hard ) );
// outgoing particles
for(cjt=_currenttree->outgoingLines().begin();
cjt!=_currenttree->outgoingLines().end();++cjt)
particlesToShower.push_back(((*cjt).first));
// remake the colour partners if needed
if(_currenttree->hardMatrixElementCorrection() && !_theUseCKKW) {
setColourPartners(hard);
_currenttree->resetShowerProducts();
}
// if CKKW, reset the initial scales
if (_theUseCKKW) {
for (vector<ShowerProgenitorPtr>::iterator p = particlesToShower.begin();
p != particlesToShower.end(); ++p)
// if not coloured, don't consider
if ((**p).original()->coloured()) {
tClusteringParticlePtr historyP = _reconstructor->clusteringParticle((**p).original());
if (!historyP)
throw Exception() << "Shower : Evolver::setupShower (CKKW): No external leg for particle"
<< " found in cascade history" << Exception::eventerror;
#ifdef HERWIG_DEBUG_CKKW_EXTREME
generator()->log() << "resetting hard scale for " << (**p).original()
<< " PDGId = " << (**p).original()->id()
<< " to " << sqrt(historyP->showerScale())/GeV << " GeV "
<< " using clustering partilce " << endl;
historyP->debugDump(generator()->log());
#endif
(**p).progenitor()->setEvolutionScale(ShowerIndex::QCD,sqrt(historyP->showerScale()));
}
}
return particlesToShower;
}
void Evolver::setColourPartners(bool hard) {
vector<ShowerParticlePtr> particles;
map<ShowerProgenitorPtr, ShowerParticlePtr>::const_iterator cit;
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cjt;
for(cit=_currenttree->incomingLines().begin();
cit!=_currenttree->incomingLines().end();++cit)
particles.push_back(cit->first->progenitor());
assert((particles.size()==1&&!hard)||(particles.size()==2&&hard));
// outgoing particles
for(cjt=_currenttree->outgoingLines().begin();
cjt!=_currenttree->outgoingLines().end();++cjt)
particles.push_back(cjt->first->progenitor());
// Set the initial evolution scales
if(_splittingGenerator->isInteractionON(ShowerIndex::QCD))
_model->partnerFinder()->setQCDInitialEvolutionScales(particles,!hard);
if(_splittingGenerator->isInteractionON(ShowerIndex::QED))
_model->partnerFinder()->setQEDInitialEvolutionScales(particles,!hard);
if(_splittingGenerator->isInteractionON(ShowerIndex::EWK))
_model->partnerFinder()->setEWKInitialEvolutionScales(particles,!hard);
}
diff --git a/Shower/Base/Evolver.h b/Shower/Base/Evolver.h
--- a/Shower/Base/Evolver.h
+++ b/Shower/Base/Evolver.h
@@ -1,579 +1,590 @@
// -*- C++ -*-
//
// Evolver.h is a part of Herwig++ - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2007 The Herwig Collaboration
//
// Herwig++ is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_Evolver_H
#define HERWIG_Evolver_H
//
// This is the declaration of the Evolver class.
//
#include "ThePEG/Interface/Interfaced.h"
#include "Herwig++/Shower/SplittingFunctions/SplittingGenerator.h"
#include "ShowerModel.h"
#include "ThePEG/PDF/BeamParticleData.h"
#include "ShowerTree.fh"
#include "MECorrectionBase.fh"
#include "ShowerProgenitor.fh"
#include "Herwig++/Shower/ShowerHandler.fh"
#include "ShowerVeto.h"
#include "Herwig++/Shower/CKKW/Clustering/CascadeReconstructor.h"
#include "Herwig++/Shower/CKKW/Reweighting/DefaultReweighter.h"
#include "Herwig++/Shower/CKKW/Reweighting/DefaultCKKWVeto.h"
#include "Evolver.fh"
namespace Herwig {
using namespace ThePEG;
#ifdef HERWIG_CHECK_VETOES
struct vetoed_points {
inline vetoed_points ()
: timelike (), spacelike(), spacelike_decay () { }
inline vetoed_points (const vetoed_points&)
: timelike (), spacelike(), spacelike_decay () { }
ofstream timelike;
ofstream spacelike;
ofstream spacelike_decay;
};
#endif
/** \ingroup Shower
* Here is the documentation of the Evolver class.
*
* @see \ref EvolverInterfaces "The interfaces"
* defined for Evolver.
*/
class Evolver: public Interfaced {
/**
* The ShowerHandler is a friend to set some parameters at initialisation
*/
friend class ShowerHandler;
/**
* The MECorrectionBase class is a friend to access some protected
* member functions to set the radiation enhancement factors
*/
friend class MECorrectionBase;
public:
/**
* Default Constructor
*/
inline Evolver();
/**
* Member to perform the shower
*/
//@{
/**
* Perform the shower of the hard process
*/
virtual void showerHardProcess(ShowerTreePtr);
/**
* Initialize the Shower for ME/PS merging,
* given the minimum and maximum multiplicity.
* The cascade history is available through
* the reconstructor object.
*/
virtual void initCKKWShower (const CascadeHistory&, unsigned int currentMult, unsigned int maxMult);
/**
* Perform the shower of a decay
*/
virtual void showerDecay(ShowerTreePtr);
//@}
/**
* Access to the flags and shower variables
*/
//@{
/**
* Is there any showering switched on
*/
inline bool showeringON() const;
/**
* It returns true/false if the initial-state radiation is on/off.
*/
inline bool isISRadiationON() const;
/**
* It returns true/false if the final-state radiation is on/off.
*/
inline bool isFSRadiationON() const;
/**
* Get the ShowerModel
*/
inline ShowerModelPtr showerModel() const;
/**
* Set the cascade reconstructor and reweighter
* for ME/PS merging. This also communicates the
* splitting functions used in the Shower and
* initializes the reweighter.
*/
void useCKKW (CascadeReconstructorPtr,ReweighterPtr);
//@}
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/**
* Generate the hard matrix element correction
*/
virtual void hardMatrixElementCorrection();
/**
* Extract the particles to be showered, set the evolution scales
* and apply the hard matrix element correction
* @param hard Whether this is a hard process or decay
* @return The particles to be showered
*/
vector<ShowerProgenitorPtr> setupShower(bool hard);
/**
* set the colour partners
*/
void setColourPartners(bool hard);
/**
* Methods to perform the evolution of an individual particle, including
* recursive calling on the products
*/
//@{
/**
* It does the forward evolution of the time-like input particle
* (and recursively for all its radiation products).
* accepting only emissions which conforms to the showerVariables
* and soft matrix element correction pointed by meCorrectionPtr.
* If at least one emission has occurred then the method returns true.
* @param particle The particle to be showered
*/
virtual bool timeLikeShower(tShowerParticlePtr particle);
/**
* It does the backward evolution of the space-like input particle
* (and recursively for all its time-like radiation products).
* accepting only emissions which conforms to the showerVariables.
* If at least one emission has occurred then the method returns true
* @param particle The particle to be showered
* @param beam The beam particle
*/
virtual bool spaceLikeShower(tShowerParticlePtr particle,PPtr beam);
/**
* If does the forward evolution of the input on-shell particle
* involved in a decay
* (and recursively for all its time-like radiation products).
* accepting only emissions which conforms to the showerVariables.
* @param particle The particle to be showered
* @param maxscale The maximum scale for the shower.
* @param minimumMass The minimum mass of the final-state system
*/
virtual bool spaceLikeDecayShower(tShowerParticlePtr particle,
vector<Energy> maxscale,
Energy minimumMass);
//@}
/**
* Switches for matrix element corrections
*/
//@{
/**
* Any ME correction?
*/
inline bool MECOn() const;
/**
* Any hard ME correction?
*/
inline bool hardMEC() const;
/**
* Any soft ME correction?
*/
inline bool softMEC() const;
//@}
/**
* Switch for intrinsic pT
*/
//@{
/**
* Any intrinsic pT?
*/
inline bool ipTon() const;
//@}
/**@name Additional shower vetoes */
//@{
/**
* Insert a veto.
*/
inline void addVeto (ShowerVetoPtr);
/**
* Remove a veto.
*/
inline void removeVeto (ShowerVetoPtr);
//@}
/**
* Switches for vetoing hard emissions
*/
//@{
/**
* Vetos on?
*/
inline bool hardVetoOn() const;
/**
* veto hard emissions in IS shower?
*/
inline bool hardVetoIS() const;
/**
* veto hard emissions in FS shower?
*/
inline bool hardVetoFS() const;
/**
* veto hard emissions according to lastScale from XComb?
*/
inline bool hardVetoXComb() const;
//@}
/**
* Enhancement factors for radiation needed to generate the soft matrix
* element correction.
*/
//@{
/**
* Access the enhancement factor for initial-state radiation
*/
inline double initialStateRadiationEnhancementFactor() const;
/**
* Access the enhancement factor for final-state radiation
*/
inline double finalStateRadiationEnhancementFactor() const;
/**
* Set the enhancement factor for initial-state radiation
*/
inline void initialStateRadiationEnhancementFactor(double);
/**
* Set the enhancement factor for final-state radiation
*/
inline void finalStateRadiationEnhancementFactor(double);
//@}
/**
* Access/set the beam particle for the current initial-state shower
*/
//@{
/**
* Get the beam particle data
*/
inline Ptr<BeamParticleData>::const_pointer beamParticle() const;
/**
* Set the beam particle data
*/
inline void setBeamParticle(Ptr<BeamParticleData>::const_pointer);
//@}
/**
* Calculate the intrinsic \f$p_T\f$.
*/
virtual void generateIntrinsicpT(vector<ShowerProgenitorPtr>);
/**
* find the maximally allowed pt acc to the hard process.
*/
void setupMaximumScales(ShowerTreePtr, vector<ShowerProgenitorPtr>);
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
inline 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.
*/
inline virtual IBPtr fullclone() const;
//@}
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object. Called in the run phase just before
* a run begins.
*/
virtual void doinitrun();
/**
* 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.
*/
inline virtual void rebind(const TranslationMap & trans)
throw(RebindException);
/**
* Return a vector of all pointers to Interfaced objects used in this
* object.
* @return a vector of pointers.
*/
inline virtual IVector getReferences();
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<Evolver> initEvolver;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
Evolver & operator=(const Evolver &);
private:
/**
* Pointer to the model for the shower evolution model
*/
ShowerModelPtr _model;
/**
* Pointer to the splitting generator
*/
SplittingGeneratorPtr _splittingGenerator;
/**
* Maximum number of tries to generate the shower of a particular tree
*/
unsigned int _maxtry;
/**
* Matrix element correction switch
*/
unsigned int _meCorrMode;
/**
* Hard emission veto switch
*/
unsigned int _hardVetoMode;
/**
* Hard veto to be read switch
*/
unsigned int _hardVetoRead;
/**
* rms intrinsic pT of Gaussian distribution
*/
Energy _iptrms;
/**
* Proportion of inverse quadratic intrinsic pT distribution
*/
double _beta;
/**
* Parameter for inverse quadratic: 2*Beta*Gamma/(sqr(Gamma)+sqr(intrinsicpT))
*/
Energy _gamma;
/**
* Upper bound on intrinsic pT for inverse quadratic
*/
Energy _iptmax;
/**
+ * Limit the number of emissions for testing
+ */
+ unsigned int _limitEmissions;
+
+ /**
* The progenitor of the current shower
*/
-
ShowerProgenitorPtr _progenitor;
/**
* Matrix element correction used for the current shower
*/
MECorrectionPtr _currentme;
/**
* The ShowerTree currently being showered
*/
ShowerTreePtr _currenttree;
/**
* Radiation enhancement factors for use with the veto algorithm
* if needed by the soft matrix element correction
*/
//@{
/**
* Enhancement factor for initial-state radiation
*/
double _initialenhance;
/**
* Enhancement factor for final-state radiation
*/
double _finalenhance;
//@}
/**
* The beam particle data for the current initial-state shower
*/
Ptr<BeamParticleData>::const_pointer _beam;
/**
* Storage of the intrinsic \f$p_t\f$ of the particles
*/
map<tShowerProgenitorPtr,pair<Energy,double> > _intrinsic;
/**
* Vetoes
*/
vector<ShowerVetoPtr> _vetoes;
/**@name Members related to CKKW ME/PS merging */
//@{
/**
* The cascade reconstructor used.
*/
CascadeReconstructorPtr _reconstructor;
/**
* The reweighter used.
*/
DefaultReweighterPtr _reweighter;
/**
* The CKKW veto used
*/
DefaultCKKWVetoPtr _ckkwVeto;
/**
* Wether or not CKKW is used
*/
bool _useCKKW;
/**
* Wether or not CKKW applies to the current tree
*/
bool _theUseCKKW;
#ifdef HERWIG_CHECK_VETOES
vetoed_points _vetoed_points;
#endif
//@}
+ /**
+ * number of IS emissions
+ */
+ unsigned int _nis;
+
+ /**
+ * Number of FS emissions
+ */
+ unsigned int _nfs;
+
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of Evolver. */
template <>
struct BaseClassTrait<Herwig::Evolver,1> {
/** Typedef of the first base class of Evolver. */
typedef Interfaced NthBase;
};
/** This template specialization informs ThePEG about the name of
* the Evolver class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::Evolver>
: public ClassTraitsBase<Herwig::Evolver> {
/** Return a platform-independent class name */
static string className() { return "Herwig::Evolver"; }
/**
* The name of a file containing the dynamic library where the class
* Evolver is implemented. It may also include several, space-separated,
* libraries if the class Evolver depends on other classes (base classes
* excepted). In this case the listed libraries will be dynamically
* linked in the order they are specified.
*/
static string library() { return "HwMPI.so HwMPIPDF.so HwRemDecayer.so HwShower.so"; }
};
/** @endcond */
}
#include "Evolver.icc"
-#ifndef ThePEG_TEMPLATES_IN_CC_FILE
-// #include "Evolver.tcc"
-#endif
#endif /* HERWIG_Evolver_H */
diff --git a/Shower/Base/Evolver.icc b/Shower/Base/Evolver.icc
--- a/Shower/Base/Evolver.icc
+++ b/Shower/Base/Evolver.icc
@@ -1,133 +1,134 @@
// -*- C++ -*-
//
// Evolver.icc is a part of Herwig++ - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2007 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 inlined member functions of
// the Evolver class.
//
namespace Herwig {
inline Evolver::Evolver() : _maxtry(100), _meCorrMode(1), _hardVetoMode(1),
_hardVetoRead(0),
- _iptrms(), _beta(), _gamma(), _iptmax(),
+ _iptrms(0.*GeV), _beta(0.), _gamma(0.*GeV), _iptmax(),
+ _limitEmissions(0),
_initialenhance(1.), _finalenhance(1.), _useCKKW(false),
_theUseCKKW(false)
{}
inline IBPtr Evolver::clone() const {
return new_ptr(*this);
}
inline IBPtr Evolver::fullclone() const {
return new_ptr(*this);
}
inline bool Evolver::showeringON() const
{
return
_splittingGenerator->isISRadiationON()||
_splittingGenerator->isFSRadiationON();
}
inline bool Evolver::isISRadiationON() const {
return _splittingGenerator->isISRadiationON();
}
inline bool Evolver::isFSRadiationON() const {
return _splittingGenerator->isFSRadiationON();
}
inline ShowerModelPtr Evolver::showerModel() const {
return _model;
}
inline bool Evolver::ipTon() const {
return _iptrms != 0.0*MeV || ( _beta == 1.0 && _gamma != 0.0*MeV && _iptmax !=0.0*MeV );
}
inline bool Evolver::MECOn() const {
return _meCorrMode > 0;
}
inline bool Evolver::hardMEC() const {
return (_meCorrMode == 1 || _meCorrMode == 2);
}
inline bool Evolver::softMEC() const {
return (_meCorrMode == 1 || _meCorrMode > 2);
}
inline bool Evolver::hardVetoOn() const {
return _hardVetoMode > 0;
}
inline bool Evolver::hardVetoIS() const {
return (_hardVetoMode == 1 || _hardVetoMode == 2);
}
inline bool Evolver::hardVetoFS() const {
return (_hardVetoMode == 1 || _hardVetoMode > 2);
}
inline bool Evolver::hardVetoXComb() const {
return (_hardVetoRead == 1);
}
inline double Evolver::initialStateRadiationEnhancementFactor() const {
return _initialenhance;
}
inline double Evolver::finalStateRadiationEnhancementFactor() const {
return _finalenhance;
}
inline void Evolver::initialStateRadiationEnhancementFactor(double in) {
_initialenhance=in;
}
inline void Evolver::finalStateRadiationEnhancementFactor(double in) {
_finalenhance=in;
}
inline Ptr<BeamParticleData>::const_pointer
Evolver::beamParticle() const {
return _beam;
}
inline void Evolver::setBeamParticle(Ptr<BeamParticleData>::const_pointer in) {
_beam=in;
}
inline void Evolver::addVeto (ShowerVetoPtr v) {
_vetoes.push_back(v);
}
inline void Evolver::removeVeto (ShowerVetoPtr v) {
vector<ShowerVetoPtr>::iterator vit = find(_vetoes.begin(),_vetoes.end(),v);
if (vit != _vetoes.end())
_vetoes.erase(vit);
}
inline void Evolver::rebind(const TranslationMap & trans)
throw(RebindException) {
_reconstructor=trans.translate(_reconstructor);
_reweighter=trans.translate(_reweighter);
Interfaced::rebind(trans);
}
inline IVector Evolver::getReferences() {
IVector ret = Interfaced::getReferences();
ret.push_back(_reconstructor);
ret.push_back(_reweighter);
return ret;
}
}
diff --git a/Shower/Base/ShowerTree.cc b/Shower/Base/ShowerTree.cc
--- a/Shower/Base/ShowerTree.cc
+++ b/Shower/Base/ShowerTree.cc
@@ -1,795 +1,794 @@
// -*- C++ -*-
//
// ShowerTree.cc is a part of Herwig++ - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2007 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.
//
#include "ShowerProgenitor.h"
#include "ShowerTree.h"
#include "Herwig++/Shower/Base/ShowerParticle.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Handlers/EventHandler.h"
#include "ThePEG/Handlers/XComb.h"
#include "KinematicsReconstructor.h"
#include <cassert>
namespace Herwig {
using namespace ThePEG;
// constructor from hard process
ShowerTree::ShowerTree(const ParticleVector & out,
multimap<Energy,ShowerTreePtr>& decay)
: _hardMECorrection(false), _wasHard(true),
_parent(ShowerTreePtr()), _showerHandler(ShowerHandler::currentHandler()),
_hasShowered(false) {
tPPair beam = _showerHandler->generator()->currentEvent()->incoming();
PPtr in1 = _showerHandler->currentSubProcess()->incoming().first;
PPtr in2 = _showerHandler->currentSubProcess()->incoming().second;
double x1(in1->momentum().rho()/beam.first->momentum().rho());
double x2(in2->momentum().rho()/beam.second->momentum().rho());
// must have two incoming particles
assert(in1 && in2);
// set the parent tree
_parent=ShowerTreePtr();
// tempory vectors to contain all the particles before insertion into
// the data structure
vector<PPtr> original,copy;
vector<ShowerParticlePtr> shower;
// create copies of ThePEG particles for the incoming particles
original.push_back(in1);copy.push_back(new_ptr(Particle(*in1)));
original.push_back(in2);copy.push_back(new_ptr(Particle(*in2)));
// and same for outgoing
map<PPtr,ShowerTreePtr> trees;
for (ParticleVector::const_iterator it = out.begin();it != out.end(); ++it) {
// if decayed or should be decayed in shower make the tree
PPtr orig=*it;
if(!orig->children().empty()||
(_showerHandler->decayInShower(orig->id())&&!orig->dataPtr()->stable())) {
ShowerTreePtr newtree=new_ptr(ShowerTree(orig,decay));
newtree->setParents();
trees.insert(make_pair(orig,newtree));
Energy width=orig->dataPtr()->generateWidth(orig->mass());
decay.insert(make_pair(width,newtree));
}
original.push_back(orig);
copy.push_back(new_ptr(Particle(*orig)));
}
// colour isolate the hard process
colourIsolate(original,copy);
// now create the Shower particles
// create ShowerParticles for the incoming particles
assert(original.size() == copy.size());
for(unsigned int ix=0;ix<original.size();++ix) {
ShowerParticlePtr temp=new_ptr(ShowerParticle(*copy[ix],1,ix>=2));
fixColour(temp);
// incoming
if(ix<2) {
if(ix==0) temp->x(x1);
else if(ix==1) temp->x(x2);
_incomingLines.insert(make_pair(new_ptr(ShowerProgenitor(original[ix],
copy[ix],temp)),
temp));
_backward.insert(temp);
}
// outgoing
else {
_outgoingLines.insert(make_pair(new_ptr(ShowerProgenitor(original[ix],
copy[ix],temp)),
temp));
_forward.insert(temp);
}
}
// set up the map of daughter trees
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator mit;
for(mit=_outgoingLines.begin();mit!=_outgoingLines.end();++mit)
{
map<PPtr,ShowerTreePtr>::const_iterator tit=trees.find(mit->first->original());
if(tit!=trees.end())
_treelinks.insert(make_pair(tit->second,
make_pair(mit->first,mit->first->progenitor())));
}
}
ShowerTree::ShowerTree(PPtr in,
multimap<Energy,ShowerTreePtr>& decay)
: _hardMECorrection(false), _wasHard(false),
_showerHandler(ShowerHandler::currentHandler()), _hasShowered(false) {
// there must be an incoming particle
assert(in);
// tempory vectors to contain all the particles before insertion into
// the data structure
vector<PPtr> original,copy;
// insert place holder for incoming particle
original.push_back(in);copy.push_back(PPtr());
// we need to deal with the decay products if decayed
map<PPtr,ShowerTreePtr> trees;
if(!in->children().empty()) {
ParticleVector children=in->children();
for(unsigned int ix=0;ix<children.size();++ix) {
// if decayed or should be decayed in shower make the tree
PPtr orig=children[ix];
in->abandonChild(orig);
if(!orig->children().empty()||
(_showerHandler->decayInShower(orig->id())&&!orig->dataPtr()->stable())) {
ShowerTreePtr newtree=new_ptr(ShowerTree(orig,decay));
trees.insert(make_pair(orig,newtree));
Energy width=orig->dataPtr()->generateWidth(orig->mass());
decay.insert(make_pair(width,newtree));
newtree->setParents();
newtree->_parent=this;
}
original.push_back(orig);
copy.push_back(new_ptr(Particle(*orig)));
}
}
// create the incoming particle
copy[0] = new_ptr(Particle(*in));
// isolate the colour
colourIsolate(original,copy);
// create the parent
ShowerParticlePtr sparent(new_ptr(ShowerParticle(*copy[0],2,false)));
fixColour(sparent);
_incomingLines.insert(make_pair(new_ptr(ShowerProgenitor(original[0],copy[0],sparent))
,sparent));
// return if not decayed
if(original.size()==1) return;
// create the children
assert(copy.size() == original.size());
for (unsigned int ix=1;ix<original.size();++ix) {
ShowerParticlePtr stemp= new_ptr(ShowerParticle(*copy[ix],2,true));
fixColour(stemp);
_outgoingLines.insert(make_pair(new_ptr(ShowerProgenitor(original[ix],copy[ix],
stemp)),
stemp));
_forward.insert(stemp);
}
// set up the map of daughter trees
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator mit;
for(mit=_outgoingLines.begin();mit!=_outgoingLines.end();++mit) {
map<PPtr,ShowerTreePtr>::const_iterator tit=trees.find(mit->first->original());
if(tit!=trees.end())
_treelinks.insert(make_pair(tit->second,
make_pair(mit->first,mit->first->progenitor())));
}
}
void ShowerTree::updateFinalStateShowerProduct(ShowerProgenitorPtr progenitor,
ShowerParticlePtr parent,
const ShowerParticleVector & children) {
assert(children.size()==2);
bool matches[2];
for(unsigned int ix=0;ix<2;++ix)
{matches[ix]=children[ix]->id()==progenitor->id();}
ShowerParticlePtr newpart;
if(matches[0]&&matches[1]) {
if(parent->showerKinematics()->z()>0.5) newpart=children[0];
else newpart=children[1];
}
else if(matches[0]) newpart=children[0];
else if(matches[1]) newpart=children[1];
else newpart=ShowerParticlePtr();
_outgoingLines[progenitor]=newpart;
}
void ShowerTree::updateInitialStateShowerProduct(ShowerProgenitorPtr progenitor,
ShowerParticlePtr newParent) {
_incomingLines[progenitor]=newParent;
}
void ShowerTree::colourIsolate(const vector<PPtr> & original,
const vector<PPtr> & copy) {
// vectors must have same size
assert(original.size()==copy.size());
// create a temporary map with all the particles to make looping easier
vector<pair<PPtr,PPtr> > particles;
particles.reserve(original.size());
for(unsigned int ix=0;ix<original.size();++ix)
particles.push_back(make_pair(copy[ix],original[ix]));
// reset the colour of the copies
vector<pair<PPtr,PPtr> >::const_iterator cit,cjt;
for(cit=particles.begin();cit!=particles.end();++cit)
if((*cit).first->colourInfo()) (*cit).first->colourInfo(new_ptr(ColourBase()));
map<tColinePtr,tColinePtr> cmap;
// make the colour connections of the copies
for(cit=particles.begin();cit!=particles.end();++cit) {
ColinePtr c1=ColinePtr(),newline=ColinePtr();
// if particle has a colour line
if((*cit).second->colourLine()&&!(*cit).first->colourLine()) {
c1=(*cit).second->colourLine();
newline=ColourLine::create((*cit).first);
cmap[c1]=newline;
for(cjt=particles.begin();cjt!=particles.end();++cjt) {
if(cjt==cit) continue;
if((*cjt).second->colourLine()==c1)
newline->addColoured((*cjt).first);
else if((*cjt).second->antiColourLine()==c1)
newline->addColoured((*cjt).first,true);
}
}
// if anticolour line
if((*cit).second->antiColourLine()&&!(*cit).first->antiColourLine()) {
c1=(*cit).second->antiColourLine();
newline=ColourLine::create((*cit).first,true);
cmap[c1]=newline;
for(cjt=particles.begin();cjt!=particles.end();++cjt) {
if(cjt==cit) continue;
if((*cjt).second->colourLine()==c1)
newline->addColoured((*cjt).first);
else if((*cjt).second->antiColourLine()==c1)
newline->addColoured((*cjt).first,true);
}
}
}
// sort out sinks and sources
for(cit=particles.begin();cit!=particles.end();++cit) {
tColinePtr cline[2];
tColinePair cpair;
for(unsigned int ix=0;ix<4;++ix) {
cline[0] = ix<2 ? cit->second->colourLine() : cit->second->antiColourLine();
cline[1] = ix<2 ? cit->first ->colourLine() : cit->first ->antiColourLine();
if(cline[0]) {
switch (ix) {
case 0: case 2:
cpair = cline[0]->sinkNeighbours();
break;
case 1: case 3:
cpair = cline[0]->sourceNeighbours();
break;
};
}
else {
cpair = make_pair(tColinePtr(),tColinePtr());
}
if(cline[0]&&cpair.first) {
map<tColinePtr,tColinePtr>::const_iterator
mit[2] = {cmap.find(cpair.first),cmap.find(cpair.second)};
if(mit[0]!=cmap.end()&&mit[1]!=cmap.end()) {
if(ix==0||ix==2) {
cline[1]->setSinkNeighbours(mit[0]->second,mit[1]->second);
}
else {
cline[1]->setSourceNeighbours(mit[0]->second,mit[1]->second);
}
}
}
}
}
}
void ShowerTree::insertHard(StepPtr pstep, bool ISR, bool) {
assert(_incomingLines.size()==2);
_colour.clear();
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cit;
// construct the map of colour lines for hard process
for(cit=_incomingLines.begin();cit!=_incomingLines.end();++cit) {
if(!cit->first->perturbative()) continue;
if((*cit).first->copy()->colourLine())
_colour.insert(make_pair((*cit).first->copy()->colourLine(),
(*cit).first->original()->colourLine()));
if((*cit).first->copy()->antiColourLine())
_colour.insert(make_pair((*cit).first->copy()->antiColourLine(),
(*cit).first->original()->antiColourLine()));
}
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cjt;
for(cjt=_outgoingLines.begin();cjt!=_outgoingLines.end();++cjt) {
if(!cjt->first->perturbative()) continue;
if((*cjt).first->copy()->colourLine())
_colour.insert(make_pair((*cjt).first->copy()->colourLine(),
(*cjt).first->original()->colourLine()));
if((*cjt).first->copy()->antiColourLine())
_colour.insert(make_pair((*cjt).first->copy()->antiColourLine(),
(*cjt).first->original()->antiColourLine()));
}
// initial-state radiation
if(ISR) {
for(cit=incomingLines().begin();cit!=incomingLines().end();++cit) {
ShowerParticlePtr init=(*cit).first->progenitor();
if(!init->getThePEGBase())
throw Exception() << "Initial-state particle must have a ThePEGBase"
<< " in ShowerTree::fillEventRecord()"
<< Exception::runerror;
PPtr original = (*cit).first->original();
if(original->parents().empty()) continue;
PPtr hadron= original->parents()[0];
assert(!original->children().empty());
PPtr copy=cit->first->copy();
ParticleVector intermediates=original->children();
for(unsigned int ix=0;ix<intermediates.size();++ix) {
init->abandonChild(intermediates[ix]);
copy->abandonChild(intermediates[ix]);
}
// if not from a matrix element correction
if(cit->first->perturbative()) {
// break mother/daugther relations
init->addChild(original);
hadron->abandonChild(original);
// if particle showers add shower
if(cit->first->hasEmitted()) {
addInitialStateShower(init,hadron,pstep,false);
}
// no showering for this particle
else {
updateColour(init);
hadron->addChild(init);
pstep->addIntermediate(init);
}
}
// from matrix element correction
else {
// break mother/daugther relations
hadron->abandonChild(original);
copy->addChild(original);
updateColour(copy);
init->addChild(copy);
pstep->addIntermediate(copy);
// if particle showers add shower
if(cit->first->hasEmitted()) {
addInitialStateShower(init,hadron,pstep,false);
}
// no showering for this particle
else {
updateColour(init);
hadron->addChild(init);
pstep->addIntermediate(init);
}
}
}
}
// final-state radiation
PPair incoming=_showerHandler->currentSubProcess()->incoming();
for(cjt=outgoingLines().begin();cjt!=outgoingLines().end();++cjt) {
ShowerParticlePtr init=(*cjt).first->progenitor();
if(!init->getThePEGBase())
throw Exception() << "Final-state particle must have a ThePEGBase"
<< " in ShowerTree::fillEventRecord()"
<< Exception::runerror;
// if not from a matrix element correction
if(cjt->first->perturbative()) {
// register the shower particle as a
// copy of the one from the hard process
tParticleVector parents=init->parents();
for(unsigned int ix=0;ix<parents.size();++ix)
{parents[ix]->abandonChild(init);}
(*cjt).first->original()->addChild(init);
pstep->addDecayProduct(init);
}
// from a matrix element correction
else {
if(cjt->first->original()==incoming.first||
cjt->first->original()==incoming.second) {
updateColour((*cjt).first->copy());
(*cjt).first->original()->parents()[0]->
addChild((*cjt).first->copy());
pstep->addDecayProduct((*cjt).first->copy());
(*cjt).first->copy()->addChild(init);
pstep->addDecayProduct(init);
}
else {
updateColour((*cjt).first->copy());
(*cjt).first->original()->addChild((*cjt).first->copy());
pstep->addDecayProduct((*cjt).first->copy());
(*cjt).first->copy()->addChild(init);
pstep->addDecayProduct(init);
}
}
updateColour(init);
// insert shower products
addFinalStateShower(init,pstep);
}
_colour.clear();
}
void ShowerTree::addFinalStateShower(PPtr p, StepPtr s) {
if(!p->children().empty()) {
ParticleVector::const_iterator child;
for(child=p->children().begin(); child != p->children().end(); ++child) {
updateColour(*child);
s->addDecayProduct(*child);
addFinalStateShower(*child,s);
}
}
}
void ShowerTree::updateColour(PPtr particle) {
// if attached to a colour line
if(particle->colourLine()) {
bool reset=false;
// if colour line from hard process reconnect
if(_colour.find(particle->colourLine())!=_colour.end()) {
ColinePtr c1=particle->colourLine();
c1->removeColoured(particle);
_colour[c1]->addColoured(particle);
reset=true;
}
// ensure properly connected to the line
if(!reset) {
ColinePtr c1=particle->colourLine();
c1->removeColoured(particle);
c1->addColoured(particle);
}
}
// if attached to an anticolour line
if(particle->antiColourLine()) {
bool reset=false;
// if anti colour line from hard process reconnect
if(_colour.find(particle->antiColourLine())!=_colour.end()) {
ColinePtr c1=particle->antiColourLine();
c1->removeColoured(particle,true);
_colour[c1]->addColoured(particle,true);
reset=true;
}
if(!reset) {
ColinePtr c1=particle->antiColourLine();
c1->removeColoured(particle,true);
c1->addColoured(particle,true);
}
}
}
void ShowerTree::addInitialStateShower(PPtr p, PPtr hadron,
StepPtr s, bool addchildren) {
// Each parton here should only have one parent
if(!p->parents().empty()) {
if(p->parents().size()!=1)
throw Exception() << "Particle must only have one parent in ShowerTree"
<< "::addInitialStateShower" << Exception::runerror;
addInitialStateShower(p->parents()[0],hadron,s);
}
else {
hadron->addChild(p);
s->addIntermediate(p);
}
updateColour(p);
ParticleVector::const_iterator child;
// if not adding children return
if(!addchildren) return;
// add children
for(child = p->children().begin(); child != p->children().end(); ++child) {
// if a final-state particle update the colour
ShowerParticlePtr schild =
dynamic_ptr_cast<ShowerParticlePtr>(*child);
if(schild && schild->isFinalState()) updateColour(*child);
// if there are grandchildren of p
if(!(*child)->children().empty()) {
// Add child as intermediate
s->addIntermediate(*child);
// If child is shower particle and final-state, add children
if(schild && schild->isFinalState()) addFinalStateShower(schild,s);
}
else
s->addDecayProduct(*child);
}
}
void ShowerTree::decay(multimap<Energy,ShowerTreePtr> & decay) {
// must be one incoming particle
assert(_incomingLines.size()==1);
// if not already decayed decay it
if(_outgoingLines.empty()) {
// now we need to replace the particle with a new copy after the shower
// find particle after the shower
ShowerParticlePtr newparent=_parent->_treelinks[this].second;
// now make the new progenitor
vector<PPtr> original,copy;
original.push_back(newparent);
copy.push_back(new_ptr(Particle(*newparent)));
// reisolate the colour
colourIsolate(original,copy);
// make the new progenitor
ShowerParticlePtr stemp=new_ptr(ShowerParticle(*copy[0],2,false));
fixColour(stemp);
ShowerProgenitorPtr newprog=new_ptr(ShowerProgenitor(original[0],copy[0],stemp));
_incomingLines.clear();
_incomingLines.insert(make_pair(newprog,stemp));
// now we need to decay the copy
PPtr parent=copy[0];
unsigned int ntry = 0;
while (true) {
// exit if fails
if (++ntry>=200)
throw Exception() << "Failed to perform decay in ShowerTree::decay()"
<< " after " << 200
<< " attempts for " << parent->PDGName()
<< Exception::eventerror;
// select decay mode
tDMPtr dm(parent->data().selectMode(*parent));
if(!dm)
throw Exception() << "Failed to select decay mode in ShowerTree::decay()"
<< "for " << newparent->PDGName()
<< Exception::eventerror;
if(!dm->decayer())
throw Exception() << "No Decayer for selected decay mode "
<< " in ShowerTree::decay()"
<< Exception::runerror;
// start of try block
try {
ParticleVector children = dm->decayer()->decay(*dm, *parent);
// if no children have another go
if(children.empty()) continue;
// set up parent
parent->decayMode(dm);
// add children
for (unsigned int i = 0, N = children.size(); i < N; ++i ) {
children[i]->setLabVertex(parent->labDecayVertex());
parent->addChild(children[i]);
parent->scale(0.0*GeV2);
}
// if succeeded break out of loop
break;
}
catch(KinematicsReconstructionVeto) {}
}
// insert the trees from the children
ParticleVector children=parent->children();
map<PPtr,ShowerTreePtr> trees;
for(unsigned int ix=0;ix<children.size();++ix) {
PPtr orig=children[ix];
parent->abandonChild(orig);
// if particle has children or decays in shower
if(!orig->children().empty()||
(_showerHandler->decayInShower(orig->id())&&!orig->dataPtr()->stable())) {
ShowerTreePtr newtree=new_ptr(ShowerTree(orig,decay));
trees.insert(make_pair(orig,newtree));
Energy width=orig->dataPtr()->generateWidth(orig->mass());
decay.insert(make_pair(width,newtree));
}
// now create the shower progenitors
PPtr ncopy=new_ptr(Particle(*orig));
//copy[0]->addChild(ncopy);
ShowerParticlePtr nshow=new_ptr(ShowerParticle(*ncopy,2,true));
fixColour(nshow);
ShowerProgenitorPtr prog=new_ptr(ShowerProgenitor(children[ix],
ncopy,nshow));
_outgoingLines.insert(make_pair(prog,nshow));
}
// set up the map of daughter trees
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator mit;
for(mit=_outgoingLines.begin();mit!=_outgoingLines.end();++mit) {
map<PPtr,ShowerTreePtr>::const_iterator tit=trees.find(mit->first->original());
if(tit!=trees.end()) {
_treelinks.insert(make_pair(tit->second,
make_pair(mit->first,
mit->first->progenitor())));
tit->second->_parent=this;
}
}
}
// all ready decayed
else {
// need to boost the system to conserve momentum
// find parent tree and particle
ShowerTreePtr ptree=ShowerTreePtr(this);
ShowerParticlePtr newparent=_parent->_treelinks[ptree].second;
// workout the lorentz boost
Lorentz5Momentum ptemp(_incomingLines.begin()->first->progenitor()->momentum());
LorentzRotation boost(ptemp.findBoostToCM(),ptemp.e()/ptemp.mass());
boost.boost(newparent->momentum().boostVector(),
newparent->momentum().e()/newparent->mass());
// now boost all the particles
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cit;
for(cit=_incomingLines.begin();cit!=_incomingLines.end();++cit) {
cit->first->progenitor()->deepTransform(boost);
cit->first->original()->deepTransform(boost);
cit->first->copy()->deepTransform(boost);
}
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cjt;
for(cjt=_outgoingLines.begin();cjt!=_outgoingLines.end();++cjt) {
cjt->first->progenitor()->deepTransform(boost);
cjt->first->original()->deepTransform(boost);
cjt->first->copy()->deepTransform(boost);
}
}
}
void ShowerTree::insertDecay(StepPtr pstep,bool ISR, bool) {
assert(_incomingLines.size()==1);
_colour.clear();
// find final particle from previous tree
ShowerParticlePtr final=_parent->_treelinks[this].second;
// construct the map of colour lines
PPtr copy=_incomingLines.begin()->first->copy();
if(copy->colourLine())
_colour.insert(make_pair(copy->colourLine(),final->colourLine()));
if(copy->antiColourLine())
_colour.insert(make_pair(copy->antiColourLine(),final->antiColourLine()));
// initial-state radiation
if(ISR&&!_incomingLines.begin()->first->progenitor()->children().empty()) {
ShowerParticlePtr init=_incomingLines.begin()->first->progenitor();
updateColour(init);
final->addChild(init);
pstep->addDecayProduct(init);
// insert shower products
addFinalStateShower(init,pstep);
// sort out colour
final=_incomingLines.begin()->second;
_colour.clear();
if(copy->colourLine())
_colour.insert(make_pair(copy->colourLine(),final->colourLine()));
if(copy->antiColourLine())
_colour.insert(make_pair(copy->antiColourLine(),final->antiColourLine()));
}
// get the decaying particles
// make the copy
tColinePair cline=make_pair(copy->colourLine(),copy->antiColourLine());
updateColour(copy);
// sort out sinks and sources if needed
if(cline.first) {
if(cline.first->sourceNeighbours().first) {
copy->colourLine()->setSourceNeighbours(cline.first->sourceNeighbours().first,
cline.first->sourceNeighbours().second);
}
else if (cline.first->sinkNeighbours().first) {
copy->colourLine()->setSinkNeighbours(cline.first->sinkNeighbours().first,
cline.first->sinkNeighbours().second);
}
}
if(cline.second) {
if(cline.second->sourceNeighbours().first) {
copy->antiColourLine()->setSourceNeighbours(cline.second->sourceNeighbours().first,
cline.second->sourceNeighbours().second);
}
else if (cline.second->sinkNeighbours().first) {
copy->antiColourLine()->setSinkNeighbours(cline.second->sinkNeighbours().first,
cline.second->sinkNeighbours().second);
}
}
// copy of the one from the hard process
tParticleVector dpar=copy->parents();
for(unsigned int ix=0;ix<dpar.size();++ix) dpar[ix]->abandonChild(copy);
final->addChild(copy);
pstep->addDecayProduct(copy);
// final-state radiation
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cit;
for(cit=outgoingLines().begin();cit!=outgoingLines().end();++cit) {
ShowerParticlePtr init=cit->first->progenitor();
if(!init->getThePEGBase())
throw Exception() << "Final-state particle must have a ThePEGBase"
<< " in ShowerTree::fillEventRecord()"
<< Exception::runerror;
// if not from matrix element correction
if(cit->first->perturbative()) {
// add the child
updateColour(cit->first->copy());
PPtr orig=cit->first->original();
copy->addChild(orig);
pstep->addDecayProduct(orig);
orig->addChild(cit->first->copy());
pstep->addDecayProduct(cit->first->copy());
// register the shower particle as a
// copy of the one from the hard process
tParticleVector parents=init->parents();
for(unsigned int ix=0;ix<parents.size();++ix)
{parents[ix]->abandonChild(init);}
(*cit).first->copy()->addChild(init);
pstep->addDecayProduct(init);
updateColour(init);
}
// from a matrix element correction
else {
if(copy->children().end()==
find(copy->children().begin(),copy->children().end(),
cit->first->original())) {
updateColour(cit->first->original());
copy->addChild(cit->first->original());
pstep->addDecayProduct(cit->first->original());
}
updateColour(cit->first->copy());
cit->first->original()->addChild(cit->first->copy());
pstep->addDecayProduct(cit->first->copy());
// register the shower particle as a
// copy of the one from the hard process
tParticleVector parents=init->parents();
for(unsigned int ix=0;ix<parents.size();++ix)
{parents[ix]->abandonChild(init);}
(*cit).first->copy()->addChild(init);
pstep->addDecayProduct(init);
updateColour(init);
}
// insert shower products
addFinalStateShower(init,pstep);
}
_colour.clear();
}
void ShowerTree::clear() {
// reset the has showered flag
_hasShowered=false;
// clear the colour map
_colour.clear();
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cit;
map<ShowerProgenitorPtr, ShowerParticlePtr>::const_iterator cjt;
// abandon the children of the outgoing particles
for(cit=_outgoingLines.begin();cit!=_outgoingLines.end();++cit) {
ShowerParticlePtr orig=cit->first->progenitor();
orig->set5Momentum(cit->first->copy()->momentum());
ParticleVector children=orig->children();
for(unsigned int ix=0;ix<children.size();++ix) orig->abandonChild(children[ix]);
_outgoingLines[cit->first]=orig;
cit->first->hasEmitted(false);
}
// forward products
_forward.clear();
for(cit=_outgoingLines.begin();cit!=_outgoingLines.end();++cit)
_forward.insert(cit->first->progenitor());
// if a decay
if(!_wasHard) {
ShowerParticlePtr orig=_incomingLines.begin()->first->progenitor();
orig->set5Momentum(_incomingLines.begin()->first->copy()->momentum());
ParticleVector children=orig->children();
for(unsigned int ix=0;ix<children.size();++ix) orig->abandonChild(children[ix]);
}
// if a hard process
else {
for(cjt=_incomingLines.begin();cjt!=_incomingLines.end();++cjt) {
- PPtr parent=cjt->first->original()->parents()[0];
+ tPPtr parent = cjt->first->original()->parents().empty() ?
+ tPPtr() : cjt->first->original()->parents()[0];
ShowerParticlePtr temp=
new_ptr(ShowerParticle(*cjt->first->copy(),
cjt->first->progenitor()->perturbative(),
cjt->first->progenitor()->isFinalState()));
fixColour(temp);
temp->x(cjt->first->progenitor()->x());
- assert(parent);
cjt->first->hasEmitted(false);
- if(!(cjt->first->progenitor()==cjt->second)&&cjt->second)
+ if(!(cjt->first->progenitor()==cjt->second)&&cjt->second&&parent)
parent->abandonChild(cjt->second);
cjt->first->progenitor(temp);
_incomingLines[cjt->first]=temp;
}
}
// reset the particles at the end of the shower
_backward.clear();
// if hard process backward products
if(_wasHard)
for(cjt=_incomingLines.begin();cjt!=_incomingLines.end();++cjt)
_backward.insert(cjt->first->progenitor());
}
void ShowerTree::resetShowerProducts() {
map<ShowerProgenitorPtr, ShowerParticlePtr>::const_iterator cit;
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cjt;
_backward.clear();
_forward.clear();
for(cit=_incomingLines.begin();cit!=_incomingLines.end();++cit)
_backward.insert(cit->second);
for(cjt=_outgoingLines.begin();cjt!=_outgoingLines.end();++cjt)
_forward.insert(cjt->second);
}
-void ShowerTree::updateAfterShower(multimap<Energy,ShowerTreePtr> & decay)
-{
+void ShowerTree::updateAfterShower(multimap<Energy,ShowerTreePtr> & decay) {
// update the links
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator mit;
map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::iterator tit;
for(tit=_treelinks.begin();tit!=_treelinks.end();++tit) {
if(tit->second.first) {
mit=_outgoingLines.find(tit->second.first);
if(mit!=_outgoingLines.end()) tit->second.second=mit->second;
}
}
// get the particles coming from those in the hard process
set<tShowerParticlePtr> hard;
for(mit=_outgoingLines.begin();mit!=_outgoingLines.end();++mit)
hard.insert(mit->second);
// find the shower particles which should be decayed in the
// shower but didn't come from the hard process
set<tShowerParticlePtr>::const_iterator cit;
for(cit=_forward.begin();cit!=_forward.end();++cit) {
if(_showerHandler->decayInShower((**cit).id())&&
hard.find(*cit)==hard.end()) {
ShowerTreePtr newtree=new_ptr(ShowerTree(*cit,decay));
newtree->setParents();
newtree->_parent=this;
Energy width=(**cit).dataPtr()->generateWidth((**cit).mass());
decay.insert(make_pair(width,newtree));
_treelinks.insert(make_pair(newtree,
make_pair(tShowerProgenitorPtr(),*cit)));
}
}
}
}
diff --git a/Shower/Base/ShowerTree.h b/Shower/Base/ShowerTree.h
--- a/Shower/Base/ShowerTree.h
+++ b/Shower/Base/ShowerTree.h
@@ -1,331 +1,336 @@
// -*- C++ -*-
//
// ShowerTree.h is a part of Herwig++ - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2007 The Herwig Collaboration
//
// Herwig++ is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_ShowerTree_H
#define HERWIG_ShowerTree_H
#include "ThePEG/Config/ThePEG.h"
#include "Herwig++/Shower/ShowerHandler.h"
#include "Herwig++/Shower/ShowerConfig.h"
#include "Herwig++/Shower/Base/ShowerParticle.h"
#include "ShowerProgenitor.h"
#include "ThePEG/EventRecord/Step.h"
#include <cassert>
#include "ShowerTree.fh"
namespace Herwig {
using namespace ThePEG;
/** \ingroup Shower
*
* The ShowerTree class stores the basic information needed for
* each hard interaction, either a scattering process or decay, which
* needs to be showered.
*
*/
class ShowerTree : public Base
{
public:
/**
* Constructors and Destructors
*/
//@{
/**
* Constructor for a scattering process
* @param out The outgoing particles
* @param decay Map into which the trees for any unstable particles are inserted
*/
ShowerTree(const ParticleVector & out,
multimap<Energy,ShowerTreePtr> & decay);
/**
* Constructor for a decay
* @param in The decaying particle
* @param decay Map into which the trees for any unstable particles are inserted
*/
ShowerTree(PPtr in, multimap<Energy,ShowerTreePtr> & decay);
//@}
public:
/**
* Insert the tree into the event record
* @param pstep The step into which the particles should be inserted
* @param ISR Whether or not ISR is switched on
* @param FSR Whether or not FSR is switched on
*/
inline void fillEventRecord(StepPtr pstep,bool ISR,bool FSR);
/**
* Set the parent tree to this tree for trees which come from this one.
* This needs to be run after the constructor.
*/
void setParents();
/**
* Perform the decay for a tree starting with an unstable particle
* @param decay The map of widths and ShowerTrees for the decays so that
* any unstable decay products can be added.
*/
void decay(multimap<Energy,ShowerTreePtr> & decay);
/**
* Access methods for the type of interaction
*/
//@{
/**
* Whether or not this is a scattering process
*/
bool isHard() const;
/**
* Whether or not this is a decay.
*/
bool isDecay() const;
//@}
/**
* Flags relating to the application of the hard matrix element correction
*/
//@{
/**
* Was the hard matrix element correction applied
*/
inline bool hardMatrixElementCorrection() const;
/**
* Set whether or not the hard matrix element correction was applied
*/
inline void hardMatrixElementCorrection(bool in);
//@}
/**
* Get the incoming shower particles
*/
inline map<ShowerProgenitorPtr,ShowerParticlePtr> & incomingLines();
/**
* Get the outgoing shower particles
*/
inline map<ShowerProgenitorPtr,tShowerParticlePtr> & outgoingLines();
/**
* Update the shower product for a final-state particle
*/
void updateFinalStateShowerProduct(ShowerProgenitorPtr progenitor,
ShowerParticlePtr parent,
const ShowerParticleVector & children);
/**
* Update the shower product for an initial-state particle
*/
void updateInitialStateShowerProduct(ShowerProgenitorPtr progenitor,
ShowerParticlePtr newParent);
/**
* Get the current final shower product for a final-state particle
*/
inline tShowerParticlePtr getFinalStateShowerProduct(ShowerProgenitorPtr progenitor);
/**
* Add a final-state branching. This method removes the parent of the branching
* from the list of particles at the end of the shower and inserts the children
* @param parent The parent for the branching
* @param children The outgoing particles in the branching
*/
inline void addFinalStateBranching(ShowerParticlePtr parent,
const ShowerParticleVector & children);
/**
* Add an initial-state branching. This method removes the oldParent of the
* branching and inserts the result of the backward evolution and the
* outgoing particle into the relevant lists.
* @param oldParent The particle being backward evolved
* @param newParent The initial-state particle resulting from the backward evolution
* @param otherChild The final-state particle produced in the evolution.
*/
inline void addInitialStateBranching(ShowerParticlePtr oldParent,
ShowerParticlePtr newParent,
ShowerParticlePtr otherChild);
/**
* Member called at the end of the shower of a tree to perform a number of
* updates.
* @param decay The map of widths and ShowerTrees for the decays so that
* any unstable decay products can be added.
*/
void updateAfterShower(multimap<Energy,ShowerTreePtr> & decay);
/**
* Access and set the flag for whether this tree has been showered
*/
//@{
/**
* Access the flag
*/
inline bool hasShowered() const;
/**
* Set the flag
*/
inline void hasShowered(bool);
//@}
/**
* Access the parent tree
*/
inline ShowerTreePtr parent() const;
/**
* Clear all the shower products so that the event can be reshowered
* if the first attempt fail
*/
void clear();
/**
* Reset the particles resulting from the shower to those which started
* the shower
*/
void resetShowerProducts();
/**
* Extract the progenitors for the reconstruction
*/
inline vector<ShowerProgenitorPtr> extractProgenitors();
+ /**
+ * Access to the outgoing particles
+ */
+ inline const set<tShowerParticlePtr> & forwardParticles() const;
+
protected:
/**
* Functions to add the shower to the event record.
*/
//@{
/**
* Insert a hard process
* @param pstep The step into which the particles should be inserted
* @param ISR Whether or not ISR is switched on
* @param FSR Whether or not FSR is switched on
*/
void insertHard(StepPtr pstep,bool ISR,bool FSR);
/**
* Insert a decay process
* @param pstep The step into which the particles should be inserted
* @param ISR Whether or not ISR is switched on
* @param FSR Whether or not FSR is switched on
*/
void insertDecay(StepPtr pstep,bool ISR,bool FSR);
/**
* Recursively add the final-state shower from the particle to the event record.
* @param particle The final-state particle
* @param step The step
*/
void addFinalStateShower(PPtr particle, StepPtr step);
/**
* Add the initial-state shwoer from the particle to the step
* @param particle The final-state particle
* @param hadron The incoming hadron
* @param step The step
* @param addchildren Add the children of the particle
*/
void addInitialStateShower(PPtr particle, PPtr hadron,
StepPtr step, bool addchildren=true);
/**
* Update the colour information of a particle prior to insertion into the
* event record.
* @param particle The particle for which the colour is updated.
*/
void updateColour(PPtr particle);
//@}
/**
* Isolate the colour of the process from the rest of the event.
* Called in the constructor
* @param original The original particles
* @param copy The colour isolated copies
*/
void colourIsolate(const vector<PPtr> & original, const vector<PPtr> & copy);
/**
* After the creatation of a ShowerParticle make sure it is properly attached
* to its ColourLine
* @param part The particle
*/
inline void fixColour(tShowerParticlePtr part);
private:
/**
* The incoming ShowerParticles connected to the interaction
* as the index of a map with the particle the shower backward evolves
* them to as the value
*/
map<ShowerProgenitorPtr,ShowerParticlePtr> _incomingLines;
/**
* The outgoing ShowerParticles connected to the interaction
* as the index of a map with the particle the shower
* evolves them to as the value
*/
map<ShowerProgenitorPtr,tShowerParticlePtr> _outgoingLines;
/**
* The outgoing ShowerParticles at the end of the final-state shower
*/
set<tShowerParticlePtr> _forward;
/**
* The incoming ShowerParticles at the end of the initial-state shower
*/
set<tShowerParticlePtr> _backward;
/**
* Was the hard matrix element correction applied
*/
bool _hardMECorrection;
/**
* Was this a scattering process or a decay
*/
bool _wasHard;
/**
* Map of colour lines used to reset colours when inserted into the event
*/
map<ColinePtr,ColinePtr> _colour;
/**
* Map of particles in this Tree which are the initial particles in other
* trees
*/
map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> > _treelinks;
/**
* The parent tree
*/
tShowerTreePtr _parent;
/**
* Pointer to the shower variables
*/
tcShowerHandlerPtr _showerHandler;
/**
* Has this tree showered
*/
bool _hasShowered;
};
}
#include "ShowerTree.icc"
#endif
diff --git a/Shower/Base/ShowerTree.icc b/Shower/Base/ShowerTree.icc
--- a/Shower/Base/ShowerTree.icc
+++ b/Shower/Base/ShowerTree.icc
@@ -1,109 +1,112 @@
// -*- C++ -*-
//
// ShowerTree.icc is a part of Herwig++ - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2007 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.
//
namespace Herwig {
using namespace ThePEG;
inline bool ShowerTree::hardMatrixElementCorrection() const {
return _hardMECorrection;
}
inline void ShowerTree::hardMatrixElementCorrection(bool in) {
_hardMECorrection=in;
}
inline map<ShowerProgenitorPtr,ShowerParticlePtr> & ShowerTree::incomingLines() {
return _incomingLines;
}
inline map<ShowerProgenitorPtr,tShowerParticlePtr> & ShowerTree::outgoingLines() {
return _outgoingLines;
}
inline void ShowerTree::addFinalStateBranching(ShowerParticlePtr parent,
const ShowerParticleVector & children) {
assert(children.size()==2);
_forward.erase(parent);
for(unsigned int ix=0; ix<children.size(); ++ix) {
_forward.insert(children[ix]);
}
}
inline void ShowerTree::addInitialStateBranching(ShowerParticlePtr oldParent,
ShowerParticlePtr newParent,
ShowerParticlePtr otherChild) {
_backward.erase(oldParent);
_backward.insert(newParent);
_forward.insert(otherChild);
}
inline tShowerParticlePtr
ShowerTree::getFinalStateShowerProduct(ShowerProgenitorPtr progenitor) {
return _outgoingLines.find(progenitor)==_outgoingLines.end()
? tShowerParticlePtr() : _outgoingLines[progenitor];
}
inline bool ShowerTree::isHard() const {
return _wasHard;
}
inline bool ShowerTree::isDecay() const {
return !_wasHard;
}
inline void ShowerTree::setParents() {
// set the parent tree of the children
map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator tit;
for(tit=_treelinks.begin();tit!=_treelinks.end();++tit)
tit->first->_parent=this;
}
inline void ShowerTree::fillEventRecord(StepPtr pstep, bool ISR, bool FSR) {
if(_wasHard) insertHard(pstep,ISR,FSR);
else insertDecay(pstep,ISR,FSR);
}
inline bool ShowerTree::hasShowered() const {
return _hasShowered;
}
inline void ShowerTree::hasShowered(bool in) {
_hasShowered=in;
}
inline ShowerTreePtr ShowerTree::parent() const {
return _parent;
}
inline void ShowerTree::fixColour(tShowerParticlePtr part) {
ColinePtr line=part->colourLine();
if(line) {
line->removeColoured(part);
line->addColoured(part);
}
line=part->antiColourLine();
if(line) {
line->removeAntiColoured(part);
line->addAntiColoured(part);
}
}
inline vector<ShowerProgenitorPtr> ShowerTree::extractProgenitors() {
// extract the particles from the ShowerTree
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator mit;
vector<ShowerProgenitorPtr> ShowerHardJets;
for(mit=incomingLines().begin();mit!=incomingLines().end();++mit)
ShowerHardJets.push_back((*mit).first);
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator mjt;
for(mjt=outgoingLines().begin();mjt!=outgoingLines().end();++mjt)
ShowerHardJets.push_back((*mjt).first);
return ShowerHardJets;
}
+inline const set<tShowerParticlePtr> & ShowerTree::forwardParticles() const {
+ return _forward;
}
+}
diff --git a/Shower/Default/MECorrections/DISMECorrection.cc b/Shower/Default/MECorrections/DISMECorrection.cc
new file mode 100644
--- /dev/null
+++ b/Shower/Default/MECorrections/DISMECorrection.cc
@@ -0,0 +1,667 @@
+// -*- C++ -*-
+//
+// This is the implementation of the non-inlined, non-templated member
+// functions of the DISMECorrection class.
+//
+
+#include "DISMECorrection.h"
+#include "ThePEG/Interface/Switch.h"
+#include "ThePEG/Interface/Parameter.h"
+#include "ThePEG/Interface/ParVector.h"
+#include "ThePEG/Interface/ClassDocumentation.h"
+#include "ThePEG/Persistency/PersistentOStream.h"
+#include "ThePEG/Persistency/PersistentIStream.h"
+#include <numeric>
+#include "Herwig++/Utilities/Maths.h"
+
+using namespace Herwig;
+
+void DISMECorrection::persistentOutput(PersistentOStream & os) const {
+ os << _meopt << _comptonint << _bgfint << _procprob << _sinW << _cosW
+ << ounit(_mz2,GeV2) << _initial << _final;
+}
+
+void DISMECorrection::persistentInput(PersistentIStream & is, int) {
+ is >> _meopt >> _comptonint >> _bgfint >> _procprob >> _sinW >> _cosW
+ >> iunit(_mz2,GeV2) >> _initial >> _final;
+}
+
+ClassDescription<DISMECorrection> DISMECorrection::initDISMECorrection;
+// Definition of the static class description member.
+
+void DISMECorrection::Init() {
+
+ static ClassDocumentation<DISMECorrection> documentation
+ ("The DISMECorrection class implements the matrix element correction for DIS");
+
+ static Parameter<DISMECorrection,double> interfaceProcessProbability
+ ("ProcessProbability",
+ "The probabilty of the QCD compton process for the process selection",
+ &DISMECorrection::_procprob, 0.3, 0.0, 1.,
+ false, false, Interface::limited);
+
+ static Switch<DISMECorrection,bool> interfaceMEOption
+ ("MEOption",
+ "Option for the treatment of the matrix element",
+ &DISMECorrection::_meopt, false, false);
+ static SwitchOption interfaceMEOptionFull
+ (interfaceMEOption,
+ "Full",
+ "Use the full matrix element",
+ true);
+ static SwitchOption interfaceMEOptionProcessIndependent
+ (interfaceMEOption,
+ "ProcessIndependent",
+ "Only use the process independent part, as in FORTRAN HERWIG",
+ false);
+
+}
+
+void DISMECorrection::doinit() throw(InitException) {
+ QTildeMECorrection::doinit();
+ // electroweak parameters
+ _sinW = generator()->standardModel()->sin2ThetaW();
+ _cosW = sqrt(1.-_sinW);
+ _sinW = sqrt(_sinW);
+ _mz2 = sqr(getParticleData(ParticleID::Z0)->mass());
+ // 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.*r5/25.*ath+sqr(Constants::pi)/3.
+ -2.*Math::ReLi2(1.-darg)-2.*Math::ReLi2(1.-1./darg));
+ _bgfint = 121./9.-56./5.*r5*ath;
+}
+
+void DISMECorrection::dofinish() {
+ MECorrectionBase::dofinish();
+ string fname = generator()->filename() + string("-") + name() + string(".top");
+ ofstream outfile(fname.c_str());
+ outfile << "SET FONT DUPLEX\n";
+ outfile << "SET ORDER X Y\n";
+ outfile << "SET WINDOW X 2 9 Y 2 9\n";
+ outfile << "TITLE BOTTOM \"x0p1\"\n";
+ outfile << "CASE \" X X\"\n";
+ outfile << "TITLE LEFT \"z0p1\"\n";
+ outfile << "CASE \" X X\"\n";
+ outfile << "SET LIMITS X 0 1 Y 0 1\n";
+ int nfortran(0);
+ for(unsigned int ix=0;ix<_compton.size();++ix) {
+ double xp = _compton[ix].first, zp = _compton[ix].second;
+ double xpmax = (1.+4.*zp*(1.-zp))/(1.+6.*zp*(1.-zp));
+ Complex a = 10.-45.*xp+18.*sqr(xp)+3.*Complex(0.,1.)*
+ sqrt(3.*(9.+66.*xp-93.*sqr(xp)+12.*pow(xp,3)-8.*pow(xp,4)
+ +24.*pow(xp,5)-8.*pow(xp,6)));
+ Complex b = pow(a,1./3.)*(0.5+sqrt(3.)/2.*Complex(0.,1.));
+ double zpmax = 1.-2./3.*xp*(1.+b.real());
+ outfile << xp << "\t" << zp << "\n";
+ if(xp<xpmax&&zp<zpmax) ++nfortran;
+ if(ix%50000==0&&ix>0) outfile << "PLOT\n";
+ }
+ if(!_compton.empty()) outfile << "PLOT\n";
+ cerr << nfortran << " would have been accepted by FORTRAN HERWIG for the "
+ << "compton process of " << _compton.size() << " accepted by the C++\n";
+ for(double xp=0;xp<=1.001;xp+=0.01) {
+ outfile << xp << "\t" << 1./(1.+xp-sqr(xp)) << "\n";
+ }
+ outfile << "JOIN BLUE\n";
+ for(double z=0;z<=1.001;z+=0.01) {
+ outfile << 1./(1+z*(1.-z)) << "\t" << z << "\n";
+ }
+ outfile << "JOIN BLUE\n";
+ for(double zp=0.;zp<=1.001;zp+=0.01) {
+ outfile << (1.+4.*zp*(1.-zp))/(1.+6.*zp*(1.-zp)) << "\t" << zp << "\n";
+ }
+ outfile << "JOIN GREEN\n";
+ for(double xp=0.;xp<=1.001;xp+=0.01) {
+ Complex a = 10.-45.*xp+18.*sqr(xp)+3.*Complex(0.,1.)*
+ sqrt(3.*(9.+66.*xp-93.*sqr(xp)+12.*pow(xp,3)-8.*pow(xp,4)
+ +24.*pow(xp,5)-8.*pow(xp,6)));
+ Complex b = pow(a,1./3.)*(0.5+sqrt(3.)/2.*Complex(0.,1.));
+ outfile << xp << "\t" << 1.-2./3.*xp*(1.+b.real()) << "\n";
+ }
+ outfile << "JOIN GREEN\n";
+ outfile << "NEW FRAME\n";
+ outfile << "SET FONT DUPLEX\n";
+ outfile << "SET ORDER X Y\n";
+ outfile << "SET WINDOW X 2 9 Y 2 9\n";
+ outfile << "TITLE BOTTOM \"x0p1\"\n";
+ outfile << "CASE \" X X\"\n";
+ outfile << "TITLE LEFT \"z0p1\"\n";
+ outfile << "CASE \" X X\"\n";
+ outfile << "SET LIMITS X 0 1 Y 0 1\n";
+ for(unsigned int ix=0;ix<_comptonover.size();++ix) {
+ outfile << _comptonover[ix].first << "\t" << _comptonover[ix].second << "\n";
+ if(ix%50000==0&&ix>0) outfile << "PLOT RED\n";
+ }
+ if(!_comptonover.empty()) outfile << "PLOT RED\n";
+ for(double xp=0;xp<=1.001;xp+=0.01) {
+ outfile << xp << "\t" << 1./(1.+xp-sqr(xp)) << "\n";
+ }
+ outfile << "JOIN BLUE\n";
+ for(double z=0;z<=1.001;z+=0.01) {
+ outfile << 1./(1+z*(1.-z)) << "\t" << z << "\n";
+ }
+ outfile << "JOIN BLUE\n";
+ for(double zp=0.;zp<=1.001;zp+=0.01) {
+ outfile << (1.+4.*zp*(1.-zp))/(1.+6.*zp*(1.-zp)) << "\t" << zp << "\n";
+ }
+ outfile << "JOIN GREEN\n";
+ for(double xp=0.;xp<=1.001;xp+=0.01) {
+ Complex a = 10.-45.*xp+18.*sqr(xp)+3.*Complex(0.,1.)*
+ sqrt(3.*(9.+66.*xp-93.*sqr(xp)+12.*pow(xp,3)-8.*pow(xp,4)
+ +24.*pow(xp,5)-8.*pow(xp,6)));
+ Complex b = pow(a,1./3.)*(0.5+sqrt(3.)/2.*Complex(0.,1.));
+ outfile << xp << "\t" << 1.-2./3.*xp*(1.+b.real()) << "\n";
+ }
+ outfile << "JOIN GREEN\n";
+ outfile << "NEW FRAME\n";
+ outfile << "SET FONT DUPLEX\n";
+ outfile << "SET ORDER X Y\n";
+ outfile << "SET WINDOW X 2 9 Y 2 9\n";
+ outfile << "TITLE BOTTOM \"x0p1\"\n";
+ outfile << "CASE \" X X\"\n";
+ outfile << "TITLE LEFT \"z0p1\"\n";
+ outfile << "CASE \" X X\"\n";
+ outfile << "SET LIMITS X 0 1 Y 0 1\n";
+ nfortran=0;
+ for(unsigned int ix=0;ix<_bgf.size();++ix) {
+ double xp = _bgf[ix].first, zp = _bgf[ix].second;
+ Complex a = 10.-45.*xp+18.*sqr(xp)+3.*Complex(0.,1.)*
+ sqrt(3.*(9.+66.*xp-93.*sqr(xp)+12.*pow(xp,3)-8.*pow(xp,4)
+ +24.*pow(xp,5)-8.*pow(xp,6)));
+ Complex b = pow(a,1./3.)*(0.5+sqrt(3.)/2.*Complex(0.,1.));
+ double zpmax = 1.-2./3.*xp*(1.+b.real()),zpmin=1.-zpmax;
+ if(zp>zpmin&&zp<zpmax) ++nfortran;
+ outfile << _bgf[ix].first << "\t" << _bgf[ix].second << "\n";
+ if(ix%50000==0&&ix>0) outfile << "PLOT\n";
+ }
+ cerr << nfortran << " would have been accepted by FORTRAN HERWIG for the "
+ << "BGF process of " << _bgf.size() << " accepted by the C++\n";
+ if(!_bgf.empty()) outfile << "PLOT\n";
+ for(double z=0;z<=1.001;z+=0.01) {
+ double xp = 2.*z/(1.+(1.-z)+sqrt(sqr(1.+(1.-z))-4.*z*(1.-z)));
+ double zp = 0.5* (1.-(1.-z)+sqrt(sqr(1.+(1.-z))-4.*z*(1.-z)));
+ outfile << xp << "\t" << zp << "\n";
+ }
+ outfile << "JOIN BLUE\n";
+ for(double z=0;z<=1.001;z+=0.01) {
+ double xp = 2.*z/(1.+(1.-z)+sqrt(sqr(1.+(1.-z))-4.*z*(1.-z)));
+ double zp = 0.5* (1.-(1.-z)+sqrt(sqr(1.+(1.-z))-4.*z*(1.-z)));
+ outfile << xp << "\t" << 1.-zp << "\n";
+ }
+ outfile << "JOIN BLUE\n";
+ for(double xp=0.;xp<=1.001;xp+=0.01) {
+ Complex a = 10.-45.*xp+18.*sqr(xp)+3.*Complex(0.,1.)*
+ sqrt(3.*(9.+66.*xp-93.*sqr(xp)+12.*pow(xp,3)-8.*pow(xp,4)
+ +24.*pow(xp,5)-8.*pow(xp,6)));
+ Complex b = pow(a,1./3.)*(0.5+sqrt(3.)/2.*Complex(0.,1.));
+ outfile << xp << "\t" << 1.-2./3.*xp*(1.+b.real()) << "\n";
+ }
+ outfile << "JOIN GREEN\n";
+ for(double xp=0.;xp<=1.001;xp+=0.01) {
+ Complex a = 10.-45.*xp+18.*sqr(xp)+3.*Complex(0.,1.)*
+ sqrt(3.*(9.+66.*xp-93.*sqr(xp)+12.*pow(xp,3)-8.*pow(xp,4)
+ +24.*pow(xp,5)-8.*pow(xp,6)));
+ Complex b = pow(a,1./3.)*(0.5+sqrt(3.)/2.*Complex(0.,1.));
+ outfile << xp << "\t" << +2./3.*xp*(1.+b.real()) << "\n";
+ }
+ outfile << "JOIN GREEN\n";
+ outfile << "NEW FRAME\n";
+ outfile << "SET FONT DUPLEX\n";
+ outfile << "SET ORDER X Y\n";
+ outfile << "SET WINDOW X 2 9 Y 2 9\n";
+ outfile << "TITLE BOTTOM \"x0p1\"\n";
+ outfile << "CASE \" X X\"\n";
+ outfile << "TITLE LEFT \"z0p1\"\n";
+ outfile << "CASE \" X X\"\n";
+ outfile << "SET LIMITS X 0 1 Y 0 1\n";
+ for(unsigned int ix=0;ix<_bgfover.size();++ix) {
+ outfile << _bgfover[ix].first << "\t" << _bgfover[ix].second << "\n";
+ if(ix%50000==0&&ix>0) outfile << "PLOT RED\n";
+ }
+ if(!_bgfover.empty()) outfile << "PLOT RED\n";
+ for(double z=0;z<=1.001;z+=0.01) {
+ double xp = 2.*z/(1.+(1.-z)+sqrt(sqr(1.+(1.-z))-4.*z*(1.-z)));
+ double zp = 0.5* (1.-(1.-z)+sqrt(sqr(1.+(1.-z))-4.*z*(1.-z)));
+ outfile << xp << "\t" << zp << "\n";
+ }
+ outfile << "JOIN BLUE\n";
+ for(double z=0;z<=1.001;z+=0.01) {
+ double xp = 2.*z/(1.+(1.-z)+sqrt(sqr(1.+(1.-z))-4.*z*(1.-z)));
+ double zp = 0.5* (1.-(1.-z)+sqrt(sqr(1.+(1.-z))-4.*z*(1.-z)));
+ outfile << xp << "\t" << 1.-zp << "\n";
+ }
+ outfile << "JOIN BLUE\n";
+ for(double xp=0.;xp<=1.001;xp+=0.01) {
+ Complex a = 10.-45.*xp+18.*sqr(xp)+3.*Complex(0.,1.)*
+ sqrt(3.*(9.+66.*xp-93.*sqr(xp)+12.*pow(xp,3)-8.*pow(xp,4)
+ +24.*pow(xp,5)-8.*pow(xp,6)));
+ Complex b = pow(a,1./3.)*(0.5+sqrt(3.)/2.*Complex(0.,1.));
+ outfile << xp << "\t" << 1.-2./3.*xp*(1.+b.real()) << "\n";
+ }
+ outfile << "JOIN GREEN\n";
+ for(double xp=0.;xp<=1.001;xp+=0.01) {
+ Complex a = 10.-45.*xp+18.*sqr(xp)+3.*Complex(0.,1.)*
+ sqrt(3.*(9.+66.*xp-93.*sqr(xp)+12.*pow(xp,3)-8.*pow(xp,4)
+ +24.*pow(xp,5)-8.*pow(xp,6)));
+ Complex b = pow(a,1./3.)*(0.5+sqrt(3.)/2.*Complex(0.,1.));
+ outfile << xp << "\t" << +2./3.*xp*(1.+b.real()) << "\n";
+ }
+ outfile << "JOIN GREEN\n";
+ outfile << "NEW FRAME\n";
+ double xB=-0.005;
+ for(unsigned int ix=0;ix<101;++ix) {
+ xB+=0.01;
+ if(_comptonxb[ix].second!=0.)
+ outfile << xB << "\t" << _comptonxb[ix].first/_comptonxb[ix].second << "\n";
+ else
+ outfile << xB << "\t" << 0. << "\n";
+ }
+ outfile << "HIST RED\n";
+ xB=-0.005;
+ for(unsigned int ix=0;ix<101;++ix) {
+ xB+=0.01;
+ if(_bgfxb[ix].second!=0.)
+ outfile << xB << "\t" << _bgfxb[ix].first/_bgfxb[ix].second << "\n";
+ else
+ outfile << xB << "\t" << 0. << "\n";
+ }
+ outfile << "HIST BLUE\n";
+
+
+ outfile.close();
+ if(_ntry==0) return;
+ generator()->log() << "DISMECorrection when applying the hard correction "
+ << "generated " << _ntry << " trial emissions of which "
+ << _ngen << " were accepted\n";
+ if(_nover==0) return;
+ generator()->log() << "DISMECorrection 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";
+}
+
+bool DISMECorrection::canHandle(ShowerTreePtr tree,double & initial,
+ double & final,EvolverPtr) {
+ // two incoming particles
+ if(tree->incomingLines().size()!=2) return false;
+ // two outgoing particles
+ if(tree->outgoingLines().size()!=2) return false;
+ // check incoming quark and lepton
+ bool quark(false),lepton(false);
+ for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
+ cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
+ quark |= QuarkMatcher::Check(cit->first->progenitor()->data());
+ lepton |= LeptonMatcher::Check(cit->first->progenitor()->data());
+ }
+ if(!quark||!lepton) return false;
+ // check outgoing quark and lepton
+ quark = false;
+ lepton = false;
+ for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
+ cjt=tree->outgoingLines().begin();cjt!=tree->outgoingLines().end();++cjt) {
+ quark |= QuarkMatcher::Check(cjt->first->progenitor()->data());
+ lepton |= LeptonMatcher::Check(cjt->first->progenitor()->data());
+ }
+ if(!quark||!lepton) return false;
+ // can handle it
+ initial = _initial;
+ final = _final;
+ return true;
+}
+
+void DISMECorrection::applyHardMatrixElementCorrection(ShowerTreePtr tree) {
+ ++_ntry;
+ // find the incoming and outgoing quarks and leptons
+ ShowerParticlePtr quark[2],lepton[2];
+ PPtr hadron;
+ tcBeamPtr beam;
+ // incoming particles
+ for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
+ cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
+ if(QuarkMatcher::Check(cit->first->progenitor()->data())) {
+ hadron = cit->first->original()->parents()[0];
+ quark [0] = cit->first->progenitor();
+ beam = cit->first->beam();
+ }
+ else if(LeptonMatcher::Check(cit->first->progenitor()->data())) {
+ lepton[0] = cit->first->progenitor();
+ }
+ }
+ tcPDFPtr pdf=beam->pdf();
+ assert(beam&&pdf&&quark[0]&&lepton[0]);
+ // outgoing particles
+ for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
+ cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) {
+ if(QuarkMatcher::Check(cit->first->progenitor()->data()))
+ quark [1] = cit->first->progenitor();
+ else if(LeptonMatcher::Check(cit->first->progenitor()->data()))
+ lepton[1] = cit->first->progenitor();
+ }
+ assert(quark[1]&&lepton[1]);
+ // extract the born variables
+ Lorentz5Momentum q =lepton[0]->momentum()-lepton[1]->momentum();
+ _q2 = -q.m2();
+ double xB = quark[0]->x();
+ double yB =
+ ( q*quark[0]->momentum())/
+ (lepton[0]->momentum()*quark[0]->momentum());
+ _l = 2./yB-1.;
+ // calculate the A coefficient for the correlations
+ _acoeff = A(lepton[0]->dataPtr(),lepton[1]->dataPtr(),
+ quark [0]->dataPtr(),quark [1]->dataPtr());
+ vector<double> azicoeff;
+ double xp,zp,wgt,x1,x2,x3,xperp;
+ tcPDPtr gluon = getParticleData(ParticleID::g);
+ if(abs(quark[0]->id())>2) {
+ _procprob = 0.34;
+ }
+ else if(abs(quark[0]->id())==1) {
+ _procprob = 0.36;
+ }
+ else if(abs(quark[0]->id())==2) {
+ if(quark[0]->id()*hadron->id()>0) {
+ _procprob = 0.40;
+ }
+ else {
+ _procprob = 0.35;
+ }
+ }
+ // select the type of process
+ bool BGF = UseRandom::rnd()>_procprob;
+ //bool BGF=true;
+ // generate a QCD compton process
+ if(!BGF) {
+ wgt = generateComptonPoint(xp,zp);
+ if(xp<1e-6) return;
+ // common pieces
+ Energy2 scale = _q2*((1.-xp)*(1-zp)*zp/xp+1);
+ wgt *= 2./3./Constants::pi*coupling()->value(scale)/_procprob;
+ // PDF piece
+ wgt *= pdf->xfx(beam,quark[0]->dataPtr(),scale,xB/xp)/
+ pdf->xfx(beam,quark[0]->dataPtr(),_q2 ,xB);
+ // other bits
+ xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp);
+ x1 = -1./xp;
+ x2 = 1.-(1.-zp)/xp;
+ x3 = 2.+x1-x2;
+ // matrix element pieces
+ azicoeff = ComptonME(xp,x2,xperp,_acoeff,_l,true);
+ }
+ // generate a BGF process
+ else {
+ wgt = generateBGFPoint(xp,zp);
+ if(xp<1e-6) return;
+ // common pieces
+ Energy2 scale = _q2*((1.-xp)*(1-zp)*zp/xp+1);
+ wgt *= 0.25/Constants::pi*coupling()->value(scale)/(1.-_procprob);
+ // PDF piece
+ wgt *= pdf->xfx(beam,gluon ,scale,xB/xp)/
+ pdf->xfx(beam,quark[0]->dataPtr(),_q2 ,xB);
+ // other bits
+ xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp);
+ x1 = -1./xp;
+ x2 = 1.-(1.-zp)/xp;
+ x3 = 2.+x1-x2;
+ // matrix element pieces
+ azicoeff = BGFME(xp,x2,x3,xperp,_acoeff,_l,true);
+ }
+ // compute the azimuthal average of the weight
+ wgt *= (azicoeff[0]+0.5*azicoeff[2]);
+ // decide whether or not to accept the weight
+ if(UseRandom::rnd()>wgt) return;
+ // if generate generate phi
+ unsigned int itry(0);
+ double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.);
+ double phiwgt,phi;
+ do {
+ phi = UseRandom::rnd()*Constants::twopi;
+ double cphi(cos(phi));
+ phiwgt = azicoeff[0]+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi);
+ ++itry;
+ }
+ while (phimax*UseRandom::rnd() > phiwgt && itry<200);
+ if(itry==200) throw Exception() << "Too many tries in DISMECorrection"
+ << "::applyHardMatrixElementCorrection() to"
+ << " generate phi" << Exception::eventerror;
+ // 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);
+ // 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(1.-sqr(axis.z())));
+ rot.rotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.));
+ Lorentz5Momentum pl = rot*lepton[0]->momentum();
+ rot.rotateZ(-atan2(pl.y(),pl.x()));
+ // we need the Lorentz transform back to the lab
+ rot.invert();
+ // transform the momenta to lab frame
+ pin *= rot;
+ p1 *= rot;
+ p2 *= rot;
+ // test to ensure outgoing particles can be put on-shell
+ if(!BGF) {
+ if(p1.e()<quark[1]->dataPtr()->constituentMass()) return;
+ if(p2.e()<gluon ->constituentMass()) return;
+ }
+ else {
+ if(p1.e()<quark[1]->dataPtr() ->constituentMass()) return;
+ if(p2.e()<quark[0]->dataPtr()->CC()->constituentMass()) return;
+ }
+ // stats for weights > 1
+ if(wgt>1.) {
+ ++_nover;
+ if(!BGF) {
+ _maxwgt.first = max(_maxwgt.first ,wgt);
+ _comptonover.push_back(make_pair(xp,zp));
+ }
+ else {
+ _maxwgt.second = max(_maxwgt.second,wgt);
+ _bgfover.push_back(make_pair(xp,zp));
+ }
+ }
+ if(!BGF) {
+ if(_comptonxb.empty()) _comptonxb.resize(101,make_pair(0.,0.));
+ int iloc = int(xB/0.01);
+ _comptonxb[iloc].first += wgt;
+ _comptonxb[iloc].second += 1. ;
+ }
+ else {
+ if(_bgfxb.empty()) _bgfxb .resize(101,make_pair(0.,0.));
+ int iloc = int(xB/0.01);
+ _bgfxb[iloc].first += wgt;
+ _bgfxb[iloc].second += 1. ;
+ }
+ // points into hist
+ ++_ngen;
+ if(!BGF) _compton.push_back(make_pair(xp,zp));
+ else _bgf .push_back(make_pair(xp,zp));
+ // create the new particles and add to ShowerTree
+ bool isquark = quark[0]->colourLine();
+ if(!BGF) {
+ PPtr newin = new_ptr(Particle(*quark[0]));
+ newin->set5Momentum(pin);
+ PPtr newg = gluon ->produceParticle(p2 );
+ PPtr newout = quark[1]->dataPtr()->produceParticle(p1 );
+ ColinePtr col=isquark ?
+ quark[0]->colourLine() : quark[0]->antiColourLine();
+ ColinePtr newline=new_ptr(ColourLine());
+ // final-state emission
+ if(xp>zp) {
+ col->removeColoured(newout,!isquark);
+ col->addColoured(newin,!isquark);
+ col->addColoured(newg,!isquark);
+ newline->addColoured(newg,isquark);
+ newline->addColoured(newout,!isquark);
+ }
+ // initial-state emission
+ else {
+ col->removeColoured(newin ,!isquark);
+ col->addColoured(newout,!isquark);
+ col->addColoured(newg,isquark);
+ newline->addColoured(newg,!isquark);
+ newline->addColoured(newin,!isquark);
+ }
+ PPtr orig;
+ for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
+ cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
+ if(cit->first->progenitor()!=quark[0]) continue;
+ // remove old particles from colour line
+ col->removeColoured(cit->first->copy(),!isquark);
+ col->removeColoured(cit->first->progenitor(),!isquark);
+ // insert new particles
+ cit->first->copy(newin);
+ ShowerParticlePtr sp(new_ptr(ShowerParticle(*newin,1,false)));
+ cit->first->progenitor(sp);
+ tree->incomingLines()[cit->first]=sp;
+ sp->x(xB/xp);
+ cit->first->perturbative(xp>zp);
+ if(xp<=zp) orig=cit->first->original();
+ }
+ for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
+ cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) {
+ if(cit->first->progenitor()!=quark[1]) continue;
+ // remove old particles from colour line
+ col->removeColoured(cit->first->copy(),!isquark);
+ col->removeColoured(cit->first->progenitor(),!isquark);
+ // insert new particles
+ cit->first->copy(newout);
+ ShowerParticlePtr sp(new_ptr(ShowerParticle(*newout,1,true)));
+ cit->first->progenitor(sp);
+ tree->outgoingLines()[cit->first]=sp;
+ cit->first->perturbative(xp<=zp);
+ if(xp>zp) orig=cit->first->original();
+ }
+ assert(orig);
+ // add the gluon
+ ShowerParticlePtr sg=new_ptr(ShowerParticle(*newg,1,true));
+ ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(orig,newg,sg));
+ gluon->perturbative(false);
+ tree->outgoingLines().insert(make_pair(gluon,sg));
+ tree->hardMatrixElementCorrection(true);
+ }
+ else {
+ PPtr newin = gluon ->produceParticle(pin);
+ PPtr newqbar = quark[0]->dataPtr()->CC()->produceParticle(p2 );
+ PPtr newout = quark[1]->dataPtr() ->produceParticle(p1 );
+ ColinePtr col=isquark ? quark[0]->colourLine() : quark[0]->antiColourLine();
+ ColinePtr newline=new_ptr(ColourLine());
+ col ->addColoured(newin ,!isquark);
+ newline->addColoured(newin , isquark);
+ col ->addColoured(newout ,!isquark);
+ newline->addColoured(newqbar, isquark);
+ PPtr orig;
+ for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
+ cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
+ if(cit->first->progenitor()!=quark[0]) continue;
+ // remove old particles from colour line
+ col->removeColoured(cit->first->copy(),!isquark);
+ col->removeColoured(cit->first->progenitor(),!isquark);
+ // insert new particles
+ cit->first->copy(newin);
+ ShowerParticlePtr sp(new_ptr(ShowerParticle(*newin,1,false)));
+ cit->first->progenitor(sp);
+ tree->incomingLines()[cit->first]=sp;
+ sp->x(xB/xp);
+ cit->first->perturbative(false);
+ orig=cit->first->original();
+ }
+ for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
+ cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) {
+ if(cit->first->progenitor()!=quark[1]) continue;
+ // remove old particles from colour line
+ col->removeColoured(cit->first->copy(),!isquark);
+ col->removeColoured(cit->first->progenitor(),!isquark);
+ // insert new particles
+ cit->first->copy(newout);
+ ShowerParticlePtr sp(new_ptr(ShowerParticle(*newout,1,true)));
+ cit->first->progenitor(sp);
+ tree->outgoingLines()[cit->first]=sp;
+ cit->first->perturbative(true);
+ }
+ assert(orig);
+ // add the (anti)quark
+ ShowerParticlePtr sqbar=new_ptr(ShowerParticle(*newqbar,1,true));
+ ShowerProgenitorPtr qbar=new_ptr(ShowerProgenitor(orig,newqbar,sqbar));
+ qbar->perturbative(false);
+ tree->outgoingLines().insert(make_pair(qbar,sqbar));
+ tree->hardMatrixElementCorrection(true);
+ }
+}
+
+bool DISMECorrection::softMatrixElementVeto(ShowerProgenitorPtr initial,
+ ShowerParticlePtr parent,Branching br) {
+ bool veto = !UseRandom::rndbool(parent->isFinalState() ? 1./_final : 1./_initial);
+ // check if me correction should be applied
+ long id[2]={initial->id(),parent->id()};
+ if(id[0]!=id[1]||id[1]==ParticleID::g) return veto;
+ // get the pT
+ Energy pT=br.kinematics->pT();
+ // check if hardest so far
+ if(pT<initial->pT()) return veto;
+ double kappa(sqr(br.kinematics->scale())/_q2),z(br.kinematics->z());
+ double zk((1.-z)*kappa);
+ // final-state
+ double wgt(0.);
+ if(parent->isFinalState()) {
+ double zp=z,xp=1./(1.+z*zk);
+ double xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp);
+ double x2 = 1.-(1.-zp)/xp;
+ vector<double> azicoeff = ComptonME(xp,x2,xperp,_acoeff,_l,false);
+ wgt = (azicoeff[0]+0.5*azicoeff[2])*xp/(1.+sqr(z))/_final;
+ if(wgt<.0||wgt>1.)
+ generator()->log() << "Soft ME correction weight too large or "
+ << "negative for FSR in DISMECorrection::"
+ << "softMatrixElementVeto() soft weight "
+ << " xp = " << xp
+ << " zp = " << zp
+ << " weight = " << wgt << "\n";
+ }
+ 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));
+ // compton
+ if(br.ids[0]!=ParticleID::g) {
+ double xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp);
+ double x2 = 1.-(1.-zp)/xp;
+ vector<double> azicoeff = ComptonME(xp,x2,xperp,_acoeff,_l,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 {
+ double xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp);
+ double x1 = -1./xp, x2 = 1.-(1.-zp)/xp, x3 = 2.+x1-x2;
+ vector<double> azicoeff = BGFME(xp,x2,x3,xperp,_acoeff,_l,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.)
+ generator()->log() << "Soft ME correction weight too large or "
+ << "negative for ISR in DISMECorrection::"
+ << "softMatrixElementVeto() soft weight "
+ << " xp = " << xp
+ << " zp = " << zp
+ << " weight = " << wgt << "\n";
+ }
+ // if not vetoed
+ if(UseRandom::rndbool(wgt)) {
+ initial->pT(pT);
+ return false;
+ }
+ // otherwise
+ parent->setEvolutionScale(ShowerIndex::QCD,br.kinematics->scale());
+ return true;
+}
diff --git a/Shower/Default/MECorrections/DISMECorrection.fh b/Shower/Default/MECorrections/DISMECorrection.fh
new file mode 100644
--- /dev/null
+++ b/Shower/Default/MECorrections/DISMECorrection.fh
@@ -0,0 +1,22 @@
+// -*- C++ -*-
+//
+// This is the forward declaration of the DISMECorrection class.
+//
+#ifndef HERWIG_DISMECorrection_FH
+#define HERWIG_DISMECorrection_FH
+
+#include "ThePEG/Config/Pointers.h"
+
+namespace Herwig {
+
+class DISMECorrection;
+
+}
+
+namespace ThePEG {
+
+ThePEG_DECLARE_POINTERS(Herwig::DISMECorrection,DISMECorrectionPtr);
+
+}
+
+#endif
diff --git a/Shower/Default/MECorrections/DISMECorrection.h b/Shower/Default/MECorrections/DISMECorrection.h
new file mode 100644
--- /dev/null
+++ b/Shower/Default/MECorrections/DISMECorrection.h
@@ -0,0 +1,358 @@
+// -*- C++ -*-
+#ifndef HERWIG_DISMECorrection_H
+#define HERWIG_DISMECorrection_H
+//
+// This is the declaration of the DISMECorrection class.
+//
+
+#include "QTildeMECorrection.h"
+#include "ThePEG/StandardModel/StandardModelBase.h"
+#include "DISMECorrection.fh"
+
+namespace Herwig {
+
+using namespace ThePEG;
+
+/**
+ * The DISMECorrection class implements the matrix element correction for DIS events.
+ *
+ * @see \ref DISMECorrectionInterfaces "The interfaces"
+ * defined for DISMECorrection.
+ */
+class DISMECorrection: public QTildeMECorrection {
+
+/**
+ * Typedef for BeamParticleData pointers
+ */
+typedef Ptr<BeamParticleData>::transient_const_pointer tcBeamPtr;
+
+public:
+
+ /**
+ * The default constructor.
+ */
+ inline DISMECorrection();
+
+ /**
+ * Members to override those in the base class and implemented
+ * the matrix element correction
+ */
+ //@{
+ /**
+ * Can the matrix element correction handle a given hard process or decay
+ * @param tree The shower tree currently being showered
+ * @param initial The initial-state radiation enhancement factor
+ * @param final The final-state radiation enhancement factor
+ * @param evolver Pointer to the Evolver.
+ */
+ virtual bool canHandle(ShowerTreePtr tree,double & initial,
+ double & final,EvolverPtr evolver);
+
+ /**
+ * Apply the hard matrix element correction to a given hard process or decay
+ */
+ virtual void applyHardMatrixElementCorrection(ShowerTreePtr);
+
+ /**
+ * Apply the soft matrix element correction
+ * @param initial The particle from the hard process which started the
+ * shower
+ * @param parent The initial particle in the current branching
+ * @param br The branching struct
+ * @return If true the emission should be vetoed
+ */
+ virtual bool softMatrixElementVeto(ShowerProgenitorPtr initial,
+ ShowerParticlePtr parent,Branching br);
+ //@}
+
+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() throw(InitException);
+
+ /**
+ * Finalize this object. Called in the run phase just after a
+ * run has ended. Used eg. to write out statistics.
+ */
+ virtual void dofinish();
+ //@}
+
+protected:
+
+ /** @name Clone Methods. */
+ //@{
+ /**
+ * Make a simple clone of this object.
+ * @return a pointer to the new object.
+ */
+ inline 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.
+ */
+ inline virtual IBPtr fullclone() const;
+ //@}
+
+private:
+
+ /**
+ * Generate the values of \f$x_p\f$ and \f$z_p\f$
+ * @param xp The value of xp, output
+ * @param zp The value of zp, output
+ */
+ inline double generateComptonPoint(double &xp, double & zp);
+
+ /**
+ * Generate the values of \f$x_p\f$ and \f$z_p\f$
+ * @param xp The value of xp, output
+ * @param zp The value of zp, output
+ */
+ inline double generateBGFPoint(double &xp, double & zp);
+
+ /**
+ * Calculate the coefficient A for the correlations
+ */
+ inline double A(tcPDPtr qin, tcPDPtr qout, tcPDPtr lin, tcPDPtr lout);
+
+ /**
+ * Return the coefficients for the matrix element piece for
+ * the QCD compton case. The output is the \f$a_i\f$ coefficients to
+ * give the function as
+ * \f$a_0+a_1\cos\phi+a_2\sin\phi+a_3\cos^2\phi+a_4\sin^2\phi\f$
+ * @param xp \f$x_p\f$
+ * @param x2 \f$x_2\f$
+ * @param xperp \f$x_\perp\f$
+ * @param A \f$\mathcal{A}\f$
+ * @param l \f$l=2/y_B-1\f$
+ * @param norm Normalise to the large $l$ value of the ME
+ */
+ inline vector<double> ComptonME(double xp, double x2, double xperp,
+ double A, double l, bool norm);
+
+ /**
+ * Return the coefficients for the matrix element piece for
+ * the QCD compton case. The output is the \f$a_i\f$ coefficients to
+ * give the function as
+ * \f$a_0+a_1\cos\phi+a_2\sin\phi+a_3\cos^2\phi+a_4\sin^2\phi\f$
+ * @param xp \f$x_p\f$
+ * @param x2 \f$x_3\f$
+ * @param x3 \f$x_2\f$
+ * @param xperp \f$x_\perp\f$
+ * @param A \f$\mathcal{A}\f$
+ * @param l \f$l=2/y_B-1\f$
+ * @param norm Normalise to the large $l$ value of the ME
+ */
+ inline vector<double> BGFME(double xp, double x2, double x3, double xperp,
+ double A, double l, bool norm);
+
+
+private:
+
+ /**
+ * The static object used to initialize the description of this class.
+ * Indicates that this is a concrete class with persistent data.
+ */
+ static ClassDescription<DISMECorrection> initDISMECorrection;
+
+ /**
+ * The assignment operator is private and must never be called.
+ * In fact, it should not even be implemented.
+ */
+ DISMECorrection & operator=(const DISMECorrection &);
+
+private:
+
+ /**
+ * Parameter to control matrix element used
+ */
+ bool _meopt;
+
+ /**
+ * Radiation enhancement factors
+ */
+ //@{
+ /**
+ * Enchancement factor for ISR
+ */
+ double _initial;
+
+ /**
+ * Enchancement factor for FSR
+ */
+ double _final;
+ //@}
+
+ /**
+ * Parameters for the phase-space sampling
+ */
+ //@{
+ /**
+ * Relative fraction of compton and BGF processes to generate
+ */
+ double _procprob;
+
+ /**
+ * Integral for compton process
+ */
+ double _comptonint;
+
+ /**
+ * Integral for BGF process
+ */
+ double _bgfint;
+ //@}
+
+ /**
+ * Electroweak parameters
+ */
+ //@{
+ /**
+ * \f$\sin\theta_W\f$
+ */
+ double _sinW;
+
+ /**
+ * \f$\cos\theta_W\f$
+ */
+ double _cosW;
+
+ /**
+ * The square of the Z mass
+ */
+ Energy2 _mz2;
+
+ /**
+ * The coefficient for the correlations
+ */
+ double _acoeff;
+ //@}
+
+ /**
+ * Parameters for the point being generated
+ */
+ //@{
+ /**
+ * \f$Q^2\f$
+ */
+ Energy2 _q2;
+
+ /**
+ *
+ */
+ double _l;
+ //@}
+
+ /**
+ * Testing of weights etc
+ */
+ //@{
+ /**
+ * Number of weights greater than 1
+ */
+ unsigned int _nover;
+
+ /**
+ * Number of attempts
+ */
+ unsigned int _ntry;
+
+ /**
+ * Number which suceed
+ */
+ unsigned int _ngen;
+
+ /**
+ * Maximum weight
+ */
+ pair<double,double> _maxwgt;
+
+ /**
+ * points for the compton process
+ */
+ vector<pair<double,double> > _compton,_comptonover;
+
+ /**
+ * points for the BGF process
+ */
+ vector<pair<double,double> > _bgf,_bgfover;
+
+ /**
+ * Analysis of the x_B dependence
+ */
+ vector<pair<double,double> > _comptonxb,_bgfxb;
+ //@}
+};
+
+}
+
+#include "ThePEG/Utilities/ClassTraits.h"
+
+namespace ThePEG {
+
+/** @cond TRAITSPECIALIZATIONS */
+
+/** This template specialization informs ThePEG about the
+ * base classes of DISMECorrection. */
+template <>
+struct BaseClassTrait<Herwig::DISMECorrection,1> {
+ /** Typedef of the first base class of DISMECorrection. */
+ typedef Herwig::QTildeMECorrection NthBase;
+};
+
+/** This template specialization informs ThePEG about the name of
+ * the DISMECorrection class and the shared object where it is defined. */
+template <>
+struct ClassTraits<Herwig::DISMECorrection>
+ : public ClassTraitsBase<Herwig::DISMECorrection> {
+ /** Return a platform-independent class name */
+ static string className() { return "Herwig::DISMECorrection"; }
+ /**
+ * The name of a file containing the dynamic library where the class
+ * DISMECorrection is implemented. It may also include several, space-separated,
+ * libraries if the class DISMECorrection depends on other classes (base classes
+ * excepted). In this case the listed libraries will be dynamically
+ * linked in the order they are specified.
+ */
+ static string library() { return "HwMPI.so HwMPIPDF.so HwRemDecayer.so HwShower.so"; }
+};
+
+/** @endcond */
+
+}
+
+#include "DISMECorrection.icc"
+
+#endif /* HERWIG_DISMECorrection_H */
diff --git a/Shower/Default/MECorrections/DISMECorrection.icc b/Shower/Default/MECorrections/DISMECorrection.icc
new file mode 100644
--- /dev/null
+++ b/Shower/Default/MECorrections/DISMECorrection.icc
@@ -0,0 +1,163 @@
+// -*- C++ -*-
+//
+// This is the implementation of the inlined member functions of
+// the DISMECorrection class.
+//
+
+namespace Herwig {
+
+ inline DISMECorrection::DISMECorrection() : _meopt(true), _initial(6.), _final(3.),
+ _procprob(0.35),
+ _comptonint(0.), _bgfint(0.),
+ _sinW(0.), _cosW(0.), _mz2(0.*GeV2),
+ _nover(0), _ntry(0), _ngen(0),
+ _maxwgt(make_pair(0.,0.)) {
+}
+
+inline IBPtr DISMECorrection::clone() const {
+ return new_ptr(*this);
+}
+
+inline IBPtr DISMECorrection::fullclone() const {
+ return new_ptr(*this);
+}
+
+inline double DISMECorrection::generateComptonPoint(double &xp, double & zp) {
+ static const double maxwgt = 50.;
+ 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) cerr << "testing violates compton max " << wgt << "\n";
+ }
+ while(wgt<UseRandom::rnd()*maxwgt);
+ return _comptonint;
+}
+
+inline double DISMECorrection::generateBGFPoint(double &xp, double & zp) {
+ static const double maxwgt = 2.,npow=0.34,ac=1.0;
+ double wgt;
+ do {
+ double rho = UseRandom::rnd();
+ xp = 1.-pow(rho,1./(1.-npow));
+ wgt = (sqr(xp)+ac+sqr(1.-xp));
+ if(wgt>1.+ac) cerr << "testing violates BGF maxA " << wgt << "\n";
+ }
+ while(wgt<UseRandom::rnd()*(1.+ac));
+ double xpwgt = -((6.-5.*npow+sqr(npow))*ac-3.*npow+sqr(npow)+4)
+ /(sqr(npow)*(npow-6.)+11.*npow-6.);
+ xpwgt *= pow(1.-xp,npow)/wgt;
+ double xp2(sqr(xp)),lxp(log(xp)),xp4(sqr(xp2)),lxp1(log(1.-xp));
+ double zpwgt = (2.*xp4*(lxp+lxp1-3.)+4.*xp*xp2*(3.-lxp-lxp1)
+ +xp2*(-13.+lxp+lxp1)+xp*(+7.+lxp+lxp1)-lxp-lxp1-1.)/(1.+xp-xp2);
+ do {
+ double zpmax = 1./(1.+xp*(1.-xp)), zpmin = 1.-zpmax;
+ zp = 1.-pow((1.-zpmin)/(1.-zpmax),UseRandom::rnd())*(1.-zpmax);
+ wgt = log((1.-zpmin)/(1.-zpmax))*(1.-zp);
+ double x1 = -1./xp;
+ double x2 = 1.-(1.-zp)/xp;
+ double x3 = 2.+x1-x2;
+ double xperp2 = 4.*(1.-xp)*(1.-zp)*zp/xp;
+ wgt *= sqr(xp)/(1.-zp)*(sqr(x3)+sqr(x2)+3.*xperp2);
+ if(wgt>maxwgt*zpwgt) cerr << "testing violates BGF maxB " << wgt/xpwgt << "\n";
+ }
+ while(wgt<UseRandom::rnd()*maxwgt);
+ return zpwgt*xpwgt;
+}
+
+inline double DISMECorrection::A(tcPDPtr qin, tcPDPtr,
+ tcPDPtr lin, tcPDPtr lout) {
+ double output;
+ // charged current
+ if(lin->id()!=lout->id()) {
+ output = 2;
+ }
+ // neutral current
+ else {
+ double fact = 0.25*_q2/(_q2+_mz2)/_sinW/_cosW;
+ double cvl,cal,cvq,caq;
+ if(abs(lin->id())%2==0) {
+ cvl = generator()->standardModel()->vnu()*fact+generator()->standardModel()->enu();
+ cal = generator()->standardModel()->anu()*fact;
+ }
+ else {
+ cvl = generator()->standardModel()->ve()*fact+generator()->standardModel()->ee();
+ cal = generator()->standardModel()->ae()*fact;
+ }
+ if(abs(qin->id())%2==0) {
+ cvq = generator()->standardModel()->vu()*fact+generator()->standardModel()->eu();
+ caq = generator()->standardModel()->au()*fact;
+ }
+ else {
+ cvq = generator()->standardModel()->vd()*fact+generator()->standardModel()->ed();
+ caq = generator()->standardModel()->ad()*fact;
+ }
+ output = 8.*cvl*cal*cvq*caq/(sqr(cvl)+sqr(cal))/(sqr(cvq)+sqr(caq));
+ }
+ if(qin->id()<0) output *= -1.;
+ if(lin->id()<0) output *= -1;
+ return output;
+}
+
+inline vector<double> DISMECorrection::ComptonME(double xp, double x2, double xperp,
+ double A, double l, bool norm) {
+ vector<double> output(3,0.);
+ double cos2 = x2 /sqrt(sqr(x2)+sqr(xperp));
+ double sin2 = xperp/sqrt(sqr(x2)+sqr(xperp));
+ if(_meopt) {
+ double root = sqrt(sqr(l)-1.);
+ output[0] = sqr(cos2)-A*cos2*l+sqr(l);
+ output[1] = A*cos2*root*sin2-2.*l*root*sin2;
+ output[2] = sqr(root)*sqr(sin2);
+ double lo(1+A*l+sqr(l));
+ for(unsigned int ix=0;ix<output.size();++ix) output[ix] /= lo;
+ }
+ else {
+ output[0] = 1.;
+ output[1] = -2.*sin2;
+ output[2] = sqr(sin2);
+ }
+ double denom = norm ? 1.+sqr(xp)*(sqr(x2)+1.5*sqr(xperp)) : 1.;
+ double fact = sqr(xp)*(sqr(x2)+sqr(xperp));
+ for(unsigned int ix=0;ix<output.size();++ix)
+ output[ix] = ((ix==0 ? 1. : 0.) +fact*output[ix])/denom;
+ return output;
+}
+
+inline vector<double> DISMECorrection::BGFME(double xp, double x2, double x3,
+ double xperp, double A, double l,
+ bool norm) {
+ vector<double> output(3,0.);
+ double cos2 = x2 /sqrt(sqr(x2)+sqr(xperp));
+ double sin2 = xperp/sqrt(sqr(x2)+sqr(xperp));
+ double fact2 = sqr(xp)*(sqr(x2)+sqr(xperp));
+ double cos3 = x3 /sqrt(sqr(x3)+sqr(xperp));
+ double sin3 = xperp/sqrt(sqr(x3)+sqr(xperp));
+ double fact3 = sqr(xp)*(sqr(x3)+sqr(xperp));
+ if(_meopt) {
+ double root = sqrt(sqr(l)-1.);
+ output[0] = fact3*(sqr(cos3)-A*cos3*l+sqr(l))+
+ fact2*(sqr(cos2)-A*cos2*l+sqr(l));
+ output[1] =-fact3*(A*cos3*root*sin3-2.*l*root*sin3)+
+ fact2*(A*cos2*root*sin2-2.*l*root*sin2);
+ output[2] = fact3*(sqr(root)*sqr(sin3))+
+ fact2*(sqr(root)*sqr(sin2));
+ double lo(1+A*l+sqr(l));
+ for(unsigned int ix=0;ix<output.size();++ix) output[ix] /=lo;
+ }
+ else {
+ output[0] = fact3+fact2;
+ output[1] = -2.*sin2*fact2+2.*sin3*fact3;
+ output[2] = sqr(sin2)*fact2+sqr(sin3)*fact3;
+ }
+ double denom = norm ? sqr(xp)*(sqr(x3)+sqr(x2)+3.*sqr(xperp)) : 1.;
+ for(unsigned int ix=0;ix<output.size();++ix) output[ix] /=denom;
+ return output;
+}
+
+}
diff --git a/Shower/Default/MECorrections/DrellYanMECorrection.cc b/Shower/Default/MECorrections/DrellYanMECorrection.cc
--- a/Shower/Default/MECorrections/DrellYanMECorrection.cc
+++ b/Shower/Default/MECorrections/DrellYanMECorrection.cc
@@ -1,663 +1,662 @@
// -*- C++ -*-
//
// DrellYanMECorrection.cc is a part of Herwig++ - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2007 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 DrellYanMECorrection class.
//
#include "DrellYanMECorrection.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/Repository/CurrentGenerator.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig++/Shower/Base/Evolver.h"
#include "Herwig++/Shower/Base/KinematicsReconstructor.h"
#include "Herwig++/Shower/Base/PartnerFinder.h"
using namespace Herwig;
void DrellYanMECorrection::doinit() throw(InitException) {
MECorrectionBase::doinit();
_channelweights.push_back(_channelwgtA/(1.+_channelwgtA));
_channelweights.push_back(_channelweights[0]+1./(1.+_channelwgtA)/(1+_channelwgtB));
_channelweights.push_back(1.0);
}
void DrellYanMECorrection::dofinish() {
MECorrectionBase::dofinish();
if(_nover==0) return;
generator()->log() << "DrellYanMECorrection when applying the hard correction "
<< _nover << " weights larger than one were generated of which"
<< " the largest was " << _maxwgt << "\n";
}
void DrellYanMECorrection::persistentOutput(PersistentOStream & os) const {
os << _channelwgtA << _channelwgtB << _channelweights;
}
void DrellYanMECorrection::persistentInput(PersistentIStream & is, int) {
is >> _channelwgtA >> _channelwgtB >> _channelweights;
}
ClassDescription<DrellYanMECorrection> DrellYanMECorrection::initDrellYanMECorrection;
// Definition of the static class description member.
void DrellYanMECorrection::Init() {
static ClassDocumentation<DrellYanMECorrection> documentation
("The DrellYanMECorrection class implements the soft and hard"
" matrix element correction for the Drell-Yan process. 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.");
static Parameter<DrellYanMECorrection,double> interfaceQQbarChannelWeight
("QQbarChannelWeight",
"The relative weights of the q qbar abd q g channels for selection."
" This is a technical parameter for the phase-space generation and "
"should not affect the results only the efficiency and fraction"
" of events with weight > 1.",
&DrellYanMECorrection::_channelwgtA, 0.12, 0.01, 100.,
false, false, Interface::limited);
static Parameter<DrellYanMECorrection,double> interfaceQGChannelWeight
("QGChannelWeight",
"The relative weights of the qg abd qbar g channels for selection."
" This is a technical parameter for the phase-space generation and "
"should not affect the results only the efficiency and fraction",
&DrellYanMECorrection::_channelwgtB, 2., 0.01, 100.,
false, false, Interface::limited);
}
bool DrellYanMECorrection::canHandle(ShowerTreePtr tree, double & initial,
double & final, EvolverPtr evolver) {
// check on type of radiation
if(!evolver->isISRadiationON()) return false;
// two incoming particles
if(tree->incomingLines().size()!=2) return false;
// should be a quark and an antiquark
unsigned int ix(0);
ShowerParticlePtr part[2];
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cit;
for(cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit)
{part[ix]=cit->first->progenitor();++ix;}
// check quark and antiquark
if(!(part[0]->id()>0&&part[0]->id()<6&&part[1]->id()<0&&part[1]->id()>-6)&&
!(part[1]->id()>0&&part[1]->id()<6&&part[0]->id()<0&&part[0]->id()>-6))
return false;
// one or two outgoing particles
if(tree->outgoingLines().size()>2) return false;
// find the outgoing particles
ix=0;
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cjt;
for(cjt=tree->outgoingLines().begin();cjt!=tree->outgoingLines().end();++cjt)
{part[ix]=cjt->first->progenitor();++ix;}
// outgoing particles (1 which is W/Z)
if(tree->outgoingLines().size()==1&&
!(part[0]->id()!=ParticleID::gamma||part[0]->id()!=ParticleID::Z0||
abs(part[0]->id())==ParticleID::Wplus))
return false;
else if(tree->outgoingLines().size()==2)
{
if(part[0]->parents().empty()||part[1]->parents().empty()) return false;
if(part[0]->parents()[0]!=part[1]->parents()[0]) return false;
if(!(part[0]->parents()[0]->id()==ParticleID::gamma||
part[0]->parents()[0]->id()==ParticleID::Z0||
abs(part[0]->parents()[0]->id())==ParticleID::Wplus)) return false;
}
// extract the boson mass and store
if(tree->outgoingLines().size()==1) _mb2=sqr(part[0]->mass());
else _mb2=sqr(part[0]->parents()[0]->mass());
// can handle it
initial = 1.;
final = 1.;
return true;
}
void DrellYanMECorrection::applyHardMatrixElementCorrection(ShowerTreePtr tree) {
assert(tree->outgoingLines().size());
// get the quark,antiquark and the gauge boson
// get the quarks
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cit;
ShowerParticleVector incoming;
vector<tcBeamPtr> beams;
for(cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
incoming.push_back(cit->first->progenitor());
beams.push_back(cit->first->beam());
}
// get the gauge bosons
PPtr boson;
if(tree->outgoingLines().size()==1)
{boson=tree->outgoingLines().begin()->first->copy();}
else
{boson=tree->outgoingLines().begin()->first->copy()->parents()[0];}
// ensure that the quark is first
bool quarkfirst(true);
if(incoming[0]->id()<incoming[1]->id())
{
quarkfirst=false;
swap(incoming[0],incoming[1]);
swap(beams[0],beams[1]);
}
// calculate the momenta
unsigned int iemit,itype;
vector<Lorentz5Momentum> pnew;
LorentzRotation trans;
pair<double,double> xnew;
// if not accepted return
if(!applyHard(incoming,beams,boson,iemit,itype,pnew,trans,xnew)) return;
// if applying ME correction create the new particles
if(itype==0) {
// get the momenta of the new particles
Lorentz5Momentum pquark(pnew[0]),panti(pnew[1]),pgluon(pnew[2]);
if(iemit==2) swap(pquark,panti);
// ensure gluon can be put on shell
Lorentz5Momentum ptest(pgluon);
if(ptest.boost(-(pquark+panti).boostVector()).e() <
getParticleData(ParticleID::g)->constituentMass()) return;
// create the new gluon
PPtr newg= getParticleData(ParticleID::g)->produceParticle(pgluon);
PPtr newq,newa;
ColinePtr col;
// make the new particles
if(iemit==1) {
col=incoming[0]->colourLine();
newq = getParticleData(incoming[0]->id())->produceParticle(pquark);
newa = new_ptr(Particle(*incoming[1]));
col->removeAntiColoured(newa);
newa->set5Momentum(panti);
}
else {
col=incoming[1]->antiColourLine();
newa = getParticleData(incoming[1]->id())->produceParticle(panti);
newq = new_ptr(Particle(*incoming[0]));
col->removeColoured(newq);
newq->set5Momentum(pquark);
}
// set the colour lines
ColinePtr newline=new_ptr(ColourLine());
if(iemit==1) {
newline->addColoured(newq);
newline->addColoured(newg);
col->addAntiColoured(newg);
col->addAntiColoured(newa);
}
else {
newline->addAntiColoured(newa);
newline->addAntiColoured(newg);
col->addColoured(newg);
col->addColoured(newq);
}
// change the existing quark and antiquark
PPtr orig;
for(cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
if(cit->first->progenitor()->id()==newq->id()) {
// remove old particles from colour line
col->removeColoured(cit->first->copy());
col->removeColoured(cit->first->progenitor());
// insert new particles
cit->first->copy(newq);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newq,1,false)));
sp->x(xnew.first);
cit->first->progenitor(sp);
tree->incomingLines()[cit->first]=sp;
cit->first->perturbative(iemit!=1);
if(iemit==1) orig=cit->first->original();
}
else {
// remove old particles from colour line
col->removeAntiColoured(cit->first->copy());
col->removeColoured(cit->first->progenitor());
// insert new particles
cit->first->copy(newa);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newa,1,false)));
sp->x(xnew.second);
cit->first->progenitor(sp);
tree->incomingLines()[cit->first]=sp;
cit->first->perturbative(iemit==1);
if(iemit==2) orig=cit->first->original();
}
}
// fix the momentum of the gauge boson
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt=tree->outgoingLines().begin();
Boost boostv=cjt->first->progenitor()->momentum().findBoostToCM();
trans *=LorentzRotation(boostv);
cjt->first->progenitor()->transform(trans);
cjt->first->copy()->transform(trans);
tree->hardMatrixElementCorrection(true);
// add the gluon
ShowerParticlePtr sg=new_ptr(ShowerParticle(*newg,1,true));
ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(orig,newg,sg));
gluon->perturbative(false);
tree->outgoingLines().insert(make_pair(gluon,sg));
}
else if(itype==1) {
Lorentz5Momentum pin(pnew[0]),pout(pnew[1]),pgluon(pnew[2]);
if(iemit==2) swap(pin,pout);
// ensure outgoing quark can be put on-shell
Lorentz5Momentum ptest(pout);
if(ptest.boost(-(pin+pgluon).boostVector()).e() <
incoming[1]->dataPtr()->constituentMass()) return;
// create the new gluon
PPtr newg = getParticleData(ParticleID::g)->produceParticle(pgluon);
// create the new outgoing quark
PPtr newout= getParticleData(-incoming[1]->id())->produceParticle(pout);
// create the new incoming quark
PPtr newin = new_ptr(Particle(*incoming[0]));
newin->set5Momentum(pin);
// colour info
ColinePtr col=incoming[0]->colourLine();
col->removeColoured(newin);
ColinePtr newline=new_ptr(ColourLine());
newline->addColoured(newout);
newline->addColoured(newg);
col->addAntiColoured(newg);
col->addColoured(newin);
// change the existing incoming partons
PPtr orig;
for(cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
if(cit->first->progenitor()->id()==newin->id()) {
// remove old particles from colour line
col->removeColoured(cit->first->copy());
col->removeColoured(cit->first->progenitor());
// insert new particles
cit->first->copy(newin);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newin,1,false)));
sp->x(xnew.first);
cit->first->progenitor(sp);
tree->incomingLines()[cit->first]=sp;
cit->first->perturbative(true);
}
else {
// remove old particles from colour line
col->removeAntiColoured(cit->first->copy());
col->removeColoured(cit->first->progenitor());
// insert new particles
cit->first->copy(newg);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newg,1,false)));
sp->x(xnew.second);
cit->first->progenitor(sp);
tree->incomingLines()[cit->first]=sp;
cit->first->perturbative(false);
orig=cit->first->original();
}
}
// fix the momentum of the gauge boson
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt=tree->outgoingLines().begin();
Boost boostv=cjt->first->progenitor()->momentum().findBoostToCM();
trans *=LorentzRotation(boostv);
cjt->first->progenitor()->transform(trans);
cjt->first->copy()->transform(trans);
tree->hardMatrixElementCorrection(true);
// add the outgoing quark
ShowerParticlePtr sout=new_ptr(ShowerParticle(*newout,1,true));
ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(orig,newout,sout));
out->perturbative(false);
tree->outgoingLines().insert(make_pair(out,sout));
}
else if(itype==2) {
Lorentz5Momentum pin(pnew[0]),pout(pnew[1]),pgluon(pnew[2]);
if(iemit==2) swap(pin,pout);
// ensure outgoing antiquark can be put on-shell
Lorentz5Momentum ptest(pout);
if(ptest.boost(-(pin+pgluon).boostVector()).e() <
incoming[0]->dataPtr()->constituentMass()) return;
// create the new gluon
PPtr newg = getParticleData(ParticleID::g)->produceParticle(pgluon);
// create the new outgoing antiquark
PPtr newout= getParticleData(-incoming[0]->id())->produceParticle(pout);
// create the new incoming antiquark
PPtr newin = new_ptr(Particle(*incoming[1]));
newin->set5Momentum(pin);
// colour info
ColinePtr col=incoming[0]->colourLine();
col->removeAntiColoured(newin);
ColinePtr newline=new_ptr(ColourLine());
newline->addAntiColoured(newout);
newline->addAntiColoured(newg);
col->addColoured(newg);
col->addAntiColoured(newin);
// change the existing incoming partons
PPtr orig;
for(cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
if(cit->first->progenitor()->id()==newin->id()) {
// remove old particles from colour line
col->removeAntiColoured(cit->first->copy());
col->removeColoured(cit->first->progenitor());
// insert new particles
cit->first->copy(newin);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newin,1,false)));
sp->x(xnew.second);
cit->first->progenitor(sp);
tree->incomingLines()[cit->first]=sp;
cit->first->perturbative(true);
}
else {
// remove old particles from colour line
col->removeColoured(cit->first->copy());
col->removeColoured(cit->first->progenitor());
// insert new particles
cit->first->copy(newg);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newg,1,false)));
sp->x(xnew.first);
cit->first->progenitor(sp);
tree->incomingLines()[cit->first]=sp;
cit->first->perturbative(false);
orig=cit->first->original();
}
}
// fix the momentum of the gauge boson
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt=tree->outgoingLines().begin();
Boost boostv=cjt->first->progenitor()->momentum().findBoostToCM();
trans *=LorentzRotation(boostv);
cjt->first->progenitor()->transform(trans);
cjt->first->copy()->transform(trans);
tree->hardMatrixElementCorrection(true);
// add the outgoing antiquark
ShowerParticlePtr sout=new_ptr(ShowerParticle(*newout,1,true));
ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(orig,newout,sout));
out->perturbative(false);
tree->outgoingLines().insert(make_pair(out,sout));
}
}
bool DrellYanMECorrection::softMatrixElementVeto(ShowerProgenitorPtr initial,
- ShowerParticlePtr parent,Branching br)
-{
+ ShowerParticlePtr parent,Branching br) {
if(parent->isFinalState()) return false;
// check if me correction should be applied
long id[2]={initial->id(),parent->id()};
if(id[0]!=id[1]||id[1]==ParticleID::g) return false;
// get the pT
Energy pT=br.kinematics->pT();
// check if hardest so far
if(pT<initial->pT()) return false;
// compute the invariants
double kappa(sqr(br.kinematics->scale())/_mb2),z(br.kinematics->z());
Energy2 shat(_mb2/z*(1.+(1.-z)*kappa)),that(-(1.-z)*kappa*_mb2),uhat(-(1.-z)*shat);
// check which type of process
// g qbar
double wgt(1.);
if(id[0]>0&&br.ids[0]==ParticleID::g)
wgt=_mb2/(shat+uhat)*(sqr(_mb2-that)+sqr(_mb2-shat))/(sqr(shat+uhat)+sqr(uhat));
else if(id[0]>0&&br.ids[0]==id[0])
wgt=_mb2/(shat+uhat)*(sqr(_mb2-uhat)+sqr(_mb2-that))/(sqr(shat)+sqr(shat+uhat));
else if(id[0]<0&&br.ids[0]==ParticleID::g)
wgt=_mb2/(shat+uhat)*(sqr(_mb2-that)+sqr(_mb2-shat))/(sqr(shat+uhat)+sqr(uhat));
else if(id[0]<0&&br.ids[0]==-id[0])
wgt=_mb2/(shat+uhat)*(sqr(_mb2-uhat)+sqr(_mb2-that))/(sqr(shat)+sqr(shat+uhat));
else return false;
if(wgt<.0||wgt>1.) generator()->log() << "Soft ME correction weight too large or "
<< "negative in DrellYanMECorrection::"
<< "softMatrixElementVeto()soft weight "
<< " sbar = " << shat/_mb2
<< " tbar = " << that/_mb2
<< "weight = " << wgt << "\n";
// if not vetoed
if(UseRandom::rndbool(wgt)) {
initial->pT(pT);
return false;
}
// otherwise
parent->setEvolutionScale(ShowerIndex::QCD,br.kinematics->scale());
return true;
}
bool DrellYanMECorrection::applyHard(ShowerParticleVector quarks,
vector<tcBeamPtr> beams,PPtr boson,
unsigned int & iemit,unsigned int & itype,
vector<Lorentz5Momentum> & pnew,
LorentzRotation & trans,
pair<double,double> & xout) {
// check that quark along +z and qbar along -z
bool quarkplus=quarks[0]->momentum().z()>quarks[1]->momentum().z();
// calculate the limits on s
Energy mb(boson->mass());
_mb2=sqr(mb);
Energy2 smin=_mb2;
Energy2 s=
(CurrentGenerator::current().currentEvent()->incoming().first->momentum()+
CurrentGenerator::current().currentEvent()->incoming().second->momentum()).m2();
Energy2 smax(s);
// calculate the rapidity of the boson
double yB=0.5*log((boson->momentum().e()+boson->momentum().z())/
(boson->momentum().e()-boson->momentum().z()));
if(!quarkplus) yB=-yB;
// if no phase-space return
if(smax<smin) return false;
// get the evolution scales (this needs improving)
double kappa[2]={1.,1.};
// get the momentum fractions for the leading order process
// and the values of the PDF's
double x[2],fx[2];
tcPDFPtr pdf[2];
for(unsigned int ix=0;ix<quarks.size();++ix) {
x[ix]=quarks[ix]->x();
assert(beams[ix]);
pdf[ix]=beams[ix]->pdf();
assert(pdf[ix]);
fx[ix]=pdf[ix]->xfx(beams[ix],quarks[ix]->dataPtr(),_mb2,x[ix]);
}
// select the type of process and generate the kinematics
double rn(UseRandom::rnd());
Energy2 shat(0.*GeV2),uhat(0.*GeV2),that(0.*GeV2);
double weight(0.),xnew[2]={1.,1.};
// generate the value of s according to 1/s^2
shat = smax*smin/(smin+UseRandom::rnd()*(smax-smin));
Energy2 jacobian = sqr(shat)*(1./smin-1./smax);
double sbar=shat/_mb2;
// calculate limits on that
Energy2 tmax=_mb2*kappa[0]*(1.-sbar)/(kappa[0]+sbar);
Energy2 tmin=shat*(1.-sbar)/(kappa[1]+sbar);
// calculate the limits on uhat
Energy2 umax(_mb2-shat-tmin),umin(_mb2-shat-tmax);
// check inside phase space
if(tmax<tmin||umax<umin) return false;
// q qbar -> g V
if(rn<_channelweights[0]) {
// generate t and u according to 1/t+1/u
// generate in 1/t
if(UseRandom::rndbool(0.5)) {
that=tmax*pow(tmin/tmax,UseRandom::rnd());
uhat=_mb2-shat-that;
jacobian *=log(tmin/tmax);
}
// generate in 1/u
else {
uhat=umax*pow(umin/umax,UseRandom::rnd());
that=_mb2-shat-uhat;
jacobian *=log(umin/umax);
}
Energy4 jacobian2 = jacobian * 2.*uhat*that/(shat-_mb2);
// new scale (this is mt^2=pt^2+mb^2)
Energy2 scale(uhat*that/shat+_mb2);
// the PDF's with the emitted gluon
double fxnew[2];
xnew[0]=exp(yB)/sqrt(s)*sqrt(shat*(_mb2-uhat)/(_mb2-that));
xnew[1]=shat/(s*xnew[0]);
for(unsigned int ix=0;ix<2;++ix)
{fxnew[ix]=pdf[ix]->xfx(beams[ix],quarks[ix]->dataPtr(),scale,xnew[ix]);}
// jacobian and me parts of the weight
weight=jacobian2*(sqr(_mb2-that)+sqr(_mb2-uhat))/(sqr(shat)*that*uhat);
// pdf part of the weight
weight *=fxnew[0]*fxnew[1]*x[0]*x[1]/(fx[0]*fx[1]*xnew[0]*xnew[1]);
// finally coupling, colour factor and different channel pieces
weight *= 2./3./Constants::pi/_channelweights[0]*coupling()->value(scale);
// select the emiting particle
iemit=1;
if(UseRandom::rnd()<sqr(_mb2-uhat)/(sqr(_mb2-uhat)+sqr(_mb2-that))) iemit=2;
itype=0;
}
// incoming gluon
else {
// generate t
if(rn>_channelweights[1]) {
swap(tmax,tmin);
tmax=_mb2-shat-tmax;
tmin=_mb2-shat-tmin;
}
that=tmax*pow(tmin/tmax,UseRandom::rnd());
uhat=_mb2-shat-that;
Energy4 jacobian2 = jacobian * that*log(tmax/tmin);
// new scale (this is mt^2=pt^2+mb^2)
Energy2 scale(uhat*that/shat+_mb2);
// g qbar -> qbar V
double fxnew[2];
if(rn<_channelweights[1]) {
itype=2;
xnew[0]=exp(yB)/sqrt(s)*sqrt(shat*(_mb2-uhat)/(_mb2-that));
xnew[1]=shat/(s*xnew[0]);
fxnew[0]=pdf[0]->xfx(beams[0],getParticleData(ParticleID::g),scale,xnew[0]);
fxnew[1]=pdf[1]->xfx(beams[1],quarks[1]->dataPtr(),scale,xnew[1]);
jacobian2/=(_channelweights[1]-_channelweights[0]);
}
// q g -> q V
else {
itype=1;
xnew[0]=exp(yB)/sqrt(s)*sqrt(shat*(_mb2-that)/(_mb2-uhat));
xnew[1]=shat/(s*xnew[0]);
fxnew[0]=pdf[0]->xfx(beams[0],quarks[0]->dataPtr(),scale,xnew[0]);
fxnew[1]=pdf[1]->xfx(beams[1],getParticleData(ParticleID::g),scale,xnew[1]);
jacobian2/=(_channelweights[2]-_channelweights[1]);
}
// jacobian and me parts of the weight
weight=-jacobian2*(sqr(_mb2-that)+sqr(_mb2-shat))/(sqr(shat)*shat*that);
// pdf part of the weight
weight *=fxnew[0]*fxnew[1]*x[0]*x[1]/(fx[0]*fx[1]*xnew[0]*xnew[1]);
// finally coupling, colour factor and different channel pieces
weight *= 0.25/Constants::pi*coupling()->value(scale);
// select the emiting particle
iemit=1;
if(UseRandom::rnd()<sqr(_mb2-that)/(sqr(_mb2-that)+sqr(_mb2-shat))) iemit=2;
}
// if me correction should be applied
if(weight>1.) {
++_nover;
_maxwgt=max(_maxwgt,weight);
weight=1.;
}
if(UseRandom::rnd()>weight) return false;
// construct the momenta in the rest frame of the boson
Lorentz5Momentum pb(0.*MeV,0.*MeV,0.*MeV,mb,mb),pspect,pg,pemit;
double cos3;
if(itype==0)
{
pg = Lorentz5Momentum(0.*MeV,0.*MeV,0.*MeV,0.5*(shat-_mb2)/mb,0.*MeV);
Energy2 tp(that),up(uhat);
double zsign(-1.);
if(iemit==2)
{
tp=uhat;
up=that;
zsign=1.;
}
pspect = Lorentz5Momentum(0.*MeV,0.*MeV,zsign*0.5*(_mb2-tp)/mb,
0.5*(_mb2-tp)/mb,0.*MeV);
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(0.*MeV,0*MeV,0.*MeV,0.5*(_mb2-uhat)/mb,0.*MeV);
double zsign(1.);
if(iemit==1)
{
if(itype==1) zsign=-1.;
pspect=Lorentz5Momentum(0.*MeV,0.*MeV,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(0.*MeV,0.*MeV,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))),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;
}
diff --git a/Shower/Default/MECorrections/Makefile.am b/Shower/Default/MECorrections/Makefile.am
--- a/Shower/Default/MECorrections/Makefile.am
+++ b/Shower/Default/MECorrections/Makefile.am
@@ -1,14 +1,18 @@
## libHwDefaultMECorrections.la will go into HwShower.so
noinst_LTLIBRARIES = libHwDefaultMECorrections.la
libHwDefaultMECorrections_la_SOURCES = \
QTildeMECorrection.icc QTildeMECorrection.fh QTildeMECorrection.h QTildeMECorrection.cc\
VectorBosonQQBarMECorrection.h VectorBosonQQBarMECorrection.fh \
VectorBosonQQBarMECorrection.icc VectorBosonQQBarMECorrection.cc\
TopDecayMECorrection.h TopDecayMECorrection.fh \
TopDecayMECorrection.icc TopDecayMECorrection.cc \
DrellYanMECorrection.h DrellYanMECorrection.fh \
DrellYanMECorrection.icc DrellYanMECorrection.cc \
GGtoHMECorrection.h GGtoHMECorrection.fh \
-GGtoHMECorrection.icc GGtoHMECorrection.cc
+GGtoHMECorrection.icc GGtoHMECorrection.cc \
+DISMECorrection.h DISMECorrection.fh \
+DISMECorrection.icc DISMECorrection.cc \
+VBFMECorrection.h VBFMECorrection.fh \
+VBFMECorrection.icc VBFMECorrection.cc
libHwDefaultMECorrections_la_CPPFLAGS=$(AM_CPPFLAGS) $(GSLINCLUDE)
diff --git a/Shower/Default/MECorrections/VBFMECorrection.cc b/Shower/Default/MECorrections/VBFMECorrection.cc
new file mode 100644
--- /dev/null
+++ b/Shower/Default/MECorrections/VBFMECorrection.cc
@@ -0,0 +1,545 @@
+// -*- C++ -*-
+//
+// This is the implementation of the non-inlined, non-templated member
+// functions of the VBFMECorrection class.
+//
+
+#include "VBFMECorrection.h"
+#include "ThePEG/Interface/ClassDocumentation.h"
+#include "ThePEG/Interface/Parameter.h"
+#include "ThePEG/Persistency/PersistentOStream.h"
+#include "ThePEG/Persistency/PersistentIStream.h"
+#include <numeric>
+#include "Herwig++/Utilities/Maths.h"
+
+using namespace Herwig;
+
+void VBFMECorrection::persistentOutput(PersistentOStream & os) const {
+ os << _procprob << _comptonint;
+}
+
+void VBFMECorrection::persistentInput(PersistentIStream & is, int) {
+ is >> _procprob >> _comptonint;
+}
+
+ClassDescription<VBFMECorrection> VBFMECorrection::initVBFMECorrection;
+// Definition of the static class description member.
+
+void VBFMECorrection::Init() {
+
+ static ClassDocumentation<VBFMECorrection> documentation
+ ("The VBFMECorrection class implements the matrix element"
+ " correction for VBF Higgs production");
+
+ static Parameter<VBFMECorrection,double> interfaceProcessProbability
+ ("ProcessProbability",
+ "The probabilty of the QCD compton process for the process selection",
+ &VBFMECorrection::_procprob, 0.3, 0.0, 1.,
+ false, false, Interface::limited);
+
+}
+
+bool VBFMECorrection::canHandle(ShowerTreePtr tree,double & initial,
+ double & final,EvolverPtr evolver) {
+ // two incoming particles
+ if(tree->incomingLines().size()!=2) return false;
+ // three outgoing particles
+ if(tree->outgoingLines().size()!=3) return false;
+ // extract the incoming quarks
+ vector<PPtr> incoming;
+ for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
+ cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
+ if(QuarkMatcher::Check(cit->first->progenitor()->data()))
+ incoming.push_back(cit->first->progenitor());
+ }
+ if(incoming.size()!=2) return false;
+ // extract the outgoing quarks and the higgs
+ bool higgs = false;
+ vector<PPtr> outgoing;
+ for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
+ cjt=tree->outgoingLines().begin();cjt!=tree->outgoingLines().end();++cjt) {
+ if(cjt->first->progenitor()->id()==ParticleID::h0) higgs = true;
+ else if(QuarkMatcher::Check(cjt->first->progenitor()->data()))
+ outgoing.push_back(cjt->first->progenitor());
+ }
+ if(!higgs||outgoing.size()!=2) return false;
+ // check things match up
+ unsigned int nmatch(0);
+ for(unsigned int ix=0;ix<incoming.size();++ix) {
+ if(incoming[ix]->colourLine()) {
+ for(unsigned int iy=0;iy<outgoing.size();++iy) {
+ if(outgoing[iy]->colourLine()==incoming[ix]->colourLine()) {
+ ++nmatch;
+ break;
+ }
+ }
+ }
+ else {
+ for(unsigned int iy=0;iy<outgoing.size();++iy) {
+ if(outgoing[iy]->antiColourLine()==incoming[ix]->antiColourLine()) {
+ ++nmatch;
+ break;
+ }
+ }
+ }
+ }
+ if(nmatch!=2) return false;
+ // can handle it
+ initial = 1.;
+ final = 1.;
+ return true;
+}
+
+void VBFMECorrection::applyHardMatrixElementCorrection(ShowerTreePtr tree) {
+ ++_ntry;
+ //cerr << "testing in apply hard\n";
+ //cerr << *generator()->currentEvent() << "\n";
+ vector<tChannelPair> systems;
+ for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
+ cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
+ if(QuarkMatcher::Check(cit->first->progenitor()->data())) {
+ systems.push_back(tChannelPair());
+ systems.back().hadron = cit->first->original()->parents()[0];
+ systems.back().beam = cit->first->beam();
+ systems.back().incoming = cit->first->progenitor();
+ systems.back().pdf = systems.back().beam->pdf();
+ }
+ }
+ assert(systems.size()==2);
+ // extract the outgoing quarks and the higgs
+ PPtr higgs;
+ vector<ShowerParticlePtr> outgoing;
+ for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
+ cjt=tree->outgoingLines().begin();cjt!=tree->outgoingLines().end();++cjt) {
+ if(cjt->first->progenitor()->id()==ParticleID::h0)
+ higgs = cjt->first->progenitor();
+ else if(QuarkMatcher::Check(cjt->first->progenitor()->data()))
+ outgoing.push_back(cjt->first->progenitor());
+ }
+ assert(outgoing.size()==2&&higgs);
+ // match up the quarks
+ for(unsigned int ix=0;ix<systems.size();++ix) {
+ if(systems[ix].incoming->colourLine()) {
+ for(unsigned int iy=0;iy<outgoing.size();++iy) {
+ if(outgoing[iy]->colourLine()==systems[ix].incoming->colourLine()) {
+ systems[ix].outgoing=outgoing[iy];
+ break;
+ }
+ }
+ }
+ else {
+ for(unsigned int iy=0;iy<outgoing.size();++iy) {
+ if(outgoing[iy]->antiColourLine()==systems[ix].incoming->antiColourLine()) {
+ systems[ix].outgoing=outgoing[iy];
+ break;
+ }
+ }
+ }
+ }
+ assert(systems[0].outgoing&&systems[1].outgoing);
+// for(unsigned int ix=0;ix<systems.size();++ix) {
+// cerr << *systems[ix].hadron;
+// cerr << *systems[ix].incoming << "\n" << *systems[ix].outgoing << "\n";
+// cerr << "testing scale " << sqrt(-(systems[ix].incoming->momentum()-systems[ix].outgoing->momentum()).m2()/GeV2) << "\n";
+// }
+ // select emitting line
+ if(UseRandom::rndbool()) swap(systems[0],systems[1]);
+ // extract the born variables
+ Lorentz5Momentum q = systems[0].outgoing->momentum()-
+ systems[0].incoming->momentum();
+ // extract born variables
+ Energy2 q2 = -q.m2();
+ Energy Q = sqrt(q2);
+ double xB = systems[0].incoming->x();
+// cerr << "testing q2 " << q2/GeV2 << " " << Q/GeV << " " << xB << "\n";
+ // 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*q;
+ pcmf.rescaleMass();
+ LorentzRotation rot(-pcmf.boostVector());
+ Lorentz5Momentum pbeam = rot*phadron;
+ Axis axis(pbeam.vect().unit());
+ double sinth(sqrt(1.-sqr(axis.z())));
+ 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()));
+// cerr << "testing momenta in the Breit frame\n";
+// cerr << rot*systems[0].incoming->momentum()/GeV << "\n";
+// cerr << rot*systems[0].outgoing->momentum()/GeV << "\n";
+// cerr << rot*systems[1].incoming->momentum()/GeV << "\n";
+// cerr << rot*systems[1].outgoing->momentum()/GeV << "\n";
+// cerr << rot*higgs->momentum()/GeV << "\n";
+// cerr << rot*(systems[1].outgoing->momentum()+higgs->momentum())/GeV << "\n";
+ // calculate the A coefficient for the correlations
+ double acoeff = A(systems[0].incoming->dataPtr(),systems[0].outgoing->dataPtr(),
+ systems[1].incoming->dataPtr(),systems[1].outgoing->dataPtr());
+ vector<double> azicoeff;
+ // select the type of process
+ bool BGF = UseRandom::rnd()>_procprob;
+ tcPDPtr gluon = getParticleData(ParticleID::g);
+ double wgt,xp,zp,x1,x2,x3,xperp;
+ LorentzVector<double> l(2.*(rot*systems[1].incoming->momentum())/Q);
+ LorentzVector<double> m(2.*(rot*systems[1].outgoing->momentum())/Q);
+ //cerr << "testing scale " << Q/2/GeV << "\n";
+ //cerr << "testing other momentum " << rot*systems[1].incoming->momentum()/GeV << "\n";
+ //cerr << "testing other momentum " << rot*systems[1].outgoing->momentum()/GeV << "\n";
+ //cerr << "testing l " << l << "\n";
+ //cerr << "testing m " << m << "\n";
+ if(!BGF) {
+ wgt = generateComptonPoint(xp,zp);
+ if(xp<1e-6) return;
+ // common pieces
+ Energy2 scale = q2*((1.-xp)*(1-zp)*zp/xp+1);
+ //cerr << "testing weight A1 " << wgt << "\n";
+ wgt *= 2./3./Constants::pi*coupling()->value(scale)/_procprob;
+ //cerr << "testing weight B1 " << wgt << "\n";
+ // PDF piece
+ wgt *= systems[0].pdf->xfx(systems[0].beam,systems[0].incoming->dataPtr(),scale,xB/xp)/
+ systems[0].pdf->xfx(systems[0].beam,systems[0].incoming->dataPtr(),q2 ,xB);
+ //cerr << "testing weight C1 " << wgt << "\n";
+ // 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,acoeff,l,m);
+
+
+
+// Energy2 dp1p2=systems[0].outgoing->momentum()*systems[1].outgoing->momentum();
+// Energy2 dk1k2=systems[0].incoming->momentum()*systems[1].incoming->momentum();
+// Energy2 dk1p2=systems[0].incoming->momentum()*systems[1].outgoing->momentum();
+// Energy2 dk2p1=systems[0].outgoing->momentum()*systems[1].incoming->momentum();
+// Energy4 meb = 8*(dp1p2*dk1k2*(1.+0.5*acoeff)+dk1p2*dk2p1*(1.-0.5*acoeff));
+// cerr << "testing acoeff " << acoeff << "\n";
+// double denom = -l.z()*m.z()+l.t()*m.t()+0.5*acoeff*(l.t()*m.z()-l.z()*m.t());
+// cerr << "testing ME " << meb/pow<4,1>(Q) << " " << denom << " "
+// << meb/pow<4,1>(Q)/denom << "\n";
+ }
+ else {
+ wgt = generateBGFPoint(xp,zp);
+ if(xp<1e-6) return;
+ // common pieces
+ Energy2 scale = q2*((1.-xp)*(1-zp)*zp/xp+1);
+ wgt *= 0.25/Constants::pi*coupling()->value(scale)/(1.-_procprob);
+ // PDF piece
+ wgt *= systems[0].pdf->xfx(systems[0].beam,gluon ,scale,xB/xp)/
+ systems[0].pdf->xfx(systems[0].beam,systems[0].incoming->dataPtr(),q2 ,xB);
+ // 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,acoeff,l,m);
+ }
+ // compute the azimuthal average of the weight
+ wgt *= azicoeff[0]+0.5*azicoeff[2]+0.5*azicoeff[4];
+ // finally factor as picked one line
+ wgt *= 2.;
+ // decide whether or not to accept the weight
+ if(UseRandom::rnd()>wgt) return;
+ // if accepted generate generate phi
+ unsigned int itry(0);
+ double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.);
+ double phiwgt,phi;
+ do {
+ phi = UseRandom::rnd()*Constants::twopi;
+ double cphi(cos(phi)),sphi(sin(phi));
+ phiwgt = azicoeff[0]+azicoeff[5]*sphi*cphi
+ +azicoeff[1]*cphi+azicoeff[2]*sqr(cphi)
+ +azicoeff[3]*sphi+azicoeff[4]*sqr(sphi);
+ ++itry;
+ }
+ while (phimax*UseRandom::rnd() > phiwgt && itry<200);
+ if(itry==200) throw Exception() << "Too many tries in VBFMECorrection"
+ << "::applyHardMatrixElementCorrection() to"
+ << " generate phi" << Exception::eventerror;
+ // compute the new incoming and outgoing momenta
+ Lorentz5Momentum p1 = Lorentz5Momentum( 0.5*Q*xperp*cos(phi), 0.5*Q*xperp*sin(phi),
+ -0.5*Q*x2,0.*GeV,0.*GeV);
+ p1.rescaleEnergy();
+ Lorentz5Momentum p2 = Lorentz5Momentum(-0.5*Q*xperp*cos(phi),-0.5*Q*xperp*sin(phi),
+ -0.5*Q*x3,0.*GeV,0.*GeV);
+ p2.rescaleEnergy();
+ Lorentz5Momentum pin(0.*GeV,0.*GeV,-0.5*x1*Q,-0.5*x1*Q,0.*GeV);
+ // we need inverse of the rotation, i.e back to lab from breit
+ rot.invert();
+ // transform the momenta to lab frame
+ pin *= rot;
+ p1 *= rot;
+ p2 *= rot;
+ // test to ensure outgoing particles can be put on-shell
+ if(!BGF) {
+ if(p1.e()<systems[0].outgoing->dataPtr()->constituentMass()) return;
+ if(p2.e()<gluon ->constituentMass()) return;
+ }
+ else {
+ if(p1.e()<systems[0].outgoing->dataPtr() ->constituentMass()) return;
+ if(p2.e()<systems[0].incoming->dataPtr()->CC()->constituentMass()) return;
+ }
+ // stats for weights > 1
+ if(wgt>1.) {
+ ++_nover;
+ if(!BGF) {
+ _maxwgt.first = max(_maxwgt.first ,wgt);
+ _comptonover.push_back(make_pair(xp,zp));
+ }
+ else {
+ _maxwgt.second = max(_maxwgt.second,wgt);
+ _bgfover.push_back(make_pair(xp,zp));
+ }
+ }
+ // points into hist
+ ++_ngen;
+ if(!BGF) _compton.push_back(make_pair(xp,zp));
+ else _bgf .push_back(make_pair(xp,zp));
+ // create the new particles and add to ShowerTree
+ bool isquark = systems[0].incoming->colourLine();
+ if(!BGF) {
+ PPtr newin = new_ptr(Particle(*systems[0].incoming));
+ newin->set5Momentum(pin);
+ PPtr newg = gluon ->produceParticle(p2 );
+ PPtr newout = systems[0].outgoing->dataPtr()->produceParticle(p1 );
+ ColinePtr col=isquark ?
+ systems[0].incoming->colourLine() : systems[0].incoming->antiColourLine();
+ ColinePtr newline=new_ptr(ColourLine());
+ // final-state emission
+ if(xp>zp) {
+ col->removeColoured(newout,!isquark);
+ col->addColoured(newin,!isquark);
+ col->addColoured(newg,!isquark);
+ newline->addColoured(newg,isquark);
+ newline->addColoured(newout,!isquark);
+ }
+ // initial-state emission
+ else {
+ col->removeColoured(newin ,!isquark);
+ col->addColoured(newout,!isquark);
+ col->addColoured(newg,isquark);
+ newline->addColoured(newg,!isquark);
+ newline->addColoured(newin,!isquark);
+ }
+ PPtr orig;
+ for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
+ cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
+ if(cit->first->progenitor()!=systems[0].incoming) continue;
+ // remove old particles from colour line
+ col->removeColoured(cit->first->copy(),!isquark);
+ col->removeColoured(cit->first->progenitor(),!isquark);
+ // insert new particles
+ cit->first->copy(newin);
+ ShowerParticlePtr sp(new_ptr(ShowerParticle(*newin,1,false)));
+ cit->first->progenitor(sp);
+ tree->incomingLines()[cit->first]=sp;
+ sp->x(xB/xp);
+ cit->first->perturbative(xp>zp);
+ if(xp<=zp) orig=cit->first->original();
+ }
+ for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
+ cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) {
+ if(cit->first->progenitor()!=systems[0].outgoing) continue;
+ // remove old particles from colour line
+ col->removeColoured(cit->first->copy(),!isquark);
+ col->removeColoured(cit->first->progenitor(),!isquark);
+ // insert new particles
+ cit->first->copy(newout);
+ ShowerParticlePtr sp(new_ptr(ShowerParticle(*newout,1,true)));
+ cit->first->progenitor(sp);
+ tree->outgoingLines()[cit->first]=sp;
+ cit->first->perturbative(xp<=zp);
+ if(xp>zp) orig=cit->first->original();
+ }
+ assert(orig);
+ // add the gluon
+ ShowerParticlePtr sg=new_ptr(ShowerParticle(*newg,1,true));
+ ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(orig,newg,sg));
+ gluon->perturbative(false);
+ tree->outgoingLines().insert(make_pair(gluon,sg));
+ tree->hardMatrixElementCorrection(true);
+ //cerr << *newin << "\n";
+ //cerr << *newout << "\n";
+ //cerr << *sg << "\n";
+ }
+ else {
+ PPtr newin = gluon ->produceParticle(pin);
+ PPtr newqbar = systems[0].incoming->dataPtr()->CC()->produceParticle(p2 );
+ PPtr newout = systems[0].outgoing->dataPtr() ->produceParticle(p1 );
+ ColinePtr col=isquark ? systems[0].incoming->colourLine() : systems[0].incoming->antiColourLine();
+ ColinePtr newline=new_ptr(ColourLine());
+ col ->addColoured(newin ,!isquark);
+ newline->addColoured(newin , isquark);
+ col ->addColoured(newout ,!isquark);
+ newline->addColoured(newqbar, isquark);
+ PPtr orig;
+ for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
+ cit=tree->incomingLines().begin();cit!=tree->incomingLines().end();++cit) {
+ if(cit->first->progenitor()!=systems[0].incoming) continue;
+ // remove old particles from colour line
+ col->removeColoured(cit->first->copy(),!isquark);
+ col->removeColoured(cit->first->progenitor(),!isquark);
+ // insert new particles
+ cit->first->copy(newin);
+ ShowerParticlePtr sp(new_ptr(ShowerParticle(*newin,1,false)));
+ cit->first->progenitor(sp);
+ tree->incomingLines()[cit->first]=sp;
+ sp->x(xB/xp);
+ cit->first->perturbative(false);
+ orig=cit->first->original();
+ }
+ for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
+ cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) {
+ if(cit->first->progenitor()!=systems[0].outgoing) continue;
+ // remove old particles from colour line
+ col->removeColoured(cit->first->copy(),!isquark);
+ col->removeColoured(cit->first->progenitor(),!isquark);
+ // insert new particles
+ cit->first->copy(newout);
+ ShowerParticlePtr sp(new_ptr(ShowerParticle(*newout,1,true)));
+ cit->first->progenitor(sp);
+ tree->outgoingLines()[cit->first]=sp;
+ cit->first->perturbative(true);
+ }
+ assert(orig);
+ // add the (anti)quark
+ ShowerParticlePtr sqbar=new_ptr(ShowerParticle(*newqbar,1,true));
+ ShowerProgenitorPtr qbar=new_ptr(ShowerProgenitor(orig,newqbar,sqbar));
+ qbar->perturbative(false);
+ tree->outgoingLines().insert(make_pair(qbar,sqbar));
+ tree->hardMatrixElementCorrection(true);
+ //cerr << *newin << "\n";
+ //cerr << *newout << "\n";
+ //cerr << *sqbar << "\n";
+ }
+}
+
+bool VBFMECorrection::softMatrixElementVeto(ShowerProgenitorPtr initial,
+ ShowerParticlePtr parent,Branching br) {
+ return false;
+}
+
+void VBFMECorrection::dofinish() {
+ MECorrectionBase::dofinish();
+ string fname = generator()->filename() + string("-") + name() + string(".top");
+ ofstream outfile(fname.c_str());
+ outfile << "SET FONT DUPLEX\n";
+ outfile << "SET ORDER X Y\n";
+ outfile << "SET WINDOW X 2 9 Y 2 9\n";
+ outfile << "TITLE BOTTOM \"x0p1\"\n";
+ outfile << "CASE \" X X\"\n";
+ outfile << "TITLE LEFT \"z0p1\"\n";
+ outfile << "CASE \" X X\"\n";
+ outfile << "SET LIMITS X 0 1 Y 0 1\n";
+ for(unsigned int ix=0;ix<_compton.size();++ix) {
+ outfile << _compton[ix].first << "\t" << _compton[ix].second << "\n";
+ if(ix%50000==0&&ix>0) outfile << "PLOT\n";
+ }
+ if(!_compton.empty()) outfile << "PLOT\n";
+ for(double xp=0;xp<=1.001;xp+=0.01) {
+ outfile << xp << "\t" << 1./(1.+xp-sqr(xp)) << "\n";
+ }
+ outfile << "JOIN BLUE\n";
+ for(double z=0;z<=1.001;z+=0.01) {
+ outfile << 1./(1+z*(1.-z)) << "\t" << z << "\n";
+ }
+ outfile << "JOIN BLUE\n";;
+ outfile << "NEW FRAME\n";
+ outfile << "SET FONT DUPLEX\n";
+ outfile << "SET ORDER X Y\n";
+ outfile << "SET WINDOW X 2 9 Y 2 9\n";
+ outfile << "TITLE BOTTOM \"x0p1\"\n";
+ outfile << "CASE \" X X\"\n";
+ outfile << "TITLE LEFT \"z0p1\"\n";
+ outfile << "CASE \" X X\"\n";
+ outfile << "SET LIMITS X 0 1 Y 0 1\n";
+ for(unsigned int ix=0;ix<_comptonover.size();++ix) {
+ outfile << _comptonover[ix].first << "\t" << _comptonover[ix].second << "\n";
+ if(ix%50000==0&&ix>0) outfile << "PLOT RED\n";
+ }
+ if(!_comptonover.empty()) outfile << "PLOT RED\n";
+ for(double xp=0;xp<=1.001;xp+=0.01) {
+ outfile << xp << "\t" << 1./(1.+xp-sqr(xp)) << "\n";
+ }
+ outfile << "JOIN BLUE\n";
+ for(double z=0;z<=1.001;z+=0.01) {
+ outfile << 1./(1+z*(1.-z)) << "\t" << z << "\n";
+ }
+ outfile << "JOIN BLUE\n";
+ outfile << "NEW FRAME\n";
+ outfile << "SET FONT DUPLEX\n";
+ outfile << "SET ORDER X Y\n";
+ outfile << "SET WINDOW X 2 9 Y 2 9\n";
+ outfile << "TITLE BOTTOM \"x0p1\"\n";
+ outfile << "CASE \" X X\"\n";
+ outfile << "TITLE LEFT \"z0p1\"\n";
+ outfile << "CASE \" X X\"\n";
+ outfile << "SET LIMITS X 0 1 Y 0 1\n";
+ for(unsigned int ix=0;ix<_bgf.size();++ix) {
+ outfile << _bgf[ix].first << "\t" << _bgf[ix].second << "\n";
+ if(ix%50000==0&&ix>0) outfile << "PLOT\n";
+ }
+ if(!_bgf.empty()) outfile << "PLOT\n";
+ for(double z=0;z<=1.001;z+=0.01) {
+ double xp = 2.*z/(1.+(1.-z)+sqrt(sqr(1.+(1.-z))-4.*z*(1.-z)));
+ double zp = 0.5* (1.-(1.-z)+sqrt(sqr(1.+(1.-z))-4.*z*(1.-z)));
+ outfile << xp << "\t" << zp << "\n";
+ }
+ outfile << "JOIN BLUE\n";
+ for(double z=0;z<=1.001;z+=0.01) {
+ double xp = 2.*z/(1.+(1.-z)+sqrt(sqr(1.+(1.-z))-4.*z*(1.-z)));
+ double zp = 0.5* (1.-(1.-z)+sqrt(sqr(1.+(1.-z))-4.*z*(1.-z)));
+ outfile << xp << "\t" << 1.-zp << "\n";
+ }
+ outfile << "JOIN BLUE\n";;
+ outfile << "NEW FRAME\n";
+ outfile << "SET FONT DUPLEX\n";
+ outfile << "SET ORDER X Y\n";
+ outfile << "SET WINDOW X 2 9 Y 2 9\n";
+ outfile << "TITLE BOTTOM \"x0p1\"\n";
+ outfile << "CASE \" X X\"\n";
+ outfile << "TITLE LEFT \"z0p1\"\n";
+ outfile << "CASE \" X X\"\n";
+ outfile << "SET LIMITS X 0 1 Y 0 1\n";
+ for(unsigned int ix=0;ix<_bgfover.size();++ix) {
+ outfile << _bgfover[ix].first << "\t" << _bgfover[ix].second << "\n";
+ if(ix%50000==0&&ix>0) outfile << "PLOT RED\n";
+ }
+ if(!_bgfover.empty()) outfile << "PLOT RED\n";
+ for(double z=0;z<=1.001;z+=0.01) {
+ double xp = 2.*z/(1.+(1.-z)+sqrt(sqr(1.+(1.-z))-4.*z*(1.-z)));
+ double zp = 0.5* (1.-(1.-z)+sqrt(sqr(1.+(1.-z))-4.*z*(1.-z)));
+ outfile << xp << "\t" << zp << "\n";
+ }
+ outfile << "JOIN BLUE\n";
+ for(double z=0;z<=1.001;z+=0.01) {
+ double xp = 2.*z/(1.+(1.-z)+sqrt(sqr(1.+(1.-z))-4.*z*(1.-z)));
+ double zp = 0.5* (1.-(1.-z)+sqrt(sqr(1.+(1.-z))-4.*z*(1.-z)));
+ outfile << xp << "\t" << 1.-zp << "\n";
+ }
+ outfile << "JOIN BLUE\n";;
+ outfile.close();
+ if(_ntry==0) return;
+ generator()->log() << "VBFMECorrection when applying the hard correction "
+ << "generated " << _ntry << " trial emissions of which "
+ << _ngen << " were accepted\n";
+ 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 VBFMECorrection::doinit() throw(InitException) {
+ MECorrectionBase::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.*r5/25.*ath+sqr(Constants::pi)/3.
+ -2.*Math::ReLi2(1.-darg)-2.*Math::ReLi2(1.-1./darg));
+}
diff --git a/Shower/Default/MECorrections/VBFMECorrection.fh b/Shower/Default/MECorrections/VBFMECorrection.fh
new file mode 100644
--- /dev/null
+++ b/Shower/Default/MECorrections/VBFMECorrection.fh
@@ -0,0 +1,22 @@
+// -*- C++ -*-
+//
+// This is the forward declaration of the VBFMECorrection class.
+//
+#ifndef HERWIG_VBFMECorrection_FH
+#define HERWIG_VBFMECorrection_FH
+
+#include "ThePEG/Config/Pointers.h"
+
+namespace Herwig {
+
+class VBFMECorrection;
+
+}
+
+namespace ThePEG {
+
+ThePEG_DECLARE_POINTERS(Herwig::VBFMECorrection,VBFMECorrectionPtr);
+
+}
+
+#endif
diff --git a/Shower/Default/MECorrections/VBFMECorrection.h b/Shower/Default/MECorrections/VBFMECorrection.h
new file mode 100644
--- /dev/null
+++ b/Shower/Default/MECorrections/VBFMECorrection.h
@@ -0,0 +1,321 @@
+// -*- C++ -*-
+#ifndef HERWIG_VBFMECorrection_H
+#define HERWIG_VBFMECorrection_H
+//
+// This is the declaration of the VBFMECorrection class.
+//
+
+#include "QTildeMECorrection.h"
+#include "ThePEG/StandardModel/StandardModelBase.h"
+#include "VBFMECorrection.fh"
+
+namespace Herwig {
+
+using namespace ThePEG;
+
+
+/**
+ * Typedef for BeamParticleData pointers
+ */
+typedef Ptr<BeamParticleData>::transient_const_pointer tcBeamPtr;
+
+/**
+ * Struct to contain the hadronic system
+ */
+struct tChannelPair{
+
+ /**
+ * The hadron
+ */
+ PPtr hadron;
+
+ /**
+ * The beam particle data object
+ */
+ tcBeamPtr beam;
+
+ /**
+ * The incoming particle
+ */
+ ShowerParticlePtr incoming;
+
+ /**
+ * The outgoing particle
+ */
+ ShowerParticlePtr outgoing;
+
+ /**
+ * The PDF
+ */
+ tcPDFPtr pdf;
+};
+
+/**
+ * The VBFMECorrection class implements the matrix element correction
+ * for VBF processes
+ *
+ * @see \ref VBFMECorrectionInterfaces "The interfaces"
+ * defined for VBFMECorrection.
+ */
+class VBFMECorrection: public QTildeMECorrection {
+
+public:
+
+ /**
+ * The default constructor.
+ */
+ inline VBFMECorrection();
+
+ /**
+ * Members to override those in the base class and implemented
+ * the matrix element correction
+ */
+ //@{
+ /**
+ * Can the matrix element correction handle a given hard process or decay
+ * @param tree The shower tree currently being showered
+ * @param initial The initial-state radiation enhancement factor
+ * @param final The final-state radiation enhancement factor
+ * @param evolver Pointer to the Evolver.
+ */
+ virtual bool canHandle(ShowerTreePtr tree,double & initial,
+ double & final,EvolverPtr evolver);
+
+ /**
+ * Apply the hard matrix element correction to a given hard process or decay
+ */
+ virtual void applyHardMatrixElementCorrection(ShowerTreePtr);
+
+ /**
+ * Apply the soft matrix element correction
+ * @param initial The particle from the hard process which started the
+ * shower
+ * @param parent The initial particle in the current branching
+ * @param br The branching struct
+ * @return If true the emission should be vetoed
+ */
+ virtual bool softMatrixElementVeto(ShowerProgenitorPtr initial,
+ ShowerParticlePtr parent,Branching br);
+ //@}
+
+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();
+
+ /**
+ * Calculate the coefficient A for the correlations
+ */
+ inline double A(tcPDPtr qin1, tcPDPtr qout1, tcPDPtr qin2, tcPDPtr qout2);
+
+
+ /**
+ * Return the coefficients for the matrix element piece for
+ * the QCD compton case. The output is the \f$a_i\f$ coefficients to
+ * give the function as
+ * \f$a_0+a_1\cos\phi+a_2\sin\phi+a_3\cos^2\phi+a_4\sin^2\phi\f$
+ * @param xp \f$x_p\f$
+ * @param x2 \f$x_2\f$
+ * @param xperp \f$x_\perp\f$
+ * @param A \f$\mathcal{A}\f$
+ * @param l Scaled momentum of incoming spectator
+ * @param m Scaled momentum of outgoing spectator
+ *
+ */
+ inline vector<double> ComptonME(double xp, double x2, double xperp,
+ double A, LorentzVector<double> l,
+ LorentzVector<double> m);
+
+ /**
+ * Return the coefficients for the matrix element piece for
+ * the QCD compton case. The output is the \f$a_i\f$ coefficients to
+ * give the function as
+ * \f$a_0+a_1\cos\phi+a_2\sin\phi+a_3\cos^2\phi+a_4\sin^2\phi\f$
+ * @param xp \f$x_p\f$
+ * @param x2 \f$x_3\f$
+ * @param x3 \f$x_2\f$
+ * @param xperp \f$x_\perp\f$
+ * @param A \f$\mathcal{A}\f$
+ * @param l Scaled momentum of incoming spectator
+ * @param m Scaled momentum of outgoing spectator
+ *
+ */
+ inline vector<double> BGFME(double xp, double x2, double x3, double xperp,
+ double A, LorentzVector<double> l,
+ LorentzVector<double> m);
+
+ /**
+ * Generate the values of \f$x_p\f$ and \f$z_p\f$
+ * @param xp The value of xp, output
+ * @param zp The value of zp, output
+ */
+ inline double generateComptonPoint(double &xp, double & zp);
+
+ /**
+ * Generate the values of \f$x_p\f$ and \f$z_p\f$
+ * @param xp The value of xp, output
+ * @param zp The value of zp, output
+ */
+ inline double generateBGFPoint(double &xp, double & zp);
+
+
+protected:
+
+ /** @name Clone Methods. */
+ //@{
+ /**
+ * Make a simple clone of this object.
+ * @return a pointer to the new object.
+ */
+ inline 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.
+ */
+ inline virtual IBPtr fullclone() const;
+ //@}
+
+protected:
+
+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() throw(InitException);
+
+ /**
+ * Finalize this object. Called in the run phase just after a
+ * run has ended. Used eg. to write out statistics.
+ */
+ virtual void dofinish();
+ //@}
+
+private:
+
+ /**
+ * The static object used to initialize the description of this class.
+ * Indicates that this is a concrete class with persistent data.
+ */
+ static ClassDescription<VBFMECorrection> initVBFMECorrection;
+
+ /**
+ * The assignment operator is private and must never be called.
+ * In fact, it should not even be implemented.
+ */
+ VBFMECorrection & operator=(const VBFMECorrection &);
+
+private:
+
+ /**
+ * Relative fraction of compton and BGF processes to generate
+ */
+ double _procprob;
+
+ /**
+ * Integral for compton process
+ */
+ double _comptonint;
+
+ /**
+ * Testing of weights etc
+ */
+ //@{
+ /**
+ * Number of weights greater than 1
+ */
+ unsigned int _nover;
+
+ /**
+ * Number of attempts
+ */
+ unsigned int _ntry;
+
+ /**
+ * Number which suceed
+ */
+ unsigned int _ngen;
+
+ /**
+ * Maximum weight
+ */
+ pair<double,double> _maxwgt;
+
+ /**
+ * points for the compton process
+ */
+ vector<pair<double,double> > _compton,_comptonover;
+
+ /**
+ * points for the BGF process
+ */
+ vector<pair<double,double> > _bgf,_bgfover;
+ //@}
+};
+
+}
+
+#include "ThePEG/Utilities/ClassTraits.h"
+
+namespace ThePEG {
+
+/** @cond TRAITSPECIALIZATIONS */
+
+/** This template specialization informs ThePEG about the
+ * base classes of VBFMECorrection. */
+template <>
+struct BaseClassTrait<Herwig::VBFMECorrection,1> {
+ /** Typedef of the first base class of VBFMECorrection. */
+ typedef Herwig::QTildeMECorrection NthBase;
+};
+
+/** This template specialization informs ThePEG about the name of
+ * the VBFMECorrection class and the shared object where it is defined. */
+template <>
+struct ClassTraits<Herwig::VBFMECorrection>
+ : public ClassTraitsBase<Herwig::VBFMECorrection> {
+ /** Return a platform-independent class name */
+ static string className() { return "Herwig::VBFMECorrection"; }
+ /**
+ * The name of a file containing the dynamic library where the class
+ * VBFMECorrection is implemented. It may also include several, space-separated,
+ * libraries if the class VBFMECorrection depends on other classes (base classes
+ * excepted). In this case the listed libraries will be dynamically
+ * linked in the order they are specified.
+ */
+ static string library() { return "HwMPI.so HwMPIPDF.so HwRemDecayer.so HwShower.so"; }
+};
+
+/** @endcond */
+
+}
+
+#include "VBFMECorrection.icc"
+
+#endif /* HERWIG_VBFMECorrection_H */
diff --git a/Shower/Default/MECorrections/VBFMECorrection.icc b/Shower/Default/MECorrections/VBFMECorrection.icc
new file mode 100644
--- /dev/null
+++ b/Shower/Default/MECorrections/VBFMECorrection.icc
@@ -0,0 +1,166 @@
+// -*- C++ -*-
+//
+// This is the implementation of the inlined member functions of
+// the VBFMECorrection class.
+//
+
+namespace Herwig {
+
+inline VBFMECorrection::VBFMECorrection() : _procprob(0.5),
+ _nover(0), _ntry(0), _ngen(0),
+ _maxwgt(make_pair(0.,0.))
+{}
+
+inline IBPtr VBFMECorrection::clone() const {
+ return new_ptr(*this);
+}
+
+inline IBPtr VBFMECorrection::fullclone() const {
+ return new_ptr(*this);
+}
+
+inline double VBFMECorrection::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;
+}
+
+inline vector<double> VBFMECorrection::ComptonME(double xp, double x2, double xperp,
+ double A, LorentzVector<double> l,
+ LorentzVector<double> m) {
+ vector<double> output(6,0.);
+ double cos2 = x2 /sqrt(sqr(x2)+sqr(xperp));
+ double sin2 = xperp/sqrt(sqr(x2)+sqr(xperp));
+ // no phi dependence
+ output[0] = l.t()*m.t()-l.z()*m.z()*sqr(cos2)+0.5*A*cos2*(l.z()*m.t()-l.t()*m.z());
+ // cos(phi)
+ output[1] = -sin2*(l.x()*m.t()+l.t()*m.x())+sin2*(l.x()*m.z()-l.z()*m.x());
+ // cos(phi)^2
+ output[2] = +sqr(sin2)*l.x()*m.x();
+ // sin(phi)
+ output[3] = -l.t()*sin2*m.y()-0.5*A*cos2*sin2*l.z()*m.y();
+ // sin(phi)^2
+ output[4] = 0.;
+ // sin(phi)cos(phi)
+ output[5] = +sqr(sin2)*m.y()*l.x();
+ // additional factors
+ double denom = -l.z()*m.z()+l.t()*m.t()+0.5*A*(l.t()*m.z()-l.z()*m.t());
+ double fact = sqr(xp)*(sqr(x2)+sqr(xperp))/denom;
+ for(unsigned int ix=0;ix<output.size();++ix) output[ix] *=fact;
+ output[0] += 1.;
+ return output;
+}
+
+inline double VBFMECorrection::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) cerr << "testing violates compton max " << wgt << "\n";
+ }
+ while(wgt<UseRandom::rnd()*maxwgt);
+ return _comptonint/((1.+sqr(xp)*(sqr(x2)+1.5*xperp2))/(1.-xp)/(1.-zp));
+}
+
+inline double VBFMECorrection::generateBGFPoint(double &xp, double & zp) {
+ static const double maxwgt = 2.,npow=0.4,ac=1.0;
+ double wgt;
+ do {
+ double rho = UseRandom::rnd();
+ xp = 1.-pow(rho,1./(1.-npow));
+ wgt = (sqr(xp)+ac+sqr(1.-xp));
+ if(wgt>1.+ac) cerr << "testing violates BGF maxA " << wgt << "\n";
+ }
+ while(wgt<UseRandom::rnd()*(1.+ac));
+ double xpwgt = -((6.-5.*npow+sqr(npow))*ac-3.*npow+sqr(npow)+4)
+ /(sqr(npow)*(npow-6.)+11.*npow-6.);
+ xpwgt *= pow(1.-xp,npow)/wgt;
+ double xp2(sqr(xp)),lxp(log(xp)),xp4(sqr(xp2)),lxp1(log(1.-xp));
+ double zpwgt = (2.*xp4*(lxp+lxp1-3.)+4.*xp*xp2*(3.-lxp-lxp1)
+ +xp2*(-13.+lxp+lxp1)+xp*(+7.+lxp+lxp1)-lxp-lxp1-1.)/(1.+xp-xp2);
+ double wgt2;
+ do {
+ double zpmax = 1./(1.+xp*(1.-xp)), zpmin = 1.-zpmax;
+ zp = 1.-pow((1.-zpmin)/(1.-zpmax),UseRandom::rnd())*(1.-zpmax);
+ wgt = log((1.-zpmin)/(1.-zpmax))*(1.-zp);
+ double x1 = -1./xp;
+ double x2 = 1.-(1.-zp)/xp;
+ double x3 = 2.+x1-x2;
+ double xperp2 = 4.*(1.-xp)*(1.-zp)*zp/xp;
+ wgt2 = sqr(xp)/(1.-zp)*(sqr(x3)+sqr(x2)+3.*xperp2);
+ wgt *= wgt2;
+ if(wgt>maxwgt*zpwgt) cerr << "testing violates BGF maxB " << wgt/xpwgt << "\n";
+ }
+ while(wgt<UseRandom::rnd()*maxwgt);
+ return zpwgt*xpwgt/wgt2;
+}
+
+inline vector<double> VBFMECorrection::BGFME(double xp, double x2, double x3,
+ double xperp, double A,
+ LorentzVector<double> l,
+ LorentzVector<double> m) {
+ vector<double> output(6,0.);
+ double cos2 = x2 /sqrt(sqr(x2)+sqr(xperp));
+ double sin2 = xperp/sqrt(sqr(x2)+sqr(xperp));
+ 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));
+ // no phi dependence
+ output[0] = fact3*(+l.t()*m.t()-l.z()*m.z()*sqr(cos3)+0.5*A*cos3*(l.z()*m.t()-l.t()*m.z()))
+ +fact2*(+l.t()*m.t()-l.z()*m.z()*sqr(cos2)+0.5*A*cos2*(l.z()*m.t()-l.t()*m.z()));
+ // cos(phi)
+ output[1] = fact3*(+sin3*(l.x()*m.t()+l.t()*m.x())-0.5*A*cos3*sin3*(l.x()*m.z()-l.z()*m.x()))
+ +fact2*(-sin2*(l.x()*m.t()+l.t()*m.x())+0.5*A*cos2*sin2*(l.x()*m.z()-l.z()*m.x()));
+ // cos(phi)^2
+ output[2] = fact3*(+sqr(sin3)*l.x()*m.x())
+ +fact2*(+sqr(sin2)*l.x()*m.x());
+ // sin(phi)
+ output[3] = fact3*(+l.t()*sin3*m.y()+0.5*A*cos3*sin3*l.z()*m.y())
+ +fact2*(-l.t()*sin2*m.y()-0.5*A*cos2*sin2*l.z()*m.y());
+ // sin(phi)^2
+ output[4] = 0.;
+ // sin(phi)cos(phi)
+ output[5] = fact3*(+sqr(sin3)*m.y()*l.x())
+ +fact2*(+sqr(sin2)*m.y()*l.x());
+ // additional factors
+ double denom = -l.z()*m.z()+l.t()*m.t()+0.5*A*(l.t()*m.z()-l.z()*m.t());
+ for(unsigned int ix=0;ix<output.size();++ix) output[ix] /= denom;
+ return output;
+}
+
+}
diff --git a/Shower/Default/QTildeReconstructor.cc b/Shower/Default/QTildeReconstructor.cc
--- a/Shower/Default/QTildeReconstructor.cc
+++ b/Shower/Default/QTildeReconstructor.cc
@@ -1,874 +1,923 @@
// -*- C++ -*-
//
// QTildeReconstructor.cc is a part of Herwig++ - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2007 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 QTildeReconstructor class.
//
#include "QTildeReconstructor.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/EventRecord/Event.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig++/Shower/SplittingFunctions/SplittingFunction.h"
using namespace Herwig;
namespace {
enum SystemType { UNDEFINED=-1, II, IF, F ,I };
struct ColourSingletSystem {
ColourSingletSystem() : type(UNDEFINED) {};
ColourSingletSystem(SystemType intype,ShowerProgenitorPtr inpart)
: type(intype),jets(1,inpart) {};
-
/**
* The type of system
*/
SystemType type;
/**
* The jets in the system
*/
vector<ShowerProgenitorPtr> jets;
};
}
void QTildeReconstructor::persistentOutput(PersistentOStream & os) const {
os << _reconopt;
}
void QTildeReconstructor::persistentInput(PersistentIStream & is, int) {
is >> _reconopt;
}
ClassDescription<QTildeReconstructor> QTildeReconstructor::initQTildeReconstructor;
// Definition of the static class description member.
void QTildeReconstructor::Init() {
static ClassDocumentation<QTildeReconstructor> documentation
( "This class is responsible for the kinematics reconstruction of the showering,",
" including the kinematics reshuffling necessary to compensate for the recoil"
"of the emissions." );
static Switch<QTildeReconstructor,unsigned int> interfaceReconstructionOption
("ReconstructionOption",
"Option for the kinematics reconstruction",
&QTildeReconstructor::_reconopt, 0, false, false);
static SwitchOption interfaceReconstructionOptionGeneral
(interfaceReconstructionOption,
"General",
"Use the general solution which ignores the colour structure for all processes",
0);
static SwitchOption interfaceReconstructionOptionColour
(interfaceReconstructionOption,
"Colour",
"Use the colour structure of the process to determine the reconstruction procedure.",
1);
}
bool QTildeReconstructor::
reconstructTimeLikeJet(const tShowerParticlePtr particleJetParent,
unsigned int iopt) const {
if(!particleJetParent)
throw Exception() << "must have a particle in Kinematics"
<< "Reconstructor::reconstructTimeLikeJet"
<< Exception::eventerror;
bool emitted=true;
// if this is not a fixed point in the reconstruction
if( !particleJetParent->isReconstructionFixedPoint() ) {
// if not a reconstruction fixpoint, dig deeper for all children:
for ( ParticleVector::const_iterator cit = particleJetParent->children().begin();
cit != particleJetParent->children().end(); ++cit )
reconstructTimeLikeJet(dynamic_ptr_cast<ShowerParticlePtr>(*cit),iopt);
}
// it is a reconstruction fixpoint, ie kinematical data has to be available
else {
// check if the parent was part of the shower
ShowerParticlePtr jetGrandParent;
if(!particleJetParent->parents().empty())
jetGrandParent= dynamic_ptr_cast<ShowerParticlePtr>
(particleJetParent->parents()[0]);
// update if so
if (jetGrandParent) {
if (jetGrandParent->showerKinematics()) {
if(particleJetParent->id()==_progenitor->id()&&
!_progenitor->data().stable()) {
jetGrandParent->showerKinematics()->reconstructLast(particleJetParent,iopt,
_progenitor->mass());
}
else {
jetGrandParent->showerKinematics()->reconstructLast(particleJetParent,iopt);
}
}
}
// otherwise
else {
Energy dm = particleJetParent->data().constituentMass();
if (abs(dm-particleJetParent->momentum().m())>0.001*MeV
//if (abs(dm-particleJetParent->momentum().mass())>0.05*MeV
&&particleJetParent->dataPtr()->stable()
&&particleJetParent->id()!=ParticleID::gamma) {
Lorentz5Momentum dum = particleJetParent->momentum();
if(dm>dum.e()) throw KinematicsReconstructionVeto();
dum.setMass(dm);
dum.rescaleRho();
particleJetParent->set5Momentum(dum);
}
else {
emitted=false;
}
}
}
// recursion has reached an endpoint once, ie we can reconstruct the
// kinematics from the children.
if( !(particleJetParent->isReconstructionFixedPoint()) )
particleJetParent->showerKinematics()
->reconstructParent( particleJetParent, particleJetParent->children() );
return emitted;
}
bool QTildeReconstructor::
reconstructHardJets(ShowerTreePtr hard,
map<tShowerProgenitorPtr,pair<Energy,double> > intrinsic) const {
_intrinsic=intrinsic;
// extract the particles from the ShowerTree
vector<ShowerProgenitorPtr> ShowerHardJets=hard->extractProgenitors();
try {
+ // old recon method, using new member functions
if(_reconopt==0) {
- bool radiated[2] = {false,false};
- // find the hard process centre-of-mass energy
- Lorentz5Momentum p_cm[2] = {Lorentz5Momentum(),Lorentz5Momentum()};
+ // general recon, all initial-state in one system and final-state
+ // in another
+ ColourSingletSystem in,out;
for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
- // final-state jet
- if(ShowerHardJets[ix]->progenitor()->isFinalState()) {
- // did it radiate
- radiated[1] |=ShowerHardJets[ix]->hasEmitted();
- // add momentum
- p_cm[1]+=ShowerHardJets[ix]->progenitor()->momentum();
- }
- // initial-state jet
- else {
- // did it radiate
- radiated[0]|=ShowerHardJets[ix]->hasEmitted();
- // add momentum
- p_cm[0]+=ShowerHardJets[ix]->progenitor()->getThePEGBase()->momentum();
- }
+ if(ShowerHardJets[ix]->progenitor()->isFinalState())
+ out.jets.push_back(ShowerHardJets[ix]);
+ else
+ in.jets.push_back(ShowerHardJets[ix]);
}
- radiated[0]|=!intrinsic.empty();
- // initial state shuffling
- // the boosts for the initial state
- Boost boostRest,boostNewF;
+ // reconstruct initial-initial system
+ Boost toRest,fromRest;
bool applyBoost(false);
- if(radiated[0])
- applyBoost=reconstructISJets(p_cm[0],ShowerHardJets,boostRest,boostNewF);
- // final-state reconstruction
- // check if in CMF frame
- Boost beta_cm = p_cm[1].findBoostToCM();
- bool gottaBoost = (beta_cm.mag() > 1e-12);
- // check if any radiation
- bool atLeastOnce = radiated[1];
- // collection of pointers to initial hard particle and jet momenta
- // for final boosts
- JetKinVect jetKinematics;
- vector<ShowerProgenitorPtr>::const_iterator cit;
- for(cit = ShowerHardJets.begin(); cit != ShowerHardJets.end(); cit++) {
- if(!(*cit)->progenitor()->isFinalState()) continue;
- JetKinStruct tempJetKin;
- tempJetKin.parent = (*cit)->progenitor();
- if(gottaBoost) tempJetKin.parent->boost(beta_cm);
- tempJetKin.p = (*cit)->progenitor()->momentum();
- _progenitor=tempJetKin.parent;
- atLeastOnce |= reconstructTimeLikeJet((*cit)->progenitor(),0);
- tempJetKin.q = (*cit)->progenitor()->momentum();
- jetKinematics.push_back(tempJetKin);
- }
- // find the rescaling factor
- double k = 0.0;
- if(atLeastOnce) {
- k = solveKfactor(p_cm[1].mag(), jetKinematics);
- if(k< 0.) return false;
- }
- // perform the rescaling and boosts
- for(JetKinVect::iterator it = jetKinematics.begin();
- it != jetKinematics.end(); ++it) {
- LorentzRotation Trafo = LorentzRotation();
- if(atLeastOnce) Trafo = solveBoost(k, it->q, it->p);
- if(gottaBoost) Trafo.boost(-beta_cm);
- if(atLeastOnce || gottaBoost) it->parent->deepTransform(Trafo);
- if(applyBoost) {
- it->parent->deepBoost(boostRest);
- it->parent->deepBoost(boostNewF);
- }
- }
+ reconstructInitialInitialSystem(applyBoost,toRest,fromRest,in.jets);
+ // reconstruct the final-state systems
+ reconstructFinalStateSystem(applyBoost,toRest,fromRest,out.jets);
}
+ // reconstruction based on coloured systems
else {
// identify the colour singlet systems
vector<ColourSingletSystem> systems;
vector<bool> done(ShowerHardJets.size(),false);
for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
// if not treated create new system
if(done[ix]) continue;
systems.push_back(ColourSingletSystem(UNDEFINED,ShowerHardJets[ix]));
if(!ShowerHardJets[ix]->progenitor()->coloured()) continue;
// now find the colour connected particles
done[ix] = true;
vector<unsigned int> iloc(1,ix);
do {
vector<unsigned int> temp=findPartners(iloc.back(),ShowerHardJets);
done[iloc.back()] = true;
iloc.pop_back();
for(unsigned int iy=0;iy<temp.size();++iy) {
if(!done[temp[iy]]) {
done[temp[iy]] = true;
iloc.push_back(temp[iy]);
systems.back().jets.push_back(ShowerHardJets[temp[iy]]);
}
}
}
while(!iloc.empty());
}
// catagorize the systems
unsigned int nnun(0),nnii(0),nnif(0),nnf(0),nni(0);
for(unsigned int ix=0;ix<systems.size();++ix) {
unsigned int ni(0),nf(0);
for(unsigned int iy=0;iy<systems[ix].jets.size();++iy) {
if(systems[ix].jets[iy]->progenitor()->isFinalState()) ++nf;
else ++ni;
}
// type
// initial-initial
if(ni==2&&nf==0) {
systems[ix].type = II;
++nnii;
}
// initial only
else if(ni==1&&nf==0) {
systems[ix].type = I;
++nni;
}
// initial-final
else if(ni==1&&nf>0) {
systems[ix].type = IF;
++nnif;
}
// final only
else if(ni==0&&nf>0) {
systems[ix].type = F;
++nnf;
}
// otherwise unknown
else {
systems[ix].type = UNDEFINED;
++nnun;
}
}
// now decide what to do
// initial-initial connection and final-state colour singlet systems
+ // Drell-Yan type
if(nnun==0&&nnii==1&&nnif==0&&nnf>0&&nni==0) {
- throw Exception() << "Initial-Initial system not implemented for new reconstruction"
- << Exception::runerror;
- }
- else if(nnun==0&&nnii==0&&nnif==1&&nnf>0&&nni==1) {
- bool recon(false);
+ // reconstruct initial-initial system
+ Boost toRest,fromRest;
+ bool applyBoost(false);
for(unsigned int ix=0;ix<systems.size();++ix) {
- if(systems[ix].type==IF) recon=reconstructInitialFinalSystem(systems[ix].jets);
+ if(systems[ix].type==II)
+ reconstructInitialInitialSystem(applyBoost,toRest,fromRest,systems[ix].jets);
+ }
+ // reconstruct the final-state systems
+ if(nnf>1) {
+ for(unsigned int ix=0;ix<systems.size();++ix) {
+ if(systems[ix].type==F)
+ reconstructFinalStateSystem(applyBoost,toRest,fromRest,systems[ix].jets);
+ }
+ }
+ else {
+ for(unsigned int ix=0;ix<systems.size();++ix) {
+ if(systems[ix].type==F)
+ reconstructFinalStateSystem(applyBoost,toRest,fromRest,systems[ix].jets);
+ }
}
}
+ // DIS type
+ else if(nnun==0&&nnii==0&&nnif==1&&nnf>0&&nni==1) {
+ for(unsigned int ix=0;ix<systems.size();++ix) {
+ if(systems[ix].type==IF)
+ reconstructInitialFinalSystem(systems[ix].jets);
+ }
+ }
+ // e+e- type
else if(nnun==0&&nnii==0&&nnif==0&&nnf>0&&nni==2) {
- throw Exception() << "LEP not implemented for new reconstruction"
- << Exception::runerror;
+ Boost toRest,fromRest;
+ bool applyBoost(false);
+ for(unsigned int ix=0;ix<systems.size();++ix) {
+ if(systems[ix].type==F)
+ reconstructFinalStateSystem(applyBoost,toRest,fromRest,systems[ix].jets);
+ }
}
- else if(nnun==0&&nnii==0&&nnif==2&&nnf>0&&nni==2) {
- throw Exception() << "2*DIS system not implemented for new reconstruction"
- << Exception::runerror;
+ // VBF type
+ else if(nnun==0&&nnii==0&&nnif==2&&nni==0) {
+ // initial-final systems
+ for(unsigned int ix=0;ix<systems.size();++ix) {
+ if(systems[ix].type==IF)
+ reconstructInitialFinalSystem(systems[ix].jets);
+ }
+ // final-state systems
+ Boost toRest,fromRest;
+ bool applyBoost(false);
+ for(unsigned int ix=0;ix<systems.size();++ix) {
+ if(systems[ix].type==F)
+ reconstructFinalStateSystem(applyBoost,toRest,fromRest,systems[ix].jets);
+ }
}
+ // general type
else {
- throw Exception() << "General system not implemented for new reconstruction"
- << Exception::runerror;
+ // general recon, all initial-state in one system and final-state
+ // in another
+ ColourSingletSystem in,out;
+ for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
+ if(ShowerHardJets[ix]->progenitor()->isFinalState())
+ out.jets.push_back(ShowerHardJets[ix]);
+ else
+ in.jets.push_back(ShowerHardJets[ix]);
+ }
+ // reconstruct initial-initial system
+ Boost toRest,fromRest;
+ bool applyBoost(false);
+ reconstructInitialInitialSystem(applyBoost,toRest,fromRest,in.jets);
+ // reconstruct the final-state systems
+ reconstructFinalStateSystem(applyBoost,toRest,fromRest,out.jets);
}
}
}
catch(KinematicsReconstructionVeto) {
return false;
}
_progenitor=tShowerParticlePtr();
_intrinsic.clear();
return true;
}
double
QTildeReconstructor::solveKfactor(const Energy & root_s,
- const JetKinVect & jets) const
-{
+ const JetKinVect & jets) const {
Energy2 s = sqr(root_s);
// must be at least two jets
if ( jets.size() < 2) return -1.0;
// sum of jet masses must be less than roots
if(momConsEq( 0.0, root_s, jets )>0.0*MeV) return -1.0;
// if two jets simple solution
if ( jets.size() == 2 ) {
if ( sqr((jets[0].p.x()+jets[1].p.x())/MeV) < 1.e-4 &&
sqr((jets[0].p.y()+jets[1].p.y())/MeV) < 1.e-4 &&
sqr((jets[0].p.z()+jets[1].p.z())/MeV) < 1.e-4 ) {
return sqrt( ( sqr(s - jets[0].q.m2() - jets[1].q.m2())
- 4.*jets[0].q.m2()*jets[1].q.m2() )
/(4.*s*jets[0].p.vect().mag2()) );
}
else return -1;
}
// i.e. jets.size() > 2, numerically
// check convergence, if it's a problem maybe use Newton iteration?
else {
double k1 = 0.,k2 = 1.,k = 0.;
if ( momConsEq( k1, root_s, jets ) < 0.0*MeV ) {
while ( momConsEq( k2, root_s, jets ) < 0.0*MeV ) {
k1 = k2;
k2 *= 2;
}
while ( fabs( (k1 - k2)/(k1 + k2) ) > 1.e-10 ) {
if( momConsEq( k2, root_s, jets ) == 0.*MeV ) {
return k2;
} else {
k = (k1+k2)/2.;
if ( momConsEq( k, root_s, jets ) > 0*MeV ) {
k2 = k;
} else {
k1 = k;
}
}
}
return k1;
} else return -1.;
}
return -1.;
}
bool QTildeReconstructor::
reconstructSpaceLikeJet( const tShowerParticlePtr p) const {
bool emitted = true;
tShowerParticlePtr child;
tShowerParticlePtr parent;
if(!p->parents().empty())
parent = dynamic_ptr_cast<ShowerParticlePtr>(p->parents()[0]);
if(parent) {
emitted=true;
reconstructSpaceLikeJet(parent);
}
// if branching reconstruct time-like child
if(p->children().size()==2)
child = dynamic_ptr_cast<ShowerParticlePtr>(p->children()[1]);
if(p->perturbative()==0 && child) {
dynamic_ptr_cast<ShowerParticlePtr>(p->children()[0])->
showerKinematics()->reconstructParent(p,p->children());
if(!child->children().empty()) {
_progenitor=child;
reconstructTimeLikeJet(child,0);
// calculate the momentum of the particle
Lorentz5Momentum pnew=p->momentum()-child->momentum();
pnew.rescaleMass();
p->children()[0]->set5Momentum(pnew);
}
}
return emitted;
}
Boost QTildeReconstructor::
solveBoostBeta( const double k, const Lorentz5Momentum & newq, const Lorentz5Momentum & oldp ) {
// try something different, purely numerical first:
// a) boost to rest frame of newq, b) boost with kp/E
Energy q = newq.vect().mag();
Energy2 qs = sqr(q);
Energy2 Q2 = newq.m2();
Energy kp = k*(oldp.vect().mag());
Energy2 kps = sqr(kp);
// usually we take the minus sign, since this boost will be smaller.
// we only require |k \vec p| = |\vec q'| which leaves the sign of
// the boost open but the 'minus' solution gives a smaller boost
// parameter, i.e. the result should be closest to the previous
// result. this is to be changed if we would get many momentum
// conservation violations at the end of the shower from a hard
// process.
double betam = (q*sqrt(qs + Q2) - kp*sqrt(kps + Q2))/(kps + qs + Q2);
// move directly to 'return'
Boost beta = -betam*(k/kp)*oldp.vect();
// note that (k/kp)*oldp.vect() = oldp.vect()/oldp.vect().mag() but cheaper.
// leave this out if it's running properly!
if ( betam >= 0 ) return beta;
else return Boost(0., 0., 0.);
}
bool QTildeReconstructor::
-reconstructISJets(Lorentz5Momentum pcm,
- const vector<ShowerProgenitorPtr> & ShowerHardJets,
- Boost & boostRest, Boost & boostNewF) const {
- bool atLeastOnce = false;
- vector<Lorentz5Momentum> p, pq, p_in;
- for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
- // only look at initial state particles
- if(ShowerHardJets[ix]->progenitor()->isFinalState()) continue;
- // at momentum to vector
- p_in.push_back(ShowerHardJets[ix]->progenitor()->getThePEGBase()->momentum());
- // reconstruct the jet
- atLeastOnce |= reconstructSpaceLikeJet(ShowerHardJets[ix]->progenitor());
- assert(!ShowerHardJets[ix]->original()->parents().empty());
- Energy etemp = ShowerHardJets[ix]->original()->
- parents()[0]->momentum().z();
- Lorentz5Momentum ptemp = Lorentz5Momentum(0*MeV, 0*MeV, etemp, abs(etemp));
- pq.push_back(ptemp);
- }
- // add the intrinsic pt if needed
- atLeastOnce |=addIntrinsicPt(ShowerHardJets);
- for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
- if(ShowerHardJets[ix]->progenitor()->isFinalState()) continue;
- p.push_back(ShowerHardJets[ix]->progenitor()->momentum());
- }
- double x1 = p_in[0].z()/pq[0].z();
- double x2 = p_in[1].z()/pq[1].z();
- Energy MDY = (p_in[0] + p_in[1]).m();
- Energy2 S = (pq[0]+pq[1]).m2();
- // if not need don't apply boosts
- if(!(atLeastOnce && p.size() == 2 && pq.size() == 2)) return false;
- // find alphas and betas in terms of desired basis
- Energy2 p12 = pq[0]*pq[1];
- double a1 = p[0]*pq[1]/p12;
- double b1 = p[0]*pq[0]/p12;
- double a2 = p[1]*pq[1]/p12;
- double b2 = p[1]*pq[0]/p12;
- Lorentz5Momentum p1p = p[0] - a1*pq[0] - b1*pq[1];
- Lorentz5Momentum p2p = p[1] - a2*pq[0] - b2*pq[1];
- // compute kappa12
- // DGRELL is this textbook method for solving a quadratic
- // numerically stable if 4AC ~= B^2 ? check Numerical Recipes
- double kp = 1.0;
- Energy2 A = a1*b2*S;
- Energy2 B = Energy2(sqr(MDY)) - (a1*b1+a2*b2)*S - (p1p+p2p).mag2();
- Energy2 C = a2*b1*S;
- double rad = 1.-4.*A*C/sqr(B);
- if (rad >= 0) {kp = B/(2.*A)*(1.+sqrt(rad));}
- else throw KinematicsReconstructionVeto();
- // now compute k1, k2
- double k1 = 1.0, k2 = 1.0;
- rad = kp*(b1+kp*b2)/(kp*a1+a2)*(x1/x2);
- if (rad > 0) {
- k1 = sqrt(rad);
- k2 = kp/k1;
- }
- else throw KinematicsReconstructionVeto();
- double beta1 = getBeta((a1+b1), (a1-b1),
- (k1*a1+b1/k1), (k1*a1-b1/k1));
- double beta2 = getBeta((a2+b2), (a2-b2),
- (a2/k2+k2*b2), (a2/k2-k2*b2));
- if (pq[0].z() > 0*MeV) {
- beta1 = -beta1;
- beta2 = -beta2;
- }
- tPVector toBoost;
- for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
- if(!ShowerHardJets[ix]->progenitor()->isFinalState())
- toBoost.push_back(ShowerHardJets[ix]->progenitor());
- }
- // before boost
- Boost betaboost(0, 0, beta1);
- tPPtr parent;
- boostChain(toBoost[0], LorentzRotation(betaboost),parent);
- if(parent->momentum().e()/pq[0].e()>1.||parent->momentum().z()/pq[0].z()>1.) throw KinematicsReconstructionVeto();
- betaboost = Boost(0, 0, beta2);
- boostChain(toBoost[1], LorentzRotation(betaboost),parent);
- if(parent->momentum().e()/pq[1].e()>1.||parent->momentum().z()/pq[1].z()>1.) throw KinematicsReconstructionVeto();
- boostRest = pcm.findBoostToCM();
- Lorentz5Momentum newcmf=(toBoost[0]->momentum() + toBoost[1]->momentum());
- if(newcmf.m()<0.*GeV||newcmf.e()<0.*GeV) throw KinematicsReconstructionVeto();
- boostNewF = newcmf.boostVector();
- return true;
-}
-
-bool QTildeReconstructor::
reconstructDecayJets(ShowerTreePtr decay) const {
try {
// extract the particles from the ShowerTree
vector<ShowerProgenitorPtr> ShowerHardJets=decay->extractProgenitors();
bool radiated[2]={false,false};
// find the decaying particle and check if particles radiated
ShowerProgenitorPtr initial;
for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
// only consider initial-state jets
if(ShowerHardJets[ix]->progenitor()->isFinalState()) {
radiated[1] |=ShowerHardJets[ix]->hasEmitted();
}
else {
initial=ShowerHardJets[ix];
radiated[0]|=ShowerHardJets[ix]->hasEmitted();
}
}
// if initial state radiation reconsturct the jet and set up the basis vectors
bool initialrad=false;
Lorentz5Momentum pjet;
Lorentz5Momentum nvect;
ShowerParticlePtr partner;
Lorentz5Momentum ppartner[2];
if(radiated[0]) {
// find the partner
partner=initial->progenitor()->
partners()[initial->progenitor()->showerKinematics()->
splittingFn()->interactionType()];
if(partner) ppartner[0]=partner->momentum();
// reconstruct the decay jet
initialrad=true;
reconstructDecayJet(initial->progenitor());
// momentum of decaying particle after ISR
pjet=initial->progenitor()->momentum()
-decay->incomingLines().begin()->second->momentum();
pjet.rescaleMass();
// get the n reference vector
nvect= initial->progenitor()->showerKinematics()->getBasis()[1];
}
// find boost to the rest frame if needed
Boost boosttorest=-initial->progenitor()->momentum().boostVector();
double gammarest =
initial->progenitor()->momentum().e()/
initial->progenitor()->momentum().mass();
// check if need to boost to rest frame
bool gottaBoost = (boosttorest.mag() > 1e-12);
// boost initial state jet and basis vector if needed
if(gottaBoost) {
pjet.boost(boosttorest,gammarest);
nvect.boost(boosttorest,gammarest);
ppartner[0].boost(boosttorest,gammarest);
}
// loop over the final-state particles and do the reconstruction
JetKinVect possiblepartners;
JetKinVect jetKinematics;
bool atLeastOnce = radiated[0];
LorentzRotation restboost(boosttorest,gammarest);
Energy inmass(0.*GeV);
for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
// only consider final-state jets
if(!ShowerHardJets[ix]->progenitor()->isFinalState()) {
inmass=ShowerHardJets[ix]->progenitor()->mass();
continue;
}
// do the reconstruction
JetKinStruct tempJetKin;
tempJetKin.parent = ShowerHardJets[ix]->progenitor();
if(ShowerHardJets.size()==2) {
Lorentz5Momentum dum=ShowerHardJets[ix]->progenitor()->momentum();
dum.setMass(inmass);
dum.rescaleRho();
tempJetKin.parent->set5Momentum(dum);
}
tempJetKin.p = ShowerHardJets[ix]->progenitor()->momentum();
if(gottaBoost) tempJetKin.p.boost(boosttorest,gammarest);
_progenitor=tempJetKin.parent;
atLeastOnce |= reconstructTimeLikeJet(tempJetKin.parent,0);
if(gottaBoost) tempJetKin.parent->deepTransform(restboost);
tempJetKin.q = ShowerHardJets[ix]->progenitor()->momentum();
jetKinematics.push_back(tempJetKin);
// check if potential partner of the decay particle
ShowerParticlePtr ptemp=ShowerHardJets[ix]->progenitor()->partners()
[ShowerIndex::QCD];
if(ptemp&&!partner&&!ptemp->isFinalState())
possiblepartners.push_back(tempJetKin);
}
// now select the partner of the decaying particle if needed
if(!partner&&!possiblepartners.empty()) {
unsigned int iloc = UseRandom::irnd(0,possiblepartners.size()-1);
partner = possiblepartners[iloc].parent;
nvect = possiblepartners[iloc].p;
nvect = Lorentz5Momentum(0.*MeV,0.5*initial->progenitor()->mass()*
nvect.vect().unit());
nvect.boost(-boosttorest,gammarest);
ppartner[0] = possiblepartners[iloc].p;
}
if(partner) ppartner[1]=partner->momentum();
// calculate the rescaling parameters
double k1,k2;
Lorentz5Momentum qt;
if(!solveDecayKFactor(initial->progenitor()->mass(),nvect,pjet,
jetKinematics,partner,ppartner,k1,k2,qt)) return false;
// apply boosts and rescalings to final-state jets
for(JetKinVect::iterator it = jetKinematics.begin();
it != jetKinematics.end(); ++it) {
LorentzRotation Trafo = LorentzRotation();
if(it->parent!=partner) {
// boost for rescaling
if(atLeastOnce) {
if(it->parent->children().empty()) {
Lorentz5Momentum pnew(k2*it->p.vect(),
sqrt(sqr(k2*it->p.vect().mag())+it->q.mass2()),
it->q.mass());
it->parent->set5Momentum(pnew);
}
else {
Trafo = solveBoost(k2, it->q, it->p);
}
}
if(gottaBoost) Trafo.boost(-boosttorest,gammarest);
if(atLeastOnce || gottaBoost) it->parent->deepTransform(Trafo);
}
else {
Lorentz5Momentum pnew=ppartner[0];
pnew *=k1;
pnew-=qt;
pnew.setMass(ppartner[1].mass());
pnew.rescaleEnergy();
LorentzRotation Trafo=solveBoost(1.,ppartner[1],pnew);
if(gottaBoost) Trafo.boost(-boosttorest,gammarest);
partner->deepTransform(Trafo);
}
}
}
catch(KinematicsReconstructionVeto) {
return false;
- }
-
+ }
return true;
}
bool QTildeReconstructor::
reconstructDecayJet( const tShowerParticlePtr p) const {
if(p->children().empty()) return false;
tShowerParticlePtr child;
// if branching reconstruct time-like child
child = dynamic_ptr_cast<ShowerParticlePtr>(p->children()[1]);
if(child) {
_progenitor=child;
reconstructTimeLikeJet(child,1);
// calculate the momentum of the particle
Lorentz5Momentum pnew=p->momentum()-child->momentum();
pnew.rescaleMass();
p->children()[0]->set5Momentum(pnew);
child=dynamic_ptr_cast<ShowerParticlePtr>(p->children()[0]);
reconstructDecayJet(child);
return true;
}
return false;
}
bool QTildeReconstructor::
solveDecayKFactor(Energy mb, Lorentz5Momentum n, Lorentz5Momentum pjet,
const JetKinVect & jetKinematics, ShowerParticlePtr partner,
Lorentz5Momentum ppartner[2],
double & k1, double & k2,Lorentz5Momentum & qt) const {
Energy2 pjn = partner ? pjet.vect()*n.vect() : 0.*MeV2;
Energy2 pcn = partner ? ppartner[0].vect()*n.vect() : 1.*MeV2;
Energy2 nmag = n.vect().mag2();
Lorentz5Momentum pn=(pjn/nmag)*n;
qt=pjet-pn;qt.setE(0.*MeV);
Energy2 pt2=qt.vect().mag2();
Energy Ejet = pjet.e();
// magnitudes of the momenta for fast access
vector<Energy2> pmag;
Energy total(Ejet);
Lorentz5Momentum ptest;
for(unsigned int ix=0;ix<jetKinematics.size();++ix) {
pmag.push_back(jetKinematics[ix].p.vect().mag2());
total+=jetKinematics[ix].q.mass();
ptest+=jetKinematics[ix].p;
}
// return if no possible solution
if(total>mb) return false;
Energy2 pcmag=ppartner[0].vect().mag2();
// used newton-raphson to get the rescaling
static const Energy eps=1e-8*GeV;
long double d1(1.),d2(1.);
Energy roots, ea, ec, ds;
unsigned int ix=0;
do {
++ix;
d2 = d1 + pjn/pcn;
roots = Ejet;
ds = 0.*MeV;
for(unsigned int iy=0;iy<jetKinematics.size();++iy) {
if(jetKinematics[iy].parent==partner) continue;
ea = sqrt(sqr(d2)*pmag[iy]+jetKinematics[iy].q.mass2());
roots += ea;
ds += d2/ea*pmag[iy];
}
if(partner) {
ec = sqrt(sqr(d1)*pcmag + pt2 + ppartner[1].mass2());
roots += ec;
ds += d1/ec*pcmag;
}
d1 += (mb-roots)/ds;
d2 = d1 + pjn/pcn;
++ix;
}
while(abs(mb-roots)>eps&&ix<100);
k1=d1;
k2=d2;
// return true if N-R succeed, otherwise false
return ix<100;
}
vector<unsigned int> QTildeReconstructor::findPartners(unsigned int iloc ,
vector<ShowerProgenitorPtr> jets) const {
vector<unsigned int> output;
for(unsigned int iy=0;iy<jets.size();++iy) {
if(!jets[iy]->progenitor()->data().coloured()||iy==iloc) continue;
bool isPartner = false;
// both in either initial or final state
if(jets[iloc]->progenitor()->isFinalState()!=jets[iy]->progenitor()->isFinalState()) {
if(jets[iloc]->progenitor()->colourLine() &&
jets[iloc]->progenitor()->colourLine() == jets[iy]->progenitor()->colourLine())
isPartner = true;
if(jets[iloc]->progenitor()->antiColourLine() &&
jets[iloc]->progenitor()->antiColourLine() == jets[iy]->progenitor()->antiColourLine())
isPartner = true;
}
else {
if(jets[iloc]->progenitor()->colourLine() &&
jets[iloc]->progenitor()->colourLine() == jets[iy]->progenitor()->antiColourLine())
isPartner = true;
if(jets[iloc]->progenitor()->antiColourLine() &&
jets[iloc]->progenitor()->antiColourLine() == jets[iy]->progenitor()->colourLine())
isPartner = true;
}
if(isPartner) output.push_back(iy);
}
return output;
}
-bool QTildeReconstructor::
-reconstructInitialFinalSystem(vector<ShowerProgenitorPtr> ShowerHardJets) const {
+void QTildeReconstructor::
+reconstructInitialFinalSystem(vector<ShowerProgenitorPtr> jets) const {
Lorentz5Momentum pin[2],pout[2];
bool atLeastOnce(false);
- for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
+ for(unsigned int ix=0;ix<jets.size();++ix) {
// final-state parton
- if(ShowerHardJets[ix]->progenitor()->isFinalState()) {
- pout[0] +=ShowerHardJets[ix]->progenitor()->momentum();
- _progenitor = ShowerHardJets[ix]->progenitor();
- atLeastOnce |= reconstructTimeLikeJet(ShowerHardJets[ix]->progenitor(),0);
+ if(jets[ix]->progenitor()->isFinalState()) {
+ pout[0] +=jets[ix]->progenitor()->momentum();
+ _progenitor = jets[ix]->progenitor();
+ atLeastOnce |= reconstructTimeLikeJet(jets[ix]->progenitor(),0);
}
// initial-state parton
else {
- pin[0] +=ShowerHardJets[ix]->progenitor()->momentum();
- atLeastOnce |= reconstructSpaceLikeJet(ShowerHardJets[ix]->progenitor());
- assert(!ShowerHardJets[ix]->original()->parents().empty());
+ pin[0] +=jets[ix]->progenitor()->momentum();
+ atLeastOnce |= reconstructSpaceLikeJet(jets[ix]->progenitor());
+ assert(!jets[ix]->original()->parents().empty());
}
}
// add intrinsic pt if needed
- atLeastOnce |= addIntrinsicPt(ShowerHardJets);
+ atLeastOnce |= addIntrinsicPt(jets);
// momenta after showering
- for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
- if(ShowerHardJets[ix]->progenitor()->isFinalState())
- pout[1] +=ShowerHardJets[ix]->progenitor()->momentum();
+ for(unsigned int ix=0;ix<jets.size();++ix) {
+ if(jets[ix]->progenitor()->isFinalState())
+ pout[1] += jets[ix]->progenitor()->momentum();
else
- pin[1] +=ShowerHardJets[ix]->progenitor()->momentum();
+ pin[1] += jets[ix]->progenitor()->momentum();
}
// work out the boost to the Breit frame
Lorentz5Momentum pa = pout[0]-pin[0];
Lorentz5Momentum pb = pin[0];
Lorentz5Momentum pc = pout[0];
Axis axis(pa.vect().unit());
LorentzRotation rot;
double sinth(sqrt(1.-sqr(axis.z())));
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*pb;
Boost trans = -1./ptemp.e()*ptemp.vect();
trans.setZ(0.);
rot.boost(trans);
pa *=rot;
// project and calculate rescaling
// reference vectors
Lorentz5Momentum n1(0.*MeV,0.*MeV,-pa.z(),-pa.z());
Lorentz5Momentum n2(0.*MeV,0.*MeV, pa.z(),-pa.z());
Energy2 n1n2 = n1*n2;
// decompose the momenta
Lorentz5Momentum qbp=rot*pin[1],qcp= rot*pout[1];
double a[2],b[2];
a[0] = n2*qbp/n1n2;
b[0] = n1*qbp/n1n2;
Lorentz5Momentum qperp = qbp-a[0]*n1-b[0]*n2;
a[1] = 0.5*(qcp.m2()-qperp.m2())/n1n2;
b[1] = 1.;
double A(0.5*a[0]),B(b[0]*a[0]-a[1]*b[1]-0.25),C(-0.5*b[0]);
- if(sqr(B)-4.*A*C<0.) return false;
+ if(sqr(B)-4.*A*C<0.) throw KinematicsReconstructionVeto();
double kb = 0.5*(-B+sqrt(sqr(B)-4.*A*C))/A;
double kc = (a[0]*kb-0.5)/a[1];
Lorentz5Momentum pnew[2] = { a[0]*kb*n1+b[0]/kb*n2+qperp,
a[1]*kc*n1+b[1]/kc*n2+qperp};
LorentzRotation rotinv=rot.inverse();
LorentzRotation transb=rotinv*solveBoost(pnew[0],qbp)*rot;
LorentzRotation transc=rotinv*solveBoost(pnew[1],qcp)*rot;
- for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
- if(ShowerHardJets[ix]->progenitor()->isFinalState())
- ShowerHardJets[ix]->progenitor()->deepTransform(transc);
+ for(unsigned int ix=0;ix<jets.size();++ix) {
+ if(jets[ix]->progenitor()->isFinalState())
+ jets[ix]->progenitor()->deepTransform(transc);
else {
tPPtr parent;
- boostChain(ShowerHardJets[ix]->progenitor(),transb,parent);
+ boostChain(jets[ix]->progenitor(),transb,parent);
}
}
- return true;
}
-bool QTildeReconstructor::addIntrinsicPt(vector<ShowerProgenitorPtr> ShowerHardJets) const {
+bool QTildeReconstructor::addIntrinsicPt(vector<ShowerProgenitorPtr> jets) const {
bool added=false;
// add the intrinsic pt if needed
- for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
+ for(unsigned int ix=0;ix<jets.size();++ix) {
// only for initial-state particles which haven't radiated
- if(ShowerHardJets[ix]->progenitor()->isFinalState()||
- ShowerHardJets[ix]->hasEmitted()) continue;
- if(_intrinsic.find(ShowerHardJets[ix])==_intrinsic.end()) continue;
- pair<Energy,double> pt=_intrinsic[ShowerHardJets[ix]];
- Energy etemp = ShowerHardJets[ix]->original()->parents()[0]->momentum().z();
+ if(jets[ix]->progenitor()->isFinalState()||
+ jets[ix]->hasEmitted()) continue;
+ if(_intrinsic.find(jets[ix])==_intrinsic.end()) continue;
+ pair<Energy,double> pt=_intrinsic[jets[ix]];
+ Energy etemp = jets[ix]->original()->parents()[0]->momentum().z();
Lorentz5Momentum
p_basis(0*MeV, 0*MeV, etemp, abs(etemp)),
n_basis(0*MeV, 0*MeV,-etemp, abs(etemp));
- double alpha = ShowerHardJets[ix]->progenitor()->x();
- double beta = 0.5*(sqr(ShowerHardJets[ix]->progenitor()->data().mass())+
+ double alpha = jets[ix]->progenitor()->x();
+ double beta = 0.5*(sqr(jets[ix]->progenitor()->data().mass())+
sqr(pt.first))/alpha/(p_basis*n_basis);
Lorentz5Momentum pnew=alpha*p_basis+beta*n_basis;
pnew.setX(pt.first*cos(pt.second));
pnew.setY(pt.first*sin(pt.second));
pnew.rescaleMass();
- ShowerHardJets[ix]->progenitor()->set5Momentum(pnew);
+ jets[ix]->progenitor()->set5Momentum(pnew);
added = true;
}
return added;
}
LorentzRotation QTildeReconstructor::solveBoost(const Lorentz5Momentum & q,
const Lorentz5Momentum & p ) const {
Energy modp = p.vect().mag();
Energy modq = q.vect().mag();
double betam = (p.e()*modp-q.e()*modq)/(sqr(modq)+sqr(modp)+p.mass2());
Boost beta = -betam*q.vect().unit();
Vector3<Energy2> ax = p.vect().cross( q.vect() );
double delta = p.vect().angle( q.vect() );
LorentzRotation R;
using Constants::pi;
if ( ax.mag2()/GeV2/MeV2 > 1e-16 ) {
R.rotate( delta, unitVector(ax) ).boost( beta );
}
else {
R.boost( beta );
}
return R;
}
+
+void QTildeReconstructor::
+reconstructFinalStateSystem(bool applyBoost, Boost toRest, Boost fromRest,
+ vector<ShowerProgenitorPtr> jets) const {
+ // special for case of individual particle
+ if(jets.size()==1) {
+ jets[0]->progenitor()->deepBoost(toRest);
+ jets[0]->progenitor()->deepBoost(fromRest);
+ return;
+ }
+ bool radiated(false);
+ // find the hard process centre-of-mass energy
+ Lorentz5Momentum pcm;
+ // check if radiated and calculate total momentum
+ for(unsigned int ix=0;ix<jets.size();++ix) {
+ radiated |=jets[ix]->hasEmitted();
+ pcm += jets[ix]->progenitor()->momentum();
+ }
+ // check if in CMF frame
+ Boost beta_cm = pcm.findBoostToCM();
+ bool gottaBoost = (beta_cm.mag() > 1e-12);
+ // collection of pointers to initial hard particle and jet momenta
+ // for final boosts
+ JetKinVect jetKinematics;
+ vector<ShowerProgenitorPtr>::const_iterator cit;
+ for(cit = jets.begin(); cit != jets.end(); cit++) {
+ JetKinStruct tempJetKin;
+ tempJetKin.parent = (*cit)->progenitor();
+ if(gottaBoost) tempJetKin.parent->boost(beta_cm);
+ tempJetKin.p = (*cit)->progenitor()->momentum();
+ _progenitor=tempJetKin.parent;
+ radiated |= reconstructTimeLikeJet((*cit)->progenitor(),0);
+ tempJetKin.q = (*cit)->progenitor()->momentum();
+ jetKinematics.push_back(tempJetKin);
+ }
+ // find the rescaling factor
+ double k = 0.0;
+ if(radiated) {
+ k = solveKfactor(pcm.mag(), jetKinematics);
+ if(k< 0.) throw KinematicsReconstructionVeto();
+ }
+ // perform the rescaling and boosts
+ for(JetKinVect::iterator it = jetKinematics.begin();
+ it != jetKinematics.end(); ++it) {
+ LorentzRotation Trafo = LorentzRotation();
+ if(radiated) Trafo = solveBoost(k, it->q, it->p);
+ if(gottaBoost) Trafo.boost(-beta_cm);
+ if(radiated || gottaBoost) it->parent->deepTransform(Trafo);
+ if(applyBoost) {
+ it->parent->deepBoost(toRest);
+ it->parent->deepBoost(fromRest);
+ }
+ }
+}
+
+void QTildeReconstructor::
+reconstructInitialInitialSystem(bool & applyBoost, Boost & toRest, Boost & fromRest,
+ vector<ShowerProgenitorPtr> jets) const {
+ bool radiated = false;
+ Lorentz5Momentum pcm;
+ // check whether particles radiated and calculate total momentum
+ for(unsigned int ix=0;ix<jets.size();++ix) {
+ radiated |= jets[ix]->hasEmitted();
+ pcm += jets[ix]->progenitor()->getThePEGBase()->momentum();
+ }
+ // check if intrinsic pt to be added
+ radiated |= !_intrinsic.empty();
+ // if no radiation return
+ if(!radiated) return;
+ // initial state shuffling
+ applyBoost=false;
+ vector<Lorentz5Momentum> p, pq, p_in;
+ for(unsigned int ix=0;ix<jets.size();++ix) {
+ // at momentum to vector
+ p_in.push_back(jets[ix]->progenitor()->getThePEGBase()->momentum());
+ // reconstruct the jet
+ radiated |= reconstructSpaceLikeJet(jets[ix]->progenitor());
+ assert(!jets[ix]->original()->parents().empty());
+ Energy etemp = jets[ix]->original()->parents()[0]->momentum().z();
+ Lorentz5Momentum ptemp = Lorentz5Momentum(0*MeV, 0*MeV, etemp, abs(etemp));
+ pq.push_back(ptemp);
+ }
+ // add the intrinsic pt if needed
+ radiated |=addIntrinsicPt(jets);
+ for(unsigned int ix=0;ix<jets.size();++ix) {
+ p.push_back(jets[ix]->progenitor()->momentum());
+ }
+ double x1 = p_in[0].z()/pq[0].z();
+ double x2 = p_in[1].z()/pq[1].z();
+ Energy MDY = (p_in[0] + p_in[1]).m();
+ Energy2 S = (pq[0]+pq[1]).m2();
+ // if not need don't apply boosts
+ if(!(radiated && p.size() == 2 && pq.size() == 2)) return;
+ applyBoost=true;
+ // find alphas and betas in terms of desired basis
+ Energy2 p12 = pq[0]*pq[1];
+ double a[2] = {p[0]*pq[1]/p12,p[1]*pq[1]/p12};
+ double b[2] = {p[0]*pq[0]/p12,p[1]*pq[0]/p12};
+ Lorentz5Momentum p1p = p[0] - a[0]*pq[0] - b[0]*pq[1];
+ Lorentz5Momentum p2p = p[1] - a[1]*pq[0] - b[1]*pq[1];
+ // compute kappa[0]2
+ // DGRELL is this textbook method for solving a quadratic
+ // numerically stable if 4AC ~= B^2 ? check Numerical Recipes
+ Energy2 A = a[0]*b[1]*S;
+ Energy2 B = Energy2(sqr(MDY)) - (a[0]*b[0]+a[1]*b[1])*S - (p1p+p2p).mag2();
+ Energy2 C = a[1]*b[0]*S;
+ double rad = 1.-4.*A*C/sqr(B);
+ if(rad < 0.) throw KinematicsReconstructionVeto();
+ double kp = B/(2.*A)*(1.+sqrt(rad));
+ // now compute k1, k2
+ rad = kp*(b[0]+kp*b[1])/(kp*a[0]+a[1])*(x1/x2);
+ if(rad <= 0.) throw KinematicsReconstructionVeto();
+ double k1 = sqrt(rad);
+ double k2 = kp/k1;
+ double beta[2] =
+ {getBeta((a[0]+b[0]), (a[0]-b[0]), (k1*a[0]+b[0]/k1), (k1*a[0]-b[0]/k1)),
+ getBeta((a[1]+b[1]), (a[1]-b[1]), (a[1]/k2+k2*b[1]), (a[1]/k2-k2*b[1]))};
+ if (pq[0].z() > 0*MeV) {
+ beta[0] = -beta[0];
+ beta[1] = -beta[1];
+ }
+ // apply the boosts
+ Lorentz5Momentum newcmf;
+ for(unsigned int ix=0;ix<jets.size();++ix) {
+ tPPtr toBoost = jets[ix]->progenitor();
+ Boost betaboost(0, 0, beta[ix]);
+ tPPtr parent;
+ boostChain(toBoost, LorentzRotation(betaboost),parent);
+ if(parent->momentum().e()/pq[ix].e()>1.||
+ parent->momentum().z()/pq[ix].z()>1.) throw KinematicsReconstructionVeto();
+ newcmf+=toBoost->momentum();
+ }
+ if(newcmf.m()<0.*GeV||newcmf.e()<0.*GeV) throw KinematicsReconstructionVeto();
+ toRest = pcm.findBoostToCM();
+ fromRest = newcmf.boostVector();
+}
diff --git a/Shower/Default/QTildeReconstructor.h b/Shower/Default/QTildeReconstructor.h
--- a/Shower/Default/QTildeReconstructor.h
+++ b/Shower/Default/QTildeReconstructor.h
@@ -1,365 +1,373 @@
// -*- C++ -*-
//
// QTildeReconstructor.h is a part of Herwig++ - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2007 The Herwig Collaboration
//
// Herwig++ is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_QTildeReconstructor_H
#define HERWIG_QTildeReconstructor_H
//
// This is the declaration of the QTildeReconstructor class.
//
#include "Herwig++/Shower/Base/KinematicsReconstructor.h"
#include "ThePEG/Repository/UseRandom.h"
#include "QTildeReconstructor.fh"
#include <cassert>
namespace Herwig {
using namespace ThePEG;
/** \ingroup Shower
* A simple struct to store the information we need on the
* showering
*/
struct JetKinStruct {
/**
* Parent particle of the jet
*/
tShowerParticlePtr parent;
/**
* Momentum of the particle before reconstruction
*/
Lorentz5Momentum p;
/**
* Momentum of the particle after reconstruction
*/
Lorentz5Momentum q;
};
/**
* typedef for a vector of JetKinStruct
*/
typedef vector<JetKinStruct> JetKinVect;
/** \ingroup Shower
*
* This class is responsible for the kinematical reconstruction
* after each showering step, and also for the necessary Lorentz boosts
* in order to preserve energy-momentum conservation in the overall collision,
* and also the invariant mass and the rapidity of the hard subprocess system.
* In the case of multi-step showering, there will be not unnecessary
* kinematical reconstructions.
*
* Notice:
* - although we often use the term "jet" in either methods or variables names,
* or in comments, which could appear applicable only for QCD showering,
* there is indeed no "dynamics" represented in this class: only kinematics
* is involved, as the name of this class remainds. Therefore it can be used
* for any kind of showers (QCD-,QED-,EWK-,... bremsstrahlung).
*
* @see ShowerParticle
* @see ShowerKinematics
* @see \ref QTildeReconstructorInterfaces "The interfaces"
* defined for QTildeReconstructor.
*/
class QTildeReconstructor: public KinematicsReconstructor {
public:
/**
* Default constructor
*/
inline QTildeReconstructor();
/**
* Methods to reconstruct the kinematics of a scattering or decay process
*/
//@{
/**
* Given in input a vector of the particles which initiated the showers
* the method does the reconstruction of such jets,
* including the appropriate boosts (kinematics reshufflings)
* needed to conserve the total energy-momentum of the collision
* and preserving the invariant mass and the rapidity of the
* hard subprocess system.
*/
virtual bool reconstructHardJets(ShowerTreePtr hard,
map<tShowerProgenitorPtr,
pair<Energy,double> > pt) const;
/**
* Given in input a vector of the particles which initiated the showers
* the method does the reconstruction of such jets,
* including the appropriate boosts (kinematics reshufflings)
* needed to conserve the total energy-momentum of the collision
* and preserving the invariant mass and the rapidity of the
* hard subprocess system.
*/
virtual bool reconstructDecayJets(ShowerTreePtr decay) const;
//@}
protected:
/**
- * Reconstruct the initial state jets
- */
- virtual bool reconstructISJets(Lorentz5Momentum pcm,
- const vector<ShowerProgenitorPtr> & ShowerHardJets,
- Boost & boostRest, Boost & boostNewF) const;
-
- /**
* Methods to reconstruct the kinematics of individual jets
*/
//@{
/**
* Given the particle (ShowerParticle object) that
* originates a forward (time-like) jet, this method reconstructs the kinematics
* of the jet. That is, by starting from the final grand-children (which
* originates directly or indirectly from particleJetParent,
* and which don't have children), and moving "backwards" (in a physical
* time picture), towards the particleJetParent, the
* ShowerKinematics objects associated with the various particles,
* which have been created during the showering, are now completed.
* In particular, at the end, we get the mass of the jet, which is the
* main information we want.
* This methods returns false if there was no radiation or rescaling required
*/
virtual bool reconstructTimeLikeJet(const tShowerParticlePtr particleJetParent,
unsigned int iopt) const;
/**
* Exactly similar to the previous one, but for a space-like jet.
* Also in this case we start from the final grand-children (which
* are childless) of the particle which originates the jet, but in
* this case we proceed "forward" (in the physical time picture)
* towards the particleJetParent.
* This methods returns false if there was no radiation or rescaling required
*/
bool reconstructSpaceLikeJet(const tShowerParticlePtr particleJetParent) const;
/**
* Exactly similar to the previous one, but for a decay jet
* This methods returns false if there was no radiation or rescaling required
*/
bool reconstructDecayJet(const tShowerParticlePtr particleJetParent) 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:
/**
* Given a vector of 5-momenta of jets, where the 3-momenta are the initial
* ones before showering and the masses are reconstructed after the showering,
* this method returns the overall scaling factor for the 3-momenta of the
* vector of particles, vec{P}_i -> k * vec{P}_i, such to preserve energy-
* momentum conservation, i.e. after the rescaling the center of mass 5-momentum
* is equal to the one specified in input, cmMomentum.
* The method returns 0 if such factor cannot be found.
* @param root_s Centre-of-mass energy
* @param jets The jets
*/
double solveKfactor( const Energy & root_s, const JetKinVect & jets ) const;
/**
* Calculate the rescaling factors for the jets in a particle decay where
* there was initial-state radiation
* @param mb The mass of the decaying particle
* @param n The reference vector for the initial state radiation
* @param pjet The momentum of the initial-state jet
* @param jetKinematics The JetKinStruct objects for the jets
* @param partner The colour partner
* @param ppartner The momentum of the colour partner of the decaying particle
* before and after radiation
* @param k1 The rescaling parameter for the partner
* @param k2 The rescaling parameter for the outgoing singlet
* @param qt The transverse momentum vector
*/
bool solveDecayKFactor(Energy mb, Lorentz5Momentum n, Lorentz5Momentum pjet,
const JetKinVect & jetKinematics, ShowerParticlePtr partner,
Lorentz5Momentum ppartner[2],
double & k1, double & k2,Lorentz5Momentum & qt) const;
/**
* Check the rescaling conserves momentum
* @param k The rescaling
* @param root_s The centre-of-mass energy
* @param jets The jets
*/
inline Energy momConsEq(const double & k, const Energy & root_s,
const JetKinVect & jets) const;
/**
* Compute the boost to get from the the old momentum to the new
*/
inline LorentzRotation solveBoost(const double k, const Lorentz5Momentum & newq,
const Lorentz5Momentum & oldp) const;
/**
* Recursively boost the initial-state shower
* @param p The particle
* @param bv The boost
* @param parent The parent of the chain
*/
inline void boostChain(tPPtr p, const LorentzRotation & bv, tPPtr & parent) const;
/**
* Given a 5-momentum and a scale factor, the method returns the
* Lorentz boost that transforms the 3-vector vec{momentum} --->
* k*vec{momentum}. The method returns the null boost in the case no
* solution exists. This will only work in the case where the
* outgoing jet-momenta are parallel to the momenta of the particles
* leaving the hard subprocess.
*/
Boost solveBoostBeta( const double k, const Lorentz5Momentum & newq,
const Lorentz5Momentum & oldp);
/**
* Compute boost parameter along z axis to get (Ep, any perp, qp)
* from (E, same perp, q).
*/
inline double getBeta(const double E, const double q,
const double Ep, const double qp) const;
/**
* Find the colour partners of a particle to identify the colour singlet
* systems.
*/
vector<unsigned int> findPartners(unsigned int ,vector<ShowerProgenitorPtr>) const;
/**
* Perform the reconstruction of a system with one incoming and at least one
* outgoing particle
*/
- bool reconstructInitialFinalSystem(vector<ShowerProgenitorPtr>) const;
+ void reconstructInitialFinalSystem(vector<ShowerProgenitorPtr>) const;
+
+ /**
+ * Perform the reconstruction of a system with only final-state
+ * particles
+ */
+ void reconstructFinalStateSystem(bool applyBoost, Boost toRest, Boost fromRest,
+ vector<ShowerProgenitorPtr>) const;
+
+ /**
+ * Perform the reconstruction of a system with only final-state
+ * particles
+ */
+ void reconstructInitialInitialSystem(bool & applyBoost,
+ Boost & toRest, Boost & fromRest,
+ vector<ShowerProgenitorPtr>) const;
/**
* Add the intrinsic \f$p_T\f$ to the system if needed
*/
bool addIntrinsicPt(vector<ShowerProgenitorPtr>) const;
/**
* Compute the boost needed to go from p to q.
*/
LorentzRotation solveBoost(const Lorentz5Momentum & q,
const Lorentz5Momentum & p ) const;
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
inline 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.
*/
inline virtual IBPtr fullclone() const;
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is an concrete class without persistent data.
*/
static ClassDescription<QTildeReconstructor> initQTildeReconstructor;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
QTildeReconstructor & operator=(const QTildeReconstructor &);
private:
/**
* Option for handling the reconstruction
*/
unsigned int _reconopt;
/**
* The progenitor of the jet currently being reconstructed
*/
mutable tShowerParticlePtr _progenitor;
/**
* Storage of the intrinsic \f$p_T\f$
*/
mutable map<tShowerProgenitorPtr,pair<Energy,double> > _intrinsic;
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of QTildeReconstructor. */
template <>
struct BaseClassTrait<Herwig::QTildeReconstructor,1> {
/** Typedef of the first base class of QTildeReconstructor. */
typedef Herwig::KinematicsReconstructor NthBase;
};
/** This template specialization informs ThePEG about the name of
* the QTildeReconstructor class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::QTildeReconstructor>
: public ClassTraitsBase<Herwig::QTildeReconstructor> {
/** Return a platform-independent class name */
static string className() { return "Herwig::QTildeReconstructor"; }
/**
* The name of a file containing the dynamic library where the class
* QTildeReconstructor is implemented. It may also include several, space-separated,
* libraries if the class QTildeReconstructor depends on other classes (base classes
* excepted). In this case the listed libraries will be dynamically
* linked in the order they are specified.
*/
static string library() { return "HwMPI.so HwMPIPDF.so HwRemDecayer.so HwShower.so"; }
};
/** @endcond */
}
#include "QTildeReconstructor.icc"
#endif /* HERWIG_QTildeReconstructor_H */
diff --git a/Shower/ShowerHandler.cc b/Shower/ShowerHandler.cc
--- a/Shower/ShowerHandler.cc
+++ b/Shower/ShowerHandler.cc
@@ -1,725 +1,766 @@
// -*- C++ -*-
//
// ShowerHandler.cc is a part of Herwig++ - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2007 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 ShowerHandler class.
//
#include "ShowerHandler.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/ParVector.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Deleted.h"
#include "ThePEG/MatrixElement/MEBase.h"
#include "ThePEG/PDF/PartonExtractor.h"
#include "ThePEG/PDF/PartonBinInstance.h"
#include "Herwig++/PDT/StandardMatchers.h"
#include "ThePEG/Cuts/Cuts.h"
#include "ThePEG/Handlers/XComb.h"
#include "ThePEG/Utilities/Throw.h"
#include "Herwig++/Shower/Base/Evolver.h"
#include "Herwig++/Shower/Base/ShowerParticle.h"
#include "Herwig++/Utilities/EnumParticles.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "Herwig++/Utilities/EnumParticles.h"
#include "Herwig++/PDF/MPIPDF.h"
#include "ThePEG/Handlers/EventHandler.h"
#include "Herwig++/Shower/Base/ShowerTree.h"
#include "Herwig++/Shower/Base/KinematicsReconstructor.h"
#include "Herwig++/Shower/Base/PartnerFinder.h"
#include "Herwig++/Shower/Base/MECorrectionBase.h"
#include "Herwig++/Shower/CKKW/Clustering/CascadeReconstructor.h"
#include "Herwig++/Shower/CKKW/Reweighting/Reweighter.h"
#include <cassert>
using namespace Herwig;
ShowerHandler::~ShowerHandler() {}
ShowerHandler * ShowerHandler::theHandler = 0;
void ShowerHandler::doinit() throw(InitException) {
CascadeHandler::doinit();
// copy particles to decay before showering from input vector to the
// set used in the simulation
_particlesDecayInShower.insert(_inputparticlesDecayInShower.begin(),
_inputparticlesDecayInShower.end());
// check for CKKW and setup if present
if (_reconstructor && _reweighter) {
_reconstructor->setup();
_evolver->useCKKW(_reconstructor,_reweighter);
_useCKKW = true;
} else {
_useCKKW = false;
}
}
IBPtr ShowerHandler::clone() const {
return new_ptr(*this);
}
IBPtr ShowerHandler::fullclone() const {
return new_ptr(*this);
}
ShowerHandler::ShowerHandler() :
theOrderSecondaries(true), theMPIOnOff(true), _pdfFreezingScale(2.5*GeV),
_maxtry(10),_maxtryMPI(10), theSubProcess(tSubProPtr()), _useCKKW(false) {
_inputparticlesDecayInShower.push_back( 6 ); // top
_inputparticlesDecayInShower.push_back( 1000001 ); // SUSY_d_L
_inputparticlesDecayInShower.push_back( 1000002 ); // SUSY_u_L
_inputparticlesDecayInShower.push_back( 1000003 ); // SUSY_s_L
_inputparticlesDecayInShower.push_back( 1000004 ); // SUSY_c_L
_inputparticlesDecayInShower.push_back( 1000005 ); // SUSY_b_1
_inputparticlesDecayInShower.push_back( 1000006 ); // SUSY_t_1
_inputparticlesDecayInShower.push_back( 1000011 ); // SUSY_e_Lminus
_inputparticlesDecayInShower.push_back( 1000012 ); // SUSY_nu_eL
_inputparticlesDecayInShower.push_back( 1000013 ); // SUSY_mu_Lminus
_inputparticlesDecayInShower.push_back( 1000014 ); // SUSY_nu_muL
_inputparticlesDecayInShower.push_back( 1000015 ); // SUSY_tau_1minus
_inputparticlesDecayInShower.push_back( 1000016 ); // SUSY_nu_tauL
_inputparticlesDecayInShower.push_back( 1000021 ); // SUSY_g
_inputparticlesDecayInShower.push_back( 1000022 ); // SUSY_chi_10
_inputparticlesDecayInShower.push_back( 1000023 ); // SUSY_chi_20
_inputparticlesDecayInShower.push_back( 1000024 ); // SUSY_chi_1plus
_inputparticlesDecayInShower.push_back( 1000025 ); // SUSY_chi_30
_inputparticlesDecayInShower.push_back( 1000035 ); // SUSY_chi_40
_inputparticlesDecayInShower.push_back( 1000037 ); // SUSY_chi_2plus
_inputparticlesDecayInShower.push_back( 1000039 ); // SUSY_gravitino
_inputparticlesDecayInShower.push_back( 2000001 ); // SUSY_d_R
_inputparticlesDecayInShower.push_back( 2000002 ); // SUSY_u_R
_inputparticlesDecayInShower.push_back( 2000003 ); // SUSY_s_R
_inputparticlesDecayInShower.push_back( 2000004 ); // SUSY_c_R
_inputparticlesDecayInShower.push_back( 2000005 ); // SUSY_b_2
_inputparticlesDecayInShower.push_back( 2000006 ); // SUSY_t_2
_inputparticlesDecayInShower.push_back( 2000011 ); // SUSY_e_Rminus
_inputparticlesDecayInShower.push_back( 2000012 ); // SUSY_nu_eR
_inputparticlesDecayInShower.push_back( 2000013 ); // SUSY_mu_Rminus
_inputparticlesDecayInShower.push_back( 2000014 ); // SUSY_nu_muR
_inputparticlesDecayInShower.push_back( 2000015 ); // SUSY_tau_2minus
_inputparticlesDecayInShower.push_back( 2000016 ); // SUSY_nu_tauR
_inputparticlesDecayInShower.push_back( 25 ); // h0
_inputparticlesDecayInShower.push_back( 35 ); // H0
_inputparticlesDecayInShower.push_back( 36 ); // A0
_inputparticlesDecayInShower.push_back( 37 ); // H+
_inputparticlesDecayInShower.push_back( 23 ); // Z0
_inputparticlesDecayInShower.push_back( 24 ); // W+/-
}
void ShowerHandler::doinitrun(){
CascadeHandler::doinitrun();
//can't use IsMPIOn here, because the EventHandler is not set at that stage
if(theMPIHandler) theMPIHandler->initialize();
if (_useCKKW) {
_reweighter->initialize();
}
}
void ShowerHandler::dofinish(){
CascadeHandler::dofinish();
if(theMPIHandler) theMPIHandler->finalize();
}
void ShowerHandler::persistentOutput(PersistentOStream & os) const {
os << _evolver << theRemDec << ounit(_pdfFreezingScale,GeV) << _maxtry
<< _maxtryMPI << _inputparticlesDecayInShower
<< _particlesDecayInShower << theOrderSecondaries
- << theMPIOnOff << theMPIHandler << theSubProcess
+ << theMPIOnOff << theMPIHandler
<< _useCKKW << _reconstructor << _reweighter;
}
void ShowerHandler::persistentInput(PersistentIStream & is, int) {
is >> _evolver >> theRemDec >> iunit(_pdfFreezingScale,GeV) >> _maxtry
>> _maxtryMPI >> _inputparticlesDecayInShower
>> _particlesDecayInShower >> theOrderSecondaries
- >> theMPIOnOff >> theMPIHandler >> theSubProcess
+ >> theMPIOnOff >> theMPIHandler
>> _useCKKW >> _reconstructor >> _reweighter;
}
ClassDescription<ShowerHandler> ShowerHandler::initShowerHandler;
// Definition of the static class description member.
void ShowerHandler::Init() {
static ClassDocumentation<ShowerHandler> documentation
("Main driver class for the showering.");
static Reference<ShowerHandler,Evolver>
interfaceEvolver("Evolver",
"A reference to the Evolver object",
&Herwig::ShowerHandler::_evolver,
false, false, true, false);
static Reference<ShowerHandler,HwRemDecayer>
interfaceRemDecayer("RemDecayer",
"A reference to the Remnant Decayer object",
&Herwig::ShowerHandler::theRemDec,
false, false, true, false);
static Parameter<ShowerHandler,Energy> interfacePDFFreezingScale
("PDFFreezingScale",
"The PDF freezing scale",
&ShowerHandler::_pdfFreezingScale, GeV, 2.5*GeV, 2.0*GeV, 10.0*GeV,
false, false, Interface::limited);
static Parameter<ShowerHandler,unsigned int> interfaceMaxTry
("MaxTry",
"The maximum number of attempts for the main showering loop",
&ShowerHandler::_maxtry, 10, 1, 100,
false, false, Interface::limited);
static Parameter<ShowerHandler,unsigned int> interfaceMaxTryMPI
("MaxTryMPI",
"The maximum number of regeneration attempts for an additional scattering",
&ShowerHandler::_maxtryMPI, 10, 0, 100,
false, false, Interface::limited);
static ParVector<ShowerHandler,long> interfaceDecayInShower
("DecayInShower",
"PDG codes of the particles to be decayed in the shower",
&ShowerHandler::_inputparticlesDecayInShower, -1, 0l, -10000000l, 10000000l,
false, false, Interface::limited);
static Reference<ShowerHandler,MPIHandler> interfaceMPIHandler
("MPIHandler",
"The object that admisinsters all additional semihard partonic scatterings.",
&ShowerHandler::theMPIHandler, false, false, true, true);
static Switch<ShowerHandler,bool> interfaceMPIOnOff
("MPI", "Flag is outdated. Kept for backward compatibility",
&ShowerHandler::theMPIOnOff, 1, false, false);
string desc("The supported way of switching MPI off is setting the ");
desc += "reference ShowerHandler:MPIHandler to NULL. Otherwise MPI is on.";
static Deleted<ShowerHandler> delint("MPI", desc);
static SwitchOption interfaceMPIOnOff0
(interfaceMPIOnOff,
"No",
"Multiple parton interactions are off",
false);
static SwitchOption interfaceMPIOnOff1
(interfaceMPIOnOff,
"Yes",
"Multiple parton interactions are on",
true);
static Switch<ShowerHandler,bool> interfaceOrderSecondaries
("OrderSecondaries",
"flag to switch the ordering of the additional interactions on or off",
&ShowerHandler::theOrderSecondaries, 1, false, false);
desc = "This option has been removed, due to its negligible impact.";
static Deleted<ShowerHandler> delint2("OrderSecondaries", desc);
static SwitchOption interfaceOrderSecondaries0
(interfaceOrderSecondaries,
"No",
"Multiple parton interactions aren't ordered",
false);
static SwitchOption interfaceOrderSecondaries1
(interfaceOrderSecondaries,
"Yes",
"Multiple parton interactions are ordered according to their scale",
true);
static Reference<ShowerHandler,CascadeReconstructor> interfaceCascadeReconstructor
("CascadeReconstructor",
"Casacde reconstructor used for ME/PS merging.",
&ShowerHandler::_reconstructor, false, false, true, true, false);
static Reference<ShowerHandler,Reweighter> interfaceReweighter
("Reweighter",
"Reweighter used for ME/PS merging.",
&ShowerHandler::_reweighter, false, false, true, true, false);
}
void ShowerHandler::cascade() {
+ // get the parton bins
+ tPPair incs=eventHandler()->currentCollision()->primarySubProcess()->incoming();
+ PBIPair incbins = make_pair(lastExtractor()->partonBinInstance(incs.first),
+ lastExtractor()->partonBinInstance(incs.second));
+ // check the collision is of the beam particles
+ bool btotal(false);
+ LorentzRotation rtotal;
+ _incoming = make_pair(incbins.first ? incbins.first ->particle() : incs.first,
+ incbins.second ? incbins.second->particle() : incs.second);
+ // and if not boost collision to the right frame
+ if(_incoming.first != eventHandler()->currentCollision()->incoming().first ||
+ _incoming.second != eventHandler()->currentCollision()->incoming().second ) {
+ btotal = true;
+ boostCollision(false);
+ }
theHandler = this;
tStdXCombPtr lastXC;
SubProPtr sub;
- tPPair incs;
lastXC = dynamic_ptr_cast<StdXCombPtr>(lastXCombPtr());
sub = eventHandler()->currentCollision()->primarySubProcess();
//first shower the hard process
try {
incs = cascade(sub);
}
catch(ShowerTriesVeto &veto){
throw Exception() << "Failed to generate the shower after "
<< veto.theTries
<< " attempts in Evolver::showerHardProcess()"
<< Exception::eventerror;
}
-
- PBIPair incbins = make_pair(lastExtractor()->partonBinInstance(incs.first),
- lastExtractor()->partonBinInstance(incs.second));
-
- if(!HadronMatcher::Check(*generator()->eventHandler()->incoming().first ) &&
- !HadronMatcher::Check(*generator()->eventHandler()->incoming().second) )
+ // if a non-hadron collision return (both incoming non-hadronic)
+ if((!incbins.first||!HadronMatcher::Check(incbins.first ->particle()->data()))&&
+ ( !incbins.second||!HadronMatcher::Check(incbins.second->particle()->data()))) {
+ if(btotal) boostCollision(true);
return;
-
+ }
+ // get the remnants for hadronic collision
pair<tRemPPtr,tRemPPtr> remnants(getRemnants(incbins));
-
// set the starting scale of the forced splitting to the PDF freezing scale
- theRemDec->initialize(remnants, *currentStep(),pdfFreezingScale());
-
+ theRemDec->initialize(remnants, _incoming, *currentStep(),pdfFreezingScale());
//do the first forcedSplitting
try {
theRemDec->doSplit(incs, make_pair(firstPDF().pdf(),
secondPDF().pdf()), true);
}
catch (ExtraScatterVeto) {
throw Exception() << "Remnant extraction failed in "
<< "ShowerHandler::cascade()"
<< Exception::eventerror;
}
-
+ // if no MPI or either of the incoming particles is non-hadronic return
if( !IsMPIOn() ) {
theRemDec->finalize();
+ if(btotal) boostCollision(true);
return;
}
+ // generate the multiple scatters
//use modified pdf's now:
const pair <PDFPtr, PDFPtr> newpdf =
make_pair(new_ptr(MPIPDF(firstPDF().pdf())),
new_ptr(MPIPDF(secondPDF().pdf())));
resetPDFs(newpdf);
unsigned int ptveto(1), veto(0);
unsigned int max(getMPIHandler()->multiplicity());
- // cerr << "\n\n" << max << " additional scatters requested\n";
for(unsigned int i=0; i<max; i++){
//check how often this scattering has been regenerated
if(veto > _maxtryMPI) break;
// cerr << "Try scattering " << i << " for the " << veto
// << " time\n";
//generate PSpoint
lastXC = getMPIHandler()->generate();
sub = lastXC->construct();
-
- //If Algorithm=1 additional scatters of the signal type with pt > ptmin have to be vetoed
+ //If Algorithm=1 additional scatters of the signal type
+ // with pt > ptmin have to be vetoed
//with probability 1/(m+1), where m is the number of occurances in this event
if( getMPIHandler()->Algorithm() == 1 ){
//get the pT
Energy pt = sub->outgoing().front()->momentum().perp();
Energy ptmin = lastCutsPtr()->minKT(sub->outgoing().front()->dataPtr());
-
if(pt > ptmin && UseRandom::rnd() < 1./(ptveto+1) ){
ptveto++;
i--;
continue;
}
}
//add to the EventHandler's list
newStep()->addSubProcess(sub);
try{
//Run the Shower. If not possible veto the scattering
incs = cascade(sub);
- }catch(ShowerTriesVeto){
-
+ }
+ //discard this extra scattering, but try the next one
+ catch(ShowerTriesVeto){
newStep()->removeSubProcess(sub);
//regenerate the scattering
veto++;
i--;
continue;
}
-
try{
//do the forcedSplitting
theRemDec->doSplit(incs, make_pair(firstPDF().pdf(),
secondPDF().pdf()), false);
-
//check if there is enough energy to extract
if( (remnants.first->momentum() - incs.first->momentum()).e() < 1.0e-3*MeV ||
(remnants.second->momentum() - incs.second->momentum()).e() < 1.0e-3*MeV )
throw ExtraScatterVeto();
- }catch(ExtraScatterVeto){
+ }
+ catch (ExtraScatterVeto) {
//remove all particles associated with the subprocess
newStep()->removeParticle(incs.first);
newStep()->removeParticle(incs.second);
//remove the subprocess from the list
newStep()->removeSubProcess(sub);
//regenerate the scattering
veto++;
i--;
continue;
}
//connect with the remnants but don't set Remnant colour,
//because that causes problems due to the multiple colour lines.
if ( !remnants.first->extract(incs.first, false) ||
!remnants.second->extract(incs.second, false) )
throw Exception() << "Remnant extraction failed in "
<< "ShowerHandler::cascade()"
<< Exception::runerror;
//reset veto counter
veto = 0;
}
theRemDec->finalize();
+ if(btotal) boostCollision(true);
theHandler = 0;
}
void ShowerHandler::fillEventRecord() {
// create a new step
StepPtr pstep = newStep();
if(_done.empty()) throw Exception() << "Must have some showers to insert in "
<< "ShowerHandler::fillEventRecord()"
<< Exception::runerror;
if(!_done[0]->isHard()) throw Exception() << "Must start filling with hard process"
<< " in ShowerHandler::fillEventRecord()"
<< Exception::runerror;
// insert the steps
for(unsigned int ix=0;ix<_done.size();++ix) {
_done[ix]->fillEventRecord(pstep,
_evolver->isISRadiationON(),
_evolver->isFSRadiationON());
}
}
void ShowerHandler::findShoweringParticles() {
// clear the storage
_hard=ShowerTreePtr();
_decay.clear();
_done.clear();
// temporary storage of the particles
set<PPtr> hardParticles;
// outgoing particles from the hard process
PVector outgoing = currentSubProcess()->outgoing();
set<PPtr> outgoingset(outgoing.begin(),outgoing.end());
// loop over the tagged particles
tPVector thetagged;
if( FirstInt() ){
thetagged = tagged();
}
else{
//get the "tagged" particles
for(PVector::const_iterator pit = currentSubProcess()->outgoing().begin();
pit != currentSubProcess()->outgoing().end(); ++pit)
thetagged.push_back(*pit);
}
tParticleVector::const_iterator taggedP = thetagged.begin();
bool isHard=false;
for (;taggedP != thetagged.end(); ++taggedP) {
// if a remnant don't consider
if(eventHandler()->currentCollision()->isRemnant(*taggedP))
continue;
// find the parent and if colourless s-channel resonance
bool isDecayProd=false;
tPPtr parent;
if(!(*taggedP)->parents().empty()) {
parent = (*taggedP)->parents()[0];
// check if from s channel decaying colourless particle
isDecayProd = decayProduct(parent);
}
// add to list of outgoing hard particles if needed
isHard |=(outgoingset.find(*taggedP) != outgoingset.end());
if(isDecayProd) hardParticles.insert(findParent(parent,isHard,outgoingset));
else hardParticles.insert(*taggedP);
}
// there must be something to shower
if(hardParticles.empty())
throw Exception() << "No particles to shower in "
<< "ShowerHandler::fillShoweringParticles"
<< Exception::eventerror;
if(!isHard)
throw Exception() << "Starting on decay not yet implemented in "
<< "ShowerHandler::findShoweringParticles()"
<< Exception::runerror;
// create the hard process ShowerTree
ParticleVector out(hardParticles.begin(),hardParticles.end());
_hard=new_ptr(ShowerTree(out, _decay));
_hard->setParents();
}
tPPair ShowerHandler::
cascade(tSubProPtr sub) {
// set the current step
_current=currentStep();
// set the current subprocess
theSubProcess = sub;
// start of the try block for the whole showering process
unsigned int countFailures=0;
ShowerTreePtr hard;
vector<ShowerTreePtr> decay;
while (countFailures<_maxtry) {
try {
// find the particles in the hard process and the decayed particles to shower
findShoweringParticles();
// check if a hard process or decay
bool isHard = _hard;
// if a hard process perform the shower for the hard process
if(isHard) {
_evolver->showerHardProcess(_hard);
_done.push_back(_hard);
_hard->updateAfterShower(_decay);
}
// if no decaying particles to shower break out of the loop
if(_decay.empty()) break;
// if no hard process
if(!isHard)
throw Exception() << "Shower starting with a decay is not yet implemented"
<< Exception::runerror;
// shower the decay products
while(!_decay.empty()) {
multimap<Energy,ShowerTreePtr>::iterator dit=--_decay.end();
while(!dit->second->parent()->hasShowered() && dit!=_decay.begin()) --dit;
// get the particle and the width
ShowerTreePtr decayingTree = dit->second;
// Energy largestWidthDecayingSystem=(*_decay.rbegin()).first;
// remove it from the multimap
_decay.erase(dit);
// make sure the particle has been decayed
decayingTree->decay(_decay);
// now shower the decay
_evolver->showerDecay(decayingTree);
_done.push_back(decayingTree);
decayingTree->updateAfterShower(_decay);
}
// suceeded break out of the loop
break;
}
catch (KinematicsReconstructionVeto) {
++countFailures;
}
}
// if loop exited because of too many tries, throw event away
if (countFailures >= _maxtry) {
_hard=ShowerTreePtr();
_decay.clear();
_done.clear();
throw Exception() << "Too many tries for main while loop "
<< "in ShowerHandler::cascade()."
<< Exception::eventerror;
}
//enter the particles in the event record
fillEventRecord();
_hard=ShowerTreePtr();
_decay.clear();
_done.clear();
- //non hadronic case:
- if (!HadronMatcher::Check(*generator()->eventHandler()->incoming().first ) &&
- !HadronMatcher::Check(*generator()->eventHandler()->incoming().second) )
- return eventHandler()->currentCollision()->incoming();
+ // non hadronic case return
+ if (!HadronMatcher::Check(_incoming.first ->data()) &&
+ !HadronMatcher::Check(_incoming.second->data()) )
+ return _incoming;
// remake the remnants (needs to be after the colours are sorted
// out in the insertion into the event record)
if ( FirstInt() ) 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.
- tPPair inc = generator()->currentEvent()->incoming();
- return make_pair(findFirstParton(sub->incoming().first, inc),
- findFirstParton(sub->incoming().second, inc));
+ return make_pair(findFirstParton(sub->incoming().first ),
+ findFirstParton(sub->incoming().second));
}
PPtr ShowerHandler::findParent(PPtr original, bool & isHard,
set<PPtr> outgoingset) const {
PPtr parent=original;
isHard |=(outgoingset.find(original) != outgoingset.end());
if(!original->parents().empty()) {
PPtr orig=original->parents()[0];
if(_current->find(orig)&&decayProduct(orig)) {
parent=findParent(orig,isHard,outgoingset);
}
}
return parent;
}
ShowerHandler::RemPair
-ShowerHandler::getRemnants(PBIPair incbins){
+ShowerHandler::getRemnants(PBIPair incbins) {
RemPair remnants;
- if( HadronMatcher::Check(*incbins.first->particleData()) &&
- incbins. first->remnants().size() != 1)
- throw Exception() << "Wrong number of Remnants "
- << "in ShowerHandler::getRemnants() for first particle."
- << Exception::runerror;
- if( HadronMatcher::Check(*incbins.second->particleData()) &&
- incbins. second->remnants().size() != 1)
- throw Exception() << "Wrong number of Remnants "
- << "in ShowerHandler::getRemnants() for second particle."
- << Exception::runerror;
-
- remnants.first = incbins.first->remnants().empty() ? tRemPPtr() :
- dynamic_ptr_cast<tRemPPtr>(incbins.first->remnants()[0] );
- if(remnants.first) {
- //remove existing colour lines from the remnants
- if(remnants.first->colourLine())
- remnants.first->colourLine()->removeColoured(remnants.first);
- if(remnants.first->antiColourLine())
- remnants.first->antiColourLine()->removeAntiColoured(remnants.first);
- //copy the remnants to the current step, as they may be changed now
- if ( remnants.first->birthStep() != newStep() ) {
- RemPPtr newrem = new_ptr(*remnants.first);
- newStep()->addDecayProduct(remnants.first, newrem, false);
- remnants.first = newrem;
+ // first beam particle
+ if(incbins.first) {
+ if( HadronMatcher::Check(*incbins.first->particleData()) &&
+ incbins. first->remnants().size() != 1)
+ throw Exception() << "Wrong number of Remnants "
+ << "in ShowerHandler::getRemnants() for first particle."
+ << Exception::runerror;
+ remnants.first = incbins.first->remnants().empty() ? tRemPPtr() :
+ dynamic_ptr_cast<tRemPPtr>(incbins.first->remnants()[0] );
+ if(remnants.first) {
+ ParticleVector children=remnants.first->children();
+ for(unsigned int ix=0;ix<children.size();++ix) {
+ if(children[ix]->dataPtr()==remnants.first->dataPtr())
+ remnants.first = dynamic_ptr_cast<RemPPtr>(children[ix]);
+ }
+ //remove existing colour lines from the remnants
+ if(remnants.first->colourLine())
+ remnants.first->colourLine()->removeColoured(remnants.first);
+ if(remnants.first->antiColourLine())
+ remnants.first->antiColourLine()->removeAntiColoured(remnants.first);
}
}
- remnants.second = incbins.second->remnants().empty() ? tRemPPtr() :
- dynamic_ptr_cast<tRemPPtr>(incbins.second->remnants()[0] );
- if(remnants.second) {
- //remove existing colour lines from the remnants
- if(remnants.second->colourLine())
- remnants.second->colourLine()->removeColoured(remnants.second);
- if(remnants.second->antiColourLine())
- remnants.second->antiColourLine()->removeAntiColoured(remnants.second);
- //copy the remnants to the current step, as they may be changed now
- if ( remnants.second->birthStep() != newStep() ) {
- RemPPtr newrem = new_ptr(*remnants.second);
- newStep()->addDecayProduct(remnants.second, newrem, false);
- remnants.second = newrem;
+ else {
+ remnants.first = tRemPPtr();
+ }
+ // seconnd beam particle
+ if(incbins.second) {
+ if( HadronMatcher::Check(*incbins.second->particleData()) &&
+ incbins. second->remnants().size() != 1)
+ throw Exception() << "Wrong number of Remnants "
+ << "in ShowerHandler::getRemnants() for second particle."
+ << Exception::runerror;
+ remnants.second = incbins.second->remnants().empty() ? tRemPPtr() :
+ dynamic_ptr_cast<tRemPPtr>(incbins.second->remnants()[0] );
+ if(remnants.second) {
+ ParticleVector children=remnants.second->children();
+ for(unsigned int ix=0;ix<children.size();++ix) {
+ if(children[ix]->dataPtr()==remnants.second->dataPtr())
+ remnants.second = dynamic_ptr_cast<RemPPtr>(children[ix]);
+ }
+ //remove existing colour lines from the remnants
+ if(remnants.second->colourLine())
+ remnants.second->colourLine()->removeColoured(remnants.second);
+ if(remnants.second->antiColourLine())
+ remnants.second->antiColourLine()->removeAntiColoured(remnants.second);
}
}
-
+ else {
+ remnants.second = tRemPPtr();
+ }
if(remnants.first || remnants.second ) return remnants;
else throw Exception() << "Remnants are not accessable "
<< "in ShowerHandler::getRemnants()."
<< Exception::runerror;
}
-tPPair ShowerHandler::remakeRemnant(tPPair oldp){
+tPPair ShowerHandler::remakeRemnant(tPPair oldp){
+ // get the parton extractor
PartonExtractor & pex = *lastExtractor();
- tPPair inc = generator()->currentEvent()->incoming();
-
- tPPair newp = make_pair(findFirstParton(oldp.first, inc),
- findFirstParton(oldp.second, inc));
-
+ // get the new partons
+ tPPair newp = make_pair(findFirstParton(oldp.first ),
+ findFirstParton(oldp.second));
+ // if the same do nothing
if(newp == oldp) return oldp;
- // Get the momentum of the new partons before remnant extraction
- // For normal remnants this does not change, but in general it may
- Lorentz5Momentum p1 = newp.first->momentum();
- Lorentz5Momentum p2 = newp.second->momentum();
-
// Creates the new remnants and returns the new PartonBinInstances
PBIPair newbins = pex.newRemnants(oldp, newp, newStep());
newStep()->addIntermediate(newp.first);
newStep()->addIntermediate(newp.second);
-
- // Boosting the remnants is only necessary if the momentum of the
- // incoming has changed, which is not normally true. The two last
- // flags should be false if the first and/or last side do not have
- // remnants at all. It returns an overall boost which should be
- // applied to all partons in the shower.
- //LorentzRotation tot = pex.boostRemnants(newbins, p1, p2, true, true);
-
+ // return the new partona
return newp;
-
}
-PPtr ShowerHandler::findFirstParton(tPPtr seed, tPPair incoming) const{
+PPtr ShowerHandler::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 == incoming.first ||
- parent == incoming.second ) return seed;
- else return findFirstParton(parent, incoming);
+ if(!parent || parent == _incoming.first ||
+ parent == _incoming.second ) return seed;
+ else return findFirstParton(parent);
}
bool ShowerHandler::decayProduct(tPPtr particle) const {
// must be time-like and not incoming
if(particle->momentum().m2()<=0.0*GeV2||
particle == currentSubProcess()->incoming().first||
particle == currentSubProcess()->incoming().second) return false;
// if non-coloured this is enough
if(!particle->dataPtr()->coloured()) return true;
// if coloured must be unstable
if(particle->dataPtr()->stable()) return false;
// must not be the s-channel intermediate
if(find(currentSubProcess()->incoming().first->children().begin(),
currentSubProcess()->incoming().first->children().end(),particle)!=
currentSubProcess()->incoming().first->children().end()&&
find(currentSubProcess()->incoming().second->children().begin(),
currentSubProcess()->incoming().second->children().end(),particle)!=
currentSubProcess()->incoming().second->children().end()&&
currentSubProcess()->incoming().first ->children().size()==1&&
currentSubProcess()->incoming().second->children().size()==1)
return false;
// must not have same particle type as a child
int id = particle->id();
for(unsigned int ix=0;ix<particle->children().size();++ix)
if(particle->children()[ix]->id()==id) return false;
// otherwise its a decaying particle
return true;
}
double ShowerHandler::reweightCKKW(int minMult, int maxMult) {
// return if not doing CKKW
if(!_useCKKW) return 1.;
#ifdef HERWIG_DEBUG_CKKW
generator()->log() << "== ShowerHandler::reweightCKKW" << endl;
#endif
// get the hard subprocess particles
PPair in = lastXCombPtr()->subProcess()->incoming();
ParticleVector out = lastXCombPtr()->subProcess()->outgoing();
pair<double,double> x = make_pair(lastXCombPtr()->lastX1(),lastXCombPtr()->lastX2());
bool gotHistory = false;
try {
// check resolution cut
_reweighter->unresolvedCut(in,out);
// set the generation alpha_s
_reweighter->MEalpha(lastXCombPtr()->lastAlphaS());
// reconstruct a history
gotHistory = _reconstructor->reconstruct(in,x,out);
} catch (Veto) {
// as Veto is not handled if the subprocess has not been setup
// completely, we return weight 0, which, according to Leif,
// does the same job.
return 0.;
}
if (!gotHistory)
throw Exception() << "Shower : ShowerHandler::reweightCKKW : no cascade history could be obtained."
<< Exception::eventerror;
CascadeHistory theHistory = _reconstructor->history();
double weight = _reweighter->reweight(theHistory,out.size(),minMult,maxMult);
_evolver->initCKKWShower(theHistory,out.size(),maxMult);
return weight;
}
+
+namespace {
+
+void addChildren(tPPtr in,set<tPPtr> particles) {
+ particles.insert(in);
+ for(unsigned int ix=0;ix<in->children().size();++ix)
+ addChildren(in->children()[ix],particles);
+}
+}
+
+void ShowerHandler::boostCollision(bool boost) {
+ // calculate boost from lab to rest
+ if(!boost) {
+ Lorentz5Momentum ptotal=_incoming.first ->momentum()+_incoming.second->momentum();
+ _boost = LorentzRotation(-ptotal.boostVector());
+ Axis axis((_boost*_incoming.first ->momentum()).vect().unit());
+ if(axis.perp2()>0.) {
+ double sinth(sqrt(1.-sqr(axis.z())));
+ _boost.rotate(acos(-axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.));
+ }
+ }
+ // first call performs the boost and second inverse
+ // get the particles to be boosted
+ set<tPPtr> particles;
+ addChildren(_incoming.first,particles);
+ addChildren(_incoming.second,particles);
+ // apply the boost
+ for(set<tPPtr>::const_iterator cit=particles.begin();
+ cit!=particles.end();++cit) {
+ (*cit)->transform(_boost);
+ }
+ if(!boost) _boost.invert();
+}
+
diff --git a/Shower/ShowerHandler.h b/Shower/ShowerHandler.h
--- a/Shower/ShowerHandler.h
+++ b/Shower/ShowerHandler.h
@@ -1,468 +1,484 @@
// -*- C++ -*-
//
// ShowerHandler.h is a part of Herwig++ - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2007 The Herwig Collaboration
//
// Herwig++ is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_ShowerHandler_H
#define HERWIG_ShowerHandler_H
//
// This is the declaration of the ShowerHandler class.
//
#include "ThePEG/Handlers/EventHandler.h"
#include "ThePEG/Handlers/CascadeHandler.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "ThePEG/EventRecord/SubProcess.h"
#include "ThePEG/PDT/RemnantData.h"
#include "ThePEG/PDT/RemnantDecayer.h"
#include "ThePEG/EventRecord/RemnantParticle.h"
#include "Herwig++/UnderlyingEvent/MPIHandler.h"
#include "Herwig++/Shower/Base/Evolver.fh"
#include "Herwig++/Shower/Base/ShowerParticle.fh"
#include "Herwig++/Shower/Base/ShowerTree.fh"
#include "Herwig++/PDF/HwRemDecayer.h"
#include "Herwig++/Shower/CKKW/Clustering/CascadeReconstructor.fh"
#include "Herwig++/Shower/CKKW/Reweighting/Reweighter.fh"
#include "ShowerHandler.fh"
namespace Herwig {
using namespace ThePEG;
/** \ingroup Shower
*
* This class is the main driver of the shower: it is responsible for
* the proper handling of all other specific collaborating classes
* and for the storing of the produced particles in the event record.
*
* @see \ref ShowerHandlerInterfaces "The interfaces"
*
* @see ThePEG::CascadeHandler
* @see MPIHandler
* @see HwRemDecayer
*/
class ShowerHandler: public CascadeHandler {
public:
/** Typedef for a pair of ThePEG::RemnantParticle pointers. */
typedef pair<tRemPPtr, tRemPPtr> RemPair;
/**
* The default constructor.
*/
ShowerHandler();
/**
* Destructor
*/
virtual ~ShowerHandler();
public:
/**
* The main method which manages the multiple interactions and starts the shower by calling
* cascade(sub, lastXC).
*/
virtual void cascade();
/**
* It returns true if the particle with the specified id
* is in the list of those that should be decayed during the showering
* showering.
*/
inline bool decayInShower(const long id) const;
public:
/**@name Methods related to ME/PS merging */
//@{
/**
* Perform CKKW reweighting
*/
virtual double reweightCKKW(int minMult, int maxMult);
/**
* Return the cascade reconstructor
*/
inline tCascadeReconstructorPtr cascadeReconstructor () const;
/**
* Return the reweighter
*/
inline tReweighterPtr reweighter () const;
//@}
public:
/**@name Methods related to PDF freezing */
//@{
/**
* Set the PDF freezing scale
*/
inline void pdfFreezingScale (Energy scale) {
_pdfFreezingScale = scale;
}
/**
* Get the PDF freezing scale
*/
inline Energy pdfFreezingScale () const {
return _pdfFreezingScale;
}
//@}
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();
/** @name Functions to access information. */
//@{
/**
* Return true if currently the primary subprocess is showered.
*/
inline bool FirstInt() const;
/**
* Return the currently used SubProcess.
*/
inline tSubProPtr currentSubProcess() const;
/**
* Return true if hard multiple parton interactions are ordered
* according to their scale.
*/
inline bool IsOrdered() const;
/**
* Return true if multiple parton interactions are switched on
* and can be used for this beam setup.
*/
inline bool IsMPIOn() const;
//@}
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
protected:
/**
* The main method which manages the showering of a subprocess.
*/
tPPair cascade(tSubProPtr sub);
/**
* At the end of the Showering, transform ShowerParticle objects
* into ThePEG particles and fill the event record with them.
* Notice that the parent/child relationships and the
* transformation from ShowerColourLine objects into ThePEG
* ColourLine ones must be properly handled.
*/
void fillEventRecord();
/**
* Identify the particles in the hard process and decayed particles
* which need to be showered
*/
void findShoweringParticles();
/**
* Find the final unstable time-like parent of a particle
* @param parent The ultimate parent for the decaying particle
* @param isHard Whether nay particles in chain are from the hard process
* @param outgoing The outgoing particles from the hard process
*/
PPtr findParent(PPtr parent, bool & isHard, set<PPtr> outgoing) const;
/**
* Find the parton extracted from the incoming particle after ISR
*/
- PPtr findFirstParton(tPPtr seed, tPPair incoming) const;
+ PPtr findFirstParton(tPPtr seed) const;
/**
* Fix Remnant connections after ISR
*/
tPPair remakeRemnant(tPPair oldp);
/**
* Get the remnants from the ThePEG::PartonBinInstance es and
* do some checks.
*/
RemPair getRemnants(PBIPair incbins);
/**
* Make the remnant after the shower
*/
void makeRemnants();
/**
* Test for decay products
*/
bool decayProduct(tPPtr) const;
+ /**
+ * Boost all the particles in the collision so that the collision always occurs
+ * in the rest frame with the incoming particles along the z axis
+ */
+ void boostCollision(bool boost);
+
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() throw(InitException);
/**
* Initialize this object. Called in the run phase just before
* a run begins.
*/
virtual void doinitrun();
/**
* Called at the end of the run phase.
*/
virtual void dofinish();
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<ShowerHandler> initShowerHandler;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
ShowerHandler & operator=(const ShowerHandler &);
private:
/**
* Access function for the MPIHandler. If it is a zero pointer
* an exception is thrown, because it should only be called after
* checking with IsMPIOn.
*/
inline tMPIHPtr getMPIHandler() const;
/**
* Switch for Multi Parton Interactions to be ordered
*/
bool theOrderSecondaries;
/**
* Switch for Multi Parton Interactions. Not used any more.
*/
bool theMPIOnOff;
/**
* a MPIHandler to administer the creation of several (semihard)
* partonic interactions.
*/
MPIHPtr theMPIHandler;
private:
/**
* Pointer to the evolver
*/
EvolverPtr _evolver;
/**
* Pointer to the HwRemDecayer
*/
HwRemDecPtr theRemDec;
/**
* The PDF freezing scale
*/
Energy _pdfFreezingScale;
/**
* Maximum number of attempts for the
* main showering loop
*/
unsigned int _maxtry;
/**
* Maximum number of attempts for the regeneration of an additional
* scattering, before the number of scatters is reduced.
*/
unsigned int _maxtryMPI;
/**
* PDG codes of the particles which decay during showering
* this is fast storage for use during running
*/
set<long> _particlesDecayInShower;
/**
* PDG codes of the particles which decay during showering
* this is a vector that is interfaced so they can be changed
*/
vector<long> _inputparticlesDecayInShower;
/**
* The ShowerTree for the hard process
*/
ShowerTreePtr _hard;
/**
+ * The incoming beam particles for the current collision
+ */
+ tPPair _incoming;
+
+ /**
* The ShowerTree for the decays
*/
multimap<Energy,ShowerTreePtr> _decay;
/**
* The ShowerTrees for which the initial shower
*/
vector<ShowerTreePtr> _done;
/**
* Const pointer to the current step
*/
tcStepPtr _current;
/**
* Const pointer to the currently handeled ThePEG::SubProcess
*/
tSubProPtr theSubProcess;
/**
* pointer to "this", the current ShowerHandler.
*/
static ShowerHandler * theHandler;
+ /**
+ * Boost to get back to the lab
+ */
+ LorentzRotation _boost;
+
public:
/**
* struct that is used to catch exceptions which are thrown
* due to energy conservation issues of additional scatters
*/
struct ExtraScatterVeto {};
/**
* struct that is used to catch exceptions which are thrown
* due to fact that the Shower has been invoked more than
* a defined threshold on a certain configuration
*/
struct ShowerTriesVeto {
/** variable to store the number of attempts */
int theTries;
/** constructor */
ShowerTriesVeto(int tries){theTries = tries;}
};
/**
* pointer to "this", the current ShowerHandler.
*/
static inline const ShowerHandler * currentHandler();
private:
/**
* Wether or not to use CKKW
*/
bool _useCKKW;
/**
* The cascade reconstructor used for ME/PS merging
*/
CascadeReconstructorPtr _reconstructor;
/**
* The reweighter used for ME/PS merging
*/
ReweighterPtr _reweighter;
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of ShowerHandler. */
template <>
struct BaseClassTrait<Herwig::ShowerHandler,1> {
/** Typedef of the first base class of ShowerHandler. */
typedef CascadeHandler NthBase;
};
/** This template specialization informs ThePEG about the name of
* the ShowerHandler class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::ShowerHandler>
: public ClassTraitsBase<Herwig::ShowerHandler> {
/** Return a platform-independent class name */
static string className() { return "Herwig::ShowerHandler"; }
/**
* The name of a file containing the dynamic library where the class
* ShowerHandler is implemented. It may also include several, space-separated,
* libraries if the class ShowerHandler depends on other classes (base classes
* excepted). In this case the listed libraries will be dynamically
* linked in the order they are specified.
*/
static string library() { return "HwMPI.so HwMPIPDF.so HwRemDecayer.so HwShower.so"; }
};
/** @endcond */
}
#include "ShowerHandler.icc"
#ifndef ThePEG_TEMPLATES_IN_CC_FILE
// #include "ShowerHandler.tcc"
#endif
#endif /* HERWIG_ShowerHandler_H */
diff --git a/Shower/SplittingFunctions/GtoQQbarSplitFn.cc b/Shower/SplittingFunctions/GtoQQbarSplitFn.cc
--- a/Shower/SplittingFunctions/GtoQQbarSplitFn.cc
+++ b/Shower/SplittingFunctions/GtoQQbarSplitFn.cc
@@ -1,134 +1,134 @@
// -*- C++ -*-
//
// GtoQQbarSplitFn.cc is a part of Herwig++ - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2007 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 GtoQQbarSplitFn class.
//
#include "GtoQQbarSplitFn.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/PDT/ParticleData.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "Herwig++/Shower/Base/ShowerParticle.h"
#include <cassert>
using namespace Herwig;
NoPIOClassDescription<GtoQQbarSplitFn> GtoQQbarSplitFn::initGtoQQbarSplitFn;
// Definition of the static class description member.
void GtoQQbarSplitFn::Init() {
static ClassDocumentation<GtoQQbarSplitFn> documentation
("The GtoQQbarSplitFn class implements the splitting function for g->q qbar");
}
double GtoQQbarSplitFn::P(const double z, const Energy2 t,
const IdList &ids, const bool mass) const {
double zz = z*(1.-z);
double val=1.-2.*zz;
if(mass) {
Energy m = getParticleData(ids[1])->mass();
val +=2.*sqr(m)/t;
}
return 0.5*val;
}
double GtoQQbarSplitFn::overestimateP(const double, const IdList &) const {
return 0.5;
}
double GtoQQbarSplitFn::ratioP(const double z, const Energy2 t,
const IdList &ids, const bool mass) const {
double zz = z*(1.-z);
double val = 1.-2.*zz;
if(mass) {
Energy m = getParticleData(ids[1])->mass();
val+= 2.*sqr(m)/t;
}
return val;
}
double GtoQQbarSplitFn::integOverP(const double z, const IdList & ,
unsigned int PDFfactor) const {
switch(PDFfactor) {
case 0:
- return z/2.;
+ return 0.5*z;
case 1:
return 0.5*log(z);
case 2:
return -0.5*log(1.-z);
case 3:
return 0.5*log(z/(1.-z));
default:
throw Exception() << "GtoQQbarSplitFn::integOverP() invalid PDFfactor = "
<< PDFfactor << Exception::runerror;
}
}
double GtoQQbarSplitFn::invIntegOverP(const double r, const IdList & ,
unsigned int PDFfactor) const {
switch(PDFfactor) {
case 0:
return 2.*r;
case 1:
return exp(2.*r);
case 2:
return 1.-exp(-2.*r);
case 3:
return 1./(1.+exp(-2.*r));
default:
throw Exception() << "GtoQQbarSplitFn::integOverP() invalid PDFfactor = "
<< PDFfactor << Exception::runerror;
}
}
void GtoQQbarSplitFn::colourConnection(tShowerParticlePtr parent,
tShowerParticlePtr first,
tShowerParticlePtr second,
const bool back) const {
if(!back) {
ColinePair cparent = ColinePair(parent->colourLine(),
parent->antiColourLine());
// ensure input consistency
assert(cparent.first&&cparent.second);
cparent.first ->addColoured ( first);
cparent.second->addAntiColoured(second);
}
else {
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);
}
// g -> qbar q
else {
ColinePtr newline=new_ptr(ColourLine());
cfirst.second->addAntiColoured(parent);
newline->addColoured(second);
newline->addColoured(parent);
}
}
}
bool GtoQQbarSplitFn::accept(const IdList &ids) const {
if(ids.size()!=3) return false;
if(ids[1]!=-ids[2]||ids[0]!=ParticleID::g) return false;
tcPDPtr q=getParticleData(ids[1]);
return q->iSpin()==PDT::Spin1Half&&(q->iColour()==PDT::Colour3||
q->iColour()==PDT::Colour3bar);
}
diff --git a/Shower/SplittingFunctions/GtoQQbarSplitFn.h b/Shower/SplittingFunctions/GtoQQbarSplitFn.h
--- a/Shower/SplittingFunctions/GtoQQbarSplitFn.h
+++ b/Shower/SplittingFunctions/GtoQQbarSplitFn.h
@@ -1,218 +1,215 @@
// -*- C++ -*-
//
// GtoQQbarSplitFn.h is a part of Herwig++ - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2007 The Herwig Collaboration
//
// Herwig++ is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_GtoQQbarSplitFn_H
#define HERWIG_GtoQQbarSplitFn_H
//
// This is the declaration of the GtoQQbarSplitFn class.
//
#include "SplittingFunction.h"
#include "GtoQQbarSplitFn.fh"
namespace Herwig {
using namespace ThePEG;
/**\ingroup Shower
*
* This class provides the concrete implementation of the exact leading-order
* splitting function for \f$g\to q\bar{q}\f$.
*
* In this case the splitting function is given by
* \f[P(z,t) =T_R\left(1-2z(1-z)+2\frac{m_q^2}{t}\right),\f]
* where \f$T_R=\frac12\f$
* Our choice for the overestimate is
* \f[P_{\rm over}(z) = T_R,\f]
* therefore the integral is
* \f[\int P_{\rm over}(z) {\rm d}z =T_Rz,\f]
* and its inverse is
* \f[\frac{r}{T_R}\f]
*
* @see \ref GtoQQbarSplitFnInterfaces "The interfaces"
* defined for GtoQQbarSplitFn.
*/
class GtoQQbarSplitFn: public SplittingFunction {
public:
/** @name Standard constructors and destructors. */
//@{
/**
* The default constructor.
*/
inline GtoQQbarSplitFn();
//@}
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
*/
virtual double P(const double z, const Energy2 t, const IdList & ids,
const bool mass) 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
*/
virtual double ratioP(const double z, const Energy2 t, const IdList & ids,
const bool mass) 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;
//@}
/**
* 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 back Whether this is foward or backward evolution.
*/
virtual void colourConnection(tShowerParticlePtr parent,
tShowerParticlePtr first,
tShowerParticlePtr second,
const bool back) const;
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.
*/
inline 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.
*/
inline virtual IBPtr fullclone() const;
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is an concrete class without persistent data.
*/
static NoPIOClassDescription<GtoQQbarSplitFn> initGtoQQbarSplitFn;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
GtoQQbarSplitFn & operator=(const GtoQQbarSplitFn &);
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of GtoQQbarSplitFn. */
template <>
struct BaseClassTrait<Herwig::GtoQQbarSplitFn,1> {
/** Typedef of the first base class of GtoQQbarSplitFn. */
typedef Herwig::SplittingFunction NthBase;
};
/** This template specialization informs ThePEG about the name of
* the GtoQQbarSplitFn class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::GtoQQbarSplitFn>
: public ClassTraitsBase<Herwig::GtoQQbarSplitFn> {
/** Return a platform-independent class name */
static string className() { return "Herwig::GtoQQbarSplitFn"; }
/**
* The name of a file containing the dynamic library where the class
* GtoQQbarSplitFn is implemented. It may also include several, space-separated,
* libraries if the class GtoQQbarSplitFn depends on other classes (base classes
* excepted). In this case the listed libraries will be dynamically
* linked in the order they are specified.
*/
static string library() { return "HwMPI.so HwMPIPDF.so HwRemDecayer.so HwShower.so"; }
};
/** @endcond */
}
#include "GtoQQbarSplitFn.icc"
-#ifndef ThePEG_TEMPLATES_IN_CC_FILE
-// #include "GtoQQbarSplitFn.tcc"
-#endif
#endif /* HERWIG_GtoQQbarSplitFn_H */
diff --git a/configure.ac b/configure.ac
--- a/configure.ac
+++ b/configure.ac
@@ -1,154 +1,155 @@
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ([2.59])
AC_INIT([Herwig++],[SVN],[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
case "${host}" in
*-darwin[[0156]].*)
AC_MSG_ERROR([Herwig++ requires OS X 10.3 or later])
;;
*-darwin7.*)
if test "x$MACOSX_DEPLOYMENT_TARGET" != "x10.3"; then
AC_MSG_ERROR(
[Please add 'MACOSX_DEPLOYMENT_TARGET=10.3' to the configure line.])
fi
;;
esac
dnl === disable debug symbols by default =====
if test "x$CXXFLAGS" = "x"; then
CXXFLAGS=-O2
fi
if test "x$CFLAGS" = "x"; then
CFLAGS=-O2
fi
dnl Looptools manual requires no optimization
if test "x$FCFLAGS" = "x"; then
FCFLAGS=-O0
fi
dnl ==========================================
AC_LANG([C++])
AM_INIT_AUTOMAKE([1.9 gnu dist-bzip2 -Wall])
dnl Checks for programs.
AC_PROG_CXX
AC_PROG_INSTALL
AC_PROG_MAKE_SET
AC_PROG_LN_S
dnl modified search order
AC_PROG_FC([gfortran g95 g77 xlf95 f95 fort ifort ifc efc pgf95 lf95 ftn xlf90 f90 pgf90 pghpf epcf90 xlf f77 frt pgf77 cf77 fort77 fl32 af77])
LT_PREREQ([2.2])
LT_INIT([disable-static dlopen pic-only])
dnl ####################################
dnl ####################################
dnl for Doc/fixinterfaces.pl
AC_PATH_PROG(PERL, perl)
HERWIG_CHECK_GSL
HERWIG_CHECK_THEPEG
HERWIG_COMPILERFLAGS
HERWIG_LOOPTOOLS
HERWIG_PDF_PATH
HERWIG_CHECK_HEPMC
HERWIG_CHECK_KTJET
HERWIG_CHECK_FASTJET
HERWIG_CHECK_ROOT
HERWIG_CHECK_EVTGEN
HERWIG_VERSIONSTRING
HERWIG_CHECK_ABS_BUG
HERWIG_ENABLE_MODELS
AM_CONDITIONAL(NEED_APPLE_FIXES,
[test "xx${host/darwin/foundit}xx" != "xx${host}xx"])
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/LHTP/Makefile
Interfaces/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
Doc/refman.conf
PDT/Makefile
PDF/Makefile
MatrixElement/Makefile
MatrixElement/General/Makefile
MatrixElement/Lepton/Makefile
MatrixElement/Hadron/Makefile
MatrixElement/DIS/Makefile
+ MatrixElement/GammaGamma/Makefile
Shower/SplittingFunctions/Makefile
Shower/Couplings/Makefile
Shower/Default/MECorrections/Makefile
Shower/Default/Makefile
Shower/Base/Makefile
Shower/CKKW/Clustering/Makefile
Shower/CKKW/Reweighting/Makefile
Shower/CKKW/Vertices/Makefile
Shower/CKKW/Processes/Makefile
Shower/CKKW/Qtilde/Makefile
Shower/CKKW/Makefile
Shower/Makefile
Utilities/Makefile
Utilities/Histogram2/Makefile
Hadronization/Makefile
lib/Makefile
include/Makefile
src/Makefile
src/defaults/Makefile
src/herwig-config
Doc/Makefile
Doc/HerwigDefaults.in
Looptools/Makefile
Analysis/Makefile
Analysis/BSM/Makefile
Analysis2/Makefile
Analysis2/Data/Makefile
src/Makefile-UserModules
src/defaults/Analysis.in
Makefile])
AC_CONFIG_FILES([Doc/fixinterfaces.pl],[chmod +x Doc/fixinterfaces.pl])
HERWIG_OVERVIEW
AC_OUTPUT
diff --git a/lib/Makefile.am b/lib/Makefile.am
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -1,38 +1,39 @@
## ugly hack to get linking done by CXX
LINK = $(LIBTOOL) --tag=CXX --mode=link $(CXX) $(AM_CXXFLAGS) $(CXXFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
pkglib_LTLIBRARIES = Herwig.la
Herwig_la_SOURCES =
Herwig_la_LDFLAGS = -module -version-info 1:0:0
Herwig_la_LDFLAGS += $(THEPEGLDFLAGS)
Herwig_la_LIBADD = \
$(top_builddir)/Hadronization/libHwHadronization.la \
$(top_builddir)/Models/StandardModel/libHwStandardModel.la \
+$(top_builddir)/PDF/libHwPDF.la \
$(top_builddir)/Decay/libHwDecay.la \
$(top_builddir)/Decay/FormFactors/libHwFormFactor.la \
$(top_builddir)/Decay/Radiation/libHwDecRad.la \
$(top_builddir)/Utilities/libHwUtils.la \
$(top_builddir)/Models/General/libHwModelGenerator.la \
$(top_builddir)/Decay/General/libHwGeneralDecay.la \
$(top_builddir)/MatrixElement/General/libHwGeneralME.la \
$(top_builddir)/MatrixElement/libHwME.la \
$(top_builddir)/Decay/WeakCurrents/libHwWeakCurrent.la \
$(THEPEGLIB) -ldl
if WANT_LOOPTOOLS
Herwig_la_LIBADD += $(top_builddir)/Looptools/libHwLooptoolsXFC.la
Herwig_la_LDFLAGS += $(FCLIBS)
endif
all-local: done-all-links
done-all-links: Herwig.la
if test ! -L Herwig++ ; then $(LN_S) -f . Herwig++ ; fi
find $(top_builddir) \( -name '*.so.*' -or -name '*.so' \) \
-not -name 'lib*' -not -path '$(top_builddir)/lib/*' -exec $(LN_S) -f \{\} \;
$(LN_S) -f .libs/Herwig*so* .
echo "stamp" > done-all-links
clean-local:
rm -f *.so *.so.* done-all-links
diff --git a/src/DIS.in b/src/DIS.in
--- a/src/DIS.in
+++ b/src/DIS.in
@@ -1,65 +1,65 @@
##################################################
# Example generator based on DIS parameters
# usage: Herwig++ read DIS.in
##################################################
##################################################
# Technical parameters for this run
##################################################
cd /Herwig/Generators
set DISGenerator:NumberOfEvents 10000000
set DISGenerator:RandomNumberGenerator:Seed 31122001
set DISGenerator:DebugLevel 1
set DISGenerator:PrintEvent 10
set DISGenerator:MaxErrors 10000
+set /Herwig/Shower/ShowerHandler:MPIHandler NULL
##################################################
# DIS physics parameters (override defaults here)
##################################################
##################################################
# Matrix Elements for lepton-hadron collisions
# (by default only neutral-current switched on)
##################################################
cd /Herwig/MatrixElements/
# Neutral current DIS
insert SimpleDIS:MatrixElements[0] MEDISNC
cd /Herwig/Generators
##################################################
# Useful analysis handlers for lepton-hadron physics
##################################################
##################################################
# Useful analysis handlers for HepMC related output
##################################################
# Schematic overview of an event (requires --with-hepmc to be set at configure time
# and the graphviz program 'dot' to produce a plot)
# insert DISGenerator:AnalysisHandlers 0 /Herwig/Analysis/Plot
# A HepMC dump file (requires --with-hepmc to be set at configure time)
# insert DISGenerator:AnalysisHandlers 0 /Herwig/Analysis/HepMCFile
# set /Herwig/Analysis/HepMCFile:PrintEvent 100
# set /Herwig/Analysis/HepMCFile:Format GenEvent
# set /Herwig/Analysis/HepMCFile:Units GeV_mm
set /Herwig/Shower/KinematicsReconstructor:ReconstructionOption 1
##################################################
# Save run for later usage with 'Herwig++ run'
##################################################
saverun DIS DISGenerator
##################################################
# uncomment this section for an example batch run
# of two repeats with different parameters
#
# Note that a separate call of 'Herwig run'
# is not required in this case
##################################################
# set DISGenerator:NumberOfEvents 10
# run DIS-full DISGenerator
#
-# set DISGenerator:EventHandler:LuminosityFunction:Energy 900.0
# run DIS-initial DISGenerator
diff --git a/src/defaults/Cuts.in b/src/defaults/Cuts.in
--- a/src/defaults/Cuts.in
+++ b/src/defaults/Cuts.in
@@ -1,89 +1,101 @@
###########################################################
# Default cuts (applied to the hard subprocess)
#
# Don't change values here, re-set them in your own input
# files using these as examples.
###########################################################
mkdir /Herwig/Matchers
cd /Herwig/Matchers
create ThePEG::Matcher<Lepton> Lepton
create ThePEG::Matcher<LightQuark> LightQuark
create ThePEG::Matcher<LightAntiQuark> LightAntiQuark
create ThePEG::Matcher<StandardQCDParton> StandardQCDParton
create ThePEG::Matcher<Photon> Photon
create ThePEG::Matcher<Top> Top
create ThePEG::Matcher<WBoson> WBoson
create ThePEG::Matcher<ZBoson> ZBoson
mkdir /Herwig/Cuts
cd /Herwig/Cuts
# create the cuts object for e+e-
create ThePEG::Cuts EECuts
set EECuts:MHatMin 22.36*GeV
# create the cuts object for hadron collisions
create ThePEG::Cuts QCDCuts
set QCDCuts:ScaleMin 1.0*GeV
set QCDCuts:X1Min 1.0e-5
set QCDCuts:X2Min 1.0e-5
set QCDCuts:MHatMin 20.*GeV
# cut on jet pt
create ThePEG::SimpleKTCut JetKtCut SimpleKTCut.so
set JetKtCut:Matcher /Herwig/Matchers/StandardQCDParton
set JetKtCut:MinKT 20.0*GeV
# cut on photon
create ThePEG::SimpleKTCut PhotonKtCut SimpleKTCut.so
set PhotonKtCut:Matcher /Herwig/Matchers/Photon
set PhotonKtCut:MinKT 20.0*GeV
set PhotonKtCut:MinEta -3.
set PhotonKtCut:MaxEta 3.
# cut on leptons
create ThePEG::SimpleKTCut LeptonKtCut SimpleKTCut.so
set LeptonKtCut:Matcher /Herwig/Matchers/Lepton
set LeptonKtCut:MinKT 0.0*GeV
# cut on top quarks
create ThePEG::SimpleKTCut TopKtCut SimpleKTCut.so
set TopKtCut:Matcher /Herwig/Matchers/Top
set TopKtCut:MinKT 0.0*GeV
# cut on W bosons
create ThePEG::SimpleKTCut WBosonKtCut SimpleKTCut.so
set WBosonKtCut:Matcher /Herwig/Matchers/WBoson
set WBosonKtCut:MinKT 0.0*GeV
# cut on Z bosons
create ThePEG::SimpleKTCut ZBosonKtCut SimpleKTCut.so
set ZBosonKtCut:Matcher /Herwig/Matchers/ZBoson
set ZBosonKtCut:MinKT 0.0*GeV
# create a cut on the invariant mass of lepton pairs
create ThePEG::V2LeptonsCut MassCut V2LeptonsCut.so
set MassCut:MaxM 14000.*GeV
set MassCut:Families All
set MassCut:CComb All
set MassCut:MinM 20.*GeV
set MassCut:MaxM 14000.*GeV
+# create a cut on Q^2 for neutral current DIS
+create ThePEG::SimpleDISCut NeutralCurrentCut SimpleDISCut.so
+set NeutralCurrentCut:MinQ2 20.
+set NeutralCurrentCut:Current Neutral
+
+# create a cut on Q^2 for charged current DIS
+create ThePEG::SimpleDISCut ChargedCurrentCut SimpleDISCut.so
+set ChargedCurrentCut:MinQ2 20.
+set ChargedCurrentCut:Current Charged
+
+# create a cut of Q^2 for charged current DIS
+
# insert into hadron cuts
insert QCDCuts:OneCuts[0] JetKtCut
insert QCDCuts:OneCuts[1] PhotonKtCut
insert QCDCuts:OneCuts[2] LeptonKtCut
insert QCDCuts:OneCuts[3] TopKtCut
insert QCDCuts:OneCuts[4] WBosonKtCut
insert QCDCuts:OneCuts[5] ZBosonKtCut
insert QCDCuts:MultiCuts[0] MassCut
# cuts for DIS
create ThePEG::Cuts DISCuts
set DISCuts:ScaleMin 1.0*GeV
set DISCuts:X1Min 1.0e-5
set DISCuts:X2Min 1.0e-5
-set DISCuts:MHatMin 20.*GeV
-insert DISCuts:OneCuts[0] JetKtCut
+insert DISCuts:TwoCuts[0] NeutralCurrentCut
+insert DISCuts:TwoCuts[1] ChargedCurrentCut
diff --git a/src/defaults/HerwigDefaults.in b/src/defaults/HerwigDefaults.in
--- a/src/defaults/HerwigDefaults.in
+++ b/src/defaults/HerwigDefaults.in
@@ -1,199 +1,199 @@
###################################################################
#
# This is the main repository setup file for Herwig++.
#
# It is read using the 'Herwig++ init' command which prepares the
# default repository file 'HerwigDefaults.rpo'.
#
# The 'Herwig++ read' step allows additional configuration
# instructions to be read from a run-specific file, to modify the
# default values. (We provide LEP.in, ILC.in, LHC.in and TVT.in as
# examples)
#
# You will not need to change any settings here.
# Any modifications can be made in your own input files.
#
###################################################################
globallibrary Herwig.so
###################################################################
# The repository contains its own internal directory structure to
# keep track of created objects. (This is entirely independent of
# the file system)
###################################################################
globallibrary Herwig.so
# Make the root directory in the Repository
rrmdir /Herwig
mkdir /Herwig
#####################################################################
# The 'create' command creates an object in the repository from
# a C++ class. The arguments are (1) the C++ class name, (2) your
# chosen repository name, and optionally, (3) the library name where
# the class can be found.
#
# Created objects are _not_ automatically associated to a run. They
# need to be assigned to it using a chain of 'set' or 'insert'
# commands (see below).
#####################################################################
# the default random number generator
create ThePEG::StandardRandom /Herwig/Random
# the default phase space sampler
create ThePEG::ACDCSampler /Herwig/ACDCSampler ACDCSampler.so
#####################################################################
# Objects in the repository are influenced through 'interfaces'.
# The most important ones can be found in these files, and the
# doxygen documentation provides complete lists.
#
# To set an interface to a new value, use the 'set' command:
# set object:interface value
#
# Note that only repository names can be used here. You must 'create'
# objects before you can use them in a 'set' command
#####################################################################
set /Herwig/ACDCSampler:Margin 1.1
###################################################################
# The 'read' command includes external files in place, to reduce
# clutter. You can also use it for blocks of settings you're likely
# to use again and again.
###################################################################
read Particles.in
read Model.in
read Partons.in
read MatrixElements.in
read UnderlyingEvent.in
read Shower.in
read Hadronization.in
read Decays.in
read QEDRadiation.in
#######################################################################
# The EventHandler is the most important object in a run. It
# (directly or indirectly) owns most of the objects that have been
# created up to now.
#
# Below we create one handler for LEP and one for LHC.
#
# Try to understand the following few lines (also look at the external
# .in files if you can't find the 'create' line for an object).
#
# If you need to make modifications, it's best to make them in your
# own input file (for the 'Herwig++ read' step) and not here.
#######################################################################
mkdir /Herwig/EventHandlers
cd /Herwig/EventHandlers
# Create LEPHandler
create ThePEG::StandardEventHandler LEPHandler
create ThePEG::FixedCMSLuminosity FixedLEPLuminosity FixedCMSLuminosity.so
set FixedLEPLuminosity:Energy 91.2
set LEPHandler:LuminosityFunction FixedLEPLuminosity
insert LEPHandler:SubProcessHandlers[0] /Herwig/MatrixElements/SimpleEE
set LEPHandler:BeamA /Herwig/Particles/e-
set LEPHandler:BeamB /Herwig/Particles/e+
set LEPHandler:Sampler /Herwig/ACDCSampler
set LEPHandler:CascadeHandler /Herwig/Shower/ShowerHandler
set LEPHandler:HadronizationHandler /Herwig/Hadronization/ClusterHadHandler
set LEPHandler:DecayHandler /Herwig/Decays/DecayHandler
# uncomment to get QED radiation off Z decay products in hard process
# insert LEPHandler:PostSubProcessHandlers 0 /Herwig/QEDRadiation/QEDRadHandler
# Create LHCHandler
create ThePEG::StandardEventHandler LHCHandler
create ThePEG::FixedCMSLuminosity FixedLHCLuminosity
set FixedLHCLuminosity:Energy 14000.0
set LHCHandler:LuminosityFunction FixedLHCLuminosity
insert LHCHandler:SubProcessHandlers[0] /Herwig/MatrixElements/SimpleQCD
set LHCHandler:BeamA /Herwig/Particles/p+
set LHCHandler:BeamB /Herwig/Particles/p+
set LHCHandler:Sampler /Herwig/ACDCSampler
set LHCHandler:BinStrategy 2
set LHCHandler:CascadeHandler /Herwig/Shower/ShowerHandler
set LHCHandler:HadronizationHandler /Herwig/Hadronization/ClusterHadHandler
set LHCHandler:DecayHandler /Herwig/Decays/DecayHandler
# uncomment to get QED radiation off W/Z decay products in hard process
# insert LHCHandler:PostSubProcessHandlers[0] /Herwig/QEDRadiation/QEDRadHandler
# Create DISHandler
create ThePEG::StandardEventHandler DISHandler
create ThePEG::LuminosityFunction DISLuminosity
-set DISHandler:BeamA /Herwig/Particles/e-
-set DISLuminosity:BeamEMaxA 30.*GeV
-set DISHandler:BeamB /Herwig/Particles/p+
-set DISLuminosity:BeamEMaxB 920.*GeV
+set DISHandler:BeamA /Herwig/Particles/p+
+set DISLuminosity:BeamEMaxA 920.*GeV
+set DISHandler:BeamB /Herwig/Particles/e-
+set DISLuminosity:BeamEMaxB 30.*GeV
set DISHandler:LuminosityFunction DISLuminosity
insert DISHandler:SubProcessHandlers[0] /Herwig/MatrixElements/SimpleDIS
set DISHandler:Sampler /Herwig/ACDCSampler
set DISHandler:BinStrategy 2
set DISHandler:CascadeHandler /Herwig/Shower/ShowerHandler
set DISHandler:HadronizationHandler /Herwig/Hadronization/ClusterHadHandler
set DISHandler:DecayHandler /Herwig/Decays/DecayHandler
mkdir /Herwig/Generators
cd /Herwig/Generators
#################################################################
# Finally, the EventGenerator objects are responsible
# for the run. They tie together an EventHandler on the one side
# with a physics model (Feynman rules, etc) and random number
# generator on the other.
#
# In your own input files, it will be this EventGenerator object
# that will be called with the 'run' command to start the event
# generation (see LEP.in, LHC.in, TVT.in or LHC.in for examples)
#################################################################
# The Strategy objects can be used for default settings
# (see the Doxygen documentation)
# Currently it only provides the LaTeX reference to Herwig++
create Herwig::HerwigStrategy DefaultStrategy
set DefaultStrategy:LocalParticlesDir /Herwig/Particles
# Now the LEPGenerator
create ThePEG::EventGenerator LEPGenerator
set LEPGenerator:RandomNumberGenerator /Herwig/Random
set LEPGenerator:StandardModelParameters /Herwig/Model
set LEPGenerator:EventHandler /Herwig/EventHandlers/LEPHandler
set LEPGenerator:Strategy DefaultStrategy
# And the LHCGenerator
create ThePEG::EventGenerator LHCGenerator
set LHCGenerator:RandomNumberGenerator /Herwig/Random
set LHCGenerator:StandardModelParameters /Herwig/Model
set LHCGenerator:EventHandler /Herwig/EventHandlers/LHCHandler
set LHCGenerator:Strategy DefaultStrategy
# And the DISGenerator
create ThePEG::EventGenerator DISGenerator
set DISGenerator:RandomNumberGenerator /Herwig/Random
set DISGenerator:StandardModelParameters /Herwig/Model
set DISGenerator:EventHandler /Herwig/EventHandlers/DISHandler
set DISGenerator:Strategy DefaultStrategy
############################################
# The default cuts
############################################
read Cuts.in
cd /Herwig/Generators
set LEPGenerator:EventHandler:Cuts /Herwig/Cuts/EECuts
set LHCGenerator:EventHandler:Cuts /Herwig/Cuts/QCDCuts
set DISGenerator:EventHandler:Cuts /Herwig/Cuts/DISCuts
##########################################
# include some default analysis handlers
##########################################
read Analysis.in
read Analysis2.in
cd /
diff --git a/src/defaults/MatrixElements.in b/src/defaults/MatrixElements.in
--- a/src/defaults/MatrixElements.in
+++ b/src/defaults/MatrixElements.in
@@ -1,105 +1,107 @@
##############################################################################
# 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
set MEee2gZ2qq:MinimumFlavour 1
set MEee2gZ2qq:MaximumFlavour 5
# e+e- -> ZH
create Herwig::MEee2ZH MEee2ZH
############################################################
# hadron-hadron matrix elements
############################################################
# q qbar -> gamma/Z -> l+l-
create Herwig::MEqq2gZ2ff MEqq2gZ2ff
set MEqq2gZ2ff:Process 3
# q qbar to W -> l nu
create Herwig::MEqq2W2ff MEqq2W2ff
set MEqq2W2ff:Process 2
# qqbar/gg -> gamma gamma
create Herwig::MEPP2GammaGamma MEGammaGamma
# hadron-hadron to gamma+jet
create Herwig::MEPP2GammaJet MEGammaJet
# hadron-hadron to higgs
create Herwig::MEPP2Higgs MEHiggs
set MEHiggs:ShapeScheme MassGenerator
set MEHiggs:Process gg
# hadron-hadron to higgs+jet
create Herwig::MEPP2HiggsJet MEHiggsJet
# QCD 2-to-2
create Herwig::MEQCD2to2 MEQCD2to2
# qqbar/gg -> t tbar
create Herwig::MEPP2QQ MEHeavyQuark
# W+jet
create Herwig::MEPP2WJet MEWJet
set MEWJet:WDecay Leptons
# Z+jet
create Herwig::MEPP2ZJet MEZJet
set MEZJet:ZDecay ChargedLeptons
# PP->ZH
create Herwig::MEPP2ZH MEPP2ZH
# PP->WH
create Herwig::MEPP2WH MEPP2WH
##########################################################
# DIS matrix elements
##########################################################
# neutral current
create Herwig::MENeutralCurrentDIS MEDISNC
+# charged current
+create Herwig::MEChargedCurrentDIS MEDISCC
##########################################################
# Set up the Subprocesses
#
# For e+e-
##########################################################
create ThePEG::SubProcessHandler SimpleEE
set SimpleEE:PartonExtractor /Herwig/Partons/EEExtractor
##########################################################
# For hadron-hadron (by default only gamma/Z switched on)
##########################################################
create ThePEG::SubProcessHandler SimpleQCD
set SimpleQCD:PartonExtractor /Herwig/Partons/QCDExtractor
##########################################################
# For DIS only neutral current on by default
##########################################################
create ThePEG::SubProcessHandler SimpleDIS
set SimpleDIS:PartonExtractor /Herwig/Partons/DISExtractor
diff --git a/src/defaults/Partons.in b/src/defaults/Partons.in
--- a/src/defaults/Partons.in
+++ b/src/defaults/Partons.in
@@ -1,28 +1,26 @@
mkdir /Herwig/Partons
cd /Herwig/Partons
create ThePEG::NoRemnants NoRemnants
create ThePEG::NoPDF NoPDF
set NoPDF:RemnantHandler NoRemnants
create ThePEG::LeptonLeptonRemnant LeptonRemnants LeptonLeptonRemnant.so
create Herwig::HwRemDecayer RemnantDecayer HwRemDecayer.so
-create Herwig::ForcedSplitting ForcedSplitting
-set RemnantDecayer:ForcedSplitter ForcedSplitting
create ThePEG::SoftRemnantHandler HadronRemnants
set HadronRemnants:RemnantDecayer RemnantDecayer
read PDF.in
# Make particle extractors
create ThePEG::PartonExtractor EEExtractor
set EEExtractor:NoPDF NoPDF
cp EEExtractor QCDExtractor
set QCDExtractor:FlatSHatY 1
cp EEExtractor DISExtractor
set DISExtractor:FlatSHatY 1
diff --git a/src/defaults/Shower.in b/src/defaults/Shower.in
--- a/src/defaults/Shower.in
+++ b/src/defaults/Shower.in
@@ -1,230 +1,230 @@
############################################################
# Setup of default parton shower
#
# Useful switches for users are marked near the top of
# this file.
#
# Don't edit this file directly, but reset the switches
# in your own input files!
############################################################
library HwMPI.so
library HwMPIPDF.so
library HwShower.so
mkdir /Herwig/Shower
cd /Herwig/Shower
create Herwig::ShowerHandler ShowerHandler
set ShowerHandler:MPIHandler /Herwig/UnderlyingEvent/MPIHandler
set ShowerHandler:RemDecayer /Herwig/Partons/RemnantDecayer
#####################################
# initial setup, don't change these!
#####################################
create Herwig::SplittingGenerator SplittingGenerator
create Herwig::ShowerAlphaQCD AlphaQCD
create Herwig::ShowerAlphaQED AlphaQED
create Herwig::Evolver Evolver
create Herwig::QTildeModel ShowerModel
create Herwig::QTildeFinder PartnerFinder
create Herwig::QTildeReconstructor KinematicsReconstructor
-set /Herwig/Partons/ForcedSplitting:AlphaS AlphaQCD
+set /Herwig/Partons/RemnantDecayer:AlphaS AlphaQCD
set ShowerHandler:Evolver Evolver
set ShowerModel:PartnerFinder PartnerFinder
set ShowerModel:KinematicsReconstructor KinematicsReconstructor
set Evolver:ShowerModel ShowerModel
set Evolver:SplittingGenerator SplittingGenerator
##################################################################
# Intrinsic pT
#
# Recommended:
# 2.2 GeV for Tevatron W/Z production.
# 5.7 GeV for LHC W/Z production
# ( assuming a linear correlation between Iptrms and ln(shat/S) )
#
# Set all parameters to 0 to disable
##################################################################
set Evolver:IntrinsicPtGaussian 2.2*GeV
set Evolver:IntrinsicPtBeta 0
set Evolver:IntrinsicPtGamma 0*GeV
set Evolver:IntrinsicPtIptmax 0*GeV
#############################################################
# Main control switches for the parton shower.
#
# Read this as a 2x3 matrix with FSR/ISR being the rows
# and QCD/QED/EWK as columns. The switches allow detailed
# control over whole rows and columns or individual entries.
#############################################################
# These switch a whole row on and off:
set SplittingGenerator:ISR Yes
set SplittingGenerator:FSR Yes
# These switch a whole column on and off (QED and EWK are not implemented):
set SplittingGenerator:QCDinteractions Yes
set SplittingGenerator:QEDinteractions No
set SplittingGenerator:EWKinteractions No
# These switches are for each entry individually.
# If their column or row is No, they are not considered.
set SplittingGenerator:ISR_QCD Yes
set SplittingGenerator:ISR_QED Yes
set SplittingGenerator:ISR_EWK Yes
set SplittingGenerator:FSR_QCD Yes
set SplittingGenerator:FSR_QED Yes
set SplittingGenerator:FSR_EWK Yes
#
#############################################################
#############################################################
# End of interesting user servicable section.
#
# Anything that follows below should only be touched if you
# know what you're doing.
#
# Really.
#############################################################
#
# create the matrix element corrections
#
# vector boson decay
create Herwig::VectorBosonQQBarMECorrection qqbarg
insert ShowerModel:MECorrections 0 qqbarg
set qqbarg:Coupling AlphaQCD
# top decay
create Herwig::TopDecayMECorrection TopME
insert ShowerModel:MECorrections 1 TopME
set TopME:Coupling AlphaQCD
# drell-yan
create Herwig::DrellYanMECorrection DrellYan
insert ShowerModel:MECorrections 2 DrellYan
set DrellYan:Coupling AlphaQCD
# higgs
create Herwig::GGtoHMECorrection GGtoHME
insert ShowerModel:MECorrections 3 GGtoHME
set GGtoHME:Coupling AlphaQCD
#
# a few default values
set Evolver:MECorrMode 1
set AlphaQCD:ScaleFactor 1.0
set AlphaQED:ScaleFactor 1.0
set AlphaQCD:NPAlphaS 2
set AlphaQCD:Qmin 0.935
set AlphaQCD:NumberOfLoops 3
set AlphaQCD:InputOption 1
set AlphaQCD:AlphaMZ 0.127
#
#
# Lets set up all the splittings
create Herwig::QtoQGSplitFn QtoQGSplitFn
create Herwig::GtoQQbarSplitFn GtoQQbarSplitFn
create Herwig::GtoGGSplitFn GtoGGSplitFn
create Herwig::QtoQGammaSplitFn QtoQGammaSplitFn
create Herwig::QtoGQSplitFn QtoGQSplitFn
#
# Now the Sudakovs
create Herwig::QTildeSudakov SudakovCommon
set SudakovCommon:Alpha AlphaQCD
set SudakovCommon:cutoffKinScale 2.80*GeV
set SudakovCommon:PDFmax 1.0
cp SudakovCommon QtoQGSudakov
set QtoQGSudakov:SplittingFunction QtoQGSplitFn
set QtoQGSudakov:PDFmax 1.9
cp SudakovCommon GtoGGSudakov
set GtoGGSudakov:SplittingFunction GtoGGSplitFn
cp SudakovCommon GtoQQbarSudakov
set GtoQQbarSudakov:SplittingFunction GtoQQbarSplitFn
set GtoQQbarSudakov:PDFmax 120.0
cp SudakovCommon GtobbbarSudakov
set GtobbbarSudakov:SplittingFunction GtoQQbarSplitFn
set GtobbbarSudakov:PDFmax 4000.0
cp SudakovCommon GtoccbarSudakov
set GtoccbarSudakov:SplittingFunction GtoQQbarSplitFn
set GtoccbarSudakov:PDFmax 2000.0
cp SudakovCommon QtoGQSudakov
set QtoGQSudakov:SplittingFunction QtoGQSplitFn
cp SudakovCommon utoGuSudakov
set utoGuSudakov:SplittingFunction QtoGQSplitFn
set utoGuSudakov:PDFFactor OverOneMinusZ
set utoGuSudakov:PDFmax 5.0
cp SudakovCommon dtoGdSudakov
set dtoGdSudakov:SplittingFunction QtoGQSplitFn
set dtoGdSudakov:PDFFactor OverOneMinusZ
cp SudakovCommon QtoQGammaSudakov
set QtoQGammaSudakov:SplittingFunction QtoQGammaSplitFn
#
# Now add the final splittings
#
set SplittingGenerator:AddFinalSplitting u->u,g; QtoQGSudakov
set SplittingGenerator:AddFinalSplitting d->d,g; QtoQGSudakov
set SplittingGenerator:AddFinalSplitting s->s,g; QtoQGSudakov
set SplittingGenerator:AddFinalSplitting c->c,g; QtoQGSudakov
set SplittingGenerator:AddFinalSplitting b->b,g; QtoQGSudakov
set SplittingGenerator:AddFinalSplitting t->t,g; QtoQGSudakov
#
set SplittingGenerator:AddFinalSplitting g->g,g; GtoGGSudakov
#
set SplittingGenerator:AddFinalSplitting g->u,ubar; GtoQQbarSudakov
set SplittingGenerator:AddFinalSplitting g->d,dbar; GtoQQbarSudakov
set SplittingGenerator:AddFinalSplitting g->s,sbar; GtoQQbarSudakov
set SplittingGenerator:AddFinalSplitting g->c,cbar; GtoccbarSudakov
set SplittingGenerator:AddFinalSplitting g->b,bbar; GtobbbarSudakov
set SplittingGenerator:AddFinalSplitting g->t,tbar; GtoQQbarSudakov
#
set SplittingGenerator:AddFinalSplitting u->u,gamma; QtoQGammaSudakov
set SplittingGenerator:AddFinalSplitting d->d,gamma; QtoQGammaSudakov
set SplittingGenerator:AddFinalSplitting s->s,gamma; QtoQGammaSudakov
set SplittingGenerator:AddFinalSplitting c->c,gamma; QtoQGammaSudakov
set SplittingGenerator:AddFinalSplitting b->b,gamma; QtoQGammaSudakov
set SplittingGenerator:AddFinalSplitting t->t,gamma; QtoQGammaSudakov
#
# Now lets add the initial splittings. Remember the form a->b,c; means
# that particle a is the particle given and we backward branch to
# particle b which is initial state and particle c which is final state
#
set SplittingGenerator:AddInitialSplitting u->u,g; QtoQGSudakov
set SplittingGenerator:AddInitialSplitting d->d,g; QtoQGSudakov
set SplittingGenerator:AddInitialSplitting s->s,g; QtoQGSudakov
set SplittingGenerator:AddInitialSplitting c->c,g; QtoQGSudakov
set SplittingGenerator:AddInitialSplitting b->b,g; QtoQGSudakov
set SplittingGenerator:AddInitialSplitting t->t,g; QtoQGSudakov
#
set SplittingGenerator:AddInitialSplitting g->g,g; GtoGGSudakov
#
set SplittingGenerator:AddInitialSplitting g->d,dbar; GtoQQbarSudakov
set SplittingGenerator:AddInitialSplitting g->u,ubar; GtoQQbarSudakov
set SplittingGenerator:AddInitialSplitting g->s,sbar; GtoQQbarSudakov
set SplittingGenerator:AddInitialSplitting g->c,cbar; GtoccbarSudakov
set SplittingGenerator:AddInitialSplitting g->b,bbar; GtobbbarSudakov
set SplittingGenerator:AddInitialSplitting g->t,tbar; GtoQQbarSudakov
#
set SplittingGenerator:AddInitialSplitting d->g,d; dtoGdSudakov
set SplittingGenerator:AddInitialSplitting u->g,u; utoGuSudakov
set SplittingGenerator:AddInitialSplitting s->g,s; QtoGQSudakov
set SplittingGenerator:AddInitialSplitting c->g,c; QtoGQSudakov
set SplittingGenerator:AddInitialSplitting b->g,b; QtoGQSudakov
set SplittingGenerator:AddInitialSplitting t->g,t; QtoGQSudakov
set SplittingGenerator:AddInitialSplitting dbar->g,dbar; dtoGdSudakov
set SplittingGenerator:AddInitialSplitting ubar->g,ubar; utoGuSudakov
set SplittingGenerator:AddInitialSplitting sbar->g,sbar; QtoGQSudakov
set SplittingGenerator:AddInitialSplitting cbar->g,cbar; QtoGQSudakov
set SplittingGenerator:AddInitialSplitting bbar->g,bbar; QtoGQSudakov
set SplittingGenerator:AddInitialSplitting tbar->g,tbar; QtoGQSudakov
diff --git a/src/defaults/bosons.in b/src/defaults/bosons.in
--- a/src/defaults/bosons.in
+++ b/src/defaults/bosons.in
@@ -1,17 +1,17 @@
#
# file containing the particle data for the bosons
#
-create ThePEG::ParticleData gamma
+create ThePEG::BeamParticleData gamma
setup gamma 22 gamma 0 0. 0 0 0 0 3 1
create ThePEG::ParticleData h0
setup h0 25 h0 115 0.003196 0.03196 0 0 0 1 0
set h0:VariableRatio 1
create ThePEG::ConstituentParticleData g
setup g 21 g 0 0. 0 0 0 8 3 1 0.9
create ThePEG::ParticleData Z0
setup Z0 23 Z0 91.1876 2.4952 24.952 0 0 0 3 0
create ThePEG::ParticleData W+
setup W+ 24 W+ 80.403 2.141 21.41 0 3 0 3 0
create ThePEG::ParticleData W-
setup W- -24 W- 80.403 2.141 21.41 0 -3 0 3 0
makeanti W- W+

File Metadata

Mime Type
text/x-diff
Expires
Sat, Dec 21, 1:31 PM (19 h, 26 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4022968
Default Alt Text
(474 KB)

Event Timeline