Page MenuHomeHEPForge

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/Decay/General/GeneralTwoBodyDecayer.h b/Decay/General/GeneralTwoBodyDecayer.h
--- a/Decay/General/GeneralTwoBodyDecayer.h
+++ b/Decay/General/GeneralTwoBodyDecayer.h
@@ -1,456 +1,461 @@
// -*- C++ -*-
//
// GeneralTwoBodyDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_GeneralTwoBodyDecayer_H
#define HERWIG_GeneralTwoBodyDecayer_H
//
// This is the declaration of the GeneralTwoBodyDecayer class.
//
#include "Herwig/Decay/DecayIntegrator.h"
#include "Herwig/Decay/DecayPhaseSpaceMode.h"
#include "ThePEG/Helicity/Vertex/VertexBase.h"
#include "GeneralTwoBodyDecayer.fh"
#include "Herwig/Shower/QTilde/Couplings/ShowerAlpha.h"
+#include "Herwig/Shower/QTilde/Base/ShowerParticle.fh"
+#include "Herwig/Shower/QTilde/Base/ShowerTree.fh"
+#include "Herwig/Shower/QTilde/Base/HardTree.fh"
+#include "Herwig/Shower/QTilde/Base/ShowerProgenitor.fh"
namespace Herwig {
using namespace ThePEG;
using Helicity::VertexBasePtr;
/** \ingroup Decay
* The GeneralTwoBodyDecayer class is designed to be the base class
* for 2 body decays for some general model. It inherits from
* DecayIntegrator and implements the modeNumber() virtual function
* that is the same for all of the decays. A decayer for
* a specific spin configuration should inherit from this and implement
* the me2() and partialWidth() member functions. The colourConnections()
* member should be called from inside me2() in the inheriting decayer
* to set up the colour lines.
*
* @see \ref GeneralTwoBodyDecayerInterfaces "The interfaces"
* defined for GeneralTwoBodyDecayer.
* @see DecayIntegrator
*/
class GeneralTwoBodyDecayer: public DecayIntegrator {
public:
/** A ParticleData ptr and (possible) mass pair.*/
typedef pair<tcPDPtr, Energy> PMPair;
public:
/**
* The default constructor.
*/
GeneralTwoBodyDecayer() : _maxweight(1.), mb_(ZERO), e_(0.), s_(0.), e2_(0.), s2_(0.),
pTmin_(GeV), pT_(ZERO), colour_(1,DVector(1,1.))
{}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* For a given decay mode and a given particle instance, perform the
* decay and return the decay products. As this is the base class this
* is not implemented.
* @return The vector of particles produced in the decay.
*/
virtual ParticleVector decay(const Particle & parent,
const tPDVector & children) const;
/**
* Which of the possible decays is required
* @param cc Is this mode the charge conjugate
* @param parent The decaying particle
* @param children The decay products
*/
virtual int modeNumber(bool & cc, tcPDPtr parent,const tPDVector & children) const;
/**
* Return the matrix element squared for a given mode and phase-space channel
* @param ichan The channel we are calculating the matrix element for.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the calculation of the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int , const Particle & part,
const ParticleVector & decay, MEOption meopt) const = 0;
/**
* Function to return partial Width
* @param inpart The decaying particle.
* @param outa One of the decay products.
* @param outb The other decay product.
*/
virtual Energy partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const;
/**
* Specify the \f$1\to2\f$ matrix element to be used in the running width
* calculation.
* @param dm The DecayMode
* @param mecode The code for the matrix element as described
* in the GenericWidthGenerator class.
* @param coupling The coupling for the matrix element.
* @return True if the the order of the particles in the
* decayer is the same as the DecayMode tag.
*/
virtual bool twoBodyMEcode(const DecayMode & dm, int & mecode,
double & coupling) const;
/**
* An overidden member to calculate a branching ratio for a certain
* particle instance.
* @param dm The DecayMode of the particle
* @param p The particle object
* @param oldbrat The branching fraction given in the DecayMode object
*/
virtual double brat(const DecayMode & dm, const Particle & p,
double oldbrat) const;
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return No;}
/**
* Member to generate the hardest emission in the POWHEG scheme
*/
virtual HardTreePtr generateHardest(ShowerTreePtr);
+
/**
* Three-body matrix element including additional QCD radiation
*/
virtual double threeBodyME(const int , const Particle & inpart,
const ParticleVector & decay, MEOption meopt);
//@}
/**
* Set the information on the decay
*/
void setDecayInfo(PDPtr incoming,PDPair outgoing,
VertexBasePtr,VertexBasePtr,
const vector<VertexBasePtr> &,
VertexBasePtr);
protected:
/** @name Functions used by inheriting decayers. */
//@{
/**
* Get vertex pointer
* @return a pointer to the vertex
*/
VertexBasePtr getVertex() const { return vertex_; }
/**
* Get vertex pointer
* @return a pointer to the vertex for QCD radiation off the decaying particle
*/
VertexBasePtr getIncomingVertex() const { return incomingVertex_; }
/**
* Get vertex pointer
* @return a pointer to the vertex for QCD radiation off the decay products
*/
vector<VertexBasePtr> getOutgoingVertices() const { return outgoingVertices_; }
/**
* Get vertex pointer
* @return a pointer to the vertex for QCD radiation from 4 point vertex
*/
VertexBasePtr getFourPointVertex() const { return fourPointVertex_; }
/**
* Set integration weight
* @param wgt Maximum integration weight
*/
void setWeight(const double & wgt) { _maxweight = wgt; }
/**
* Set colour connections
* @param parent Parent particle
* @param out Particle vector containing particles to
* connect colour lines
*/
void colourConnections(const Particle & parent,
const ParticleVector & out) const;
/**
* Type of dipole
*/
enum dipoleType {FFa, FFc, IFa, IFc, IFba, IFbc};
/**
* Compute the spin and colour factor
*/
double colourFactor(tcPDPtr in, tcPDPtr out1, tcPDPtr out2) const;
/**
* Calculate matrix element ratio R/B
*/
double matrixElementRatio(const Particle & inpart, const ParticleVector & decay2,
const ParticleVector & decay3, MEOption meopt);
/**
* Calculate momenta of all the particles
*/
bool calcMomenta(int j, Energy pT, double y, double phi, double& xg,
double& xs, double& xe, double& xe_z,
vector<Lorentz5Momentum>& particleMomenta);
/**
* Check the calculated momenta are physical
*/
bool psCheck(const double xg, const double xs);
/**
* Return the momenta including the hard emission
*/
vector<Lorentz5Momentum> hardMomenta(const ShowerProgenitorPtr &in,
const ShowerProgenitorPtr &emitter,
const ShowerProgenitorPtr &spectator,
const vector<dipoleType> &dipoles, int i);
/**
* Return dipole corresponding to the dipoleType dipoleId
*/
InvEnergy2 calculateDipole(const dipoleType & dipoleId, const Particle & inpart,
const ParticleVector & decay3, const dipoleType & emittingDipole);
/**
* Return contribution to dipole that depends on the spin of the emitter
*/
double dipoleSpinFactor(const PPtr & emitter, double z);
/**
* Work out the type of process
*/
bool identifyDipoles(vector<dipoleType> & dipoles,
ShowerProgenitorPtr & aProgenitor,
ShowerProgenitorPtr & bProgenitor,
ShowerProgenitorPtr & cProgenitor) const;
/**
* Set up the colour lines
*/
void getColourLines(vector<ColinePtr> & newline, const HardTreePtr & hardtree,
const ShowerProgenitorPtr & bProgenitor);
/**
* Return the colour coefficient of the dipole
*/
double colourCoeff(const PDT::Colour emitter, const PDT::Colour spectator,
const PDT::Colour other);
/**
* Coupling for the generation of hard radiation
*/
ShowerAlphaPtr coupling() {return coupling_;}
//@}
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
/**
* Initialize this object. Called in the run phase just before
* a run begins.
*/
virtual void doinitrun();
//@}
protected:
/**
* Member for the generation of additional hard radiation
*/
//@{
/**
* Return the matrix of colour factors
*/
typedef vector<pair<int,double > > CFlowPairVec;
typedef vector<CFlowPairVec> CFlow;
const vector<DVector> & getColourFactors(const Particle & inpart,
const ParticleVector & decay,
unsigned int & nflow);
const CFlow & colourFlows(const Particle & inpart,
const ParticleVector & decay);
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is an abstract class with persistent data.
*/
static AbstractClassDescription<GeneralTwoBodyDecayer> initGeneralTwoBodyDecayer;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
GeneralTwoBodyDecayer & operator=(const GeneralTwoBodyDecayer &);
private:
/**
* Store the incoming particle
*/
PDPtr _incoming;
/**
* Outgoing particles
*/
vector<PDPtr> _outgoing;
/**
* Pointer to vertex
*/
VertexBasePtr vertex_;
/**
* Pointer to vertex for radiation from the incoming particle
*/
VertexBasePtr incomingVertex_;
/**
* Pointer to the vertices for radiation from the outgoing particles
*/
vector<VertexBasePtr> outgoingVertices_;
/**
* Pointer to vertex for radiation coming from 4 point vertex
*/
VertexBasePtr fourPointVertex_;
/**
* Maximum weight for integration
*/
double _maxweight;
/**
* Mass of decaying particle
*/
Energy mb_;
/**
* Reduced mass of emitter child particle
*/
double e_;
/**
* Reduced mass of spectator child particle
*/
double s_;
/**
* Reduced mass of emitter child particle squared
*/
double e2_;
/**
* Reduced mass of spectator child particle squared
*/
double s2_;
/**
* Minimum \f$p_T\f$
*/
Energy pTmin_;
/**
* Transverse momentum of the emission
*/
Energy pT_;
/**
* Coupling for the generation of hard radiation
*/
ShowerAlphaPtr coupling_;
/**
* Store colour factors for ME calc.
*/
vector<DVector> colour_;
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of GeneralTwoBodyDecayer. */
template <>
struct BaseClassTrait<Herwig::GeneralTwoBodyDecayer,1> {
/** Typedef of the first base class of GeneralTwoBodyDecayer. */
typedef Herwig::DecayIntegrator NthBase;
};
/** This template specialization informs ThePEG about the name of
* the GeneralTwoBodyDecayer class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::GeneralTwoBodyDecayer>
: public ClassTraitsBase<Herwig::GeneralTwoBodyDecayer> {
/** Return a platform-independent class name */
static string className() { return "Herwig::GeneralTwoBodyDecayer"; }
};
/** @endcond */
}
#endif /* HERWIG_GeneralTwoBodyDecayer_H */
diff --git a/Decay/HwDecayerBase.cc b/Decay/HwDecayerBase.cc
--- a/Decay/HwDecayerBase.cc
+++ b/Decay/HwDecayerBase.cc
@@ -1,140 +1,151 @@
// -*- C++ -*-
//
// HwDecayerBase.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the HwDecayerBase class.
//
#include "HwDecayerBase.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Repository/CurrentGenerator.h"
-#include "Herwig/Shower/QTilde/Base/HardTree.h"
#include "Herwig/Shower/QTilde/Base/Branching.h"
+#include "Herwig/Shower/PerturbativeProcess.h"
+#include "Herwig/Shower/RealEmissionProcess.h"
using namespace Herwig;
bool HwDecayerBase::accept(const DecayMode & dm) const {
// get the primary products
tPDVector products=dm.orderedProducts();
// add products for which the decay mode is all ready specified
if(!dm.cascadeProducts().empty()) {
for(ModeMSet::const_iterator mit=dm.cascadeProducts().begin();
mit!=dm.cascadeProducts().end();++mit) {
products.push_back(const_ptr_cast<PDPtr>((**mit).parent()));
}
}
// can this mode be handled ?
return accept(dm.parent(),products);
}
ParticleVector HwDecayerBase::decay(const DecayMode & dm,
const Particle & p) const {
// handling of the decay including the special features of the
// DecayMode
// get the primary products
tPDVector products=dm.orderedProducts();
// add products for which the decay mode is all ready specified
if(!dm.cascadeProducts().empty()) {
for(ModeMSet::const_iterator mit=dm.cascadeProducts().begin();
mit!=dm.cascadeProducts().end();++mit) {
products.push_back(const_ptr_cast<PDPtr>((**mit).parent()));
}
}
// perform the primary decay
ParticleVector output=decay(p,products);
// perform the secondary decays
if(!dm.cascadeProducts().empty()) {
unsigned int iloc=dm.orderedProducts().size();
for(ModeMSet::const_iterator mit=dm.cascadeProducts().begin();
mit!=dm.cascadeProducts().end();++mit) {
if(!(*mit)->decayer())
throw Exception() << "Decay mode " << (**mit).tag()
<< "does not have a decayer, can't perform"
<< "decay in HwDecayerBase::decay()"
<< Exception::eventerror;
ParticleVector children=(*mit)->decayer()->decay(**mit,*output[iloc]);
for(unsigned int ix=0;ix<children.size();++ix) {
output[iloc]->addChild(children[ix]);
}
++iloc;
}
}
return output;
}
void HwDecayerBase::persistentOutput(PersistentOStream & os) const {
os << _initialize << _dbOutput;
}
void HwDecayerBase::persistentInput(PersistentIStream & is, int) {
is >> _initialize >> _dbOutput;
}
AbstractClassDescription<HwDecayerBase> HwDecayerBase::initHwDecayerBase;
// Definition of the static class description member.
void HwDecayerBase::Init() {
static ClassDocumentation<HwDecayerBase> documentation
("The HwDecayerBase class is the base class for Decayers in Hw++.");
static Switch<HwDecayerBase,bool> interfaceInitialize
("Initialize",
"Initialization of the phase space calculation",
&HwDecayerBase::_initialize, false, false, false);
static SwitchOption interfaceInitializeon
(interfaceInitialize,
"Yes",
"At initialisation find max weight and optimise the integration",
true);
static SwitchOption interfaceInitializeoff
(interfaceInitialize,
"No",
"Use the maximum weight and channel weights supplied for the integration",
false);
static Switch<HwDecayerBase,bool> interfaceDatabaseOutput
("DatabaseOutput",
"Whether to print the database information",
&HwDecayerBase::_dbOutput, false, false, false);
static SwitchOption interfaceDatabaseOutputYes
(interfaceDatabaseOutput,
"Yes",
"Output information on the decayer initialization",
true);
static SwitchOption interfaceDatabaseOutputNo
(interfaceDatabaseOutput,
"No",
"Do not output information about the decayer initialization",
false);
}
void HwDecayerBase::dofinish() {
Decayer::dofinish();
if(initialize() && databaseOutput()) {
string fname = CurrentGenerator::current().filename() +
string("-") + name() + string(".output");
ofstream output(fname.c_str());
dataBaseOutput(output,true);
}
}
bool HwDecayerBase::softMatrixElementVeto(ShowerProgenitorPtr,
ShowerParticlePtr,
Branching) {
return false;
}
-HardTreePtr HwDecayerBase::generateHardest(ShowerTreePtr) {
- return HardTreePtr();
+RealEmissionProcessPtr HwDecayerBase::generateHardest(PerturbativeProcessPtr) {
+ return RealEmissionProcessPtr();
}
+
+void HwDecayerBase::initializeMECorrection(PerturbativeProcessPtr , double & ,
+ double & ) {
+ assert(false);
+}
+
+RealEmissionProcessPtr HwDecayerBase::applyHardMatrixElementCorrection(PerturbativeProcessPtr) {
+ assert(false);
+ return RealEmissionProcessPtr();
+}
diff --git a/Decay/HwDecayerBase.h b/Decay/HwDecayerBase.h
--- a/Decay/HwDecayerBase.h
+++ b/Decay/HwDecayerBase.h
@@ -1,264 +1,264 @@
// -*- C++ -*-
//
// HwDecayerBase.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_HwDecayerBase_H
#define HERWIG_HwDecayerBase_H
//
// This is the declaration of the HwDecayerBase class.
//
#include "ThePEG/PDT/Decayer.h"
#include "Herwig/Shower/QTilde/Base/ShowerParticle.fh"
#include "Herwig/Shower/QTilde/Base/ShowerProgenitor.fh"
-#include "Herwig/Shower/QTilde/Base/ShowerTree.fh"
-#include "Herwig/Shower/QTilde/Base/HardTree.fh"
+#include "Herwig/Shower/PerturbativeProcess.fh"
+#include "Herwig/Shower/RealEmissionProcess.fh"
#include "HwDecayerBase.fh"
namespace Herwig {
struct Branching;
using namespace ThePEG;
/**
* The HwDecayerBase class is the base class for Decayers in Herwig. It inherits
* from the Decayer class of ThePEG and implements additional functionality for the
* output of the results to the particle database and initialization of the datbase.
*
* It also provide the option of specifying a class based on the DecayRadiationGenerator
* which should be used to generate QED radiation in the decay
*
* @see \ref HwDecayerBaseInterfaces "The interfaces"
* defined for HwDecayerBase.
*/
class HwDecayerBase: public Decayer {
public:
/**
* The default constructor.
*/
HwDecayerBase() : _initialize(false), _dbOutput(false) {}
/** @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;
/**
* 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.
* @return a ParticleVector containing the decay products.
*/
virtual ParticleVector decay(const DecayMode & dm, const Particle & p) const;
//@}
public:
/**
* Virtual members to be overridden by inheriting classes
* which implement hard corrections
*/
//@{
/**
* Type of POWHEG correction
*/
enum POWHEGType {No, ISR, FSR, Both};
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return No;}
/**
* Has an old fashioned ME correction
*/
virtual bool hasMECorrection() {return false;}
/**
* Initialize the ME correction
*/
- virtual void initializeMECorrection(ShowerTreePtr , double & ,
- double & ) {}
+ virtual void initializeMECorrection(PerturbativeProcessPtr , double & ,
+ double & );
/**
* Apply the hard matrix element correction to a given hard process or decay
*/
- virtual void applyHardMatrixElementCorrection(ShowerTreePtr) {}
+ virtual RealEmissionProcessPtr applyHardMatrixElementCorrection(PerturbativeProcessPtr);
/**
* Apply the soft matrix element correction
* @param initial The particle from the hard process which started the
* shower
* @param parent The initial particle in the current branching
* @param br The branching struct
* @return If true the emission should be vetoed
*/
virtual bool softMatrixElementVeto(ShowerProgenitorPtr initial,
ShowerParticlePtr parent,
Branching br);
/**
* Apply the POWHEG style correction
*/
- virtual HardTreePtr generateHardest(ShowerTreePtr);
+ virtual RealEmissionProcessPtr generateHardest(PerturbativeProcessPtr);
//@}
protected:
/** @name Virtual functions to replaced those from the Decayer class.
* This is so that the decay and accept members of this class can handle all
* the more complicated features of the DecayMode class
*/
//@{
/**
* Check if this decayer can perfom the decay for a particular mode
* @param parent The decaying particle
* @param children The decay products
* @return true If this decayer can handle the given mode, otherwise false.
*/
virtual bool accept(tcPDPtr parent, const tPDVector & children) const = 0;
/**
* Perform the decay of the particle to the specified decay products
* @param parent The decaying particle
* @param children The decay products
* @return a ParticleVector containing the decay products.
*/
virtual ParticleVector decay(const Particle & parent,
const tPDVector & children) const = 0;
//@}
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();
public:
/**
* Functions for the Herwig decayer
*/
//@{
/**
* Output the setup information for the particle database
* @param os The stream to output the information to
* @param header Whether or not to output the information for MySQL
*/
virtual void dataBaseOutput(ofstream & os,bool header) const = 0;
/**
* Access to the initialize variable
*/
bool initialize() const {return _initialize;}
/**
* Access the database output variable
*/
bool databaseOutput() const {return _dbOutput;}
//@}
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* 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 an abstract class with persistent data.
*/
static AbstractClassDescription<HwDecayerBase> initHwDecayerBase;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
HwDecayerBase & operator=(const HwDecayerBase &);
private:
/**
* perform initialisation
*/
bool _initialize;
/**
* Print out database
*/
bool _dbOutput;
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of HwDecayerBase. */
template <>
struct BaseClassTrait<Herwig::HwDecayerBase,1> {
/** Typedef of the first base class of HwDecayerBase. */
typedef Decayer NthBase;
};
/** This template specialization informs ThePEG about the name of
* the HwDecayerBase class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::HwDecayerBase>
: public ClassTraitsBase<Herwig::HwDecayerBase> {
/** Return a platform-independent class name */
static string className() { return "Herwig::HwDecayerBase"; }
};
/** @endcond */
}
#endif /* HERWIG_HwDecayerBase_H */
diff --git a/Decay/Perturbative/SMHiggsFermionsPOWHEGDecayer.cc b/Decay/Perturbative/SMHiggsFermionsPOWHEGDecayer.cc
--- a/Decay/Perturbative/SMHiggsFermionsPOWHEGDecayer.cc
+++ b/Decay/Perturbative/SMHiggsFermionsPOWHEGDecayer.cc
@@ -1,522 +1,523 @@
//-*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SMHiggsFermionsPOWHEGDecayer class.
//
#include "SMHiggsFermionsPOWHEGDecayer.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
-#include "Herwig/Shower/QTilde/Base/ShowerTree.h"
-#include "Herwig/Shower/QTilde/Base/HardTree.h"
+#include "Herwig/Shower/RealEmissionProcess.h"
#include "Herwig/Shower/QTilde/Base/ShowerProgenitor.h"
#include "Herwig/Shower/QTilde/Base/ShowerParticle.h"
#include "Herwig/Shower/QTilde/Base/Branching.h"
using namespace Herwig;
SMHiggsFermionsPOWHEGDecayer::SMHiggsFermionsPOWHEGDecayer()
: CF_(4./3.), pTmin_(1.*GeV)
{}
IBPtr SMHiggsFermionsPOWHEGDecayer::clone() const {
return new_ptr(*this);
}
IBPtr SMHiggsFermionsPOWHEGDecayer::fullclone() const {
return new_ptr(*this);
}
void SMHiggsFermionsPOWHEGDecayer::persistentOutput(PersistentOStream & os) const {
os << alphaS_ << gluon_ << ounit( pTmin_, GeV );
}
void SMHiggsFermionsPOWHEGDecayer::persistentInput(PersistentIStream & is, int) {
is >> alphaS_ >> gluon_ >> iunit( pTmin_, GeV );
}
ClassDescription<SMHiggsFermionsPOWHEGDecayer>
SMHiggsFermionsPOWHEGDecayer::initSMHiggsFermionsPOWHEGDecayer;
// Definition of the static class description member.
void SMHiggsFermionsPOWHEGDecayer::Init() {
static ClassDocumentation<SMHiggsFermionsPOWHEGDecayer> documentation
("There is no documentation for the SMHiggsFermionsPOWHEGDecayer class");
static Reference<SMHiggsFermionsPOWHEGDecayer,ShowerAlpha> interfaceCoupling
("Coupling",
"The object calculating the strong coupling constant",
&SMHiggsFermionsPOWHEGDecayer::alphaS_, false, false, true, false, false);
static Parameter<SMHiggsFermionsPOWHEGDecayer, Energy> interfacePtMin
("minpT",
"The pt cut on hardest emision generation",
&SMHiggsFermionsPOWHEGDecayer::pTmin_, GeV, 1.*GeV, 0*GeV, 100000.0*GeV,
false, false, Interface::limited);
}
-HardTreePtr SMHiggsFermionsPOWHEGDecayer::
-generateHardest(ShowerTreePtr tree) {
- // Get the progenitors: Q and Qbar.
- ShowerProgenitorPtr
- QProgenitor = tree->outgoingLines().begin()->first,
- QbarProgenitor = tree->outgoingLines().rbegin()->first;
- if(QProgenitor->id()<0) swap( QProgenitor, QbarProgenitor );
- partons_.resize(2);
- partons_[0] = QProgenitor->progenitor() ->dataPtr();
- partons_[1] = QbarProgenitor->progenitor()->dataPtr();
- if(!partons_[0]->coloured()) return HardTreePtr();
- // momentum of the partons
- quark_.resize(2);
- quark_[0] = QProgenitor ->copy()->momentum();
- quark_[1] = QbarProgenitor->copy()->momentum();
- // Set the existing mass entries in partons 5 vectors with the
- // once and for all.
- quark_[0].setMass(partons_[0]->mass());
- quark_[1].setMass(partons_[1]->mass());
- gauge_.setMass(0.*MeV);
- // Get the Higgs boson.
- higgs_ = tree->incomingLines().begin()->first->copy();
- // Get the Higgs boson mass.
- mh2_ = (quark_[0] + quark_[1]).m2();
- mHiggs_ = sqrt(mh2_);
- aS_ = SM().alphaS(sqr(mHiggs_));
- Energy particleMass = QProgenitor ->copy()->dataPtr()->mass();
- mu_ = particleMass/mHiggs_;
- mu2_ = sqr(mu_);
- // Generate emission and set _quark[0,1] and _gauge to be the
- // momenta of q, qbar and g after the hardest emission:
- if(!getEvent()) {
- QProgenitor ->maximumpT(pTmin_,ShowerInteraction::QCD);
- QbarProgenitor->maximumpT(pTmin_,ShowerInteraction::QCD);
- return HardTreePtr();
- }
- // Ensure the energies are greater than the constituent masses:
- for (int i=0; i<2; i++) {
- if (quark_[i].e() < partons_[i]->constituentMass()) return HardTreePtr();
- if (gauge_.e() < gluon_ ->constituentMass()) return HardTreePtr();
- }
- // set masses
- quark_[0].setMass( partons_[0]->mass() );
- quark_[1].setMass( partons_[1]->mass() );
- gauge_ .setMass( ZERO );
- // assign the emitter based on evolution scales
- unsigned int iemitter = quark_[0]*gauge_ > quark_[1]*gauge_ ? 1 : 0;
- unsigned int ispectator = iemitter==1 ? 0 : 1;
- // Make the particles for the HardTree:
- ShowerParticlePtr emitter (new_ptr(ShowerParticle(partons_[iemitter ],true)));
- ShowerParticlePtr spectator(new_ptr(ShowerParticle(partons_[ispectator],true)));
- ShowerParticlePtr gauge (new_ptr(ShowerParticle(gluon_,true)));
- ShowerParticlePtr hboson (new_ptr(ShowerParticle(higgs_->dataPtr(),false)));
- ShowerParticlePtr parent (new_ptr(ShowerParticle(partons_[iemitter ],true)));
- emitter ->set5Momentum(quark_[iemitter ]);
- spectator->set5Momentum(quark_[ispectator]);
- gauge ->set5Momentum(gauge_);
- hboson->set5Momentum(higgs_->momentum());
- Lorentz5Momentum parentMomentum(quark_[iemitter]+gauge_);
- parentMomentum.rescaleMass();
- parent->set5Momentum(parentMomentum);
- // Create the vectors of HardBranchings to create the HardTree:
- vector<HardBranchingPtr> spaceBranchings,allBranchings;
- // Incoming boson:
- spaceBranchings.push_back(new_ptr(HardBranching(hboson,SudakovPtr(),
- HardBranchingPtr(),
- HardBranching::Incoming)));
- // Outgoing particles from hard emission:
- HardBranchingPtr spectatorBranch(new_ptr(HardBranching(spectator,SudakovPtr(),
- HardBranchingPtr(),
- HardBranching::Outgoing)));
- HardBranchingPtr emitterBranch(new_ptr(HardBranching(parent,SudakovPtr(),
- HardBranchingPtr(),
- HardBranching::Outgoing)));
- emitterBranch->addChild(new_ptr(HardBranching(emitter,SudakovPtr(),
- HardBranchingPtr(),
- HardBranching::Outgoing)));
- emitterBranch->addChild(new_ptr(HardBranching(gauge,SudakovPtr(),
- HardBranchingPtr(),
- HardBranching::Outgoing)));
- emitterBranch->type(emitterBranch->branchingParticle()->id()>0 ?
- ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine);
- allBranchings.push_back(emitterBranch);
- allBranchings.push_back(spectatorBranch);
- if(iemitter==1) swap(allBranchings[0],allBranchings[1]);
- // Add incoming boson to allBranchings
- allBranchings.push_back( spaceBranchings.back() );
- // Make the HardTree from the HardBranching vectors.
- HardTreePtr hardtree = new_ptr(HardTree(allBranchings,spaceBranchings,
- ShowerInteraction::QCD));
- // Set the maximum pt for all other emissions
- Energy ptveto(pT_);
- QProgenitor ->maximumpT(ptveto,ShowerInteraction::QCD);
- QbarProgenitor->maximumpT(ptveto,ShowerInteraction::QCD);
- // Connect the particles with the branchings in the HardTree
- hardtree->connect( QProgenitor->progenitor(), allBranchings[0] );
- hardtree->connect( QbarProgenitor->progenitor(), allBranchings[1] );
- // colour flow
- ColinePtr newline=new_ptr(ColourLine());
- for(set<HardBranchingPtr>::const_iterator cit=hardtree->branchings().begin();
- cit!=hardtree->branchings().end();++cit) {
- if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3)
- newline->addColoured((**cit).branchingParticle());
- else if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3bar)
- newline->addAntiColoured((**cit).branchingParticle());
- }
- ColinePtr newLine2=new_ptr(ColourLine());
- if(emitterBranch->branchingParticle()->dataPtr()->iColour()==PDT::Colour3) {
- emitterBranch->branchingParticle()->colourLine()->addColoured(gauge);
- newLine2->addColoured(emitter);
- newLine2->addAntiColoured(gauge);
- }
- else {
- emitterBranch->branchingParticle()->antiColourLine()->addAntiColoured(gauge);
- newLine2->addAntiColoured(emitter);
- newLine2->addColoured(gauge);
- }
- // return the tree
- return hardtree;
+RealEmissionProcessPtr SMHiggsFermionsPOWHEGDecayer::
+generateHardest(PerturbativeProcessPtr tree) {
+ assert(false);
+ return RealEmissionProcessPtr();
+ // // Get the progenitors: Q and Qbar.
+ // ShowerProgenitorPtr
+ // QProgenitor = tree->outgoingLines().begin()->first,
+ // QbarProgenitor = tree->outgoingLines().rbegin()->first;
+ // if(QProgenitor->id()<0) swap( QProgenitor, QbarProgenitor );
+ // partons_.resize(2);
+ // partons_[0] = QProgenitor->progenitor() ->dataPtr();
+ // partons_[1] = QbarProgenitor->progenitor()->dataPtr();
+ // if(!partons_[0]->coloured()) return HardTreePtr();
+ // // momentum of the partons
+ // quark_.resize(2);
+ // quark_[0] = QProgenitor ->copy()->momentum();
+ // quark_[1] = QbarProgenitor->copy()->momentum();
+ // // Set the existing mass entries in partons 5 vectors with the
+ // // once and for all.
+ // quark_[0].setMass(partons_[0]->mass());
+ // quark_[1].setMass(partons_[1]->mass());
+ // gauge_.setMass(0.*MeV);
+ // // Get the Higgs boson.
+ // higgs_ = tree->incomingLines().begin()->first->copy();
+ // // Get the Higgs boson mass.
+ // mh2_ = (quark_[0] + quark_[1]).m2();
+ // mHiggs_ = sqrt(mh2_);
+ // aS_ = SM().alphaS(sqr(mHiggs_));
+ // Energy particleMass = QProgenitor ->copy()->dataPtr()->mass();
+ // mu_ = particleMass/mHiggs_;
+ // mu2_ = sqr(mu_);
+ // // Generate emission and set _quark[0,1] and _gauge to be the
+ // // momenta of q, qbar and g after the hardest emission:
+ // if(!getEvent()) {
+ // QProgenitor ->maximumpT(pTmin_,ShowerInteraction::QCD);
+ // QbarProgenitor->maximumpT(pTmin_,ShowerInteraction::QCD);
+ // return HardTreePtr();
+ // }
+ // // Ensure the energies are greater than the constituent masses:
+ // for (int i=0; i<2; i++) {
+ // if (quark_[i].e() < partons_[i]->constituentMass()) return HardTreePtr();
+ // if (gauge_.e() < gluon_ ->constituentMass()) return HardTreePtr();
+ // }
+ // // set masses
+ // quark_[0].setMass( partons_[0]->mass() );
+ // quark_[1].setMass( partons_[1]->mass() );
+ // gauge_ .setMass( ZERO );
+ // // assign the emitter based on evolution scales
+ // unsigned int iemitter = quark_[0]*gauge_ > quark_[1]*gauge_ ? 1 : 0;
+ // unsigned int ispectator = iemitter==1 ? 0 : 1;
+ // // Make the particles for the HardTree:
+ // ShowerParticlePtr emitter (new_ptr(ShowerParticle(partons_[iemitter ],true)));
+ // ShowerParticlePtr spectator(new_ptr(ShowerParticle(partons_[ispectator],true)));
+ // ShowerParticlePtr gauge (new_ptr(ShowerParticle(gluon_,true)));
+ // ShowerParticlePtr hboson (new_ptr(ShowerParticle(higgs_->dataPtr(),false)));
+ // ShowerParticlePtr parent (new_ptr(ShowerParticle(partons_[iemitter ],true)));
+ // emitter ->set5Momentum(quark_[iemitter ]);
+ // spectator->set5Momentum(quark_[ispectator]);
+ // gauge ->set5Momentum(gauge_);
+ // hboson->set5Momentum(higgs_->momentum());
+ // Lorentz5Momentum parentMomentum(quark_[iemitter]+gauge_);
+ // parentMomentum.rescaleMass();
+ // parent->set5Momentum(parentMomentum);
+ // // Create the vectors of HardBranchings to create the HardTree:
+ // vector<HardBranchingPtr> spaceBranchings,allBranchings;
+ // // Incoming boson:
+ // spaceBranchings.push_back(new_ptr(HardBranching(hboson,SudakovPtr(),
+ // HardBranchingPtr(),
+ // HardBranching::Incoming)));
+ // // Outgoing particles from hard emission:
+ // HardBranchingPtr spectatorBranch(new_ptr(HardBranching(spectator,SudakovPtr(),
+ // HardBranchingPtr(),
+ // HardBranching::Outgoing)));
+ // HardBranchingPtr emitterBranch(new_ptr(HardBranching(parent,SudakovPtr(),
+ // HardBranchingPtr(),
+ // HardBranching::Outgoing)));
+ // emitterBranch->addChild(new_ptr(HardBranching(emitter,SudakovPtr(),
+ // HardBranchingPtr(),
+ // HardBranching::Outgoing)));
+ // emitterBranch->addChild(new_ptr(HardBranching(gauge,SudakovPtr(),
+ // HardBranchingPtr(),
+ // HardBranching::Outgoing)));
+ // emitterBranch->type(emitterBranch->branchingParticle()->id()>0 ?
+ // ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine);
+ // allBranchings.push_back(emitterBranch);
+ // allBranchings.push_back(spectatorBranch);
+ // if(iemitter==1) swap(allBranchings[0],allBranchings[1]);
+ // // Add incoming boson to allBranchings
+ // allBranchings.push_back( spaceBranchings.back() );
+ // // Make the HardTree from the HardBranching vectors.
+ // HardTreePtr hardtree = new_ptr(HardTree(allBranchings,spaceBranchings,
+ // ShowerInteraction::QCD));
+ // // Set the maximum pt for all other emissions
+ // Energy ptveto(pT_);
+ // QProgenitor ->maximumpT(ptveto,ShowerInteraction::QCD);
+ // QbarProgenitor->maximumpT(ptveto,ShowerInteraction::QCD);
+ // // Connect the particles with the branchings in the HardTree
+ // hardtree->connect( QProgenitor->progenitor(), allBranchings[0] );
+ // hardtree->connect( QbarProgenitor->progenitor(), allBranchings[1] );
+ // // colour flow
+ // ColinePtr newline=new_ptr(ColourLine());
+ // for(set<HardBranchingPtr>::const_iterator cit=hardtree->branchings().begin();
+ // cit!=hardtree->branchings().end();++cit) {
+ // if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3)
+ // newline->addColoured((**cit).branchingParticle());
+ // else if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3bar)
+ // newline->addAntiColoured((**cit).branchingParticle());
+ // }
+ // ColinePtr newLine2=new_ptr(ColourLine());
+ // if(emitterBranch->branchingParticle()->dataPtr()->iColour()==PDT::Colour3) {
+ // emitterBranch->branchingParticle()->colourLine()->addColoured(gauge);
+ // newLine2->addColoured(emitter);
+ // newLine2->addAntiColoured(gauge);
+ // }
+ // else {
+ // emitterBranch->branchingParticle()->antiColourLine()->addAntiColoured(gauge);
+ // newLine2->addAntiColoured(emitter);
+ // newLine2->addColoured(gauge);
+ // }
+ // // return the tree
+ // return hardtree;
}
double SMHiggsFermionsPOWHEGDecayer::
me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const {
// fermion mass
Energy particleMass = decay[0]->dataPtr()->mass();
// leading-order result
double output = SMHiggsFermionsDecayer::me2(ichan,part,decay,meopt);
// check decay products coloured, otherwise return
if(!decay[0]->dataPtr()->coloured()||
particleMass==ZERO) return output;
// inital masses, couplings etc
// higgs mass
mHiggs_ = part.mass();
// strong coupling
aS_ = SM().alphaS(sqr(mHiggs_));
// reduced mass
mu_ = particleMass/mHiggs_;
mu2_ = sqr(mu_);
// generate y
double yminus = 0.;
double yplus = 1.-2.*mu_*(1.-mu_)/(1.-2*mu2_);
double y = yminus + UseRandom::rnd()*(yplus-yminus);
//generate z for D31,2
double v = sqrt(sqr(2.*mu2_+(1.-2.*mu2_)*(1.-y))-4.*mu2_)/(1.-2.*mu2_)/(1.-y);
double zplus = (1.+v)*(1.-2.*mu2_)*y/2./(mu2_ +(1.-2.*mu2_)*y);
double zminus = (1.-v)*(1.-2.*mu2_)*y/2./(mu2_ +(1.-2.*mu2_)*y);
double z = zminus + UseRandom::rnd()*(zplus-zminus);
// map y,z to x1,x2 for both possible emissions
double x2 = 1. - y*(1.-2.*mu2_);
double x1 = 1. - z*(x2-2.*mu2_);
//get the dipoles
InvEnergy2 D1 = dipoleSubtractionTerm( x1, x2);
InvEnergy2 D2 = dipoleSubtractionTerm( x2, x1);
InvEnergy2 dipoleSum = abs(D1) + abs(D2);
//jacobian
double jac = (1.-y)*(yplus-yminus)*(zplus-zminus);
//calculate real
Energy2 realPrefactor = 0.25*sqr(mHiggs_)*sqr(1.-2.*mu2_)
/sqrt(calculateLambda(1,mu2_,mu2_))/sqr(Constants::twopi);
InvEnergy2 realEmission = calculateRealEmission( x1, x2);
// calculate the virtual
double virtualTerm = calculateVirtualTerm();
// running mass correction
virtualTerm += (8./3. - 2.*log(mu2_))*aS_/Constants::pi;
//answer = (born + virtual + real)/born * LO
output *= 1. + virtualTerm + 2.*jac*realPrefactor*(realEmission*abs(D1)/dipoleSum - D1);
// return the answer
return output;
}
//calculate lambda
double SMHiggsFermionsPOWHEGDecayer::calculateLambda(double x, double y, double z) const{
return sqr(x)+sqr(y)+sqr(z)-2.*x*y-2.*x*z-2.*y*z;
}
//calculates the dipole subtraction term for x1, D31,2 (Dij,k),
// 2 is the spectator anti-fermion and 3 is the gluon
InvEnergy2 SMHiggsFermionsPOWHEGDecayer::
dipoleSubtractionTerm(double x1, double x2) const{
InvEnergy2 commonPrefactor = CF_*8.*Constants::pi*aS_/sqr(mHiggs_);
return commonPrefactor/(1.-x2)*
(2.*(1.-2.*mu2_)/(2.-x1-x2)-
sqrt((1.-4.*mu2_)/(sqr(x2)-4.*mu2_))*
(x2-2.*mu2_)*(2.+(x1-1.)/(x2-2.*mu2_)+2.*mu2_/(1.-x2))/(1.-2.*mu2_));
}
//return ME for real emission
InvEnergy2 SMHiggsFermionsPOWHEGDecayer::
calculateRealEmission(double x1, double x2) const {
InvEnergy2 prefactor = CF_*8.*Constants::pi*aS_/sqr(mHiggs_)/(1.-4.*mu2_);
return prefactor*(2. + (1.-x1)/(1.-x2) + (1.-x2)/(1.-x1)
+ 2.*(1.-2.*mu2_)*(1.-4.*mu2_)/(1.-x1)/(1.-x2)
- 2.*(1.-4.*mu2_)*(1./(1.-x2)+1./(1.-x1))
- 2.*mu2_*(1.-4.*mu2_)*(1./sqr(1.-x2)+1./sqr(1.-x1)));
}
double SMHiggsFermionsPOWHEGDecayer::
calculateVirtualTerm() const {
// logs and prefactors
double beta = sqrt(1.-4.*mu2_);
double L = log((1.+beta)/(1.-beta));
double prefactor = CF_*aS_/Constants::twopi;
// non-singlet piece
double nonSingletTerm = calculateNonSingletTerm(beta, L);
double virtualTerm =
-2.+4.*log(mu_)+(2./beta - 2.*beta)*L
+ (2.-4.*mu2_)/beta*(0.5*sqr(L) - 2.*L*log(beta)
+ 2.*Herwig::Math::ReLi2((1.-beta)/(1.+beta))
+ 2.*sqr(Constants::pi)/3.);
double iEpsilonTerm =
2.*(3.-sqr(Constants::pi)/2. + 0.5*log(mu2_) - 1.5*log(1.-2.*mu2_)
-(1.-2.*mu2_)/beta*(0.5*sqr(L)+sqr(Constants::pi)/6.
-2.*L*log(1.-2.*mu2_))
+ nonSingletTerm);
return prefactor*(virtualTerm+iEpsilonTerm);
}
//non-singlet piece of I(epsilon) insertion operator
double SMHiggsFermionsPOWHEGDecayer::
calculateNonSingletTerm(double beta, double L) const {
return 1.5*log(1.-2.*mu2_)
+ (1.-2.*mu2_)/beta*(- 2.*L*log(4.*(1.-2.*mu2_)/sqr(1.+beta))+
+ 2.*Herwig::Math::ReLi2(sqr((1.-beta)/(1.+beta)))
- 2.*Herwig::Math::ReLi2(2.*beta/(1.+beta))
- sqr(Constants::pi)/6.)
+ log(1.-mu_)
- 2.*log(1.-2.*mu_)
- 2.*mu2_/(1.-2.*mu2_)*log(mu_/(1.-mu_))
- mu_/(1.-mu_)
+ 2.*mu_*(2*mu_-1.)/(1.-2.*mu2_)
+ 0.5*sqr(Constants::pi);
}
void SMHiggsFermionsPOWHEGDecayer::doinit() {
SMHiggsFermionsDecayer::doinit();
gluon_ = getParticleData(ParticleID::g);
// Energy quarkMass = getParticleData(ParticleID::b )->mass();
// Energy higgsMass = getParticleData(ParticleID::h0)->mass();
// double mu = quarkMass/higgsMass;
// double beta = sqrt(1.-4.*sqr(mu));
// double beta2 = sqr(beta);
// double aS = SM().alphaS(sqr(higgsMass));
// double L = log((1.+beta)/(1.-beta));
// cerr << "testing " << beta << " " << mu << "\n";
// cerr << "testing " << aS << " " << L << "\n";
// double fact =
// 6.-0.75*(1.+beta2)/beta2+12.*log(mu)-8.*log(beta)
// +(5./beta-2.*beta+0.375*sqr(1.-beta2)/beta2/beta)*L
// +(1.+beta2)/beta*(4.*L*log(0.5*(1.+beta)/beta)
// -2.*log(0.5*(1.+beta))*log(0.5*(1.-beta))
// +8.*Herwig::Math::ReLi2((1.-beta)/(1.+beta))
// -4.*Herwig::Math::ReLi2(0.5*(1.-beta)));
// cerr << "testing correction "
// << 1.+4./3.*aS/Constants::twopi*fact
// << "\n";
// double real = 4./3.*aS/Constants::twopi*
// (8.-0.75*(1.+beta2)/beta2+8.*log(mu)-8.*log(beta)
// +(3./beta+0.375*sqr(1.-beta2)/pow(beta,3))*L
// +(1.+beta2)/beta*(-0.5*sqr(L)+4.*L*log(0.5*(1.+beta))
// -2.*L*log(beta)-2.*log(0.5*(1.+beta))*log(0.5*(1.-beta))
// +6.*Herwig::Math::ReLi2((1.-beta)/(1.+beta))
// -4.*Herwig::Math::ReLi2(0.5*(1.-beta))
// -2./3.*sqr(Constants::pi)));
// double virt = 4./3.*aS/Constants::twopi*
// (-2.+4.*log(mu)+(2./beta-2.*beta)*L
// +(1.+beta2)/beta*(0.5*sqr(L)-2.*L*log(beta)+2.*sqr(Constants::pi)/3.
// +2.*Herwig::Math::ReLi2((1.-beta)/(1.+beta))));
// cerr << "testing real " << real << "\n";
// cerr << "testing virtual " << virt << "\n";
// cerr << "testing total no mb corr " << 1.+real+virt << "\n";
// cerr << "testing total mb corr " << 1.+real+virt +(8./3. - 2.*log(sqr(mu)))*aS/Constants::pi << "\n";
// InvEnergy2 Gf = 1.166371e-5/GeV2;
// Gf = sqrt(2.)*4*Constants::pi*SM().alphaEM(sqr(higgsMass))/8./SM().sin2ThetaW()/
// sqr(getParticleData(ParticleID::Wplus)->mass());
// cerr << "testing GF " << Gf*GeV2 << "\n";
// Energy LO = (3./8./Constants::pi)*sqrt(2)*sqr(quarkMass)*Gf*higgsMass*beta*beta*beta;
// cerr << "testing LO " << LO/GeV << "\n";
// cerr << "testing quark mass " << quarkMass/GeV << "\n";
// cerr << "testing gamma " << (1.+real+virt)*LO/MeV << "\n";
}
bool SMHiggsFermionsPOWHEGDecayer::getEvent() {
// max pT
Energy pTmax = 0.5*sqrt(mh2_);
// Define over valued y_max & y_min according to the associated pt_min cut.
double ymax = acosh(pTmax/pTmin_);
double ymin = -ymax;
// pt of the emmission
pT_ = pTmax;
// prefactor
double overEst = 4.;
double prefactor = overEst*alphaS_->overestimateValue()*4./3./Constants::twopi;
// loop to generate the pt and rapidity
bool reject;
//arrays to hold the temporary probabilities whilst the for loop progresses
double probTemp[2][2]={{0.,0.},{0.,0.}};
probTemp[0][0]=probTemp[0][1]=probTemp[1][0]=probTemp[1][1]=0.;
double x1Solution[2][2] = {{0.,0.},{0.,0.}};
double x2Solution[2][2] = {{0.,0.},{0.,0.}};
double x3Solution[2] = {0.,0.};
Energy pT[2] = {pTmax,pTmax};
double yTemp[2] = {0.,0.};
for(int i=0; i<2; i++) {
do {
// reject the emission
reject = true;
// generate pt
pT[i] *= pow(UseRandom::rnd(),1./(prefactor*(ymax-ymin)));
Energy2 pT2 = sqr(pT[i]);
if(pT[i]<pTmin_) {
pT[i] = -GeV;
break;
}
// generate y
yTemp[i] = ymin + UseRandom::rnd()*(ymax-ymin);
//generate x3 & x1 from pT & y
double x1Plus = 1.;
double x1Minus = 2.*mu_;
x3Solution[i] = 2.*pT[i]*cosh(yTemp[i])/mHiggs_;
// prefactor
Energy2 weightPrefactor = mh2_/16./sqr(Constants::pi)/sqrt(1.-4.*mu2_);
weightPrefactor /= prefactor;
// calculate x1 & x2 solutions
Energy4 discrim2 = (sqr(x3Solution[i]*mHiggs_) - 4.*pT2)*
(mh2_*(x3Solution[i]-1.)*(4.*mu2_+x3Solution[i]-1.)-4.*mu2_*pT2);
//check discriminant2 is > 0
if( discrim2 < ZERO) continue;
Energy2 discriminant = sqrt(discrim2);
Energy2 fact1 = 3.*mh2_*x3Solution[i]-2.*mh2_+2.*pT2*x3Solution[i]-4.*pT2-mh2_*sqr(x3Solution[i]);
Energy2 fact2 = 2.*mh2_*(x3Solution[i]-1.)-2.*pT2;
// two solns for x1
x1Solution[i][0] = (fact1 + discriminant)/fact2;
x1Solution[i][1] = (fact1 - discriminant)/fact2;
x2Solution[i][0] = 2.-x3Solution[i]-x1Solution[i][0];
x2Solution[i][1] = 2.-x3Solution[i]-x1Solution[i][1];
bool found = false;
for(unsigned int j=0;j<2;++j) {
if(x1Solution[i][j]>=x1Minus && x1Solution[i][j]<=x1Plus &&
checkZMomenta(x1Solution[i][j], x2Solution[i][j], x3Solution[i], yTemp[i], pT[i])) {
InvEnergy2 D1 = dipoleSubtractionTerm( x1Solution[i][j], x2Solution[i][j]);
InvEnergy2 D2 = dipoleSubtractionTerm( x2Solution[i][j], x1Solution[i][j]);
double dipoleFactor = abs(D1)/(abs(D1) + abs(D2));
probTemp[i][j] = weightPrefactor*pT[i]*dipoleFactor*
calculateJacobian(x1Solution[i][j], x2Solution[i][j], pT[i])*
calculateRealEmission(x1Solution[i][j], x2Solution[i][j]);
found = true;
}
else {
probTemp[i][j] = 0.;
}
}
if(!found) continue;
// alpha S piece
double wgt = (probTemp[i][0]+probTemp[i][1])*alphaS_->value(sqr(pT[i]))/aS_;
// matrix element weight
reject = UseRandom::rnd()>wgt;
}
while(reject);
} //end of emitter for loop
// no emission
if(pT[0]<ZERO&&pT[1]<ZERO) return false;
//pick the spectator and x1 x2 values
double x1,x2,y;
//particle 1 emits, particle 2 spectates
unsigned int iemit=0;
if(pT[0]>pT[1]){
pT_ = pT[0];
y=yTemp[0];
if(probTemp[0][0]>UseRandom::rnd()*(probTemp[0][0]+probTemp[0][1])) {
x1 = x1Solution[0][0];
x2 = x2Solution[0][0];
}
else {
x1 = x1Solution[0][1];
x2 = x2Solution[0][1];
}
}
//particle 2 emits, particle 1 spectates
else {
iemit=1;
pT_ = pT[1];
y=yTemp[1];
if(probTemp[1][0]>UseRandom::rnd()*(probTemp[1][0]+probTemp[1][1])) {
x1 = x1Solution[1][0];
x2 = x2Solution[1][0];
}
else {
x1 = x1Solution[1][1];
x2 = x2Solution[1][1];
}
}
// find spectator
unsigned int ispect = iemit == 0 ? 1 : 0;
// Find the boost from the lab to the c.o.m with the spectator
// along the -z axis, and then invert it.
LorentzRotation eventFrame( ( quark_[0] + quark_[1] ).findBoostToCM() );
Lorentz5Momentum spectator = eventFrame*quark_[ispect];
eventFrame.rotateZ( -spectator.phi() );
eventFrame.rotateY( -spectator.theta() - Constants::pi );
eventFrame.invert();
//generation of phi
double phi = UseRandom::rnd() * Constants::twopi;
// spectator
quark_[ispect].setT( 0.5*x2*mHiggs_ );
quark_[ispect].setX( ZERO );
quark_[ispect].setY( ZERO );
quark_[ispect].setZ( -sqrt(0.25*mh2_*x2*x2-mh2_*mu2_) );
// gluon
gauge_.setT( pT_*cosh(y) );
gauge_.setX( pT_*cos(phi) );
gauge_.setY( pT_*sin(phi) );
gauge_.setZ( pT_*sinh(y) );
gauge_.setMass(ZERO);
// emitter reconstructed from gluon & spectator
quark_[iemit] = - gauge_ - quark_[ispect];
quark_[iemit].setT( 0.5*mHiggs_*x1 );
// boost constructed vectors into the event frame
quark_[0] = eventFrame * quark_[0];
quark_[1] = eventFrame * quark_[1];
gauge_ = eventFrame * gauge_;
// need to reset masses because for whatever reason the boost
// touches the mass component of the five-vector and can make
// zero mass objects acquire a floating point negative mass(!).
gauge_.setMass( ZERO );
quark_[iemit] .setMass(partons_[iemit ]->mass());
quark_[ispect].setMass(partons_[ispect]->mass());
return true;
}
InvEnergy SMHiggsFermionsPOWHEGDecayer::calculateJacobian(double x1, double x2, Energy pT) const{
double xPerp = abs(2.*pT/mHiggs_);
Energy jac = mHiggs_*fabs((x1*x2-2.*mu2_*(x1+x2)+sqr(x2)-x2)/xPerp/pow(sqr(x2)-4.*mu2_,1.5));
return 1./jac; //jacobian as defined is dptdy=jac*dx1dx2, therefore we have to divide by it
}
bool SMHiggsFermionsPOWHEGDecayer::checkZMomenta(double x1, double x2, double x3, double y, Energy pT) const {
double xPerp2 = 4.*pT*pT/mHiggs_/mHiggs_;
static double tolerance = 1e-6;
bool isMomentaReconstructed = false;
if(pT*sinh(y)>ZERO) {
if(abs(-sqrt(sqr(x2)-4.*mu2_)+sqrt(sqr(x3)-xPerp2) + sqrt(sqr(x1)-xPerp2 - 4.*mu2_)) <= tolerance ||
abs(-sqrt(sqr(x2)-4.*mu2_)+sqrt(sqr(x3)-xPerp2) - sqrt(sqr(x1)-xPerp2 - 4.*mu2_)) <= tolerance) isMomentaReconstructed=true;
}
else if(pT*sinh(y) < ZERO){
if(abs(-sqrt(sqr(x2)-4.*mu2_)-sqrt(sqr(x3)-xPerp2) + sqrt(sqr(x1)-xPerp2 - 4.*mu2_)) <= tolerance ||
abs(-sqrt(sqr(x2)-4.*mu2_)-sqrt(sqr(x3)-xPerp2) - sqrt(sqr(x1)-xPerp2 - 4.*mu2_)) <= tolerance) isMomentaReconstructed=true;
}
else
if(abs(-sqrt(sqr(x2)-4.*mu2_)+ sqrt(sqr(x1)-xPerp2 - 4.*mu2_)) <= tolerance) isMomentaReconstructed=true;
return isMomentaReconstructed;
}
diff --git a/Decay/Perturbative/SMHiggsFermionsPOWHEGDecayer.h b/Decay/Perturbative/SMHiggsFermionsPOWHEGDecayer.h
--- a/Decay/Perturbative/SMHiggsFermionsPOWHEGDecayer.h
+++ b/Decay/Perturbative/SMHiggsFermionsPOWHEGDecayer.h
@@ -1,272 +1,272 @@
// -*- C++ -*-
#ifndef HERWIG_SMHiggsFermionsPOWHEGDecayer_H
#define HERWIG_SMHiggsFermionsPOWHEGDecayer_H
//
// This is the declaration of the SMHiggsFermionsPOWHEGDecayer class.
//
#include "SMHiggsFermionsDecayer.h"
#include "Herwig/Utilities/Maths.h"
#include "Herwig/Shower/QTilde/Couplings/ShowerAlpha.fh"
namespace Herwig {
using namespace ThePEG;
/**
* Here is the documentation of the SMHiggsFermionsPOWHEGDecayer class.
*
* @see \ref SMHiggsFermionsPOWHEGDecayerInterfaces "The interfaces"
* defined for SMHiggsFermionsPOWHEGDecayer.
*/
class SMHiggsFermionsPOWHEGDecayer: public SMHiggsFermionsDecayer {
public:
/**
* The default constructor.
*/
SMHiggsFermionsPOWHEGDecayer();
/**
* Virtual members to be overridden by inheriting classes
* which implement hard corrections
*/
//@{
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return FSR;}
/**
* Apply the POWHEG style correction
*/
- virtual HardTreePtr generateHardest(ShowerTreePtr);
+ virtual RealEmissionProcessPtr generateHardest(PerturbativeProcessPtr);
//@}
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const;
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<SMHiggsFermionsPOWHEGDecayer> initSMHiggsFermionsPOWHEGDecayer;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
SMHiggsFermionsPOWHEGDecayer & operator=(const SMHiggsFermionsPOWHEGDecayer &);
/**
* Calcluate the Kallen function
*/
double calculateLambda(double x, double y, double z) const;
/**
* Dipole subtraction term
*/
InvEnergy2 dipoleSubtractionTerm(double x1, double x2) const;
/**
* Real emission term
*/
InvEnergy2 calculateRealEmission(double x1, double x2) const;
/**
* Virtual term
*/
double calculateVirtualTerm() const;
/**
* Non-singlet term
*/
double calculateNonSingletTerm(double beta, double L) const;
/**
* Check the sign of the momentum in the \f$z\f$-direction is correct.
*/
bool checkZMomenta(double x1, double x2, double x3, double y, Energy pT) const;
/**
* Calculate the Jacobian
*/
InvEnergy calculateJacobian(double x1, double x2, Energy pT) const;
/**
* Generate a real emission event
*/
bool getEvent();
private:
/**
* The colour factor
*/
double CF_;
/**
* The Higgs mass
*/
mutable Energy mHiggs_;
/**
* The reduced mass
*/
mutable double mu_;
/**
* The square of the reduced mass
*/
mutable double mu2_;
/**
* The strong coupling
*/
mutable double aS_;
/**
* Stuff ofr the POWHEG correction
*/
//@{
/**
* Pointer to the object calculating the strong coupling
*/
ShowerAlphaPtr alphaS_;
/**
* ParticleData object for the gluon
*/
tcPDPtr gluon_;
/**
* The cut off on pt, assuming massless quarks.
*/
Energy pTmin_;
// radiative variables (pt,y)
Energy pT_;
/**
* The ParticleData objects for the fermions
*/
vector<tcPDPtr> partons_;
/**
* The fermion momenta
*/
vector<Lorentz5Momentum> quark_;
/**
* The momentum of the radiated gauge boson
*/
Lorentz5Momentum gauge_;
/**
* The Higgs boson
*/
PPtr higgs_;
/**
* Higgs mass squared
*/
Energy2 mh2_;
//@}
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of SMHiggsFermionsPOWHEGDecayer. */
template <>
struct BaseClassTrait<Herwig::SMHiggsFermionsPOWHEGDecayer,1> {
/** Typedef of the first base class of SMHiggsFermionsPOWHEGDecayer. */
typedef Herwig::SMHiggsFermionsDecayer NthBase;
};
/** This template specialization informs ThePEG about the name of
* the SMHiggsFermionsPOWHEGDecayer class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::SMHiggsFermionsPOWHEGDecayer>
: public ClassTraitsBase<Herwig::SMHiggsFermionsPOWHEGDecayer> {
/** Return a platform-independent class name */
static string className() { return "Herwig::SMHiggsFermionsPOWHEGDecayer"; }
/**
* The name of a file containing the dynamic library where the class
* SMHiggsFermionsPOWHEGDecayer is implemented. It may also include several, space-separated,
* libraries if the class SMHiggsFermionsPOWHEGDecayer 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 "HwPerturbativeHiggsDecay.so"; }
};
/** @endcond */
}
#endif /* HERWIG_SMHiggsFermionsPOWHEGDecayer_H */
diff --git a/Decay/Perturbative/SMTopDecayer.cc b/Decay/Perturbative/SMTopDecayer.cc
--- a/Decay/Perturbative/SMTopDecayer.cc
+++ b/Decay/Perturbative/SMTopDecayer.cc
@@ -1,1202 +1,1203 @@
// -*- C++ -*-
//
// SMTopDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SMTopDecayer class.
//
#include "SMTopDecayer.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/ParVector.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "Herwig/Decay/DecayVertex.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "Herwig/PDT/ThreeBodyAllOn1IntegralCalculator.h"
-#include "Herwig/Shower/QTilde/Base/ShowerTree.h"
+#include "Herwig/Shower/RealEmissionProcess.h"
#include "Herwig/Shower/QTilde/Base/ShowerProgenitor.h"
#include "Herwig/Shower/QTilde/Base/ShowerParticle.h"
#include "Herwig/Shower/QTilde/Base/Branching.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
SMTopDecayer::SMTopDecayer()
: _wquarkwgt(6,0.),_wleptonwgt(3,0.), _xg_sampling(1.5),
_initialenhance(1.), _finalenhance(2.3), _useMEforT2(true) {
_wleptonwgt[0] = 0.302583;
_wleptonwgt[1] = 0.301024;
_wleptonwgt[2] = 0.299548;
_wquarkwgt[0] = 0.851719;
_wquarkwgt[1] = 0.0450162;
_wquarkwgt[2] = 0.0456962;
_wquarkwgt[3] = 0.859839;
_wquarkwgt[4] = 3.9704e-06;
_wquarkwgt[5] = 0.000489657;
generateIntermediates(true);
}
bool SMTopDecayer::accept(tcPDPtr parent, const tPDVector & children) const {
if(abs(parent->id()) != ParticleID::t) return false;
int id0(0),id1(0),id2(0);
for(tPDVector::const_iterator it = children.begin();
it != children.end();++it) {
int id=(**it).id(),absid(abs(id));
if(absid==ParticleID::b&&double(id)/double(parent->id())>0) {
id0=id;
}
else {
switch (absid) {
case ParticleID::nu_e:
case ParticleID::nu_mu:
case ParticleID::nu_tau:
id1 = id;
break;
case ParticleID::eminus:
case ParticleID::muminus:
case ParticleID::tauminus:
id2 = id;
break;
case ParticleID::b:
case ParticleID::d:
case ParticleID::s:
id1 = id;
break;
case ParticleID::u:
case ParticleID::c:
id2=id;
break;
default :
break;
}
}
}
if(id0==0||id1==0||id2==0) return false;
if(double(id1)/double(id2)>0) return false;
return true;
}
ParticleVector SMTopDecayer::decay(const Particle & parent,
const tPDVector & children) const {
int id1(0),id2(0);
for(tPDVector::const_iterator it = children.begin();
it != children.end();++it) {
int id=(**it).id(),absid=abs(id);
if(absid == ParticleID::b && double(id)/double(parent.id())>0) continue;
//leptons
if(absid > 10 && absid%2==0) id1=absid;
if(absid > 10 && absid%2==1) id2=absid;
//quarks
if(absid < 10 && absid%2==0) id2=absid;
if(absid < 10 && absid%2==1) id1=absid;
}
unsigned int imode(0);
if(id2 >=11 && id2<=16) imode = (id1-12)/2;
else imode = id1+1+id2/2;
bool cc = parent.id() == ParticleID::tbar;
ParticleVector out(generate(true,cc,imode,parent));
//arrange colour flow
PPtr pparent=const_ptr_cast<PPtr>(&parent);
out[1]->incomingColour(pparent,out[1]->id()<0);
ParticleVector products = out[0]->children();
if(products[0]->hasColour())
products[0]->colourNeighbour(products[1],true);
else if(products[0]->hasAntiColour())
products[0]->colourNeighbour(products[1],false);
return out;
}
void SMTopDecayer::persistentOutput(PersistentOStream & os) const {
os << _wvertex << _wquarkwgt << _wleptonwgt << _wplus << _alpha
<< _initialenhance << _finalenhance << _xg_sampling << _useMEforT2;
}
void SMTopDecayer::persistentInput(PersistentIStream & is, int) {
is >> _wvertex >> _wquarkwgt >> _wleptonwgt >> _wplus >> _alpha
>> _initialenhance >> _finalenhance >> _xg_sampling >> _useMEforT2;
}
ClassDescription<SMTopDecayer> SMTopDecayer::initSMTopDecayer;
// Definition of the static class description member.
void SMTopDecayer::Init() {
static ClassDocumentation<SMTopDecayer> documentation
("This is the implementation of the SMTopDecayer which "
"decays top quarks into bottom quarks and either leptons "
"or quark-antiquark pairs including the matrix element for top decay",
"The matrix element correction for top decay \\cite{Hamilton:2006ms}.",
"%\\cite{Hamilton:2006ms}\n"
"\\bibitem{Hamilton:2006ms}\n"
" K.~Hamilton and P.~Richardson,\n"
" ``A simulation of QCD radiation in top quark decays,''\n"
" JHEP {\\bf 0702}, 069 (2007)\n"
" [arXiv:hep-ph/0612236].\n"
" %%CITATION = JHEPA,0702,069;%%\n");
static ParVector<SMTopDecayer,double> interfaceQuarkWeights
("QuarkWeights",
"Maximum weights for the hadronic decays",
&SMTopDecayer::_wquarkwgt, 6, 1.0, 0.0, 10.0,
false, false, Interface::limited);
static ParVector<SMTopDecayer,double> interfaceLeptonWeights
("LeptonWeights",
"Maximum weights for the semi-leptonic decays",
&SMTopDecayer::_wleptonwgt, 3, 1.0, 0.0, 10.0,
false, false, Interface::limited);
static Parameter<SMTopDecayer,double> interfaceEnhancementFactor
("InitialEnhancementFactor",
"The enhancement factor for initial-state radiation in the shower to ensure"
" the weight for the matrix element correction is less than one.",
&SMTopDecayer::_initialenhance, 1.0, 1.0, 10000.0,
false, false, Interface::limited);
static Parameter<SMTopDecayer,double> interfaceFinalEnhancementFactor
("FinalEnhancementFactor",
"The enhancement factor for final-state radiation in the shower to ensure"
" the weight for the matrix element correction is less than one",
&SMTopDecayer::_finalenhance, 1.6, 1.0, 1000.0,
false, false, Interface::limited);
static Parameter<SMTopDecayer,double> interfaceSamplingTopHardMEC
("SamplingTopHardMEC",
"The importance sampling power for choosing an initial xg, "
"to sample xg according to xg^-_xg_sampling",
&SMTopDecayer::_xg_sampling, 1.5, 1.2, 2.0,
false, false, Interface::limited);
static Switch<SMTopDecayer,bool> interfaceUseMEForT2
("UseMEForT2",
"Use the matrix element correction, if available to fill the T2"
" region for the decay shower and don't fill using the shower",
&SMTopDecayer::_useMEforT2, true, false, false);
static SwitchOption interfaceUseMEForT2Shower
(interfaceUseMEForT2,
"Shower",
"Use the shower to fill the T2 region",
false);
static SwitchOption interfaceUseMEForT2ME
(interfaceUseMEForT2,
"ME",
"Use the Matrix element to fill the T2 region",
true);
static Reference<SMTopDecayer,ShowerAlpha> interfaceCoupling
("Coupling",
"Pointer to the object to calculate the coupling for the correction",
&SMTopDecayer::_alpha, false, false, true, false, false);
}
double SMTopDecayer::me2(const int, const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half)));
// spinors etc for the decaying particle
if(meopt==Initialize) {
// spinors and rho
if(inpart.id()>0)
SpinorWaveFunction ::calculateWaveFunctions(_inHalf,_rho,
const_ptr_cast<tPPtr>(&inpart),
incoming);
else
SpinorBarWaveFunction::calculateWaveFunctions(_inHalfBar,_rho,
const_ptr_cast<tPPtr>(&inpart),
incoming);
}
// setup spin info when needed
if(meopt==Terminate) {
// for the decaying particle
if(inpart.id()>0) {
SpinorWaveFunction::
constructSpinInfo(_inHalf,const_ptr_cast<tPPtr>(&inpart),incoming,true);
SpinorBarWaveFunction::constructSpinInfo(_inHalfBar,decay[0],outgoing,true);
SpinorWaveFunction ::constructSpinInfo(_outHalf ,decay[1],outgoing,true);
SpinorBarWaveFunction::constructSpinInfo(_outHalfBar,decay[2],outgoing,true);
}
else {
SpinorBarWaveFunction::
constructSpinInfo(_inHalfBar,const_ptr_cast<tPPtr>(&inpart),incoming,true);
SpinorWaveFunction::constructSpinInfo(_inHalf,decay[0],outgoing,true);
SpinorBarWaveFunction::constructSpinInfo(_outHalfBar,decay[1],outgoing,true);
SpinorWaveFunction ::constructSpinInfo(_outHalf ,decay[2],outgoing,true);
}
}
if ( ( decay[1]->momentum() + decay[2]->momentum() ).m()
< decay[1]->data().constituentMass() + decay[2]->data().constituentMass() )
return 0.0;
// spinors for the decay product
if(inpart.id()>0) {
SpinorBarWaveFunction::calculateWaveFunctions(_inHalfBar ,decay[0],outgoing);
SpinorWaveFunction ::calculateWaveFunctions(_outHalf ,decay[1],outgoing);
SpinorBarWaveFunction::calculateWaveFunctions(_outHalfBar,decay[2],outgoing);
}
else {
SpinorWaveFunction ::calculateWaveFunctions(_inHalf ,decay[0],outgoing);
SpinorBarWaveFunction::calculateWaveFunctions(_outHalfBar,decay[1],outgoing);
SpinorWaveFunction ::calculateWaveFunctions(_outHalf ,decay[2],outgoing);
}
Energy2 scale(sqr(inpart.mass()));
if(inpart.id() == ParticleID::t) {
//Define intermediate vector wave-function for Wplus
tcPDPtr Wplus(getParticleData(ParticleID::Wplus));
VectorWaveFunction inter;
unsigned int thel,bhel,fhel,afhel;
for(thel = 0;thel<2;++thel){
for(bhel = 0;bhel<2;++bhel){
inter = _wvertex->evaluate(scale,1,Wplus,_inHalf[thel],
_inHalfBar[bhel]);
for(afhel=0;afhel<2;++afhel){
for(fhel=0;fhel<2;++fhel){
(*ME())(thel,bhel,afhel,fhel) =
_wvertex->evaluate(scale,_outHalf[afhel],
_outHalfBar[fhel],inter);
}
}
}
}
}
else if(inpart.id() == ParticleID::tbar) {
VectorWaveFunction inter;
tcPDPtr Wminus(getParticleData(ParticleID::Wminus));
unsigned int tbhel,bbhel,afhel,fhel;
for(tbhel = 0;tbhel<2;++tbhel){
for(bbhel = 0;bbhel<2;++bbhel){
inter = _wvertex->
evaluate(scale,1,Wminus,_inHalf[bbhel],_inHalfBar[tbhel]);
for(afhel=0;afhel<2;++afhel){
for(fhel=0;fhel<2;++fhel){
(*ME())(tbhel,bbhel,fhel,afhel) =
_wvertex->evaluate(scale,_outHalf[afhel],
_outHalfBar[fhel],inter);
}
}
}
}
}
double output = (ME()->contract(_rho)).real();
if(abs(decay[1]->id())<=6) output *=3.;
return output;
}
void SMTopDecayer::doinit() {
DecayIntegrator::doinit();
//get vertices from SM object
tcHwSMPtr hwsm = dynamic_ptr_cast<tcHwSMPtr>(standardModel());
if(!hwsm) throw InitException() << "Must have Herwig::StandardModel in "
<< "SMTopDecayer::doinit()";
_wvertex = hwsm->vertexFFW();
//initialise
_wvertex->init();
//set up decay modes
_wplus = getParticleData(ParticleID::Wplus);
DecayPhaseSpaceModePtr mode;
DecayPhaseSpaceChannelPtr Wchannel;
tPDVector extpart(4);
vector<double> wgt(1,1.0);
extpart[0] = getParticleData(ParticleID::t);
extpart[1] = getParticleData(ParticleID::b);
//lepton modes
for(int i=11; i<17;i+=2) {
extpart[2] = getParticleData(-i);
extpart[3] = getParticleData(i+1);
mode = new_ptr(DecayPhaseSpaceMode(extpart,this));
Wchannel = new_ptr(DecayPhaseSpaceChannel(mode));
Wchannel->addIntermediate(extpart[0],0,0.0,-1,1);
Wchannel->addIntermediate(_wplus,0,0.0,2,3);
Wchannel->init();
mode->addChannel(Wchannel);
addMode(mode,_wleptonwgt[(i-11)/2],wgt);
}
//quark modes
unsigned int iz=0;
for(int ix=1;ix<6;ix+=2) {
for(int iy=2;iy<6;iy+=2) {
// check that the combination of particles is allowed
if(_wvertex->allowed(-ix,iy,ParticleID::Wminus)) {
extpart[2] = getParticleData(-ix);
extpart[3] = getParticleData( iy);
mode = new_ptr(DecayPhaseSpaceMode(extpart,this));
Wchannel = new_ptr(DecayPhaseSpaceChannel(mode));
Wchannel->addIntermediate(extpart[0],0,0.0,-1,1);
Wchannel->addIntermediate(_wplus,0,0.0,2,3);
Wchannel->init();
mode->addChannel(Wchannel);
addMode(mode,_wquarkwgt[iz],wgt);
++iz;
}
else {
throw InitException() << "SMTopDecayer::doinit() the W vertex"
<< "cannot handle all the quark modes"
<< Exception::abortnow;
}
}
}
}
void SMTopDecayer::dataBaseOutput(ofstream & os,bool header) const {
if(header) os << "update decayers set parameters=\"";
// parameters for the DecayIntegrator base class
for(unsigned int ix=0;ix<_wquarkwgt.size();++ix) {
os << "newdef " << name() << ":QuarkWeights " << ix << " "
<< _wquarkwgt[ix] << "\n";
}
for(unsigned int ix=0;ix<_wleptonwgt.size();++ix) {
os << "newdef " << name() << ":LeptonWeights " << ix << " "
<< _wleptonwgt[ix] << "\n";
}
DecayIntegrator::dataBaseOutput(os,false);
if(header) os << "\n\" where BINARY ThePEGName=\"" << fullName() << "\";" << endl;
}
void SMTopDecayer::doinitrun() {
DecayIntegrator::doinitrun();
if(initialize()) {
for(unsigned int ix=0;ix<numberModes();++ix) {
if(ix<3) _wleptonwgt[ix ] = mode(ix)->maxWeight();
else _wquarkwgt [ix-3] = mode(ix)->maxWeight();
}
}
}
WidthCalculatorBasePtr SMTopDecayer::threeBodyMEIntegrator(const DecayMode & dm) const {
// identify W decay products
int sign = dm.parent()->id() > 0 ? 1 : -1;
int iferm(0),ianti(0);
for(ParticleMSet::const_iterator pit=dm.products().begin();
pit!=dm.products().end();++pit) {
int id = (**pit).id();
if(id*sign != ParticleID::b) {
if (id*sign > 0 ) iferm = id*sign;
else ianti = id*sign;
}
}
assert(iferm!=0&&ianti!=0);
// work out which mode we are doing
int imode(-1);
for(unsigned int ix=0;ix<numberModes();++ix) {
if(mode(ix)->externalParticles(2)->id() == ianti &&
mode(ix)->externalParticles(3)->id() == iferm ) {
imode = ix;
break;
}
}
assert(imode>=0);
// get the masses we need
Energy m[3] = {mode(imode)->externalParticles(1)->mass(),
mode(imode)->externalParticles(3)->mass(),
mode(imode)->externalParticles(2)->mass()};
return
new_ptr(ThreeBodyAllOn1IntegralCalculator<SMTopDecayer>
(3,_wplus->mass(),_wplus->width(),0.0,*this,imode,m[0],m[1],m[2]));
}
InvEnergy SMTopDecayer::threeBodydGammads(const int imode, const Energy2 mt2,
const Energy2 mffb2, const Energy mb,
const Energy mf, const Energy mfb) const {
Energy mffb(sqrt(mffb2));
Energy mw(_wplus->mass());
Energy2 mw2(sqr(mw)),gw2(sqr(_wplus->width()));
Energy mt(sqrt(mt2));
Energy Eb = 0.5*(mt2-mffb2-sqr(mb))/mffb;
Energy Ef = 0.5*(mffb2-sqr(mfb)+sqr(mf))/mffb;
Energy Ebm = sqrt(sqr(Eb)-sqr(mb));
Energy Efm = sqrt(sqr(Ef)-sqr(mf));
Energy2 upp = sqr(Eb+Ef)-sqr(Ebm-Efm);
Energy2 low = sqr(Eb+Ef)-sqr(Ebm+Efm);
InvEnergy width=(dGammaIntegrand(mffb2,upp,mt,mb,mf,mfb,mw)-
dGammaIntegrand(mffb2,low,mt,mb,mf,mfb,mw))
/32./mt2/mt/8/pow(Constants::pi,3)/(sqr(mffb2-mw2)+mw2*gw2);
// couplings
width *= 0.25*sqr(4.*Constants::pi*generator()->standardModel()->alphaEM(mt2)/
generator()->standardModel()->sin2ThetaW());
width *= generator()->standardModel()->CKM(*mode(imode)->externalParticles(0),
*mode(imode)->externalParticles(1));
if(abs(mode(imode)->externalParticles(2)->id())<=6) {
width *=3.;
if(abs(mode(imode)->externalParticles(2)->id())%2==0)
width *=generator()->standardModel()->CKM(*mode(imode)->externalParticles(2),
*mode(imode)->externalParticles(3));
else
width *=generator()->standardModel()->CKM(*mode(imode)->externalParticles(3),
*mode(imode)->externalParticles(2));
}
// final spin average
assert(!isnan(width*GeV));
return 0.5*width;
}
Energy6 SMTopDecayer::dGammaIntegrand(Energy2 mffb2, Energy2 mbf2, Energy mt,
Energy mb, Energy mf, Energy mfb, Energy mw) const {
Energy2 mt2(sqr(mt)) ,mb2(sqr(mb)) ,mf2(sqr(mf )),mfb2(sqr(mfb )),mw2(sqr(mw ));
Energy4 mt4(sqr(mt2)),mb4(sqr(mb2)),mf4(sqr(mf2)),mfb4(sqr(mfb2)),mw4(sqr(mw2));
return -mbf2 * ( + 6 * mb2 * mf2 * mfb2 * mffb2 + 6 * mb2 * mt2 * mfb2 * mffb2
+ 6 * mb2 * mt2 * mf2 * mffb2 + 12 * mb2 * mt2 * mf2 * mfb2
- 3 * mb2 * mfb4 * mffb2 + 3 * mb2 * mf2 * mffb2 * mffb2
- 3 * mb2 * mf4 * mffb2 - 6 * mb2 * mt2 * mfb4
- 6 * mb2 * mt2 * mf4 - 3 * mb4 * mfb2 * mffb2
- 3 * mb4 * mf2 * mffb2 - 6 * mb4 * mf2 * mfb2
+ 3 * mt4 * mf4 + 3 * mb4 * mfb4
+ 3 * mb4 * mf4 + 3 * mt4 * mfb4
+ 3 * mb2 * mfb2 * mffb2 * mffb2 + 3 * mt2 * mfb2 * mffb2 * mffb2
- 3 * mt2 * mfb4 * mffb2 + 3 * mt2 * mf2 * mffb2 * mffb2
- 3 * mt2 * mf4 * mffb2 - 3 * mt4 * mfb2 * mffb2
- 3 * mt4 * mf2 * mffb2 - 6 * mt4 * mf2 * mfb2
+ 6 * mt2 * mf2 * mfb2 * mffb2 + 12 * mt2 * mf2 * mw4
+ 12 * mb2 * mfb2 * mw4 + 12 * mb2 * mt2 * mw4
+ 6 * mw2 * mt2 * mfb2 * mbf2 - 12 * mw2 * mt2 * mf2 * mffb2
- 6 * mw2 * mt2 * mf2 * mbf2 - 12 * mw2 * mt2 * mf2 * mfb2
- 12 * mw2 * mb2 * mfb2 * mffb2 - 6 * mw2 * mb2 * mfb2 * mbf2
+ 6 * mw2 * mb2 * mf2 * mbf2 - 12 * mw2 * mb2 * mf2 * mfb2
- 12 * mw2 * mb2 * mt2 * mfb2 - 12 * mw2 * mb2 * mt2 * mf2
+ 12 * mf2 * mfb2 * mw4 + 4 * mbf2 * mbf2 * mw4
- 6 * mfb2 * mbf2 * mw4 - 6 * mf2 * mbf2 * mw4
- 6 * mt2 * mbf2 * mw4 - 6 * mb2 * mbf2 * mw4
+ 12 * mw2 * mt2 * mf4 + 12 * mw2 * mt4 * mf2
+ 12 * mw2 * mb2 * mfb4 + 12 * mw2 * mb4 * mfb2) /mw4 / 3.;
}
-void SMTopDecayer::initializeMECorrection(ShowerTreePtr tree, double & initial,
+void SMTopDecayer::initializeMECorrection(PerturbativeProcessPtr born, double & initial,
double & final) {
// check the outgoing particles
- map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cit;
- ShowerParticlePtr part[2];
+ PPtr part[2];
unsigned int ix(0);
- for(cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) {
- part[ix]=cit->first->progenitor();
+ for(unsigned int ix=0;ix<born->outgoing().size();++ix) {
+ part[ix]= born->outgoing()[ix].first;
++ix;
}
// check the final-state particles and get the masses
if(abs(part[0]->id())==ParticleID::Wplus&&abs(part[1]->id())==ParticleID::b) {
_ma=part[0]->mass();
_mc=part[1]->mass();
}
else if(abs(part[1]->id())==ParticleID::Wplus&&abs(part[0]->id())==ParticleID::b) {
_ma=part[1]->mass();
_mc=part[0]->mass();
}
else {
return;
}
// set the top mass
- _mt=tree->incomingLines().begin()->first->progenitor()->mass();
+ _mt=born->incoming()[0].first->mass();
// set the gluon mass
_mg=getParticleData(ParticleID::g)->constituentMass();
// set the radiation enhancement factors
initial = _initialenhance;
final = _finalenhance;
// reduced mass parameters
_a=sqr(_ma/_mt);
_g=sqr(_mg/_mt);
_c=sqr(_mc/_mt);
useMe();
}
-void SMTopDecayer::applyHardMatrixElementCorrection(ShowerTreePtr tree) {
- // Get b and a and put them in particle vector ba in that order...
- ParticleVector ba;
- map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cit;
- for(cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit)
- ba.push_back(cit->first->copy());
- PPtr temp;
- if(abs(ba[0]->id())!=5) swap(ba[0],ba[1]);
- // Get the starting scales for the showers $\tilde{\kappa}_{b}$
- // $\tilde{\kappa}_{c}$. These are needed in order to know the boundary
- // of the dead zone.
- _ktb = _ktc = -1.;
- map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cjt;
- for(cjt = tree->incomingLines().begin();
- cjt!= tree->incomingLines().end();++cjt) {
- if(abs(cjt->first->progenitor()->id())!=6) continue;
- if(cjt->first->progenitor()->id()>0)
- _ktb=sqr(cjt->first->progenitor()->scales().QCD_c /_mt);
- else
- _ktb=sqr(cjt->first->progenitor()->scales().QCD_ac/_mt);
- }
- for(cit = tree->outgoingLines().begin();
- cit!= tree->outgoingLines().end();++cit) {
- if(abs(cit->first->progenitor()->id())!=5) continue;
- if(cit->first->progenitor()->id()>0)
- _ktc=sqr(cit->first->progenitor()->scales().QCD_c /_mt);
- else
- _ktc=sqr(cit->first->progenitor()->scales().QCD_ac/_mt);
- }
- if (_ktb<=0.||_ktc<=0.) {
- throw Exception()
- << "SMTopDecayer::applyHardMatrixElementCorrection()"
- << " did not set ktb,ktc"
- << Exception::abortnow;
- }
- // Now decide if we get an emission into the dead region.
- // If there is an emission newfs stores momenta for a,c,g
- // according to NLO decay matrix element.
- vector<Lorentz5Momentum> newfs = applyHard(ba,_ktb,_ktc);
- // If there was no gluon emitted return.
- if(newfs.size()!=3) return;
- // Sanity checks to ensure energy greater than mass etc :)
- bool check = true;
- tcPDPtr gluondata=getParticleData(ParticleID::g);
- if (newfs[0].e()<ba[0]->data().constituentMass()) check = false;
- if (newfs[1].e()<ba[1]->mass()) check = false;
- if (newfs[2].e()<gluondata->constituentMass()) check = false;
- // Return if insane:
- if (!check) return;
- // Set masses in 5-vectors:
- newfs[0].setMass(ba[0]->mass());
- newfs[1].setMass(ba[1]->mass());
- newfs[2].setMass(ZERO);
- // The next part of this routine sets the colour structure.
- // To do this for decays we assume that the gluon comes from c!
- // First create new particle objects for c, a and gluon:
- PPtr newg = gluondata->produceParticle(newfs[2]);
- PPtr newc,newa;
- newc = ba[0]->data().produceParticle(newfs[0]);
- newa = ba[1];
- newa->set5Momentum(newfs[1]);
- // set the colour lines
- ColinePtr col;
- if(ba[0]->id()>0) {
- col=ba[0]->colourLine();
- col->addColoured(newg);
- newg->colourNeighbour(newc);
- }
- else {
- col=ba[0]->antiColourLine();
- col->addAntiColoured(newg);
- newg->antiColourNeighbour(newc);
- }
- // change the existing quark and antiquark
- PPtr orig;
- for(cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) {
- if(cit->first->progenitor()->id()==newc->id()) {
- // remove old particles from colour line
- if(newc->id()>0) {
- col->removeColoured(cit->first->copy());
- col->removeColoured(cit->first->progenitor());
- }
- else {
- col->removeAntiColoured(cit->first->copy());
- col->removeAntiColoured(cit->first->progenitor());
- }
- // insert new particles
- cit->first->copy(newc);
- ShowerParticlePtr sp(new_ptr(ShowerParticle(*newc,2,true)));
- cit->first->progenitor(sp);
- tree->outgoingLines()[cit->first]=sp;
- cit->first->perturbative(false);
- orig=cit->first->original();
- }
- else {
- cit->first->copy(newa);
- ShowerParticlePtr sp(new_ptr(ShowerParticle(*newa,2,true)));
- map<tShowerTreePtr,pair<tShowerProgenitorPtr,
- tShowerParticlePtr> >::const_iterator tit;
- for(tit = tree->treelinks().begin();
- tit != tree->treelinks().end();++tit) {
- if(tit->second.first && tit->second.second==cit->first->progenitor())
- break;
- }
- cit->first->progenitor(sp);
- if(tit!=tree->treelinks().end())
- tree->updateLink(tit->first,make_pair(cit->first,sp));
- tree->outgoingLines()[cit->first]=sp;
- cit->first->perturbative(true);
- }
- }
- // Add the gluon to the shower:
- ShowerParticlePtr sg =new_ptr(ShowerParticle(*newg,2,true));
- ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(orig,newg,sg));
- gluon->perturbative(false);
- tree->outgoingLines().insert(make_pair(gluon,sg));
- if(!inTheDeadRegion(_xg,_xa,_ktb,_ktc)) {
- generator()->log()
- << "SMTopDecayer::applyHardMatrixElementCorrection()\n"
- << "Just found a point that escaped from the dead region!\n"
- << " _xg: " << _xg << " _xa: " << _xa
- << " newfs.size(): " << newfs.size() << endl;
- }
- tree->hardMatrixElementCorrection(true);
+RealEmissionProcessPtr SMTopDecayer::applyHardMatrixElementCorrection(PerturbativeProcessPtr born) {
+ assert(false);
+ return RealEmissionProcessPtr();
+ // // Get b and a and put them in particle vector ba in that order...
+ // ParticleVector ba;
+ // map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cit;
+ // for(cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit)
+ // ba.push_back(cit->first->copy());
+ // PPtr temp;
+ // if(abs(ba[0]->id())!=5) swap(ba[0],ba[1]);
+ // // Get the starting scales for the showers $\tilde{\kappa}_{b}$
+ // // $\tilde{\kappa}_{c}$. These are needed in order to know the boundary
+ // // of the dead zone.
+ // _ktb = _ktc = -1.;
+ // map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cjt;
+ // for(cjt = tree->incomingLines().begin();
+ // cjt!= tree->incomingLines().end();++cjt) {
+ // if(abs(cjt->first->progenitor()->id())!=6) continue;
+ // if(cjt->first->progenitor()->id()>0)
+ // _ktb=sqr(cjt->first->progenitor()->scales().QCD_c /_mt);
+ // else
+ // _ktb=sqr(cjt->first->progenitor()->scales().QCD_ac/_mt);
+ // }
+ // for(cit = tree->outgoingLines().begin();
+ // cit!= tree->outgoingLines().end();++cit) {
+ // if(abs(cit->first->progenitor()->id())!=5) continue;
+ // if(cit->first->progenitor()->id()>0)
+ // _ktc=sqr(cit->first->progenitor()->scales().QCD_c /_mt);
+ // else
+ // _ktc=sqr(cit->first->progenitor()->scales().QCD_ac/_mt);
+ // }
+ // if (_ktb<=0.||_ktc<=0.) {
+ // throw Exception()
+ // << "SMTopDecayer::applyHardMatrixElementCorrection()"
+ // << " did not set ktb,ktc"
+ // << Exception::abortnow;
+ // }
+ // // Now decide if we get an emission into the dead region.
+ // // If there is an emission newfs stores momenta for a,c,g
+ // // according to NLO decay matrix element.
+ // vector<Lorentz5Momentum> newfs = applyHard(ba,_ktb,_ktc);
+ // // If there was no gluon emitted return.
+ // if(newfs.size()!=3) return;
+ // // Sanity checks to ensure energy greater than mass etc :)
+ // bool check = true;
+ // tcPDPtr gluondata=getParticleData(ParticleID::g);
+ // if (newfs[0].e()<ba[0]->data().constituentMass()) check = false;
+ // if (newfs[1].e()<ba[1]->mass()) check = false;
+ // if (newfs[2].e()<gluondata->constituentMass()) check = false;
+ // // Return if insane:
+ // if (!check) return;
+ // // Set masses in 5-vectors:
+ // newfs[0].setMass(ba[0]->mass());
+ // newfs[1].setMass(ba[1]->mass());
+ // newfs[2].setMass(ZERO);
+ // // The next part of this routine sets the colour structure.
+ // // To do this for decays we assume that the gluon comes from c!
+ // // First create new particle objects for c, a and gluon:
+ // PPtr newg = gluondata->produceParticle(newfs[2]);
+ // PPtr newc,newa;
+ // newc = ba[0]->data().produceParticle(newfs[0]);
+ // newa = ba[1];
+ // newa->set5Momentum(newfs[1]);
+ // // set the colour lines
+ // ColinePtr col;
+ // if(ba[0]->id()>0) {
+ // col=ba[0]->colourLine();
+ // col->addColoured(newg);
+ // newg->colourNeighbour(newc);
+ // }
+ // else {
+ // col=ba[0]->antiColourLine();
+ // col->addAntiColoured(newg);
+ // newg->antiColourNeighbour(newc);
+ // }
+ // // change the existing quark and antiquark
+ // PPtr orig;
+ // for(cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit) {
+ // if(cit->first->progenitor()->id()==newc->id()) {
+ // // remove old particles from colour line
+ // if(newc->id()>0) {
+ // col->removeColoured(cit->first->copy());
+ // col->removeColoured(cit->first->progenitor());
+ // }
+ // else {
+ // col->removeAntiColoured(cit->first->copy());
+ // col->removeAntiColoured(cit->first->progenitor());
+ // }
+ // // insert new particles
+ // cit->first->copy(newc);
+ // ShowerParticlePtr sp(new_ptr(ShowerParticle(*newc,2,true)));
+ // cit->first->progenitor(sp);
+ // tree->outgoingLines()[cit->first]=sp;
+ // cit->first->perturbative(false);
+ // orig=cit->first->original();
+ // }
+ // else {
+ // cit->first->copy(newa);
+ // ShowerParticlePtr sp(new_ptr(ShowerParticle(*newa,2,true)));
+ // map<tShowerTreePtr,pair<tShowerProgenitorPtr,
+ // tShowerParticlePtr> >::const_iterator tit;
+ // for(tit = tree->treelinks().begin();
+ // tit != tree->treelinks().end();++tit) {
+ // if(tit->second.first && tit->second.second==cit->first->progenitor())
+ // break;
+ // }
+ // cit->first->progenitor(sp);
+ // if(tit!=tree->treelinks().end())
+ // tree->updateLink(tit->first,make_pair(cit->first,sp));
+ // tree->outgoingLines()[cit->first]=sp;
+ // cit->first->perturbative(true);
+ // }
+ // }
+ // // Add the gluon to the shower:
+ // ShowerParticlePtr sg =new_ptr(ShowerParticle(*newg,2,true));
+ // ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(orig,newg,sg));
+ // gluon->perturbative(false);
+ // tree->outgoingLines().insert(make_pair(gluon,sg));
+ // if(!inTheDeadRegion(_xg,_xa,_ktb,_ktc)) {
+ // generator()->log()
+ // << "SMTopDecayer::applyHardMatrixElementCorrection()\n"
+ // << "Just found a point that escaped from the dead region!\n"
+ // << " _xg: " << _xg << " _xa: " << _xa
+ // << " newfs.size(): " << newfs.size() << endl;
+ // }
+ // tree->hardMatrixElementCorrection(true);
}
vector<Lorentz5Momentum> SMTopDecayer::
applyHard(const ParticleVector &p,double ktb, double ktc) {
// ********************************* //
// First we see if we get a dead //
// region event: _xa,_xg //
// ********************************* //
vector<Lorentz5Momentum> fs;
// Return if there is no (NLO) gluon emission:
double weight = getHard(ktb,ktc);
if(weight>1.) {
generator()->log() << "Weight greater than 1 for hard emission in "
<< "SMTopDecayer::applyHard xg = " << _xg
<< " xa = " << _xa << "\n";
weight=1.;
}
// Accept/Reject
if (weight<UseRandom::rnd()||p.size()!= 2) return fs;
// Drop events if getHard returned a negative weight
// as in events that, somehow have escaped from the dead region
// or, worse, the allowed region.
if(weight<0.) return fs;
// Calculate xc by momentum conservation:
_xc = 2.-_xa-_xg;
// ************************************ //
// Now we get the boosts & rotations to //
// go from lab to top rest frame with //
// a in the +z direction. //
// ************************************ //
Lorentz5Momentum pa_lab,pb_lab,pc_lab,pg_lab;
// Calculate momentum of b:
pb_lab = p[0]->momentum() + p[1]->momentum();
// Define/assign momenta of c,a and the gluon:
if(abs(p[0]->id())==5) {
pc_lab = p[0]->momentum();
pa_lab = p[1]->momentum();
} else {
pc_lab = p[1]->momentum();
pa_lab = p[0]->momentum();
}
// Calculate the boost to the b rest frame:
SpinOneLorentzRotation rot0(pb_lab.findBoostToCM());
// Calculate the rotation matrix to position a along the +z direction
// in the rest frame of b and does a random rotation about z:
SpinOneLorentzRotation rot1 = rotateToZ(rot0*pa_lab);
// Calculate the boost from the b rest frame back to the lab:
// and the inverse of the random rotation about the z-axis and the
// rotation required to align a with +z:
SpinOneLorentzRotation invrot = rot0.inverse()*rot1.inverse();
// ************************************ //
// Now we construct the momenta in the //
// b rest frame using _xa,_xg. //
// First we construct b, then c and g, //
// finally we generate a by momentum //
// conservation. //
// ************************************ //
Lorentz5Momentum pa_brf, pb_brf(_mt), pc_brf, pg_brf;
// First we set the top quark to being on-shell and at rest.
// Second we set the energies of c and g,
pc_brf.setE(0.5*_mt*(2.-_xa-_xg));
pg_brf.setE(0.5*_mt*_xg);
// then their masses,
pc_brf.setMass(_mc);
pg_brf.setMass(ZERO);
// Now set the z-component of c and g. For pg we simply start from
// _xa and _xg, while for pc we assume it is equal to minus the sum
// of the z-components of a (assumed to point in the +z direction) and g.
double root=sqrt(_xa*_xa-4.*_a);
pg_brf.setZ(_mt*(1.-_xa-_xg+0.5*_xa*_xg-_c+_a)/root);
pc_brf.setZ(-1.*( pg_brf.z()+_mt*0.5*root));
// Now set the y-component of c and g's momenta
pc_brf.setY(ZERO);
pg_brf.setY(ZERO);
// Now set the x-component of c and g's momenta
pg_brf.setX(sqrt(sqr(pg_brf.t())-sqr(pg_brf.z())));
pc_brf.setX(-pg_brf.x());
// Momenta b,c,g are now set. Now we obtain a from momentum conservation,
pa_brf = pb_brf-pc_brf-pg_brf;
pa_brf.setMass(pa_brf.m());
pa_brf.rescaleEnergy();
// ************************************ //
// Now we orient the momenta and boost //
// them back to the original lab frame. //
// ************************************ //
// As in herwig6507 we assume that, in the rest frame
// of b, we have aligned the W boson momentum in the
// +Z direction by rot1*rot0*pa_lab, therefore
// we obtain the new pa_lab by applying:
// invrot*pa_brf.
pa_lab = invrot*pa_brf;
pb_lab = invrot*pb_brf;
pc_lab = invrot*pc_brf;
pg_lab = invrot*pg_brf;
fs.push_back(pc_lab);
fs.push_back(pa_lab);
fs.push_back(pg_lab);
return fs;
}
double SMTopDecayer::getHard(double ktb, double ktc) {
// zero the variables
_xg = 0.;
_xa = 0.;
_xc = 0.;
// Get a phase space point in the dead region:
double volume_factor = deadRegionxgxa(ktb,ktc);
// if outside region return -1
if(volume_factor<0) return volume_factor;
// Compute the weight for this phase space point:
double weight = volume_factor*me(_xa,_xg)*(1.+_a-_c-_xa);
// Alpha_S and colour factors - this hard wired Alpha_S needs removing.
weight *= (4./3.)/Constants::pi
*(_alpha->value(_mt*_mt*_xg*(1.-_xa+_a-_c)
/(2.-_xg-_xa-_c)));
return weight;
}
bool SMTopDecayer::softMatrixElementVeto(ShowerProgenitorPtr initial,
ShowerParticlePtr parent,Branching br) {
// check if we need to apply the full correction
long id[2]={abs(initial->progenitor()->id()),abs(parent->id())};
// the initial-state correction
if(id[0]==ParticleID::t&&id[1]==ParticleID::t) {
Energy pt=br.kinematics->pT();
// check if hardest so far
// if not just need to remove effect of enhancement
bool veto(false);
// if not hardest so far
if(pt<initial->highestpT())
veto=!UseRandom::rndbool(1./_initialenhance);
// if hardest so far do calculation
else {
// values of kappa and z
double z(br.kinematics->z()),kappa(sqr(br.kinematics->scale()/_mt));
// parameters for the translation
double w(1.-(1.-z)*(kappa-1.)),u(1.+_a-_c-(1.-z)*kappa),v(sqr(u)-4.*_a*w*z);
// veto if outside phase space
if(v<0.)
veto=true;
// otherwise calculate the weight
else {
v = sqrt(v);
double xa((0.5*(u+v)/w+0.5*(u-v)/z)),xg((1.-z)*kappa);
double f(me(xa,xg)),
J(0.5*(u+v)/sqr(w)-0.5*(u-v)/sqr(z)+_a*sqr(w-z)/(v*w*z));
double wgt(f*J*2./kappa/(1.+sqr(z)-2.*z/kappa)/_initialenhance);
// This next `if' prevents the hardest emission from the
// top shower ever entering the so-called T2 region of the
// phase space if that region is to be populated by the hard MEC.
if(_useMEforT2&&xg>xgbcut(_ktb)) wgt = 0.;
if(wgt>1.) {
generator()->log() << "Violation of maximum for initial-state "
<< " soft veto in "
<< "SMTopDecayer::softMatrixElementVeto"
<< "xg = " << xg << " xa = " << xa
<< "weight = " << wgt << "\n";
wgt=1.;
}
// compute veto from weight
veto = !UseRandom::rndbool(wgt);
}
// if not vetoed reset max
if(!veto) initial->highestpT(pt);
}
// if vetoing reset the scale
if(veto) parent->vetoEmission(br.type,br.kinematics->scale());
// return the veto
return veto;
}
// final-state correction
else if(id[0]==ParticleID::b&&id[1]==ParticleID::b) {
Energy pt=br.kinematics->pT();
// check if hardest so far
// if not just need to remove effect of enhancement
bool veto(false);
// if not hardest so far
if(pt<initial->highestpT()) return !UseRandom::rndbool(1./_finalenhance);
// if hardest so far do calculation
// values of kappa and z
double z(br.kinematics->z()),kappa(sqr(br.kinematics->scale()/_mt));
// momentum fractions
double xa(1.+_a-_c-z*(1.-z)*kappa),r(0.5*(1.+_c/(1.+_a-xa))),root(sqr(xa)-4.*_a);
if(root<0.) {
generator()->log() << "Imaginary root for final-state veto in "
<< "SMTopDecayer::softMatrixElementVeto"
<< "\nz = " << z << "\nkappa = " << kappa
<< "\nxa = " << xa
<< "\nroot^2= " << root;
parent->vetoEmission(br.type,br.kinematics->scale());
return true;
}
root=sqrt(root);
double xg((2.-xa)*(1.-r)-(z-r)*root);
// xfact (below) is supposed to equal xg/(1-z).
double xfact(z*kappa/2./(z*(1.-z)*kappa+_c)*(2.-xa-root)+root);
// calculate the full result
double f(me(xa,xg));
// jacobian
double J(z*root);
double wgt(f*J*2.*kappa/(1.+sqr(z)-2.*_c/kappa/z)/sqr(xfact)/_finalenhance);
if(wgt>1.) {
generator()->log() << "Violation of maximum for final-state soft veto in "
<< "SMTopDecayer::softMatrixElementVeto"
<< "xg = " << xg << " xa = " << xa
<< "weight = " << wgt << "\n";
wgt=1.;
}
// compute veto from weight
veto = !UseRandom::rndbool(wgt);
// if vetoing reset the scale
if(veto) parent->vetoEmission(br.type,br.kinematics->scale());
// return the veto
return veto;
}
// otherwise don't veto
else return !UseRandom::rndbool(1./_finalenhance);
}
double SMTopDecayer::me(double xw,double xg) {
double prop(1.+_a-_c-xw),xg2(sqr(xg));
double lambda=sqrt(1.+_a*_a+_c*_c-2.*_a-2.*_c-2.*_a*_c);
double denom=(1.-2*_a*_a+_a+_c*_a+_c*_c-2.*_c);
double wgt=-_c*xg2/prop+(1.-_a+_c)*xg-(prop*(1 - xg)+xg2)
+(0.5*(1.+2.*_a+_c)*sqr(prop-xg)*xg+2.*_a*prop*xg2)/denom;
return wgt/(lambda*prop);
}
// This function is auxiliary to the xab function.
double SMTopDecayer::xgbr(int toggle) {
return 1.+toggle*sqrt(_a)-_c*(1.-toggle*sqrt(_a))/(1.-_a);
}
// This function is auxiliary to the xab function.
double SMTopDecayer::ktr(double xgb, int toggle) {
return 2.*xgb/
(xgb+toggle*sqrt((1.-1./_a)
*(xgb-xgbr( 1))
*(xgb-xgbr(-1))));
}
// Function xab determines xa (2*W energy fraction) for a given value
// of xg (2*gluon energy fraction) and kappa tilde (q tilde squared over
// m_top squared). Hence this function allows you to draw 1: the total
// phase space volume in the xa vs xg plane 2: for a given value of
// kappa tilde (i.e. starting evolution scale) the associated contour
// in the xa vs xg plane (and hence the regions that either shower can
// populate). This calculation is done assuming the emission came from
// the top quark i.e. kappa tilde here is the q tilde squared of the TOP
// quark divided by m_top squared.
double SMTopDecayer::xab(double xgb, double kt, int toggle) {
double xab;
if(toggle==2) {
// This applies for g==0.&&kt==ktr(a,c,0.,xgb,1).
xab = -2.*_a*(xgb-2.)/(1.+_a-_c-xgb);
} else if(toggle==1) {
// This applies for kt==1&&g==0.
double lambda = sqrt(sqr(xgb-1.+_a+_c)-4.*_a*_c);
xab = (0.5/(kt-xgb))*(kt*(1.+_a-_c-xgb)-lambda)
+ (0.5/(kt+xgb*(1.-kt)))*(kt*(1.+_a-_c-xgb)+lambda);
} else {
// This is the form of xab FOR _g=0.
double ktmktrpktmktrm = kt*kt - 4.*_a*(kt-1.)*xgb*xgb
/ (sqr(1.-_a-_c-xgb)-4.*_a*_c);
if(fabs(kt-(2.*xgb-2.*_g)/(xgb-sqrt(xgb*xgb-4.*_g)))/kt>1.e-6) {
double lambda = sqrt((sqr(1.-_a-_c-xgb)-4.*_a*_c)*ktmktrpktmktrm);
xab = (0.5/(kt-xgb))*(kt*(1.+_a-_c-xgb)-lambda)
+ (0.5/(kt+xgb*(1.-kt)))*(kt*(1.+_a-_c-xgb)+lambda);
}
else {
// This is the value of xa as a function of xb when kt->infinity.
// Where we take any kt > (2.*xgb-2.*_g)/(xgb-sqrt(xgb*xgb-4.*_g))
// as being effectively infinite. This kt value is actually the
// maximum allowed value kt can have if the phase space is calculated
// without the approximation of _g=0 (massless gluon). This formula
// for xab below is then valid for _g=0 AND kt=infinity only.
xab = ( 2.*_c+_a*(xgb-2.)
+ 3.*xgb
- xgb*(_c+xgb+sqrt(_a*_a-2.*(_c-xgb+1.)*_a+sqr(_c+xgb-1.)))
- 2.
)/2./(xgb-1.);
}
}
if(isnan(xab)) {
double ktmktrpktmktrm = ( sqr(xgb*kt-2.*(xgb-_g))
-kt*kt*(1.-1./_a)*(xgb-xgbr( 1)-_g/(1.+sqrt(_a)))
*(xgb-xgbr(-1)-_g/(1.-sqrt(_a)))
)/
(xgb*xgb-(1.-1./_a)*(xgb-xgbr( 1)-_g/(1.+sqrt(_a)))
*(xgb-xgbr(-1)-_g/(1.-sqrt(_a)))
);
double lambda = sqrt((xgb-1.+sqr(sqrt(_a)+sqrt(_c-_g)))
*(xgb-1.+sqr(sqrt(_a)-sqrt(_c-_g)))*
ktmktrpktmktrm);
xab = (0.5/(kt-xgb+_g))*(kt*(1.+_a-_c+_g-xgb)-lambda)
+ (0.5/(kt+xgb*(1.-kt)-_g))*(kt*(1.+_a-_c+_g-xgb)+lambda);
if(isnan(xab))
throw Exception() << "TopMECorrection::xab complex x_a value.\n"
<< " xgb = " << xgb << "\n"
<< " xab = " << xab << "\n"
<< " toggle = " << toggle << "\n"
<< " ktmktrpktmktrm = " << ktmktrpktmktrm
<< Exception::eventerror;
}
return xab;
}
// xgbcut is the point along the xg axis where the upper bound on the
// top quark (i.e. b) emission phase space goes back on itself in the
// xa vs xg plane i.e. roughly mid-way along the xg axis in
// the xa vs xg Dalitz plot.
double SMTopDecayer::xgbcut(double kt) {
double lambda2 = 1.+_a*_a+_c*_c-2.*_a-2.*_c-2.*_a*_c;
double num1 = kt*kt*(1.-_a-_c);
double num2 = 2.*kt*sqrt(_a*(kt*kt*_c+lambda2*(kt-1.)));
return (num1-num2)/(kt*kt-4.*_a*(kt-1.));
}
double SMTopDecayer::xaccut(double kt) {
return 1.+_a-_c-0.25*kt;
}
double SMTopDecayer::z(double xac, double kt,
int toggle1, int toggle2) {
double z = -1.0;
if(toggle2==0) {
z = (kt+toggle1*sqrt(kt*(kt-4.*(1.+_a-_c-xac))))/(2.*kt);
} else if(toggle2==1) {
z = ((1.+_a+_c-xac)+toggle1*(1.+_a-_c-xac))
/(2.*(1.+_a-xac));
} else if(toggle2==2) {
z = 0.5;
} else {
throw Exception() << "Cannot determine z in SMTopDecayer::z()"
<< Exception::eventerror;
}
return z;
}
double SMTopDecayer::xgc(double xac, double kt,
int toggle1, int toggle2) {
double tiny(1.e-6);
double xaToMinBoundary(xac*xac-4.*_a);
if(xaToMinBoundary<0) {
if(fabs(xaToMinBoundary/(1.-_a)/(1.-_a))<tiny)
xaToMinBoundary *= -1.;
else
throw Exception() << "SMTopDecayer::xgc xa not in phase space!"
<< Exception::eventerror;
}
return (2.-xac)*(1.-0.5*(1.+_c/(1.+_a-xac)))
-(z(xac,kt,toggle1,toggle2)-0.5*(1.+_c/(1.+_a-xac)))
*sqrt(xaToMinBoundary);
}
double SMTopDecayer::xginvc0(double xg , double kt) {
// The function xg(kappa_tilde_c,xa) surely, enough, draws a
// line of constant kappa_tilde_c in the xg, xa Dalitz plot.
// Such a function can therefore draw the upper and lower
// edges of the phase space for emission from c (the b-quark).
// However, to sample the soft part of the dead zone effectively
// we want to generate a value of xg first and THEN distribute
// xa in the associated allowed part of the dead zone. Hence, the
// function we want, to define the dead zone in xa for a given
// xg, is the inverse of xg(kappa_tilde_c,xa). The full expression
// for xg(kappa_tilde_c,xa) is complicated and, sure enough,
// does not invert. Therefore we try to overestimate the size
// of the dead zone initially, rejecting events which do not
// fall exactly inside it afterwards, with the immediate aim
// of getting an approximate version of xg(kappa_tilde_c,xa)
// that can be inverted. We do this by simply setting c=0 i.e.
// the b-quark mass to zero (and the gluon mass of course), in
// the full expression xg(...). The result of inverting this
// function is the output of this routine (a value of xa) hence
// the name xginvc0. xginvc0 is calculated to be,
// xginvc0 = (1./3.)*(1.+a+pow((U+sqrt(4.*V*V*V+U*U))/2.,1./3.)
// -V*pow(2./(U+sqrt(4.*V*V*V+U*U)),1./3.)
// )
// U = 2.*a*a*a - 66.*a*a + 9.*a*kt*xg + 18.*a*kt
// - 66.*a + 27.*kt*xg*xg - 45.*kt*xg +18.*kt +2. ;
// V = -1.-a*a-14.*a-3.kt*xg+3.*kt;
// This function, as with many functions in this ME correction,
// is plagued by cuts that have to handled carefully in numerical
// implementation. We have analysed the cuts and hence we implement
// it in the following way, with a series of 'if' statements.
//
// A useful -definition- to know in deriving the v<0 terms is
// that tanh^-1(z) = 0.5*(log(1.+z)-log(1.-z)).
double u,v,output;
u = 2.*_a*_a*_a-66.*_a*_a
+9.*xg*kt*_a+18.*kt*_a
-66.*_a+27.*xg*xg*kt
-45.*xg*kt+18.*kt+2.;
v = -_a*_a-14.*_a-3.*xg*kt+3.*kt-1.;
double u2=u*u,v3=v*v*v;
if(v<0.) {
if(u>0.&&(4.*v3+u2)<0.) output = cos( atan(sqrt(-4.*v3-u2)/u)/3.);
else if(u>0.&&(4.*v3+u2)>0.) output = cosh(atanh(sqrt( 4.*v3+u2)/u)/3.);
else output = cos(( atan(sqrt(-4.*v3-u2)/u)
+Constants::pi)/3.);
output *= 2.*sqrt(-v);
} else {
output = sinh(log((u+sqrt(4.*v3+u2))/(2.*sqrt(v3)))/3.);
output *= 2.*sqrt(v);
}
if(isnan(output)||isinf(output)) {
throw Exception() << "TopMECorrection::xginvc0:\n"
<< "possible numerical instability detected.\n"
<< "\n v = " << v << " u = " << u << "\n4.*v3+u2 = " << 4.*v3+u2
<< "\n_a = " << _a << " ma = " << sqrt(_a*_mt*_mt/GeV2)
<< "\n_c = " << _c << " mc = " << sqrt(_c*_mt*_mt/GeV2)
<< "\n_g = " << _g << " mg = " << sqrt(_g*_mt*_mt/GeV2)
<< Exception::eventerror;
}
return ( 1.+_a +output)/3.;
}
double SMTopDecayer::approxDeadMaxxa(double xg,double ktb,double ktc) {
double maxxa(0.);
double x = min(xginvc0(xg,ktc),
xab(xg,(2.*xg-2.*_g)/(xg-sqrt(xg*xg-4.*_g)),0));
double y(-9999999999.);
if(xg>2.*sqrt(_g)&&xg<=xgbcut(ktb)) {
y = max(xab(xg,ktb,0),xab(xg,1.,1));
} else if(xg>=xgbcut(ktb)&&xg<=1.-sqr(sqrt(_a)+sqrt(_c))) {
y = max(xab(xg,ktr(xg,1),2),xab(xg,1.,1));
}
if(xg>2.*sqrt(_g)&&xg<=1.-sqr(sqrt(_a)+sqrt(_c))) {
if(x>=y) { maxxa = x ; }
else { maxxa = -9999999.; }
} else {
maxxa = -9999999.;
}
return maxxa;
}
double SMTopDecayer::approxDeadMinxa(double xg,double ktb,double ktc) {
double minxa(0.);
double x = min(xginvc0(xg,ktc),
xab(xg,(2.*xg-2.*_g)/(xg-sqrt(xg*xg-4.*_g)),0));
double y(-9999999999.);
if(xg>2.*sqrt(_g)&&xg<=xgbcut(ktb)) {
y = max(xab(xg,ktb,0),xab(xg,1.,1));
} else if(xg>=xgbcut(ktb)&&xg<=1.-sqr(sqrt(_a)+sqrt(_c))) {
if(_useMEforT2) y = xab(xg,1.,1);
else y = max(xab(xg,ktr(xg,1),2),xab(xg,1.,1));
}
if(xg>2.*sqrt(_g)&&xg<=1.-sqr(sqrt(_a)+sqrt(_c))) {
if(x>=y) { minxa = y ; }
else { minxa = 9999999.; }
} else {
minxa = 9999999.;
}
return minxa;
}
// This function returns true if the phase space point (xg,xa) is in the
// kinematically allowed phase space.
bool SMTopDecayer::inTheAllowedRegion(double xg , double xa) {
bool output(true);
if(xg<2.*sqrt(_g)||xg>1.-sqr(sqrt(_a)+sqrt(_c))) output = false;
if(xa<xab(xg,1.,1)) output = false;
if(xa>xab(xg,(2.*xg-2.*_g)/(xg-sqrt(xg*xg-4.*_g)),0)) output = false;
return output;
}
// This function returns true if the phase space point (xg,xa) is in the
// approximate (overestimated) dead region.
bool SMTopDecayer::inTheApproxDeadRegion(double xg , double xa,
double ktb, double ktc) {
bool output(true);
if(!inTheAllowedRegion(xg,xa)) output = false;
if(xa<approxDeadMinxa(xg,ktb,ktc)) output = false;
if(xa>approxDeadMaxxa(xg,ktb,ktc)) output = false;
return output;
}
// This function returns true if the phase space point (xg,xa) is in the
// dead region.
bool SMTopDecayer::inTheDeadRegion(double xg , double xa,
double ktb, double ktc) {
bool output(true);
if(!inTheApproxDeadRegion(xg,xa,ktb,ktc)) output = false;
if(xa>xaccut(ktc)) {
if(xg<xgc(max(xaccut(ktc),2.*sqrt(_a)),ktc, 1,2)&&
xg>xgc(xa,ktc, 1,0)) { output = false; }
if(xg>xgc(max(xaccut(ktc),2.*sqrt(_a)),ktc,-1,2)&&
xg<xgc(xa,ktc,-1,0)) { output = false; }
}
return output;
}
// This function attempts to generate a phase space point in the dead
// region and returns the associated phase space volume factor needed for
// the associated event weight.
double SMTopDecayer::deadRegionxgxa(double ktb,double ktc) {
_xg=0.;
_xa=0.;
// Here we set limits on xg and generate a value inside the bounds.
double xgmin(2.*sqrt(_g)),xgmax(1.-sqr(sqrt(_a)+sqrt(_c)));
// Generate _xg.
if(_xg_sampling==2.) {
_xg=xgmin*xgmax/(xgmin+UseRandom::rnd()*(xgmax-xgmin));
} else {
_xg=xgmin*xgmax/pow(( pow(xgmin,_xg_sampling-1.)
+ UseRandom::rnd()*(pow(xgmax,_xg_sampling-1.)
-pow(xgmin,_xg_sampling-1.))
),1./(_xg_sampling-1.));
}
// Here we set the bounds on _xa for given _xg.
if(_xg<xgmin||xgmin>xgmax)
throw Exception() << "TopMECorrection::deadRegionxgxa:\n"
<< "upper xg bound is less than the lower xg bound.\n"
<< "\n_xg = " << _xg
<< "\n2.*sqrt(_g) = " << 2.*sqrt(_g)
<< "\n_a = " << _a << " ma = " << sqrt(_a*_mt*_mt/GeV2)
<< "\n_c = " << _c << " mc = " << sqrt(_c*_mt*_mt/GeV2)
<< "\n_g = " << _g << " mg = " << sqrt(_g*_mt*_mt/GeV2)
<< Exception::eventerror;
double xamin(approxDeadMinxa(_xg,ktb,ktc));
double xamax(approxDeadMaxxa(_xg,ktb,ktc));
// Are the bounds sensible? If not return.
if(xamax<=xamin) return -1.;
_xa=1.+_a-(1.+_a-xamax)*pow((1.+_a-xamin)/(1.+_a-xamax),UseRandom::rnd());
// If outside the allowed region return -1.
if(!inTheDeadRegion(_xg,_xa,ktb,ktc)) return -1.;
// The integration volume for the weight
double xg_vol,xa_vol;
if(_xg_sampling==2.) {
xg_vol = (xgmax-xgmin)
/ (xgmax*xgmin);
} else {
xg_vol = (pow(xgmax,_xg_sampling-1.)-pow(xgmin,_xg_sampling-1.))
/ ((_xg_sampling-1.)*pow(xgmax*xgmin,_xg_sampling-1.));
}
xa_vol = log((1.+_a-xamin)/(1.+_a-xamax));
// Here we return the integral volume factor multiplied by the part of the
// weight left over which is not included in the BRACES function, i.e.
// the part of _xg^-2 which is not absorbed in the integration measure.
return xg_vol*xa_vol*pow(_xg,_xg_sampling-2.);
}
LorentzRotation SMTopDecayer::rotateToZ(Lorentz5Momentum v) {
// compute the rotation matrix
LorentzRotation trans;
// rotate so in z-y plane
trans.rotateZ(-atan2(v.y(),v.x()));
// rotate so along Z
trans.rotateY(-acos(v.z()/v.vect().mag()));
// generate random rotation
double c,s,cs;
do
{
c = 2.*UseRandom::rnd()-1.;
s = 2.*UseRandom::rnd()-1.;
cs = c*c+s*s;
}
while(cs>1.||cs==0.);
double cost=(c*c-s*s)/cs,sint=2.*c*s/cs;
// apply random azimuthal rotation
trans.rotateZ(atan2(sint,cost));
return trans;
}
diff --git a/Decay/Perturbative/SMTopDecayer.h b/Decay/Perturbative/SMTopDecayer.h
--- a/Decay/Perturbative/SMTopDecayer.h
+++ b/Decay/Perturbative/SMTopDecayer.h
@@ -1,523 +1,523 @@
// -*- C++ -*-
//
// SMTopDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_SMTopDecayer_H
#define HERWIG_SMTopDecayer_H
//
// This is the declaration of the SMTopDecayer class.
//
#include "Herwig/Decay/DecayIntegrator.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
#include "Herwig/Decay/DecayPhaseSpaceMode.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "Herwig/Shower/QTilde/Couplings/ShowerAlpha.fh"
namespace Herwig {
using namespace ThePEG;
using namespace ThePEG::Helicity;
/**
* \ingroup Decay
*
* The SMTopDecayer performs decays of the top quark into
* the bottom quark and qqbar pairs or to the bottom quark and lepton
* neutrino pairs via W boson exchange.
*/
class SMTopDecayer: public DecayIntegrator {
public:
/**
* The default constructor.
*/
SMTopDecayer();
public:
/**
* Virtual members to be overridden by inheriting classes
* which implement hard corrections
*/
//@{
/**
* Has an old fashioned ME correction
*/
virtual bool hasMECorrection() {return true;}
/**
* Initialize the ME correction
*/
- virtual void initializeMECorrection(ShowerTreePtr , double & ,
+ virtual void initializeMECorrection(PerturbativeProcessPtr , double & ,
double & );
/**
* Apply the hard matrix element correction to a given hard process or decay
*/
- virtual void applyHardMatrixElementCorrection(ShowerTreePtr);
+ virtual RealEmissionProcessPtr applyHardMatrixElementCorrection(PerturbativeProcessPtr);
/**
* 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:
/**
* Which of the possible decays is required
*/
virtual int modeNumber(bool & , tcPDPtr , const tPDVector & ) const {return -1;}
/**
* Check if this decayer can perfom the decay for a particular mode.
* Uses the modeNumber member but can be overridden
* @param parent The decaying particle
* @param children The decay products
*/
virtual bool accept(tcPDPtr parent, const tPDVector & children) const;
/**
* For a given decay mode and a given particle instance, perform the
* decay and return the decay products. As this is the base class this
* is not implemented.
* @return The vector of particles produced in the decay.
*/
virtual ParticleVector decay(const Particle & parent,
const tPDVector & children) const;
/**
* Return the matrix element squared for a given mode and phase-space channel.
* @param ichan The channel we are calculating the matrix element for.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the calculation of the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const;
/**
* Method to return an object to calculate the 3 (or higher body) partial width
* @param dm The DecayMode
* @return A pointer to a WidthCalculatorBase object capable of calculating the width
*/
virtual WidthCalculatorBasePtr threeBodyMEIntegrator(const DecayMode & dm) const;
/**
* The differential three body decay rate with one integral performed.
* @param imode The mode for which the matrix element is needed.
* @param q2 The scale, \e i.e. the mass squared of the decaying particle.
* @param s The invariant mass which still needs to be integrate over.
* @param m1 The mass of the first outgoing particle.
* @param m2 The mass of the second outgoing particle.
* @param m3 The mass of the third outgoing particle.
* @return The differential rate \f$\frac{d\Gamma}{ds}\f$
*/
virtual InvEnergy threeBodydGammads(const int imode, const Energy2 q2,
const Energy2 s, const Energy m1,
const Energy m2, const Energy m3) const;
/**
* Output the setup information for the particle database
* @param os The stream to output the information to
* @param header Whether or not to output the information for MySQL
*/
virtual void dataBaseOutput(ofstream & os,bool header) 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:
/**
* The integrand for the integrate partial width
*/
Energy6 dGammaIntegrand(Energy2 mffb2, Energy2 mbf2, Energy mt, Energy mb,
Energy mf, Energy mfb, Energy mw) const;
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const {return new_ptr(*this);}
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const {return new_ptr(*this);}
//@}
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving and
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
/**
* Initialize this object. Called in the run phase just before
* a run begins.
*/
virtual void doinitrun();
//@}
protected:
/**
* Apply the hard matrix element
*/
vector<Lorentz5Momentum> applyHard(const ParticleVector &p,double,double);
/**
* Get the weight for hard emission
*/
double getHard(double, double);
/**
* This function is auxiliary to the function \f$x_{a}\f$ (hXAB).
*/
double xgbr(int);
/**
* This function is auxiliary to the function \f$x_{a}\f$ (hXAB).
*/
double ktr(double,int);
/**
* This function determines \f$x_{a}\f$ as a function of \f$x_{g}\f$
* and \f$\kappa\f$ where \f$\kappa\f$ pertains to emissions from the
* b.
*/
double xab(double,double,int);
/**
* This function determines the point (\f$x_{g}\f$) where the condition that
* \f$x_{a}\f$ be real supersedes that due to the external input
* \f$\tilde{\kappa}\f$ where, again, \f$\kappa\f$ pertains to emissions from the
* b.
*/
double xgbcut(double);
/**
* This function determines the minimum value of \f$x_{a}\f$
* for a given \f$\tilde{\kappa}\f$ where \f$\kappa\f$ pertains to
* emissions from the c.
*/
double xaccut(double);
/**
* This function is auxiliary to the function \f$x_{g}\f$ (hXGC).
*/
double z(double,double,int,int);
/**
* This function determines \f$x_{g}\f$ as a function of \f$x_{a}\f$
* and \f$\kappa\f$ where \f$\kappa\f$ pertains to emissions from the
* c. It is multivalued, one selects a branch according to the
* second to last integer flag (+/-1). The last integer flag
* is used to select whether (1) or not (0) you wish to have the
* function for the special case of the full phase space, in which
* case the fifth argument \f$\kappa\f$ is irrelevant.
*/
double xgc(double,double,int,int);
/**
* This function, \f$x_{g,c=0}^{-1}\f$, returns \f$x_{a}\f$ as a function
* of \f$x_{g}\f$ for the special case of c=0, for emissions from c
* (the b-quark). The third input is \f$\tilde{\kappa}\f$ which pertains
* to emissions from c.
*/
double xginvc0(double,double);
/**
* For a given value of \f$x_{g}\f$ this returns the maximum value of \f$x_{a}\f$
* in the dead region.
*/
double approxDeadMaxxa(double,double,double);
/**
* For a given value of \f$x_{g}\f$ this returns the maximum value of \f$x_{a}\f$
* in the dead region.
*/
double approxDeadMinxa(double,double,double);
/**
* This function returns true or false according to whether the values
* xg,xa are in the allowed region, the kinematically accessible phase
* space.
*/
bool inTheAllowedRegion(double,double);
/**
* This function returns true or false according to whether the values
* xg,xa are exactly in the approximate dead region.
*/
bool inTheApproxDeadRegion(double,double,
double,double);
/**
* This function returns true or false according to whether the values
* xg,xa are exactly in the dead region.
*/
bool inTheDeadRegion(double,double,
double,double);
/**
* This function returns values of (\f$x_{g}\f$,\f$x_{a}\f$) distributed
* according to \f$\left(1+a-x_{a}\right)^{-1}x_{g}^{-2}\f$ in the
* approximate dead region.
*/
double deadRegionxgxa(double,double);
/**
* This rotation takes a 5-momentum and returns a rotation matrix
* such that it acts on the input 5-momentum so as to
* make it point in the +Z direction. Finally it performs a randomn
* rotation about the z-axis.
*/
LorentzRotation rotateToZ(Lorentz5Momentum);
/**
* Full matrix element with a factor of \f$\frac{\alpha_SC_F}{x_g^2\pi}\f$ removed.
* @param xw The momentum fraction of the W boson
* @param xg The momentum fraction of the gluon.
*/
double me(double xw, double xg);
/**
* Access to the strong coupling
*/
ShowerAlphaPtr coupling() { return _alpha;}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<SMTopDecayer> initSMTopDecayer;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
SMTopDecayer & operator=(const SMTopDecayer &);
/**
*Pointer to the W vertex
*/
AbstractFFVVertexPtr _wvertex;
/**
* Max weight for integration
*/
//@{
/**
* Weight \f$W\to q\bar{q}'\f$
*/
vector<double> _wquarkwgt;
/**
* Weight \f$W\to \ell \nu\f$
*/
vector<double> _wleptonwgt;
//@}
/**
* Pointer to the \f$W^\pm\f$
*/
PDPtr _wplus;
/**
* Spin density matrix for the decay
*/
mutable RhoDMatrix _rho;
/**
* 1st spinor for the decay
*/
mutable vector<SpinorWaveFunction > _inHalf;
/**
* 2nd spinor for the decay
*/
mutable vector<SpinorWaveFunction > _outHalf;
/**
* 1st barred spinor for the decay
*/
mutable vector<SpinorBarWaveFunction> _inHalfBar;
/**
* 2nd barred spinor for the decay
*/
mutable vector<SpinorBarWaveFunction> _outHalfBar;
/**
* The mass of the W boson
*/
Energy _ma;
/**
* The mass of the bottom quark
*/
Energy _mc;
/**
* The top mass
*/
Energy _mt;
/**
* The gluon mass.
*/
Energy _mg;
/**
* The mass ratio for the W.
*/
double _a;
/**
* The mass ratio for the bottom.
*/
double _c;
/**
* The mass ratio for the gluon.
*/
double _g;
/**
* Two times the energy fraction of a.
*/
double _ktb;
/**
* Two times the energy fraction of the gluon.
*/
double _ktc;
/**
* Two times the energy fraction of the gluon.
*/
double _xg;
/**
* Two times the energy fraction of a.
*/
double _xa;
/**
* Two times the energy fraction of c.
*/
double _xc;
/**
* This determines the hard matrix element importance
* sampling in _xg. _xg_sampling=2.0 samples as 1/xg^2.
*/
double _xg_sampling;
/**
* The enhancement factor for initial-state radiation
*/
double _initialenhance;
/**
* The enhancement factor for final-state radiation
*/
double _finalenhance;
/**
* This flag determines whether the T2 region in the decay shower
* (JHEP12(2003)_045) is populated by the ME correction (true) or
* the shower from the decaying particle.
*/
bool _useMEforT2;
/**
* Pointer to the coupling
*/
ShowerAlphaPtr _alpha;
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of SMTopDecayer. */
template <>
struct BaseClassTrait<Herwig::SMTopDecayer,1> {
/** Typedef of the first base class of SMTopDecayer. */
typedef Herwig::DecayIntegrator NthBase;
};
/** This template specialization informs ThePEG about the name of
* the SMTopDecayer class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::SMTopDecayer>
: public ClassTraitsBase<Herwig::SMTopDecayer> {
/** Return a platform-independent class name */
static string className() { return "Herwig::SMTopDecayer"; }
/** Return the name of the shared library be loaded to get
* access to the SMTopDecayer class and every other class it uses
* (except the base class). */
static string library() { return "HwPerturbativeDecay.so"; }
};
/** @endcond */
}
#endif /* HERWIG_SMTopDecayer_H */
diff --git a/Decay/Perturbative/SMTopPOWHEGDecayer.cc b/Decay/Perturbative/SMTopPOWHEGDecayer.cc
--- a/Decay/Perturbative/SMTopPOWHEGDecayer.cc
+++ b/Decay/Perturbative/SMTopPOWHEGDecayer.cc
@@ -1,407 +1,408 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SMTopPOWHEGDecayer class.
//
#include "SMTopPOWHEGDecayer.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/EventRecord/Particle.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
-#include "Herwig/Shower/QTilde/Base/HardTree.h"
-#include "Herwig/Shower/QTilde/Base/ShowerTree.h"
+#include "Herwig/Shower/RealEmissionProcess.h"
#include "Herwig/Shower/QTilde/Base/ShowerProgenitor.h"
#include "Herwig/Shower/QTilde/Base/ShowerParticle.h"
#include "Herwig/Shower/QTilde/Base/Branching.h"
using namespace Herwig;
SMTopPOWHEGDecayer::SMTopPOWHEGDecayer() : mt_(ZERO), w_(0.), b_(0.), w2_(0.), b2_(0.), pTmin_(GeV), pT_(ZERO)
{}
IBPtr SMTopPOWHEGDecayer::clone() const {
return new_ptr(*this);
}
IBPtr SMTopPOWHEGDecayer::fullclone() const {
return new_ptr(*this);
}
void SMTopPOWHEGDecayer::persistentOutput(PersistentOStream & os) const {
os << ounit(pTmin_,GeV);
}
void SMTopPOWHEGDecayer::persistentInput(PersistentIStream & is, int) {
is >> iunit(pTmin_,GeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SMTopPOWHEGDecayer,SMTopDecayer>
describeHerwigSMTopPOWHEGDecayer("Herwig::SMTopPOWHEGDecayer", "HwPerturbativeDecay.so");
void SMTopPOWHEGDecayer::Init() {
static ClassDocumentation<SMTopPOWHEGDecayer> documentation
("There is no documentation for the SMTopPOWHEGDecayer class");
static Parameter<SMTopPOWHEGDecayer,Energy> interfacepTmin
("pTmin",
"Minimum transverse momentum from gluon radiation",
&SMTopPOWHEGDecayer::pTmin_, GeV, 1.0*GeV, 0.0*GeV, 10.0*GeV,
false, false, Interface::limited);
}
-HardTreePtr SMTopPOWHEGDecayer::generateHardest(ShowerTreePtr tree) {
+RealEmissionProcessPtr SMTopPOWHEGDecayer::generateHardest(PerturbativeProcessPtr born) {
+ assert(false);
+ return RealEmissionProcessPtr();
- // get the bottom and W
- assert(tree->outgoingLines().size()==2);
- ShowerProgenitorPtr
- bProgenitor = tree->outgoingLines(). begin()->first,
- WProgenitor = tree->outgoingLines().rbegin()->first;
- if(abs(WProgenitor->id())!=ParticleID::Wplus)
- swap(bProgenitor,WProgenitor);
- // Get the top quark
- ShowerProgenitorPtr topProgenitor = tree->incomingLines().begin()->first;
- // masses of the particles
- mt_ = topProgenitor->progenitor()->momentum().mass();
- w_ = WProgenitor ->progenitor()->momentum().mass() / mt_;
- b_ = bProgenitor ->progenitor()->momentum().mass() / mt_;
- w2_ = sqr(w_);
- b2_ = sqr(b_);
+ // // get the bottom and W
+ // assert(tree->outgoingLines().size()==2);
+ // ShowerProgenitorPtr
+ // bProgenitor = tree->outgoingLines(). begin()->first,
+ // WProgenitor = tree->outgoingLines().rbegin()->first;
+ // if(abs(WProgenitor->id())!=ParticleID::Wplus)
+ // swap(bProgenitor,WProgenitor);
+ // // Get the top quark
+ // ShowerProgenitorPtr topProgenitor = tree->incomingLines().begin()->first;
+ // // masses of the particles
+ // mt_ = topProgenitor->progenitor()->momentum().mass();
+ // w_ = WProgenitor ->progenitor()->momentum().mass() / mt_;
+ // b_ = bProgenitor ->progenitor()->momentum().mass() / mt_;
+ // w2_ = sqr(w_);
+ // b2_ = sqr(b_);
- // find rotation fgrom lab to frame with W along -z
- LorentzRotation eventFrame( topProgenitor->progenitor()->momentum().findBoostToCM() );
- Lorentz5Momentum pspectator = eventFrame*WProgenitor->progenitor()->momentum();
- eventFrame.rotateZ( -pspectator.phi() );
- eventFrame.rotateY( -pspectator.theta() - Constants::pi );
+ // // find rotation fgrom lab to frame with W along -z
+ // LorentzRotation eventFrame( topProgenitor->progenitor()->momentum().findBoostToCM() );
+ // Lorentz5Momentum pspectator = eventFrame*WProgenitor->progenitor()->momentum();
+ // eventFrame.rotateZ( -pspectator.phi() );
+ // eventFrame.rotateY( -pspectator.theta() - Constants::pi );
- //invert it
- eventFrame.invert();
- //generate the hard emission
- vector<Lorentz5Momentum> momenta = hardMomenta();
+ // //invert it
+ // eventFrame.invert();
+ // //generate the hard emission
+ // vector<Lorentz5Momentum> momenta = hardMomenta();
- // if no emission return
- if(momenta.empty()) {
- topProgenitor->maximumpT(pTmin_,ShowerInteraction::QCD);
- bProgenitor ->maximumpT(pTmin_,ShowerInteraction::QCD);
- return HardTreePtr();
- }
+ // // if no emission return
+ // if(momenta.empty()) {
+ // topProgenitor->maximumpT(pTmin_,ShowerInteraction::QCD);
+ // bProgenitor ->maximumpT(pTmin_,ShowerInteraction::QCD);
+ // return HardTreePtr();
+ // }
- // rotate momenta back to the lab
- for(unsigned int ix=0;ix<momenta.size();++ix) {
- momenta[ix] *= eventFrame;
- }
+ // // rotate momenta back to the lab
+ // for(unsigned int ix=0;ix<momenta.size();++ix) {
+ // momenta[ix] *= eventFrame;
+ // }
- // get ParticleData objects
- tcPDPtr top = topProgenitor->progenitor()->dataPtr();
- tcPDPtr bottom = bProgenitor ->progenitor()->dataPtr();
- tcPDPtr Wboson = WProgenitor ->progenitor()->dataPtr();
- tcPDPtr gluon = getParticleData(ParticleID::g);
- // create new ShowerParticles
- ShowerParticlePtr emitter (new_ptr(ShowerParticle(bottom,true )));
- ShowerParticlePtr spectator(new_ptr(ShowerParticle(Wboson,true )));
- ShowerParticlePtr gauge (new_ptr(ShowerParticle(gluon ,true )));
- ShowerParticlePtr incoming (new_ptr(ShowerParticle(top ,false)));
- ShowerParticlePtr parent (new_ptr(ShowerParticle(bottom,true )));
- // set momenta
- emitter ->set5Momentum(momenta[1]);
- spectator->set5Momentum(momenta[2]);
- gauge ->set5Momentum(momenta[3]);
- incoming ->set5Momentum(topProgenitor->progenitor()->momentum());
- Lorentz5Momentum parentMomentum(momenta[1]+momenta[3]);
- parentMomentum.rescaleMass();
- parent->set5Momentum(parentMomentum);
- // Create the vectors of HardBranchings to create the HardTree:
- vector<HardBranchingPtr> spaceBranchings,allBranchings;
- // Incoming top quark
- spaceBranchings.push_back(new_ptr(HardBranching(incoming,SudakovPtr(),
- HardBranchingPtr(),
- HardBranching::Incoming)));
- // Outgoing particles from hard emission:
- HardBranchingPtr spectatorBranch(new_ptr(HardBranching(spectator,SudakovPtr(),
- HardBranchingPtr(),
- HardBranching::Outgoing)));
- HardBranchingPtr emitterBranch(new_ptr(HardBranching(parent,SudakovPtr(),
- HardBranchingPtr(),
- HardBranching::Outgoing)));
- emitterBranch->addChild(new_ptr(HardBranching(emitter,SudakovPtr(),
- HardBranchingPtr(),
- HardBranching::Outgoing)));
- emitterBranch->addChild(new_ptr(HardBranching(gauge,SudakovPtr(),
- HardBranchingPtr(),
- HardBranching::Outgoing)));
- emitterBranch->type(emitterBranch->branchingParticle()->id()>0 ?
- ShowerPartnerType::QCDColourLine :
- ShowerPartnerType::QCDAntiColourLine);
- allBranchings.push_back(spaceBranchings[0]);
- allBranchings.push_back(emitterBranch);
- allBranchings.push_back(spectatorBranch);
- // Make the HardTree from the HardBranching vectors.
- HardTreePtr hardtree = new_ptr(HardTree(allBranchings,spaceBranchings,
- ShowerInteraction::QCD));
- // Set the maximum pt for all other emissions
- topProgenitor->maximumpT(pT_,ShowerInteraction::QCD);
- bProgenitor ->maximumpT(pT_,ShowerInteraction::QCD);
- // Connect the particles with the branchings in the HardTree
- hardtree->connect( topProgenitor->progenitor(), spaceBranchings[0] );
- hardtree->connect( bProgenitor->progenitor(), allBranchings[1] );
- hardtree->connect( WProgenitor->progenitor(), allBranchings[2] );
- // colour flow
- ColinePtr newline=new_ptr(ColourLine());
- for(set<HardBranchingPtr>::const_iterator cit=hardtree->branchings().begin();
- cit!=hardtree->branchings().end();++cit) {
+ // // get ParticleData objects
+ // tcPDPtr top = topProgenitor->progenitor()->dataPtr();
+ // tcPDPtr bottom = bProgenitor ->progenitor()->dataPtr();
+ // tcPDPtr Wboson = WProgenitor ->progenitor()->dataPtr();
+ // tcPDPtr gluon = getParticleData(ParticleID::g);
+ // // create new ShowerParticles
+ // ShowerParticlePtr emitter (new_ptr(ShowerParticle(bottom,true )));
+ // ShowerParticlePtr spectator(new_ptr(ShowerParticle(Wboson,true )));
+ // ShowerParticlePtr gauge (new_ptr(ShowerParticle(gluon ,true )));
+ // ShowerParticlePtr incoming (new_ptr(ShowerParticle(top ,false)));
+ // ShowerParticlePtr parent (new_ptr(ShowerParticle(bottom,true )));
+ // // set momenta
+ // emitter ->set5Momentum(momenta[1]);
+ // spectator->set5Momentum(momenta[2]);
+ // gauge ->set5Momentum(momenta[3]);
+ // incoming ->set5Momentum(topProgenitor->progenitor()->momentum());
+ // Lorentz5Momentum parentMomentum(momenta[1]+momenta[3]);
+ // parentMomentum.rescaleMass();
+ // parent->set5Momentum(parentMomentum);
+ // // Create the vectors of HardBranchings to create the HardTree:
+ // vector<HardBranchingPtr> spaceBranchings,allBranchings;
+ // // Incoming top quark
+ // spaceBranchings.push_back(new_ptr(HardBranching(incoming,SudakovPtr(),
+ // HardBranchingPtr(),
+ // HardBranching::Incoming)));
+ // // Outgoing particles from hard emission:
+ // HardBranchingPtr spectatorBranch(new_ptr(HardBranching(spectator,SudakovPtr(),
+ // HardBranchingPtr(),
+ // HardBranching::Outgoing)));
+ // HardBranchingPtr emitterBranch(new_ptr(HardBranching(parent,SudakovPtr(),
+ // HardBranchingPtr(),
+ // HardBranching::Outgoing)));
+ // emitterBranch->addChild(new_ptr(HardBranching(emitter,SudakovPtr(),
+ // HardBranchingPtr(),
+ // HardBranching::Outgoing)));
+ // emitterBranch->addChild(new_ptr(HardBranching(gauge,SudakovPtr(),
+ // HardBranchingPtr(),
+ // HardBranching::Outgoing)));
+ // emitterBranch->type(emitterBranch->branchingParticle()->id()>0 ?
+ // ShowerPartnerType::QCDColourLine :
+ // ShowerPartnerType::QCDAntiColourLine);
+ // allBranchings.push_back(spaceBranchings[0]);
+ // allBranchings.push_back(emitterBranch);
+ // allBranchings.push_back(spectatorBranch);
+ // // Make the HardTree from the HardBranching vectors.
+ // HardTreePtr hardtree = new_ptr(HardTree(allBranchings,spaceBranchings,
+ // ShowerInteraction::QCD));
+ // // Set the maximum pt for all other emissions
+ // topProgenitor->maximumpT(pT_,ShowerInteraction::QCD);
+ // bProgenitor ->maximumpT(pT_,ShowerInteraction::QCD);
+ // // Connect the particles with the branchings in the HardTree
+ // hardtree->connect( topProgenitor->progenitor(), spaceBranchings[0] );
+ // hardtree->connect( bProgenitor->progenitor(), allBranchings[1] );
+ // hardtree->connect( WProgenitor->progenitor(), allBranchings[2] );
+ // // colour flow
+ // ColinePtr newline=new_ptr(ColourLine());
+ // for(set<HardBranchingPtr>::const_iterator cit=hardtree->branchings().begin();
+ // cit!=hardtree->branchings().end();++cit) {
- if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3)
- newline->addColoured((**cit).branchingParticle());
- else if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3bar)
- newline->addAntiColoured((**cit).branchingParticle());
- }
+ // if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3)
+ // newline->addColoured((**cit).branchingParticle());
+ // else if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3bar)
+ // newline->addAntiColoured((**cit).branchingParticle());
+ // }
- ColinePtr newLine2=new_ptr(ColourLine());
- if(emitter->dataPtr()->iColour()==PDT::Colour3) {
- allBranchings[1]->branchingParticle()->colourLine()->addColoured(gauge);
- newLine2->addColoured(emitter);
- newLine2->addAntiColoured(gauge);
- }
- else {
- allBranchings[1]->branchingParticle()->antiColourLine()->addAntiColoured(gauge);
- newLine2->addAntiColoured(emitter);
- newLine2->addColoured(gauge);
- }
- //return the tree
- return hardtree;
+ // ColinePtr newLine2=new_ptr(ColourLine());
+ // if(emitter->dataPtr()->iColour()==PDT::Colour3) {
+ // allBranchings[1]->branchingParticle()->colourLine()->addColoured(gauge);
+ // newLine2->addColoured(emitter);
+ // newLine2->addAntiColoured(gauge);
+ // }
+ // else {
+ // allBranchings[1]->branchingParticle()->antiColourLine()->addAntiColoured(gauge);
+ // newLine2->addAntiColoured(emitter);
+ // newLine2->addColoured(gauge);
+ // }
+ // //return the tree
+ // return hardtree;
}
vector<Lorentz5Momentum> SMTopPOWHEGDecayer::hardMomenta() {
double C = 6.3;
double ymax = 10.;
double ymin = -ymax;
vector<Lorentz5Momentum> particleMomenta (4);
Energy2 lambda = sqr(mt_)* sqrt( 1. + sqr(w2_) + sqr(b2_) - 2.*w2_ - 2.*b2_ - 2.*w2_*b2_);
//Calculate A
double A = (ymax - ymin) * C * (coupling()->overestimateValue() / (2.*Constants::pi));
Energy pTmax = mt_* (sqr(1.-w_) - b2_) / (2.*(1.-w_));
if (pTmax < pTmin_) particleMomenta.clear();
while (pTmax >= pTmin_) {
//Generate pT, y and phi values
Energy pT = pTmax * pow(UseRandom::rnd() , (1./A));
if (pT < pTmin_) {particleMomenta.clear(); break;}
double phi = UseRandom::rnd() * Constants::twopi;
double y = ymin + UseRandom::rnd() * (ymax-ymin);
double weight[2] = {0.,0.};
double xw[2], xb[2], xb_z[2], xg;
for (unsigned int j=0; j<2; j++) {
//Check if the momenta are physical
bool physical = calcMomenta(j, pT, y, phi, xg, xw[j], xb[j], xb_z[j],
particleMomenta);
if (! physical) continue;
//Check if point lies within phase space
bool inPS = psCheck(xg, xw[j]);
if (! inPS) continue;
//Calculate the ratio R/B
double meRatio = matrixElementRatio(particleMomenta);
//Calculate jacobian
Energy2 denom = (mt_ - particleMomenta[3].e()) *
particleMomenta[2].vect().mag() -
particleMomenta[2].e() * particleMomenta[3].z();
InvEnergy2 J = (particleMomenta[2].vect().mag2()) / (2.* lambda * denom);
//Calculate weight
weight[j] = meRatio * fabs(sqr(pT)*J) * coupling()->ratio(pT*pT) / C;
}
//Accept point if weight > R
if (weight[0] + weight[1] > UseRandom::rnd()) {
if (weight[0] > (weight[0] + weight[1])*UseRandom::rnd()) {
particleMomenta[1].setE( (mt_/2.)*xb [0]);
particleMomenta[1].setZ( (mt_/2.)*xb_z[0]);
particleMomenta[2].setE( (mt_/2.)*xw [0]);
particleMomenta[2].setZ(-(mt_/2.)*sqrt(sqr(xw[0])-4.*w2_));
}
else {
particleMomenta[1].setE( (mt_/2.)*xb [1]);
particleMomenta[1].setZ( (mt_/2.)*xb_z[1]);
particleMomenta[2].setE( (mt_/2.)*xw [1]);
particleMomenta[2].setZ(-(mt_/2.)*sqrt(sqr(xw[1])-4.*w2_));
}
pT_ = pT;
break;
}
//If there's no splitting lower the pT
pTmax = pT;
}
return particleMomenta;
}
bool SMTopPOWHEGDecayer::deadZoneCheck(double xw, double xg){
//veto events not in the dead cone
double Lambda = sqrt(1. + sqr(w2_) + sqr(b2_) - 2.*w2_ - 2.*b2_ - 2.*w2_*b2_);
double kappa = b2_ + 0.5*(1. - w2_ + b2_ + Lambda);
//invert xw for z values
double A = 1.;
double B = -1.;
double C = (1.+w2_-b2_-xw)/kappa;
if((sqr(B) - 4.*A*C) >= 0.){
double z[2];
z[0] = (-B + sqrt(sqr(B) - 4.*A*C))/(2.*A);
z[1] = (-B - sqrt(sqr(B) - 4.*A*C))/(2.*A);
double r = 0.5*(1. + b2_/(1. + w2_- xw));
double xg_lims [2];
xg_lims[0] = (2. - xw)*(1.-r) - (z[0]-r)*sqrt(sqr(xw) - 4.*w2_);
xg_lims[1] = (2. - xw)*(1.-r) - (z[1]-r)*sqrt(sqr(xw) - 4.*w2_);
double xg_low_lim = min(xg_lims[0], xg_lims[1]);
double xg_upp_lim = max(xg_lims[0], xg_lims[1]);
if (xg>=xg_low_lim && xg<=xg_upp_lim) return false;
}
double kappa_t = 1. + 0.5*(1. - w2_ + b2_ + Lambda);
double z = 1. - xg/kappa_t;
double u = 1. + w2_ - b2_ - (1.-z)*kappa_t;
double y = 1. - (1.-z)*(kappa_t-1.);
if (sqr(u) - 4.*w2_*y*z >= 0.){
double v = sqrt(sqr(u) - 4.*w2_*y*z);
double xw_lim = (u + v) / (2.*y) + (u - v) / (2.*z);
if (xw <= xw_lim) return false;
}
else if (sqr(u) - 4.*w2_*y*z < 0.){
double xg_lim = (8.*w2_ -2.*xw*(1-b2_+w2_))/(4.*w2_-2.*xw);
if (xg>=xg_lim) return false;
}
return true;
}
double SMTopPOWHEGDecayer::matrixElementRatio(
vector<Lorentz5Momentum> particleMomenta) {
double f = (1. + sqr(b2_) - 2.*sqr(w2_) + w2_ + w2_*b2_ - 2.*b2_);
double Nc = standardModel()->Nc();
double Cf = (sqr(Nc) - 1.) / (2.*Nc);
double B = f/w2_;
Energy2 PbPg = particleMomenta[1]*particleMomenta[3];
Energy2 PtPg = particleMomenta[0]*particleMomenta[3];
Energy2 PtPb = particleMomenta[0]*particleMomenta[1];
double R = Cf *((-4.*sqr(mt_)*f/w2_) * ((sqr(mt_)*b2_/sqr(PbPg)) +
(sqr(mt_)/sqr(PtPg)) - 2.*(PtPb/(PtPg*PbPg))) +
(16. + 8./w2_ + 8.*b2_/w2_) * ((PtPg/PbPg) + (PbPg/PtPg)) -
(16./w2_) * (1. + b2_));
return R/B;
}
bool SMTopPOWHEGDecayer::calcMomenta(int j, Energy pT, double y, double phi,
double& xg, double& xw, double& xb, double& xb_z,
vector<Lorentz5Momentum>& particleMomenta){
//Calculate xg
xg = 2.*pT*cosh(y) / mt_;
if (xg>(1. - sqr(b_ + w_)) || xg<0.) return false;
//Calculate xw
double xT = 2.*pT / mt_;
double A = 4. - 4.*xg + sqr(xT);
double B = 4.*(3.*xg - 2. + 2.*b2_ - 2.*w2_ - sqr(xg) - xg*b2_ + xg*w2_);
double L = 1. + sqr(w2_) + sqr(b2_) - 2.*w2_ - 2.*b2_ - 2.*w2_*b2_;
double det = 16.*( -L*sqr(xT) + pow(xT,4)*w2_ + 2.*xg*sqr(xT)*(1.-w2_-b2_) +
L*sqr(xg) - sqr(xg*xT)*(1. + w2_) + pow(xg,4) +
2.*pow(xg,3)*(- 1. + w2_ + b2_) );
if (det<0.) return false;
if (j==0) xw = (-B + sqrt(det))/(2.*A);
if (j==1) xw = (-B - sqrt(det))/(2.*A);
if (xw>(1. + w2_ - b2_) || xw<2.*w_) return false;
//Calculate xb
xb = 2. - xw - xg;
if (xb>(1. + b2_ - w2_) || xb<2.*b_) return false;
//Calculate xb_z
double epsilon_p = -sqrt(sqr(xw) - 4.*w2_) + xT*sinh(y) +
sqrt(sqr(xb) - 4.*b2_ - sqr(xT));
double epsilon_m = -sqrt(sqr(xw) - 4.*w2_) + xT*sinh(y) -
sqrt(sqr(xb) - 4.*b2_ - sqr(xT));
if (fabs(epsilon_p) < 1.e-10){
xb_z = sqrt(sqr(xb) - 4.*b2_ - sqr(xT));
}
else if (fabs(epsilon_m) < 1.e-10){
xb_z = -sqrt(sqr(xb) - 4.*b2_ - sqr(xT));
}
else return false;
//Check b is on shell
if (fabs((sqr(xb) - sqr(xT) - sqr(xb_z) - 4.*b2_))>1.e-10) return false;
//Calculate 4 momenta
particleMomenta[0].setE ( mt_);
particleMomenta[0].setX ( ZERO);
particleMomenta[0].setY ( ZERO);
particleMomenta[0].setZ ( ZERO);
particleMomenta[0].setMass( mt_);
particleMomenta[1].setE ( mt_*xb/2.);
particleMomenta[1].setX (-pT*cos(phi));
particleMomenta[1].setY (-pT*sin(phi));
particleMomenta[1].setZ ( mt_*xb_z/2.);
particleMomenta[1].setMass( mt_*b_);
particleMomenta[2].setE ( mt_*xw/2.);
particleMomenta[2].setX ( ZERO);
particleMomenta[2].setY ( ZERO);
particleMomenta[2].setZ (-mt_*sqrt(sqr(xw) - 4.*w2_)/2.);
particleMomenta[2].setMass( mt_*w_);
particleMomenta[3].setE ( pT*cosh(y));
particleMomenta[3].setX ( pT*cos(phi));
particleMomenta[3].setY ( pT*sin(phi));
particleMomenta[3].setZ ( pT*sinh(y));
particleMomenta[3].setMass( ZERO);
return true;
}
bool SMTopPOWHEGDecayer::psCheck(double xg, double xw) {
//Check is point is in allowed region of phase space
double xb_star = (1. - w2_ + b2_ - xg) / sqrt(1. - xg);
double xg_star = xg / sqrt(1. - xg);
if ((sqr(xb_star) - 4.*b2_) < 1e-10) return false;
double xw_max = (4. + 4.*w2_ - sqr(xb_star + xg_star) +
sqr(sqrt(sqr(xb_star) - 4.*b2_) + xg_star)) / 4.;
double xw_min = (4. + 4.*w2_ - sqr(xb_star + xg_star) +
sqr(sqrt(sqr(xb_star) - 4.*b2_) - xg_star)) / 4.;
if (xw < xw_min || xw > xw_max) return false;
return true;
}
diff --git a/Decay/Perturbative/SMTopPOWHEGDecayer.h b/Decay/Perturbative/SMTopPOWHEGDecayer.h
--- a/Decay/Perturbative/SMTopPOWHEGDecayer.h
+++ b/Decay/Perturbative/SMTopPOWHEGDecayer.h
@@ -1,166 +1,166 @@
// -*- C++ -*-
#ifndef Herwig_SMTopPOWHEGDecayer_H
#define Herwig_SMTopPOWHEGDecayer_H
//
// This is the declaration of the SMTopPOWHEGDecayer class.
//
#include "SMTopDecayer.h"
namespace Herwig {
using namespace ThePEG;
/**
* Here is the documentation of the SMTopPOWHEGDecayer class.
*
* @see \ref SMTopPOWHEGDecayerInterfaces "The interfaces"
* defined for SMTopPOWHEGDecayer.
*/
class SMTopPOWHEGDecayer: public SMTopDecayer {
public:
/**
* The default constructor.
*/
SMTopPOWHEGDecayer();
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return FSR;}
/**
* Apply the POWHEG style correction
*/
- virtual HardTreePtr generateHardest(ShowerTreePtr);
+ virtual RealEmissionProcessPtr generateHardest(PerturbativeProcessPtr);
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
protected:
/**
* check if event is in dead region
*/
bool deadZoneCheck(double xw, double xg);
protected:
/**
* Calculate matrix element ratio B/R
*/
double matrixElementRatio(vector<Lorentz5Momentum> particleMomenta);
protected:
/**
* Calculate momenta of t, b, W, g
*/
bool calcMomenta(int j, Energy pT, double y, double phi, double& xg,
double& xw, double& xb, double& xb_z,
vector<Lorentz5Momentum>& particleMomenta);
protected:
/**
* Check the calculated momenta are physical
*/
bool psCheck(double xg, double xw);
protected:
/**
* Return the momenta including the hard emission
*/
vector<Lorentz5Momentum> hardMomenta();
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
SMTopPOWHEGDecayer & operator=(const SMTopPOWHEGDecayer &);
private:
/**
* Top quark mass
*/
Energy mt_;
/**
* Reduced \f$W^\pm\f$ mass
*/
double w_;
/**
* Reduced bottom mass
*/
double b_;
/**
* Reduced \f$W^\pm\f$ mass squared
*/
double w2_;
/**
* Reduced bottom mass squared
*/
double b2_;
/**
* Minimum \f$p_T\f$
*/
Energy pTmin_;
/**
* Transverse momentum of the emission
*/
Energy pT_;
};
}
#endif /* Herwig_SMTopPOWHEGDecayer_H */
diff --git a/Decay/Perturbative/SMWDecayer.cc b/Decay/Perturbative/SMWDecayer.cc
--- a/Decay/Perturbative/SMWDecayer.cc
+++ b/Decay/Perturbative/SMWDecayer.cc
@@ -1,667 +1,634 @@
// -*- C++ -*-
//
// SMWDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SMWDecayer class.
//
#include "SMWDecayer.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/ParVector.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "Herwig/Decay/DecayVertex.h"
#include "ThePEG/Helicity/VectorSpinInfo.h"
#include "ThePEG/Helicity/FermionSpinInfo.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
-#include "Herwig/Shower/QTilde/Base/ShowerTree.h"
#include "Herwig/Shower/QTilde/Base/ShowerProgenitor.h"
#include "Herwig/Shower/QTilde/Base/ShowerParticle.h"
#include "Herwig/Shower/QTilde/Base/Branching.h"
+#include "Herwig/Shower/RealEmissionProcess.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
const double SMWDecayer::EPS_=0.00000001;
SMWDecayer::SMWDecayer()
: quarkWeight_(6,0.), leptonWeight_(3,0.) {
quarkWeight_[0] = 1.01596;
quarkWeight_[1] = 0.0537308;
quarkWeight_[2] = 0.0538085;
quarkWeight_[3] = 1.01377;
quarkWeight_[4] = 1.45763e-05;
quarkWeight_[5] = 0.0018143;
leptonWeight_[0] = 0.356594;
leptonWeight_[1] = 0.356593;
leptonWeight_[2] = 0.356333;
// intermediates
generateIntermediates(false);
}
void SMWDecayer::doinit() {
DecayIntegrator::doinit();
// get the vertices from the Standard Model object
tcHwSMPtr hwsm=dynamic_ptr_cast<tcHwSMPtr>(standardModel());
if(!hwsm) throw InitException() << "Must have Herwig StandardModel object in"
<< "SMWDecayer::doinit()"
<< Exception::runerror;
FFWvertex_ = dynamic_ptr_cast<FFVVertexPtr>(hwsm->vertexFFW());
// make sure they are initialized
FFWvertex_->init();
// now set up the decay modes
DecayPhaseSpaceModePtr mode;
tPDVector extpart(3);
vector<double> wgt(0);
// W modes
extpart[0]=getParticleData(ParticleID::Wplus);
// loop for the quarks
unsigned int iz=0;
for(int ix=1;ix<6;ix+=2) {
for(int iy=2;iy<6;iy+=2) {
// check that the combination of particles is allowed
if(!FFWvertex_->allowed(-ix,iy,ParticleID::Wminus))
throw InitException() << "SMWDecayer::doinit() the W vertex"
<< "cannot handle all the quark modes"
<< Exception::abortnow;
extpart[1] = getParticleData(-ix);
extpart[2] = getParticleData( iy);
mode = new_ptr(DecayPhaseSpaceMode(extpart,this));
addMode(mode,quarkWeight_[iz],wgt);
++iz;
}
}
// loop for the leptons
for(int ix=11;ix<17;ix+=2) {
// check that the combination of particles is allowed
// if(!FFWvertex_->allowed(-ix,ix+1,ParticleID::Wminus))
// throw InitException() << "SMWDecayer::doinit() the W vertex"
// << "cannot handle all the lepton modes"
// << Exception::abortnow;
extpart[1] = getParticleData(-ix);
extpart[2] = getParticleData(ix+1);
mode = new_ptr(DecayPhaseSpaceMode(extpart,this));
addMode(mode,leptonWeight_[(ix-11)/2],wgt);
}
}
int SMWDecayer::modeNumber(bool & cc,tcPDPtr parent,
const tPDVector & children) const {
int imode(-1);
if(children.size()!=2) return imode;
int id0=parent->id();
tPDVector::const_iterator pit = children.begin();
int id1=(**pit).id();
++pit;
int id2=(**pit).id();
if(abs(id0)!=ParticleID::Wplus) return imode;
int idd(0),idu(0);
if(abs(id1)%2==1&&abs(id2)%2==0) {
idd=abs(id1);
idu=abs(id2);
}
else if(abs(id1)%2==0&&abs(id2)%2==1) {
idd=abs(id2);
idu=abs(id1);
}
if(idd==0&&idu==0) {
return imode;
}
else if(idd<=5) {
imode=idd+idu/2-2;
}
else {
imode=(idd-1)/2+1;
}
cc= (id0==ParticleID::Wminus);
return imode;
}
void SMWDecayer::persistentOutput(PersistentOStream & os) const {
os << FFWvertex_ << quarkWeight_ << leptonWeight_ << alpha_;
}
void SMWDecayer::persistentInput(PersistentIStream & is, int) {
is >> FFWvertex_ >> quarkWeight_ >> leptonWeight_ >> alpha_;
}
ClassDescription<SMWDecayer> SMWDecayer::initSMWDecayer;
// Definition of the static class description member.
void SMWDecayer::Init() {
static ClassDocumentation<SMWDecayer> documentation
("The SMWDecayer class is the implementation of the decay"
" of the W boson to the Standard Model fermions.");
static ParVector<SMWDecayer,double> interfaceWquarkMax
("QuarkMax",
"The maximum weight for the decay of the W to quarks",
&SMWDecayer::quarkWeight_,
0, 0, 0, -10000, 10000, false, false, true);
static ParVector<SMWDecayer,double> interfaceWleptonMax
("LeptonMax",
"The maximum weight for the decay of the W to leptons",
&SMWDecayer::leptonWeight_,
0, 0, 0, -10000, 10000, false, false, true);
static Reference<SMWDecayer,ShowerAlpha> interfaceCoupling
("Coupling",
"Pointer to the object to calculate the coupling for the correction",
&SMWDecayer::alpha_, false, false, true, false, false);
}
// return the matrix element squared
double SMWDecayer::me2(const int, const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1Half,PDT::Spin1Half)));
int iferm(1),ianti(0);
if(decay[0]->id()>0) swap(iferm,ianti);
if(meopt==Initialize) {
VectorWaveFunction::calculateWaveFunctions(_vectors,_rho,
const_ptr_cast<tPPtr>(&inpart),
incoming,false);
}
if(meopt==Terminate) {
VectorWaveFunction::constructSpinInfo(_vectors,const_ptr_cast<tPPtr>(&inpart),
incoming,true,false);
SpinorBarWaveFunction::
constructSpinInfo(_wavebar,decay[iferm],outgoing,true);
SpinorWaveFunction::
constructSpinInfo(_wave ,decay[ianti],outgoing,true);
return 0.;
}
SpinorBarWaveFunction::
calculateWaveFunctions(_wavebar,decay[iferm],outgoing);
SpinorWaveFunction::
calculateWaveFunctions(_wave ,decay[ianti],outgoing);
// compute the matrix element
Energy2 scale(sqr(inpart.mass()));
for(unsigned int ifm=0;ifm<2;++ifm) {
for(unsigned int ia=0;ia<2;++ia) {
for(unsigned int vhel=0;vhel<3;++vhel) {
if(iferm>ianti) (*ME())(vhel,ia,ifm)=
FFWvertex_->evaluate(scale,_wave[ia],_wavebar[ifm],_vectors[vhel]);
else (*ME())(vhel,ifm,ia)=
FFWvertex_->evaluate(scale,_wave[ia],_wavebar[ifm],_vectors[vhel]);
}
}
}
double output=(ME()->contract(_rho)).real()*UnitRemoval::E2/scale;
if(abs(decay[0]->id())<=6) output*=3.;
if(decay[0]->hasColour()) decay[0]->antiColourNeighbour(decay[1]);
else if(decay[1]->hasColour()) decay[1]->antiColourNeighbour(decay[0]);
return output;
}
void SMWDecayer::doinitrun() {
DecayIntegrator::doinitrun();
if(initialize()) {
for(unsigned int ix=0;ix<numberModes();++ix) {
if(ix<6) quarkWeight_ [ix]=mode(ix)->maxWeight();
else leptonWeight_[ix-6]=mode(ix)->maxWeight();
}
}
}
void SMWDecayer::dataBaseOutput(ofstream & output,
bool header) const {
if(header) output << "update decayers set parameters=\"";
for(unsigned int ix=0;ix<quarkWeight_.size();++ix) {
output << "newdef " << name() << ":QuarkMax " << ix << " "
<< quarkWeight_[ix] << "\n";
}
for(unsigned int ix=0;ix<leptonWeight_.size();++ix) {
output << "newdef " << name() << ":LeptonMax " << ix << " "
<< leptonWeight_[ix] << "\n";
}
// parameters for the DecayIntegrator base class
DecayIntegrator::dataBaseOutput(output,false);
if(header) output << "\n\" where BINARY ThePEGName=\""
<< fullName() << "\";" << endl;
}
void SMWDecayer::
-initializeMECorrection(ShowerTreePtr tree, double & initial,
+initializeMECorrection(PerturbativeProcessPtr born, double & initial,
double & final) {
- map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cjt;
// get the quark and antiquark
ParticleVector qq;
- for(cjt=tree->outgoingLines().begin();cjt!=tree->outgoingLines().end();++cjt)
- qq.push_back(cjt->first->copy());
+ for(unsigned int ix=0;ix<born->outgoing().size();++ix)
+ qq.push_back(born->outgoing()[ix].first);
// ensure quark first
if(qq[0]->id()<0) swap(qq[0],qq[1]);
// centre of mass energy
d_Q_ = (qq[0]->momentum() + qq[1]->momentum()).m();
// quark mass
d_m_ = 0.5*(qq[0]->momentum().m()+qq[1]->momentum().m());
// set the other parameters
setRho(sqr(d_m_/d_Q_));
setKtildeSymm();
// otherwise can do it
initial=1.;
final =1.;
}
-void SMWDecayer::
-applyHardMatrixElementCorrection(ShowerTreePtr tree) {
+RealEmissionProcessPtr SMWDecayer::
+applyHardMatrixElementCorrection(PerturbativeProcessPtr born) {
// get the quark and antiquark
- ParticleVector qq;
- map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cit;
- for(cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit)
- qq.push_back(cit->first->copy());
- if(!qq[0]->dataPtr()->coloured()) return;
+ ParticleVector qq;
+ for(unsigned int ix=0;ix<born->outgoing().size();++ix)
+ qq.push_back(born->outgoing()[ix].first);
+ if(!qq[0]->dataPtr()->coloured()) return RealEmissionProcessPtr();
// ensure quark first
- if(qq[0]->id()<0) swap(qq[0],qq[1]);
+ bool order = qq[0]->id()<0;
+ if(order) swap(qq[0],qq[1]);
// get the momenta
vector<Lorentz5Momentum> newfs = applyHard(qq);
// return if no emission
- if(newfs.size()!=3) return;
+ if(newfs.size()!=3) return RealEmissionProcessPtr();
// perform final check to ensure energy greater than constituent mass
for (int i=0; i<2; i++) {
- if (newfs[i].e() < qq[i]->data().constituentMass()) return;
+ if (newfs[i].e() < qq[i]->data().constituentMass()) return RealEmissionProcessPtr();
}
if (newfs[2].e() < getParticleData(ParticleID::g)->constituentMass())
- return;
+ return RealEmissionProcessPtr();
// set masses
for (int i=0; i<2; i++) newfs[i].setMass(qq[i]->mass());
newfs[2].setMass(ZERO);
// decide which particle emits
bool firstEmits=
newfs[2].vect().perp2(newfs[0].vect())<
newfs[2].vect().perp2(newfs[1].vect());
// create the new quark, antiquark and gluon
PPtr newg = getParticleData(ParticleID::g)->produceParticle(newfs[2]);
- PPtr newq,newa;
- if(firstEmits) {
- newq = qq[0]->dataPtr()->produceParticle(newfs[0]);
- newa = new_ptr(Particle(*qq[1]));
- qq[1]->antiColourLine()->removeAntiColoured(newa);
- newa->set5Momentum(newfs[1]);
+ PPtr newq = qq[0]->dataPtr()->produceParticle(newfs[0]);
+ PPtr newa = qq[1]->dataPtr()->produceParticle(newfs[1]);
+ // create the output real emission process
+ RealEmissionProcessPtr real(new_ptr(RealEmissionProcess(born)));
+ for(unsigned int ix=0;ix<born->incoming().size();++ix) {
+ real->incoming().push_back(born->incoming()[ix]);
+ }
+ if(order) {
+ real->outgoing().push_back(make_pair(newq,PerturbativeProcessPtr()));
+ real->outgoing().push_back(make_pair(newa,PerturbativeProcessPtr()));
+ real->outgoing().push_back(make_pair(newg,PerturbativeProcessPtr()));
}
else {
- newq = new_ptr(Particle(*qq[0]));
- qq[0]->colourLine()->removeColoured(newq);
- newq->set5Momentum(newfs[0]);
- newa = qq[1]->dataPtr()->produceParticle(newfs[1]);
+ real->outgoing().push_back(make_pair(newa,PerturbativeProcessPtr()));
+ real->outgoing().push_back(make_pair(newq,PerturbativeProcessPtr()));
+ real->outgoing().push_back(make_pair(newg,PerturbativeProcessPtr()));
+ firstEmits = !firstEmits;
}
- // get the original colour line
- ColinePtr col;
- if(qq[0]->id()>0) col=qq[0]->colourLine();
- else col=qq[0]->antiColourLine();
- // set the colour lines
+ // make colour connections
+ newg->colourNeighbour(newq);
+ newa->colourNeighbour(newg);
if(firstEmits) {
- col->addColoured(newq);
- col->addAntiColoured(newg);
- newa->colourNeighbour(newg);
+ real->emitter(1);
+ real->spectator(2);
}
else {
- col->addAntiColoured(newa);
- col->addColoured(newg);
- newq->antiColourNeighbour(newg);
+ real->emitter(2);
+ real->spectator(1);
}
- // change the existing quark and antiquark
- PPtr orig;
- for(cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().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,true)));
- cit->first->progenitor(sp);
- tree->outgoingLines()[cit->first]=sp;
- cit->first->perturbative(!firstEmits);
- if(firstEmits) 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,true)));
- cit->first->progenitor(sp);
- tree->outgoingLines()[cit->first]=sp;
- cit->first->perturbative(firstEmits);
- if(!firstEmits) orig=cit->first->original();
- }
- }
- // 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);
+ return real;
}
vector<Lorentz5Momentum> SMWDecayer::
applyHard(const ParticleVector &p) {
double x, xbar;
vector<Lorentz5Momentum> fs;
// return if no emission
if (getHard(x, xbar) < UseRandom::rnd() || p.size() != 2) return fs;
// centre of mass energy
Lorentz5Momentum pcm = p[0]->momentum() + p[1]->momentum();
// momenta of quark,antiquark and gluon
Lorentz5Momentum pq, pa, pg;
if (p[0]->id() > 0) {
pq = p[0]->momentum();
pa = p[1]->momentum();
} else {
pa = p[0]->momentum();
pq = p[1]->momentum();
}
// boost to boson rest frame
Boost beta = (pcm.findBoostToCM());
pq.boost(beta);
pa.boost(beta);
// return if fails ?????
double xg = 2.-x-xbar;
if((1.-x)*(1.-xbar)*(1.-xg) < d_rho_*xg*xg) return fs;
Axis u1, u2, u3;
// moduli of momenta in units of Q and cos theta
// stick to q direction?
// p1 is the one that is kept, p2 is the other fermion, p3 the gluon.
Energy e1, e2, e3;
Energy pp1, pp2, pp3;
bool keepq = true;
if (UseRandom::rnd() > sqr(x)/(sqr(x)+sqr(xbar)))
keepq = false;
if (keepq) {
pp1 = d_Q_*sqrt(sqr(x)-4.*d_rho_)/2.;
pp2 = d_Q_*sqrt(sqr(xbar)-4.*d_rho_)/2.;
e1 = d_Q_*x/2.;
e2 = d_Q_*xbar/2.;
u1 = pq.vect().unit();
} else {
pp2 = d_Q_*sqrt(sqr(x)-4.*d_rho_)/2.;
pp1 = d_Q_*sqrt(sqr(xbar)-4.*d_rho_)/2.;
e2 = d_Q_*x/2.;
e1 = d_Q_*xbar/2.;
u1 = pa.vect().unit();
}
pp3 = d_Q_*xg/2.;
e3 = pp3;
u2 = u1.orthogonal();
u2 /= u2.mag();
u3 = u1.cross(u2);
u3 /= u3.mag();
double ct2=-2., ct3=-2.;
if (pp1 == ZERO || pp2 == ZERO || pp3 == ZERO) {
bool touched = false;
if (pp1 == ZERO) {
ct2 = 1;
ct3 = -1;
touched = true;
}
if (pp2 == ZERO || pp3 == ZERO) {
ct2 = 1;
ct3 = 1;
touched = true;
}
if (!touched)
throw Exception() << "SMWDecayer::applyHard()"
<< " did not set ct2/3"
<< Exception::abortnow;
} else {
ct3 = (sqr(pp1)+sqr(pp3)-sqr(pp2))/(2.*pp1*pp3);
ct2 = (sqr(pp1)+sqr(pp2)-sqr(pp3))/(2.*pp1*pp2);
}
double phi = Constants::twopi*UseRandom::rnd();
double cphi = cos(phi);
double sphi = sin(phi);
double st2 = sqrt(1.-sqr(ct2));
double st3 = sqrt(1.-sqr(ct3));
ThreeVector<Energy> pv1, pv2, pv3;
pv1 = pp1*u1;
pv2 = -ct2*pp2*u1 + st2*cphi*pp2*u2 + st2*sphi*pp2*u3;
pv3 = -ct3*pp3*u1 - st3*cphi*pp3*u2 - st3*sphi*pp3*u3;
if (keepq) {
pq = Lorentz5Momentum(pv1, e1);
pa = Lorentz5Momentum(pv2, e2);
} else {
pa = Lorentz5Momentum(pv1, e1);
pq = Lorentz5Momentum(pv2, e2);
}
pg = Lorentz5Momentum(pv3, e3);
pq.boost(-beta);
pa.boost(-beta);
pg.boost(-beta);
fs.push_back(pq);
fs.push_back(pa);
fs.push_back(pg);
return fs;
}
double SMWDecayer::getHard(double &x1, double &x2) {
double w = 0.0;
double y1 = UseRandom::rnd(),y2 = UseRandom::rnd();
// simply double MC efficiency
// -> weight has to be divided by two (Jacobian)
if (y1 + y2 > 1) {
y1 = 1.-y1;
y2 = 1.-y2;
}
bool inSoft = false;
if (y1 < 0.25) {
if (y2 < 0.25) {
inSoft = true;
if (y1 < y2) {
y1 = 0.25-y1;
y2 = y1*(1.5 - 2.*y2);
} else {
y2 = 0.25 - y2;
y1 = y2*(1.5 - 2.*y1);
}
} else {
if (y2 < y1 + 2.*sqr(y1)) return w;
}
} else {
if (y2 < 0.25) {
if (y1 < y2 + 2.*sqr(y2)) return w;
}
}
// inside PS?
x1 = 1.-y1;
x2 = 1.-y2;
if(y1*y2*(1.-y1-y2) < d_rho_*sqr(y1+y2)) return w;
double k1 = getKfromX(x1, x2);
double k2 = getKfromX(x2, x1);
// Is it in the quark emission zone?
if (k1 < d_kt1_) return 0.0;
// No...is it in the anti-quark emission zone?
if (k2 < d_kt2_) return 0.0;
// Point is in dead zone: compute q qbar g weight
w = MEV(x1, x2);
// for axial:
// w = MEA(x1, x2);
// Reweight soft region
if (inSoft) {
if (y1 < y2) w *= 2.*y1;
else w *= 2.*y2;
}
// alpha and colour factors
Energy2 pt2 = sqr(d_Q_)*(1.-x1)*(1.-x2);
w *= 1./3./Constants::pi*alpha_->value(pt2);
return w;
}
bool SMWDecayer::
softMatrixElementVeto(ShowerProgenitorPtr initial,ShowerParticlePtr parent,Branching br) {
// check we should be applying the veto
if(parent->id()!=initial->progenitor()->id()||
br.ids[0]!=br.ids[1]||
br.ids[2]->id()!=ParticleID::g) return false;
// calculate pt
double d_z = br.kinematics->z();
Energy d_qt = br.kinematics->scale();
Energy2 d_m2 = parent->momentum().m2();
Energy2 pPerp2 = sqr(d_z*d_qt) - d_m2;
if(pPerp2<ZERO) {
parent->vetoEmission(br.type,br.kinematics->scale());
return true;
}
Energy pPerp = (1.-d_z)*sqrt(pPerp2);
// if not hardest so far don't apply veto
if(pPerp<initial->highestpT()) return false;
// calculate the weight
double weight = 0.;
if(parent->id()>0) weight = qWeightX(d_qt, d_z);
else weight = qbarWeightX(d_qt, d_z);
// compute veto from weight
bool veto = !UseRandom::rndbool(weight);
// if vetoing reset the scale
if(veto) parent->vetoEmission(br.type,br.kinematics->scale());
// return the veto
return veto;
}
void SMWDecayer::setRho(double r)
{
d_rho_ = r;
d_v_ = sqrt(1.-4.*d_rho_);
}
void SMWDecayer::setKtildeSymm() {
d_kt1_ = (1. + sqrt(1. - 4.*d_rho_))/2.;
setKtilde2();
}
void SMWDecayer::setKtilde2() {
double num = d_rho_ * d_kt1_ + 0.25 * d_v_ *(1.+d_v_)*(1.+d_v_);
double den = d_kt1_ - d_rho_;
d_kt2_ = num/den;
}
double SMWDecayer::getZfromX(double x1, double x2) {
double uval = u(x2);
double num = x1 - (2. - x2)*uval;
double den = sqrt(x2*x2 - 4.*d_rho_);
return uval + num/den;
}
double SMWDecayer::getKfromX(double x1, double x2) {
double zval = getZfromX(x1, x2);
return (1.-x2)/(zval*(1.-zval));
}
double SMWDecayer::MEV(double x1, double x2) {
// Vector part
double num = (x1+2.*d_rho_)*(x1+2.*d_rho_) + (x2+2.*d_rho_)*(x2+2.*d_rho_)
- 8.*d_rho_*(1.+2.*d_rho_);
double den = (1.+2.*d_rho_)*(1.-x1)*(1.-x2);
return (num/den - 2.*d_rho_/((1.-x1)*(1.-x1))
- 2*d_rho_/((1.-x2)*(1.-x2)))/d_v_;
}
double SMWDecayer::MEA(double x1, double x2) {
// Axial part
double num = (x1+2.*d_rho_)*(x1+2.*d_rho_) + (x2+2.*d_rho_)*(x2+2.*d_rho_)
+ 2.*d_rho_*((5.-x1-x2)*(5.-x1-x2) - 19.0 + 4*d_rho_);
double den = d_v_*d_v_*(1.-x1)*(1.-x2);
return (num/den - 2.*d_rho_/((1.-x1)*(1.-x1))
- 2*d_rho_/((1.-x2)*(1.-x2)))/d_v_;
}
double SMWDecayer::u(double x2) {
return 0.5*(1. + d_rho_/(1.-x2+d_rho_));
}
void SMWDecayer::
getXXbar(double kti, double z, double &x, double &xbar) {
double w = sqr(d_v_) + kti*(-1. + z)*z*(2. + kti*(-1. + z)*z);
if (w < 0) {
x = -1.;
xbar = -1;
} else {
x = (1. + sqr(d_v_)*(-1. + z) + sqr(kti*(-1. + z))*z*z*z
+ z*sqrt(w)
- kti*(-1. + z)*z*(2. + z*(-2 + sqrt(w))))/
(1. - kti*(-1. + z)*z + sqrt(w));
xbar = 1. + kti*(-1. + z)*z;
}
}
double SMWDecayer::qWeight(double x, double xbar) {
double rval;
double xg = 2. - xbar - x;
// always return one in the soft gluon region
if(xg < EPS_) return 1.0;
// check it is in the phase space
if((1.-x)*(1.-xbar)*(1.-xg) < d_rho_*xg*xg) return 0.0;
double k1 = getKfromX(x, xbar);
double k2 = getKfromX(xbar, x);
// Is it in the quark emission zone?
if(k1 < d_kt1_) {
rval = MEV(x, xbar)/PS(x, xbar);
// is it also in the anti-quark emission zone?
if(k2 < d_kt2_) rval *= 0.5;
return rval;
}
return 1.0;
}
double SMWDecayer::qbarWeight(double x, double xbar) {
double rval;
double xg = 2. - xbar - x;
// always return one in the soft gluon region
if(xg < EPS_) return 1.0;
// check it is in the phase space
if((1.-x)*(1.-xbar)*(1.-xg) < d_rho_*xg*xg) return 0.0;
double k1 = getKfromX(x, xbar);
double k2 = getKfromX(xbar, x);
// Is it in the antiquark emission zone?
if(k2 < d_kt2_) {
rval = MEV(x, xbar)/PS(xbar, x);
// is it also in the quark emission zone?
if(k1 < d_kt1_) rval *= 0.5;
return rval;
}
return 1.0;
}
double SMWDecayer::qWeightX(Energy qtilde, double z) {
double x, xb;
getXXbar(sqr(qtilde/d_Q_), z, x, xb);
// if exceptionally out of phase space, leave this emission, as there
// is no good interpretation for the soft ME correction.
if (x < 0 || xb < 0) return 1.0;
return qWeight(x, xb);
}
double SMWDecayer::qbarWeightX(Energy qtilde, double z) {
double x, xb;
getXXbar(sqr(qtilde/d_Q_), z, xb, x);
// see above in qWeightX.
if (x < 0 || xb < 0) return 1.0;
return qbarWeight(x, xb);
}
double SMWDecayer::PS(double x, double xbar) {
double u = 0.5*(1. + d_rho_ / (1.-xbar+d_rho_));
double z = u + (x - (2.-xbar)*u)/sqrt(xbar*xbar - 4.*d_rho_);
double brack = (1.+z*z)/(1.-z)- 2.*d_rho_/(1-xbar);
// interesting: the splitting function without the subtraction
// term. Actually gives a much worse approximation in the collinear
// limit. double brack = (1.+z*z)/(1.-z);
double den = (1.-xbar)*sqrt(xbar*xbar - 4.*d_rho_);
return brack/den;
}
diff --git a/Decay/Perturbative/SMWDecayer.h b/Decay/Perturbative/SMWDecayer.h
--- a/Decay/Perturbative/SMWDecayer.h
+++ b/Decay/Perturbative/SMWDecayer.h
@@ -1,417 +1,417 @@
// -*- C++ -*-
//
// SMWDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_SMWDecayer_H
#define HERWIG_SMWDecayer_H
//
// This is the declaration of the SMWDecayer class.
//
#include "Herwig/Decay/DecayIntegrator.h"
#include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVVVertex.h"
#include "Herwig/Decay/DecayPhaseSpaceMode.h"
#include "Herwig/Shower/QTilde/Couplings/ShowerAlpha.fh"
namespace Herwig {
using namespace ThePEG;
using namespace ThePEG::Helicity;
/** \ingroup Decay
*
* The <code>SMWDecayer</code> is designed to perform the decay of the
* W boson to the Standard Model fermions, including the first order
* electroweak corrections.
*
* @see DecayIntegrator
*
*/
class SMWDecayer: public DecayIntegrator {
public:
/**
* Default constructor.
*/
SMWDecayer();
public:
/**
* Virtual members to be overridden by inheriting classes
* which implement hard corrections
*/
//@{
/**
* Has an old fashioned ME correction
*/
virtual bool hasMECorrection() {return true;}
/**
* Initialize the ME correction
*/
- virtual void initializeMECorrection(ShowerTreePtr , double & ,
+ virtual void initializeMECorrection(PerturbativeProcessPtr , double & ,
double & );
/**
* Apply the hard matrix element correction to a given hard process or decay
*/
- virtual void applyHardMatrixElementCorrection(ShowerTreePtr);
+ virtual RealEmissionProcessPtr applyHardMatrixElementCorrection(PerturbativeProcessPtr);
/**
* 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:
/**
* Which of the possible decays is required
* @param cc Is this mode the charge conjugate
* @param parent The decaying particle
* @param children The decay products
*/
virtual int modeNumber(bool & cc, tcPDPtr parent,
const tPDVector & children) const;
/**
* Return the matrix element squared for a given mode and phase-space channel.
* @param ichan The channel we are calculating the matrix element for.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the calculation of the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay,MEOption meopt) const;
/**
* Output the setup information for the particle database
* @param os The stream to output the information to
* @param header Whether or not to output the information for MySQL
*/
virtual void dataBaseOutput(ofstream & os,bool header) 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);
//@}
/**
* Standard Init function used to initialize the interfaces.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const {return new_ptr(*this);}
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const {return new_ptr(*this);}
//@}
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving and
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
/**
* Initialize this object. Called in the run phase just before
* a run begins.
*/
virtual void doinitrun();
//@}
protected:
/**
* Apply the hard matrix element
*/
vector<Lorentz5Momentum> applyHard(const ParticleVector &p);
/**
* Get the weight for hard emission
*/
double getHard(double &, double &);
/**
* Set the \f$\rho\f$ parameter
*/
void setRho(double);
/**
* Set the \f$\tilde{\kappa}\f$ parameters symmetrically
*/
void setKtildeSymm();
/**
* Set second \f$\tilde{\kappa}\f$, given the first.
*/
void setKtilde2();
/**
* Translate the variables from \f$x_q,x_{\bar{q}}\f$ to \f$\tilde{\kappa},z\f$
*/
//@{
/**
* Calculate \f$z\f$.
*/
double getZfromX(double, double);
/**
* Calculate \f$\tilde{\kappa}\f$.
*/
double getKfromX(double, double);
//@}
/**
* Calculate \f$x_{q},x_{\bar{q}}\f$ from \f$\tilde{\kappa},z\f$.
* @param kt \f$\tilde{\kappa}\f$
* @param z \f$z\f$
* @param x \f$x_{q}\f$
* @param xbar \f$x_{\bar{q}}\f$
*/
void getXXbar(double kt, double z, double & x, double & xbar);
/**
* Soft weight
*/
//@{
/**
* Soft quark weight calculated from \f$x_{q},x_{\bar{q}}\f$
* @param x \f$x_{q}\f$
* @param xbar \f$x_{\bar{q}}\f$
*/
double qWeight(double x, double xbar);
/**
* Soft antiquark weight calculated from \f$x_{q},x_{\bar{q}}\f$
* @param x \f$x_{q}\f$
* @param xbar \f$x_{\bar{q}}\f$
*/
double qbarWeight(double x, double xbar);
/**
* Soft quark weight calculated from \f$\tilde{q},z\f$
* @param qtilde \f$\tilde{q}\f$
* @param z \f$z\f$
*/
double qWeightX(Energy qtilde, double z);
/**
* Soft antiquark weight calculated from \f$\tilde{q},z\f$
* @param qtilde \f$\tilde{q}\f$
* @param z \f$z\f$
*/
double qbarWeightX(Energy qtilde, double z);
//@}
/**
* ????
*/
double u(double);
/**
* Vector and axial vector parts of the matrix element
*/
//@{
/**
* Vector part of the matrix element
*/
double MEV(double, double);
/**
* Axial vector part of the matrix element
*/
double MEA(double, double);
/**
* The matrix element, given \f$x_1\f$, \f$x_2\f$.
* @param x1 \f$x_1\f$
* @param x2 \f$x_2\f$
*/
double PS(double x1, double x2);
/**
* Access to the strong coupling
*/
ShowerAlphaPtr alphaS() const {return alpha_;}
//@}
private:
/**
* Describe a concrete class with persistent data.
*/
static ClassDescription<SMWDecayer> initSMWDecayer;
/**
* Private and non-existent assignment operator.
*/
SMWDecayer & operator=(const SMWDecayer &);
private:
/**
* Pointer to the W fermions vertex
*/
FFVVertexPtr FFWvertex_;
/**
* maximum weights for the different integrations
*/
//@{
/**
* Weights for the W to quarks decays.
*/
vector<double> quarkWeight_;
/**
* Weights for the W to leptons decays.
*/
vector<double> leptonWeight_;
//@}
/**
* Spin density matrix for the decay
*/
mutable RhoDMatrix _rho;
/**
* Polarization vectors for the decay
*/
mutable vector<VectorWaveFunction> _vectors;
/**
* Spinors for the decay
*/
mutable vector<SpinorWaveFunction> _wave;
/**
* Barred spinors for the decay
*/
mutable vector<SpinorBarWaveFunction> _wavebar;
private:
/**
* CM energy
*/
Energy d_Q_;
/**
* Quark mass
*/
Energy d_m_;
/**
* The rho parameter
*/
double d_rho_;
/**
* The v parameter
*/
double d_v_;
/**
* The initial kappa-tilde values for radiation from the quark
*/
double d_kt1_;
/**
* The initial kappa-tilde values for radiation from the antiquark
*/
double d_kt2_;
/**
* Cut-off parameter
*/
static const double EPS_;
/**
* Pointer to the coupling
*/
ShowerAlphaPtr alpha_;
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/**
* The following template specialization informs ThePEG about the
* base class of SMWDecayer.
*/
template <>
struct BaseClassTrait<Herwig::SMWDecayer,1> {
/** Typedef of the base class of SMWDecayer. */
typedef Herwig::DecayIntegrator NthBase;
};
/**
* The following template specialization informs ThePEG about the
* name of this class and the shared object where it is defined.
*/
template <>
struct ClassTraits<Herwig::SMWDecayer>
: public ClassTraitsBase<Herwig::SMWDecayer> {
/** Return the class name.*/
static string className() { return "Herwig::SMWDecayer"; }
/**
* Return the name of the shared library to be loaded to get
* access to this class and every other class it uses
* (except the base class).
*/
static string library() { return "HwPerturbativeDecay.so"; }
};
/** @endcond */
}
#endif /* HERWIG_SMWDecayer_H */
diff --git a/Decay/Perturbative/SMWFermionsPOWHEGDecayer.cc b/Decay/Perturbative/SMWFermionsPOWHEGDecayer.cc
--- a/Decay/Perturbative/SMWFermionsPOWHEGDecayer.cc
+++ b/Decay/Perturbative/SMWFermionsPOWHEGDecayer.cc
@@ -1,679 +1,680 @@
//-*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SMWFermionsPOWHEGDecayer class.
//
#include "SMWFermionsPOWHEGDecayer.h"
#include <numeric>
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/PDF/PolarizedBeamParticleData.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
-#include "Herwig/Shower/QTilde/Base/HardTree.h"
-#include "Herwig/Shower/QTilde/Base/ShowerTree.h"
+#include "Herwig/Shower/RealEmissionProcess.h"
#include "Herwig/Shower/QTilde/Base/ShowerProgenitor.h"
#include "Herwig/Shower/QTilde/Base/ShowerParticle.h"
#include "Herwig/Shower/QTilde/Base/Branching.h"
using namespace Herwig;
SMWFermionsPOWHEGDecayer::SMWFermionsPOWHEGDecayer()
: CF_(4./3.), pTmin_(1.*GeV)
{ }
IBPtr SMWFermionsPOWHEGDecayer::clone() const {
return new_ptr(*this);
}
IBPtr SMWFermionsPOWHEGDecayer::fullclone() const {
return new_ptr(*this);
}
void SMWFermionsPOWHEGDecayer::persistentOutput(PersistentOStream & os) const {
os << FFGVertex_ << FFWVertex_ << gluon_ << ounit( pTmin_, GeV );
}
void SMWFermionsPOWHEGDecayer::persistentInput(PersistentIStream & is, int) {
is >> FFGVertex_ >> FFWVertex_ >> gluon_ >> iunit( pTmin_, GeV );
}
ClassDescription<SMWFermionsPOWHEGDecayer>
SMWFermionsPOWHEGDecayer::initSMWFermionsPOWHEGDecayer;
// Definition of the static class description member.
void SMWFermionsPOWHEGDecayer::Init() {
static ClassDocumentation<SMWFermionsPOWHEGDecayer> documentation
("There is no documentation for the SMWFermionsPOWHEGDecayer class");
static Parameter<SMWFermionsPOWHEGDecayer, Energy> interfacePtMin
("minpT",
"The pt cut on hardest emision generation",
&SMWFermionsPOWHEGDecayer::pTmin_, GeV, 1.*GeV, 0*GeV, 100000.0*GeV,
false, false, Interface::limited);
}
-HardTreePtr SMWFermionsPOWHEGDecayer::
-generateHardest(ShowerTreePtr tree) {
- // Get the progenitors: Q and Qbar.
- ShowerProgenitorPtr
- QProgenitor = tree->outgoingLines().begin()->first,
- QbarProgenitor = tree->outgoingLines().rbegin()->first;
- if(QProgenitor->id()<0) swap( QProgenitor, QbarProgenitor );
- partons_.resize(2);
- partons_[0] = QProgenitor->progenitor() ->dataPtr();
- partons_[1] = QbarProgenitor->progenitor()->dataPtr();
- if(!partons_[0]->coloured()) return HardTreePtr();
- // momentum of the partons
- quark_.resize(2);
- quark_[0] = QProgenitor ->copy()->momentum();
- quark_[1] = QbarProgenitor->copy()->momentum();
- // Set the existing mass entries in partons 5 vectors with the
- // once and for all.
- quark_[0].setMass(partons_[0]->mass());
- quark_[1].setMass(partons_[1]->mass());
- gauge_.setMass(0.*MeV);
- // Get the W boson.
- wboson_ = tree->incomingLines().begin()->first->copy();
- // copy the particle objects
- vector<PPtr> hardProcess (3);
- hardProcess[0] = wboson_;
- hardProcess[1] = QbarProgenitor->copy();
- hardProcess[2] = QProgenitor ->copy();
- // Get the W boson mass.
- mw2_ = (quark_[0] + quark_[1]).m2();
- // Generate emission and set _quark[0,1] and _gauge to be the
- // momenta of q, qbar and g after the hardest emission:
- if(!getEvent(hardProcess)) {
- QProgenitor ->maximumpT(pTmin_,ShowerInteraction::QCD);
- QbarProgenitor->maximumpT(pTmin_,ShowerInteraction::QCD);
- return HardTreePtr();
- }
- // Ensure the energies are greater than the constituent masses:
- for (int i=0; i<2; i++) {
- if (quark_[i].e() < partons_[i]->constituentMass()) return HardTreePtr();
- if (gauge_.e() < gluon_ ->constituentMass()) return HardTreePtr();
- }
- // set masses
- quark_[0].setMass( partons_[0]->mass() );
- quark_[1].setMass( partons_[1]->mass() );
- gauge_ .setMass( ZERO );
- // assign the emitter based on evolution scales
- unsigned int iemitter = quark_[0]*gauge_ > quark_[1]*gauge_ ? 1 : 0;
- unsigned int ispectator = iemitter==1 ? 0 : 1;
- // Make the particles for the HardTree:
- ShowerParticlePtr emitter (new_ptr(ShowerParticle(partons_[iemitter ],true)));
- ShowerParticlePtr spectator(new_ptr(ShowerParticle(partons_[ispectator],true)));
- ShowerParticlePtr gauge (new_ptr(ShowerParticle(gluon_ ,true)));
- ShowerParticlePtr wboson (new_ptr(ShowerParticle(wboson_->dataPtr() ,false)));
- ShowerParticlePtr parent (new_ptr(ShowerParticle(partons_[iemitter ],true)));
- emitter ->set5Momentum(quark_[iemitter ] );
- spectator->set5Momentum(quark_[ispectator] );
- gauge ->set5Momentum(gauge_ );
- wboson ->set5Momentum(wboson_->momentum());
- Lorentz5Momentum parentMomentum(quark_[iemitter]+gauge_);
- parentMomentum.rescaleMass();
- parent->set5Momentum(parentMomentum);
- // Create the vectors of HardBranchings to create the HardTree:
- vector<HardBranchingPtr> spaceBranchings,allBranchings;
- // Incoming boson:
- spaceBranchings.push_back(new_ptr(HardBranching(wboson,SudakovPtr(),
- HardBranchingPtr(),
- HardBranching::Incoming)));
- // Outgoing particles from hard emission:
- HardBranchingPtr spectatorBranch(new_ptr(HardBranching(spectator,SudakovPtr(),
- HardBranchingPtr(),
- HardBranching::Outgoing)));
- HardBranchingPtr emitterBranch(new_ptr(HardBranching(parent,SudakovPtr(),
- HardBranchingPtr(),
- HardBranching::Outgoing)));
- emitterBranch->addChild(new_ptr(HardBranching(emitter,SudakovPtr(),
- HardBranchingPtr(),
- HardBranching::Outgoing)));
- emitterBranch->addChild(new_ptr(HardBranching(gauge,SudakovPtr(),
- HardBranchingPtr(),
- HardBranching::Outgoing)));
- emitterBranch->type(emitterBranch->branchingParticle()->id()>0 ?
- ShowerPartnerType::QCDColourLine :
- ShowerPartnerType::QCDAntiColourLine);
- allBranchings.push_back(emitterBranch);
- allBranchings.push_back(spectatorBranch);
- if(iemitter==1) swap(allBranchings[0],allBranchings[1]);
- // Add incoming boson to allBranchings
- allBranchings.push_back( spaceBranchings.back() );
- // Make the HardTree from the HardBranching vectors.
- HardTreePtr hardtree = new_ptr(HardTree(allBranchings,spaceBranchings,
- ShowerInteraction::QCD));
- // Set the maximum pt for all other emissions
- Energy ptveto(pT_);
- QProgenitor ->maximumpT(ptveto,ShowerInteraction::QCD);
- QbarProgenitor->maximumpT(ptveto,ShowerInteraction::QCD);
- // Connect the particles with the branchings in the HardTree
- hardtree->connect( QProgenitor->progenitor() , allBranchings[0] );
- hardtree->connect( QbarProgenitor->progenitor(), allBranchings[1] );
- // colour flow
- ColinePtr newline=new_ptr(ColourLine());
- for(set<HardBranchingPtr>::const_iterator cit=hardtree->branchings().begin();
- cit!=hardtree->branchings().end();++cit) {
- if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3)
- newline->addColoured((**cit).branchingParticle());
- else if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3bar)
- newline->addAntiColoured((**cit).branchingParticle());
- }
- ColinePtr newLine2=new_ptr(ColourLine());
- if(emitterBranch->branchingParticle()->dataPtr()->iColour()==PDT::Colour3) {
- emitterBranch->branchingParticle()->colourLine()->addColoured(gauge);
- newLine2->addColoured(emitter);
- newLine2->addAntiColoured(gauge);
- }
- else {
- emitterBranch->branchingParticle()->antiColourLine()->addAntiColoured(gauge);
- newLine2->addAntiColoured(emitter);
- newLine2->addColoured(gauge);
- }
- // return the tree
- return hardtree;
+RealEmissionProcessPtr SMWFermionsPOWHEGDecayer::
+generateHardest(PerturbativeProcessPtr tree) {
+ assert(false);
+ return RealEmissionProcessPtr();
+ // // Get the progenitors: Q and Qbar.
+ // ShowerProgenitorPtr
+ // QProgenitor = tree->outgoingLines().begin()->first,
+ // QbarProgenitor = tree->outgoingLines().rbegin()->first;
+ // if(QProgenitor->id()<0) swap( QProgenitor, QbarProgenitor );
+ // partons_.resize(2);
+ // partons_[0] = QProgenitor->progenitor() ->dataPtr();
+ // partons_[1] = QbarProgenitor->progenitor()->dataPtr();
+ // if(!partons_[0]->coloured()) return HardTreePtr();
+ // // momentum of the partons
+ // quark_.resize(2);
+ // quark_[0] = QProgenitor ->copy()->momentum();
+ // quark_[1] = QbarProgenitor->copy()->momentum();
+ // // Set the existing mass entries in partons 5 vectors with the
+ // // once and for all.
+ // quark_[0].setMass(partons_[0]->mass());
+ // quark_[1].setMass(partons_[1]->mass());
+ // gauge_.setMass(0.*MeV);
+ // // Get the W boson.
+ // wboson_ = tree->incomingLines().begin()->first->copy();
+ // // copy the particle objects
+ // vector<PPtr> hardProcess (3);
+ // hardProcess[0] = wboson_;
+ // hardProcess[1] = QbarProgenitor->copy();
+ // hardProcess[2] = QProgenitor ->copy();
+ // // Get the W boson mass.
+ // mw2_ = (quark_[0] + quark_[1]).m2();
+ // // Generate emission and set _quark[0,1] and _gauge to be the
+ // // momenta of q, qbar and g after the hardest emission:
+ // if(!getEvent(hardProcess)) {
+ // QProgenitor ->maximumpT(pTmin_,ShowerInteraction::QCD);
+ // QbarProgenitor->maximumpT(pTmin_,ShowerInteraction::QCD);
+ // return HardTreePtr();
+ // }
+ // // Ensure the energies are greater than the constituent masses:
+ // for (int i=0; i<2; i++) {
+ // if (quark_[i].e() < partons_[i]->constituentMass()) return HardTreePtr();
+ // if (gauge_.e() < gluon_ ->constituentMass()) return HardTreePtr();
+ // }
+ // // set masses
+ // quark_[0].setMass( partons_[0]->mass() );
+ // quark_[1].setMass( partons_[1]->mass() );
+ // gauge_ .setMass( ZERO );
+ // // assign the emitter based on evolution scales
+ // unsigned int iemitter = quark_[0]*gauge_ > quark_[1]*gauge_ ? 1 : 0;
+ // unsigned int ispectator = iemitter==1 ? 0 : 1;
+ // // Make the particles for the HardTree:
+ // ShowerParticlePtr emitter (new_ptr(ShowerParticle(partons_[iemitter ],true)));
+ // ShowerParticlePtr spectator(new_ptr(ShowerParticle(partons_[ispectator],true)));
+ // ShowerParticlePtr gauge (new_ptr(ShowerParticle(gluon_ ,true)));
+ // ShowerParticlePtr wboson (new_ptr(ShowerParticle(wboson_->dataPtr() ,false)));
+ // ShowerParticlePtr parent (new_ptr(ShowerParticle(partons_[iemitter ],true)));
+ // emitter ->set5Momentum(quark_[iemitter ] );
+ // spectator->set5Momentum(quark_[ispectator] );
+ // gauge ->set5Momentum(gauge_ );
+ // wboson ->set5Momentum(wboson_->momentum());
+ // Lorentz5Momentum parentMomentum(quark_[iemitter]+gauge_);
+ // parentMomentum.rescaleMass();
+ // parent->set5Momentum(parentMomentum);
+ // // Create the vectors of HardBranchings to create the HardTree:
+ // vector<HardBranchingPtr> spaceBranchings,allBranchings;
+ // // Incoming boson:
+ // spaceBranchings.push_back(new_ptr(HardBranching(wboson,SudakovPtr(),
+ // HardBranchingPtr(),
+ // HardBranching::Incoming)));
+ // // Outgoing particles from hard emission:
+ // HardBranchingPtr spectatorBranch(new_ptr(HardBranching(spectator,SudakovPtr(),
+ // HardBranchingPtr(),
+ // HardBranching::Outgoing)));
+ // HardBranchingPtr emitterBranch(new_ptr(HardBranching(parent,SudakovPtr(),
+ // HardBranchingPtr(),
+ // HardBranching::Outgoing)));
+ // emitterBranch->addChild(new_ptr(HardBranching(emitter,SudakovPtr(),
+ // HardBranchingPtr(),
+ // HardBranching::Outgoing)));
+ // emitterBranch->addChild(new_ptr(HardBranching(gauge,SudakovPtr(),
+ // HardBranchingPtr(),
+ // HardBranching::Outgoing)));
+ // emitterBranch->type(emitterBranch->branchingParticle()->id()>0 ?
+ // ShowerPartnerType::QCDColourLine :
+ // ShowerPartnerType::QCDAntiColourLine);
+ // allBranchings.push_back(emitterBranch);
+ // allBranchings.push_back(spectatorBranch);
+ // if(iemitter==1) swap(allBranchings[0],allBranchings[1]);
+ // // Add incoming boson to allBranchings
+ // allBranchings.push_back( spaceBranchings.back() );
+ // // Make the HardTree from the HardBranching vectors.
+ // HardTreePtr hardtree = new_ptr(HardTree(allBranchings,spaceBranchings,
+ // ShowerInteraction::QCD));
+ // // Set the maximum pt for all other emissions
+ // Energy ptveto(pT_);
+ // QProgenitor ->maximumpT(ptveto,ShowerInteraction::QCD);
+ // QbarProgenitor->maximumpT(ptveto,ShowerInteraction::QCD);
+ // // Connect the particles with the branchings in the HardTree
+ // hardtree->connect( QProgenitor->progenitor() , allBranchings[0] );
+ // hardtree->connect( QbarProgenitor->progenitor(), allBranchings[1] );
+ // // colour flow
+ // ColinePtr newline=new_ptr(ColourLine());
+ // for(set<HardBranchingPtr>::const_iterator cit=hardtree->branchings().begin();
+ // cit!=hardtree->branchings().end();++cit) {
+ // if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3)
+ // newline->addColoured((**cit).branchingParticle());
+ // else if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3bar)
+ // newline->addAntiColoured((**cit).branchingParticle());
+ // }
+ // ColinePtr newLine2=new_ptr(ColourLine());
+ // if(emitterBranch->branchingParticle()->dataPtr()->iColour()==PDT::Colour3) {
+ // emitterBranch->branchingParticle()->colourLine()->addColoured(gauge);
+ // newLine2->addColoured(emitter);
+ // newLine2->addAntiColoured(gauge);
+ // }
+ // else {
+ // emitterBranch->branchingParticle()->antiColourLine()->addAntiColoured(gauge);
+ // newLine2->addAntiColoured(emitter);
+ // newLine2->addColoured(gauge);
+ // }
+ // // return the tree
+ // return hardtree;
}
double SMWFermionsPOWHEGDecayer::
me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const {
// leading-order result
double output = SMWDecayer::me2(ichan,part,decay,meopt);
// check decay products coloured, otherwise return
if(!decay[0]->dataPtr()->coloured()) return output;
// inital masses, couplings etc
// W mass
mW_ = part.mass();
// strong coupling
aS_ = SM().alphaS(sqr(mW_));
// reduced mass
double mu1_ = (decay[0]->dataPtr()->mass())/mW_;
double mu2_ = (decay[1]->dataPtr()->mass())/mW_;
// scale
scale_ = sqr(mW_);
// now for the nlo loop correction
double virt = CF_*aS_/Constants::pi;
// now for the real correction
double realFact=0.;
for(int iemit=0;iemit<2;++iemit) {
double phi = UseRandom::rnd()*Constants::twopi;
// set the emitter and the spectator
double muj = iemit==0 ? mu1_ : mu2_;
double muk = iemit==0 ? mu2_ : mu1_;
double muj2 = sqr(muj);
double muk2 = sqr(muk);
// calculate y
double yminus = 0.;
double yplus = 1.-2.*muk*(1.-muk)/(1.-muj2-muk2);
double y = yminus + UseRandom::rnd()*(yplus-yminus);
double v = sqrt(sqr(2.*muk2 + (1.-muj2-muk2)*(1.-y))-4.*muk2)
/(1.-muj2-muk2)/(1.-y);
double zplus = (1.+v)*(1.-muj2-muk2)*y/2./(muj2+(1.-muj2-muk2)*y);
double zminus = (1.-v)*(1.-muj2-muk2)*y/2./(muj2+(1.-muj2-muk2)*y);
double z = zminus + UseRandom::rnd()*(zplus-zminus);
double jac = (1.-y)*(yplus-yminus)*(zplus-zminus);
// calculate x1,x2,x3,xT
double x2 = 1.-y*(1.-muj2-muk2)-muj2+muk2;
double x1 = 1.+muj2-muk2-z*(x2-2.*muk2);
// copy the particle objects over for calculateRealEmission
vector<PPtr> hardProcess(3);
hardProcess[0] = const_ptr_cast<PPtr>(&part);
hardProcess[1] = decay[0];
hardProcess[2] = decay[1];
realFact = 0.25*jac*sqr(1.-muj2-muk2)/
sqrt((1.-sqr(muj-muk))*(1.-sqr(muj+muk)))/Constants::twopi
*2.*CF_*aS_*calculateRealEmission(x1, x2, hardProcess, phi,
muj, muk, iemit, true);
}
// the born + virtual + real
output = output*(1. + virt + realFact);
return output;
}
double SMWFermionsPOWHEGDecayer::meRatio(vector<cPDPtr> partons,
vector<Lorentz5Momentum> momenta,
unsigned int iemitter, bool subtract) const {
Lorentz5Momentum q = momenta[1]+momenta[2]+momenta[3];
Energy2 Q2=q.m2();
Energy2 lambda = sqrt((Q2-sqr(momenta[1].mass()+momenta[2].mass()))*
(Q2-sqr(momenta[1].mass()-momenta[2].mass())));
InvEnergy2 D[2];
double lome[2];
for(unsigned int iemit=0;iemit<2;++iemit) {
unsigned int ispect = iemit==0 ? 1 : 0;
Energy2 pipj = momenta[3 ] * momenta[1+iemit ];
Energy2 pipk = momenta[3 ] * momenta[1+ispect];
Energy2 pjpk = momenta[1+iemit] * momenta[1+ispect];
double y = pipj/(pipj+pipk+pjpk);
double z = pipk/( pipk+pjpk);
Energy mij = sqrt(2.*pipj+sqr(momenta[1+iemit].mass()));
Energy2 lamB = sqrt((Q2-sqr(mij+momenta[1+ispect].mass()))*
(Q2-sqr(mij-momenta[1+ispect].mass())));
Energy2 Qpk = q*momenta[1+ispect];
Lorentz5Momentum pkt =
lambda/lamB*(momenta[1+ispect]-Qpk/Q2*q)
+0.5/Q2*(Q2+sqr(momenta[1+ispect].mass())-sqr(momenta[1+ispect].mass()))*q;
Lorentz5Momentum pijt =
q-pkt;
double muj = momenta[1+iemit ].mass()/sqrt(Q2);
double muk = momenta[1+ispect].mass()/sqrt(Q2);
double vt = sqrt((1.-sqr(muj+muk))*(1.-sqr(muj-muk)))/(1.-sqr(muj)-sqr(muk));
double v = sqrt(sqr(2.*sqr(muk)+(1.-sqr(muj)-sqr(muk))*(1.-y))-4.*sqr(muk))
/(1.-y)/(1.-sqr(muj)-sqr(muk));
// dipole term
D[iemit] = 0.5/pipj*(2./(1.-(1.-z)*(1.-y))
-vt/v*(2.-z+sqr(momenta[1+iemit].mass())/pipj));
// matrix element
vector<Lorentz5Momentum> lomom(3);
lomom[0] = momenta[0];
if(iemit==0) {
lomom[1] = pijt;
lomom[2] = pkt ;
}
else {
lomom[2] = pijt;
lomom[1] = pkt ;
}
lome[iemit] = loME(partons,lomom);
}
InvEnergy2 ratio = realME(partons,momenta)*abs(D[iemitter])
/(abs(D[0]*lome[0])+abs(D[1]*lome[1]));
if(subtract)
return Q2*(ratio-2.*D[iemitter]);
else
return Q2*ratio;
}
double SMWFermionsPOWHEGDecayer::loME(const vector<cPDPtr> & partons,
const vector<Lorentz5Momentum> & momenta) const {
// compute the spinors
vector<VectorWaveFunction> vin;
vector<SpinorWaveFunction> aout;
vector<SpinorBarWaveFunction> fout;
VectorWaveFunction win (momenta[0],partons[0],incoming);
SpinorBarWaveFunction qkout(momenta[1],partons[1],outgoing);
SpinorWaveFunction qbout(momenta[2],partons[2],outgoing);
for(unsigned int ix=0;ix<2;++ix){
qkout.reset(ix);
fout.push_back(qkout);
qbout.reset(ix);
aout.push_back(qbout);
}
for(unsigned int ix=0;ix<3;++ix){
win.reset(ix);
vin.push_back(win);
}
// temporary storage of the different diagrams
// sum over helicities to get the matrix element
double total(0.);
for(unsigned int inhel=0;inhel<3;++inhel) {
for(unsigned int outhel1=0;outhel1<2;++outhel1) {
for(unsigned int outhel2=0;outhel2<2;++outhel2) {
Complex diag1 = FFWVertex()->evaluate(scale_,aout[outhel2],fout[outhel1],vin[inhel]);
total += norm(diag1);
}
}
}
// return the answer
return total;
}
InvEnergy2 SMWFermionsPOWHEGDecayer::realME(const vector<cPDPtr> & partons,
const vector<Lorentz5Momentum> & momenta) const {
// compute the spinors
vector<VectorWaveFunction> vin;
vector<SpinorWaveFunction> aout;
vector<SpinorBarWaveFunction> fout;
vector<VectorWaveFunction> gout;
VectorWaveFunction win (momenta[0],partons[0],incoming);
SpinorBarWaveFunction qkout(momenta[1],partons[1],outgoing);
SpinorWaveFunction qbout(momenta[2],partons[2],outgoing);
VectorWaveFunction gluon(momenta[3],partons[3],outgoing);
for(unsigned int ix=0;ix<2;++ix){
qkout.reset(ix);
fout.push_back(qkout);
qbout.reset(ix);
aout.push_back(qbout);
gluon.reset(2*ix);
gout.push_back(gluon);
}
for(unsigned int ix=0;ix<3;++ix){
win.reset(ix);
vin.push_back(win);
}
vector<Complex> diag(2,0.);
double total(0.);
for(unsigned int inhel1=0;inhel1<3;++inhel1) {
for(unsigned int outhel1=0;outhel1<2;++outhel1) {
for(unsigned int outhel2=0;outhel2<2;++outhel2) {
for(unsigned int outhel3=0;outhel3<2;++outhel3) {
SpinorBarWaveFunction off1 =
FFGVertex()->evaluate(scale_,3,partons[1],fout[outhel1],gout[outhel3]);
diag[0] = FFWVertex()->evaluate(scale_,aout[outhel2],off1,vin[inhel1]);
SpinorWaveFunction off2 =
FFGVertex()->evaluate(scale_,3,partons[2],aout[outhel2],gout[outhel3]);
diag[1] = FFWVertex()->evaluate(scale_,off2,fout[outhel1],vin[inhel1]);
// sum of diagrams
Complex sum = std::accumulate(diag.begin(),diag.end(),Complex(0.));
// me2
total += norm(sum);
}
}
}
}
// divide out the coupling
total /= norm(FFGVertex()->norm());
// return the total
return total*UnitRemoval::InvE2;
}
void SMWFermionsPOWHEGDecayer::doinit() {
// cast the SM pointer to the Herwig SM pointer
tcHwSMPtr hwsm= dynamic_ptr_cast<tcHwSMPtr>(standardModel());
// do the initialisation
if(!hwsm) throw InitException()
<< "Wrong type of StandardModel object in "
<< "SMWFermionsPOWHEGDecayer::doinit() "
<< "the Herwig version must be used."
<< Exception::runerror;
// cast the vertices
FFWVertex_ = hwsm->vertexFFW();
FFWVertex_->init();
FFGVertex_ = hwsm->vertexFFG();
FFGVertex_->init();
SMWDecayer::doinit();
gluon_ = getParticleData(ParticleID::g);
}
bool SMWFermionsPOWHEGDecayer::getEvent(vector<PPtr> hardProcess) {
vector<Energy> particleMass;
for(unsigned int ix=0;ix<hardProcess.size();++ix) {
if(abs(hardProcess[ix]->id())==ParticleID::Wplus) {
mW_ = hardProcess[ix]->mass();
}
else {
particleMass.push_back(hardProcess[ix]->mass());
}
}
if (particleMass.size()!=2) {
throw Exception()
<< "Number of outgoing particles is not equal to 2 in "
<< "SMWFermionPOWHEGDecayer::getEvent()"
<< Exception::runerror;
}
// reduced mass
mu1_ = particleMass[0]/mW_;
mu2_ = particleMass[1]/mW_;
// scale
scale_ = sqr(mW_);
// max pT
Energy pTmax = 0.5*sqrt(mw2_);
if(pTmax<pTmin_) return false;
// Define over valued y_max & y_min according to the associated pt_min cut.
double ymax = acosh(pTmax/pTmin_);
double ymin = -ymax;
// pt of the emmission
pT_ = pTmax;
// prefactor
double overEst = 4.;
double prefactor = overEst*alphaS()->overestimateValue()*CF_*
(ymax-ymin)/Constants::twopi;
// loop to generate the pt and rapidity
bool reject;
//arrays to hold the temporary probabilities whilst the for loop progresses
double probTemp[2][2]={{0.,0.},{0.,0.}};
probTemp[0][0]=probTemp[0][1]=probTemp[1][0]=probTemp[1][1]=0.;
double x1Solution[2][2] = {{0.,0.},{0.,0.}};
double x2Solution[2][2] = {{0.,0.},{0.,0.}};
double x3Solution[2] = {0.,0.};
Energy pT[2] = {pTmax,pTmax};
double yTemp[2] = {0.,0.};
double phi = 0.;
// do the competition
for(int i=0; i<2; i++) {
// set the emitter and the spectator
double muj = i==0 ? mu1_ : mu2_;
double muk = i==0 ? mu2_ : mu1_;
double muj2 = sqr(muj);
double muk2 = sqr(muk);
do {
// generation of phi
phi = UseRandom::rnd() * Constants::twopi;
// reject the emission
reject = true;
// generate pt
pT[i] *= pow(UseRandom::rnd(),1./prefactor);
if(pT[i]<pTmin_) {
pT[i] = -GeV;
break;
}
// generate xT
double xT2 = sqr(2./mW_*pT[i]);
// generate y
yTemp[i] = ymin + UseRandom::rnd()*(ymax-ymin);
// generate x3 & x1 from pT & y
double x1Plus = 1-muk2+muj2;
double x1Minus = 2.*muj;
x3Solution[i] = 2.*pT[i]*cosh(yTemp[i])/mW_;
// prefactor
double weightPrefactor = 0.5/sqrt((1.-sqr(muj-muk))*(1.-sqr(muj+muk)))/overEst;
// calculate x1 & x2 solutions
double discrim2 = (-sqr(x3Solution[i])+xT2)*
(xT2*muk2+2.*x3Solution[i]-sqr(muj2)+2.*muk2+2.*muj2-sqr(x3Solution[i])-1.
+2.*muj2*muk2-sqr(muk2)-2.*muk2*x3Solution[i]-2.*muj2*x3Solution[i]);
// check discrim2 is > 0
if( discrim2 < ZERO) continue;
double fact1 =2.*sqr(x3Solution[i])-4.*muk2-6.*x3Solution[i]+4.*muj2-xT2*x3Solution[i]
+2.*xT2-2.*muj2*x3Solution[i]+2.*muk2*x3Solution[i]+4.;
double fact2 = (4.-4.*x3Solution[i]+xT2);
double discriminant = sqrt(discrim2);
// two solns for x1
x1Solution[i][0] = (fact1 + 2.*discriminant)/fact2;
x1Solution[i][1] = (fact1 - 2.*discriminant)/fact2;
bool found = false;
for(unsigned int j=0;j<2;++j) {
// calculate x2
x2Solution[i][j] = 2.-x3Solution[i]-x1Solution[i][j];
// set limits on x2
double root = max(0.,sqr(x1Solution[i][j])-4.*muj2);
root = sqrt(root);
double x2Plus = 1.+muk2-muj2
-0.5*(1.-x1Solution[i][j]+muj2-muk2)/(1.-x1Solution[i][j]+muj2)
*(x1Solution[i][j]-2.*muj2-root);
double x2Minus = 1.+muk2-muj2
-0.5*(1.-x1Solution[i][j]+muj2-muk2)/(1.-x1Solution[i][j]+muj2)
*(x1Solution[i][j]-2.*muj2+root);
if(x1Solution[i][j]>=x1Minus && x1Solution[i][j]<=x1Plus &&
x2Solution[i][j]>=x2Minus && x2Solution[i][j]<=x2Plus &&
checkZMomenta(x1Solution[i][j], x2Solution[i][j], x3Solution[i], yTemp[i], pT[i],
muj, muk)) {
probTemp[i][j] = weightPrefactor*pT[i]*
calculateJacobian(x1Solution[i][j], x2Solution[i][j], pT[i], muj, muk)*
calculateRealEmission(x1Solution[i][j], x2Solution[i][j],
hardProcess, phi, muj, muk, i, false);
found = true;
}
else {
probTemp[i][j] = 0.;
}
}
if(!found) continue;
// alpha S piece
double wgt = (probTemp[i][0]+probTemp[i][1])*alphaS()->ratio(sqr(pT[i]));
// matrix element weight
reject = UseRandom::rnd()>wgt;
}
while(reject);
} // end of emitter for loop
// no emission
if(pT[0]<ZERO&&pT[1]<ZERO) return false;
//pick the spectator and x1 x2 values
double x1,x2,y;
// particle 1 emits, particle 2 spectates
unsigned int iemit=0;
if(pT[0]>pT[1]){
pT_ = pT[0];
y=yTemp[0];
if(probTemp[0][0]>UseRandom::rnd()*(probTemp[0][0]+probTemp[0][1])) {
x1 = x1Solution[0][0];
x2 = x2Solution[0][0];
}
else {
x1 = x1Solution[0][1];
x2 = x2Solution[0][1];
}
}
// particle 2 emits, particle 1 spectates
else {
iemit=1;
pT_ = pT[1];
y=yTemp[1];
if(probTemp[1][0]>UseRandom::rnd()*(probTemp[1][0]+probTemp[1][1])) {
x1 = x1Solution[1][0];
x2 = x2Solution[1][0];
}
else {
x1 = x1Solution[1][1];
x2 = x2Solution[1][1];
}
}
// find spectator
unsigned int ispect = iemit == 0 ? 1 : 0;
double muk = iemit == 0 ? mu2_ : mu1_;
double muk2 = sqr(muk);
// Find the boost from the lab to the c.o.m with the spectator
// along the -z axis, and then invert it.
LorentzRotation eventFrame( ( quark_[0] + quark_[1] ).findBoostToCM() );
Lorentz5Momentum spectator = eventFrame*quark_[ispect];
eventFrame.rotateZ( -spectator.phi() );
eventFrame.rotateY( -spectator.theta() - Constants::pi );
eventFrame.invert();
// spectator
quark_[ispect].setT( 0.5*x2*mW_ );
quark_[ispect].setX( ZERO );
quark_[ispect].setY( ZERO );
quark_[ispect].setZ( -sqrt(0.25*mw2_*x2*x2-mw2_*muk2) );
// gluon
gauge_.setT( pT_*cosh(y) );
gauge_.setX( pT_*cos(phi) );
gauge_.setY( pT_*sin(phi) );
gauge_.setZ( pT_*sinh(y) );
gauge_.setMass(ZERO);
// emitter reconstructed from gluon & spectator
quark_[iemit] = -gauge_ - quark_[ispect];
quark_[iemit].setT( 0.5*mW_*x1 );
// boost constructed vectors into the event frame
quark_[0] = eventFrame * quark_[0];
quark_[1] = eventFrame * quark_[1];
gauge_ = eventFrame * gauge_;
// need to reset masses because for whatever reason the boost
// touches the mass component of the five-vector and can make
// zero mass objects acquire a floating point negative mass(!).
gauge_.setMass( ZERO );
quark_[iemit] .setMass(partons_[iemit ]->mass());
quark_[ispect].setMass(partons_[ispect]->mass());
return true;
}
InvEnergy SMWFermionsPOWHEGDecayer::calculateJacobian(double x1, double x2, Energy pT,
double muj, double muk) const{
double xPerp = abs(2.*pT/mW_);
Energy jac = mW_/xPerp*fabs((x2*sqr(muj)+2.*sqr(muk)*x1
+sqr(muk)*x2-x1*x2-sqr(x2)+x2)/pow((sqr(x2)-4.*sqr(muk)),1.5));
return 1./jac; //jacobian as defined is dptdy=jac*dx1dx2, therefore we have to divide by it
}
bool SMWFermionsPOWHEGDecayer::checkZMomenta(double x1, double x2, double x3,
double y, Energy pT, double muj,
double muk) const {
double xPerp2 = 4.*pT*pT/mW_/mW_;
double root1 = sqrt(max(0.,sqr(x2)-4.*sqr(muk)));
double root2 = sqrt(max(0.,sqr(x1)-xPerp2 - 4.*sqr(muj)));
static double tolerance = 1e-6;
bool isMomentaReconstructed = false;
if(pT*sinh(y) > ZERO) {
if(abs(-root1 + sqrt(sqr(x3)-xPerp2) + root2) <= tolerance ||
abs(-root1 + sqrt(sqr(x3)-xPerp2) - root2) <= tolerance)
isMomentaReconstructed=true;
}
else if(pT*sinh(y) < ZERO){
if(abs(-root1 - sqrt(sqr(x3)-xPerp2) + root2) <= tolerance ||
abs(-root1 - sqrt(sqr(x3)-xPerp2) - root2) <= tolerance)
isMomentaReconstructed=true;
}
else
if(abs(-root1+ sqrt(sqr(x1)-xPerp2 - 4.*(muj))) <= tolerance)
isMomentaReconstructed=true;
return isMomentaReconstructed;
}
double SMWFermionsPOWHEGDecayer::calculateRealEmission(double x1, double x2,
vector<PPtr> hardProcess,
double phi, double muj,
double muk, int iemit,
bool subtract) const {
// make partons data object for meRatio
vector<cPDPtr> partons (3);
for(int ix=0; ix<3; ++ix)
partons[ix] = hardProcess[ix]->dataPtr();
partons.push_back(gluon_);
// calculate x3
double x3 = 2.-x1-x2;
double xT = sqrt(max(0.,sqr(x3)-0.25*sqr(sqr(x2)+sqr(x3)-sqr(x1)-4.*sqr(muk)+4.*sqr(muj))
/(sqr(x2)-4.*sqr(muk))));
// calculate the momenta
Energy M = mW_;
Lorentz5Momentum pspect(ZERO,ZERO,-0.5*M*sqrt(max(sqr(x2)-4.*sqr(muk),0.)),
0.5*M*x2,M*muk);
Lorentz5Momentum pemit (-0.5*M*xT*cos(phi),-0.5*M*xT*sin(phi),
0.5*M*sqrt(max(sqr(x1)-sqr(xT)-4.*sqr(muj),0.)),
0.5*M*x1,M*muj);
Lorentz5Momentum pgluon(0.5*M*xT*cos(phi), 0.5*M*xT*sin(phi),
0.5*M*sqrt(max(sqr(x3)-sqr(xT),0.)),0.5*M*x3,ZERO);
if(abs(pspect.z()+pemit.z()-pgluon.z())/M<1e-6)
pgluon.setZ(-pgluon.z());
else if(abs(pspect.z()-pemit.z()+pgluon.z())/M<1e-6)
pemit .setZ(- pemit.z());
// loop over the possible emitting partons
double realwgt(0.);
// boost and rotate momenta
LorentzRotation eventFrame( ( hardProcess[1]->momentum() +
hardProcess[2]->momentum() ).findBoostToCM() );
Lorentz5Momentum spectator = eventFrame*hardProcess[iemit+1]->momentum();
eventFrame.rotateZ( -spectator.phi() );
eventFrame.rotateY( -spectator.theta() );
eventFrame.invert();
vector<Lorentz5Momentum> momenta(3);
momenta[0] = hardProcess[0]->momentum();
if(iemit==0) {
momenta[2] = eventFrame*pspect;
momenta[1] = eventFrame*pemit ;
}
else {
momenta[1] = eventFrame*pspect;
momenta[2] = eventFrame*pemit ;
}
momenta.push_back(eventFrame*pgluon);
// calculate the weight
if(1.-x1>1e-5 && 1.-x2>1e-5)
realwgt += meRatio(partons,momenta,iemit,subtract);
return realwgt;
}
diff --git a/Decay/Perturbative/SMWFermionsPOWHEGDecayer.h b/Decay/Perturbative/SMWFermionsPOWHEGDecayer.h
--- a/Decay/Perturbative/SMWFermionsPOWHEGDecayer.h
+++ b/Decay/Perturbative/SMWFermionsPOWHEGDecayer.h
@@ -1,309 +1,309 @@
// -*- C++ -*-
#ifndef HERWIG_SMWFermionsPOWHEGDecayer_H
#define HERWIG_SMWFermionsPOWHEGDecayer_H
//
// This is the declaration of the SMWFermionsPOWHEGDecayer class.
//
#include "SMWDecayer.h"
#include "Herwig/Utilities/Maths.h"
namespace Herwig {
using namespace ThePEG;
/**
* Here is the documentation of the SMWFermionsPOWHEGDecayer class.
*
* @see \ref SMWFermionsPOWHEGDecayerInterfaces "The interfaces"
* defined for SMWFermionsPOWHEGDecayer.
*/
class SMWFermionsPOWHEGDecayer: public SMWDecayer {
public:
/**
* The default constructor.
*/
SMWFermionsPOWHEGDecayer();
/**
* Virtual members to be overridden by inheriting classes
* which implement hard corrections
*/
//@{
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return FSR;}
/**
* Apply the POWHEG style correction
*/
- virtual HardTreePtr generateHardest(ShowerTreePtr);
+ virtual RealEmissionProcessPtr generateHardest(PerturbativeProcessPtr);
//@}
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const;
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<SMWFermionsPOWHEGDecayer> initSMWFermionsPOWHEGDecayer;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
SMWFermionsPOWHEGDecayer & operator=(const SMWFermionsPOWHEGDecayer &);
/**
* Pointer to the fermion-antifermion W vertex
*/
AbstractFFVVertexPtr FFWVertex() const {return FFWVertex_;}
/**
* Pointer to the fermion-antifermion G vertex
*/
AbstractFFVVertexPtr FFGVertex() const {return FFGVertex_;}
/**
* Real emission term, for use in generating the hardest emission
*/
double calculateRealEmission(double x1, double x2,
vector<PPtr> hardProcess,
double phi, double muj, double muk,
int iemit, bool subtract) const;
/**
* Check the sign of the momentum in the \f$z\f$-direction is correct.
*/
bool checkZMomenta(double x1, double x2, double x3, double y, Energy pT,
double muj, double muk) const;
/**
* Calculate the Jacobian
*/
InvEnergy calculateJacobian(double x1, double x2, Energy pT,
double muj, double muk) const;
/**
* Calculate the ratio between NLO & LO ME
*/
double meRatio(vector<cPDPtr> partons,
vector<Lorentz5Momentum> momenta,
unsigned int iemitter,bool subtract) const;
/**
* Calculate the LO ME
*/
double loME(const vector<cPDPtr> & partons,
const vector<Lorentz5Momentum> & momenta) const;
/**
* Calculate the NLO real emission piece of ME
*/
InvEnergy2 realME(const vector<cPDPtr> & partons,
const vector<Lorentz5Momentum> & momenta) const;
/**
* Generate a real emission event
*/
bool getEvent(vector<PPtr> hardProcess);
private:
/**
* Pointer to the fermion-antifermion W vertex
*/
AbstractFFVVertexPtr FFWVertex_;
/**
* Pointer to the fermion-antifermion G vertex
*/
AbstractFFVVertexPtr FFGVertex_;
/**
* The colour factor
*/
double CF_;
/**
* The W mass
*/
mutable Energy mW_;
// TODO: delete this
mutable double mu_;
/**
* The reduced mass of particle 1
*/
mutable double mu1_;
/**
* The reduced mass of particle 1 squared
*/
mutable double mu12_;
/**
* The reduceed mass of particle 2
*/
mutable double mu2_;
/**
* The reduceed mass of particle 2 squared
*/
mutable double mu22_;
/**
* The strong coupling
*/
mutable double aS_;
/**
* The scale
*/
mutable Energy2 scale_;
/**
* Stuff for the POWHEG correction
*/
//@{
/**
* ParticleData object for the gluon
*/
tcPDPtr gluon_;
/**
* The cut off on pt, assuming massless quarks.
*/
Energy pTmin_;
// radiative variables (pt,y)
Energy pT_;
/**
* The ParticleData objects for the fermions
*/
vector<tcPDPtr> partons_;
/**
* The fermion momenta
*/
vector<Lorentz5Momentum> quark_;
/**
* The momentum of the radiated gauge boson
*/
Lorentz5Momentum gauge_;
/**
* The W boson
*/
PPtr wboson_;
/**
* W mass squared
*/
Energy2 mw2_;
//@}
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of SMWFermionsPOWHEGDecayer. */
template <>
struct BaseClassTrait<Herwig::SMWFermionsPOWHEGDecayer,1> {
/** Typedef of the first base class of SMWFermionsPOWHEGDecayer. */
typedef Herwig::SMWDecayer NthBase;
};
/** This template specialization informs ThePEG about the name of
* the SMWFermionsPOWHEGDecayer class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::SMWFermionsPOWHEGDecayer>
: public ClassTraitsBase<Herwig::SMWFermionsPOWHEGDecayer> {
/** Return a platform-independent class name */
static string className() { return "Herwig::SMWFermionsPOWHEGDecayer"; }
/**
* The name of a file containing the dynamic library where the class
* SMWFermionsPOWHEGDecayer is implemented. It may also include several, space-separated,
* libraries if the class SMWFermionsPOWHEGDecayer 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 "HwPerturbativeDecay.so"; }
};
/** @endcond */
}
#endif /* HERWIG_SMWFermionsPOWHEGDecayer_H */
diff --git a/Decay/Perturbative/SMZDecayer.cc b/Decay/Perturbative/SMZDecayer.cc
--- a/Decay/Perturbative/SMZDecayer.cc
+++ b/Decay/Perturbative/SMZDecayer.cc
@@ -1,925 +1,892 @@
// -*- C++ -*-
//
// SMZDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SMZDecayer class.
//
#include "SMZDecayer.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/ParVector.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "Herwig/Decay/DecayVertex.h"
#include "ThePEG/Helicity/VectorSpinInfo.h"
#include "ThePEG/Helicity/FermionSpinInfo.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
-#include "Herwig/Shower/QTilde/Base/ShowerTree.h"
#include "Herwig/Shower/QTilde/Base/ShowerProgenitor.h"
#include "Herwig/Shower/QTilde/Base/ShowerParticle.h"
#include "Herwig/Shower/QTilde/Base/Branching.h"
+#include "Herwig/Shower/RealEmissionProcess.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
const double SMZDecayer::EPS_=0.00000001;
SMZDecayer::SMZDecayer()
: quarkWeight_(5,0.), leptonWeight_(6,0.) {
quarkWeight_[0] = 0.488029;
quarkWeight_[1] = 0.378461;
quarkWeight_[2] = 0.488019;
quarkWeight_[3] = 0.378027;
quarkWeight_[4] = 0.483207;
leptonWeight_[0] = 0.110709;
leptonWeight_[1] = 0.220276;
leptonWeight_[2] = 0.110708;
leptonWeight_[3] = 0.220276;
leptonWeight_[4] = 0.110458;
leptonWeight_[5] = 0.220276;
// intermediates
generateIntermediates(false);
// QED corrections
hasRealEmissionME(true);
hasOneLoopME(true);
}
void SMZDecayer::doinit() {
DecayIntegrator::doinit();
// get the vertices from the Standard Model object
tcHwSMPtr hwsm=dynamic_ptr_cast<tcHwSMPtr>(standardModel());
if(!hwsm) throw InitException() << "Must have Herwig StandardModel object in"
<< "SMZDecayer::doinit()"
<< Exception::runerror;
FFZvertex_ = dynamic_ptr_cast<FFVVertexPtr>(hwsm->vertexFFZ());
FFPvertex_ = hwsm->vertexFFP();
// make sure they are initialized
FFZvertex_->init();
FFPvertex_->init();
// now set up the decay modes
DecayPhaseSpaceModePtr mode;
tPDVector extpart(3);
vector<double> wgt(0);
// the Z decay modes
extpart[0]=getParticleData(ParticleID::Z0);
// loop over the quarks and the leptons
for(int istep=0;istep<11;istep+=10) {
for(int ix=1;ix<7;++ix) {
int iy=istep+ix;
if(iy==6) continue;
extpart[1] = getParticleData(-iy);
extpart[2] = getParticleData( iy);
mode = new_ptr(DecayPhaseSpaceMode(extpart,this));
if(iy<=6) addMode(mode, quarkWeight_.at(ix-1),wgt);
else addMode(mode,leptonWeight_.at(iy-11),wgt);
}
}
}
int SMZDecayer::modeNumber(bool & cc,tcPDPtr parent,
const tPDVector & children) const {
int imode(-1);
if(children.size()!=2) return imode;
int id0=parent->id();
tPDVector::const_iterator pit = children.begin();
int id1=(**pit).id();
++pit;
int id2=(**pit).id();
// Z to quarks or leptons
cc =false;
if(id0!=ParticleID::Z0) return imode;
if(abs(id1)<6&&id1==-id2) {
imode=abs(id1)-1;
}
else if(abs(id1)>=11&&abs(id1)<=16&&id1==-id2) {
imode=abs(id1)-6;
}
cc = false;
return imode;
}
void SMZDecayer::persistentOutput(PersistentOStream & os) const {
os << FFZvertex_ << FFPvertex_ << quarkWeight_ << leptonWeight_ << alpha_;
}
void SMZDecayer::persistentInput(PersistentIStream & is, int) {
is >> FFZvertex_ >> FFPvertex_ >> quarkWeight_ >> leptonWeight_ >> alpha_;
}
ClassDescription<SMZDecayer> SMZDecayer::initSMZDecayer;
// Definition of the static class description member.
void SMZDecayer::Init() {
static ClassDocumentation<SMZDecayer> documentation
("The SMZDecayer class is the implementation of the decay"
" Z boson to the Standard Model fermions.");
static ParVector<SMZDecayer,double> interfaceZquarkMax
("QuarkMax",
"The maximum weight for the decay of the Z to quarks",
&SMZDecayer::quarkWeight_,
0, 0, 0, -10000, 10000, false, false, true);
static ParVector<SMZDecayer,double> interfaceZleptonMax
("LeptonMax",
"The maximum weight for the decay of the Z to leptons",
&SMZDecayer::leptonWeight_,
0, 0, 0, -10000, 10000, false, false, true);
static Reference<SMZDecayer,ShowerAlpha> interfaceCoupling
("Coupling",
"Pointer to the object to calculate the coupling for the correction",
&SMZDecayer::alpha_, false, false, true, false, false);
}
// return the matrix element squared
double SMZDecayer::me2(const int, const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1Half,PDT::Spin1Half)));
int iferm(1),ianti(0);
if(decay[0]->id()>0) swap(iferm,ianti);
if(meopt==Initialize) {
VectorWaveFunction::calculateWaveFunctions(_vectors,_rho,
const_ptr_cast<tPPtr>(&inpart),
incoming,false);
}
if(meopt==Terminate) {
VectorWaveFunction::constructSpinInfo(_vectors,const_ptr_cast<tPPtr>(&inpart),
incoming,true,false);
SpinorBarWaveFunction::
constructSpinInfo(_wavebar,decay[iferm],outgoing,true);
SpinorWaveFunction::
constructSpinInfo(_wave ,decay[ianti],outgoing,true);
return 0.;
}
SpinorBarWaveFunction::
calculateWaveFunctions(_wavebar,decay[iferm],outgoing);
SpinorWaveFunction::
calculateWaveFunctions(_wave ,decay[ianti],outgoing);
// compute the matrix element
Energy2 scale(sqr(inpart.mass()));
unsigned int ifm,ia,vhel;
for(ifm=0;ifm<2;++ifm) {
for(ia=0;ia<2;++ia) {
for(vhel=0;vhel<3;++vhel) {
if(iferm>ianti) (*ME())(vhel,ia,ifm)=
FFZvertex_->evaluate(scale,_wave[ia],_wavebar[ifm],_vectors[vhel]);
else (*ME())(vhel,ifm,ia)=
FFZvertex_->evaluate(scale,_wave[ia],_wavebar[ifm],_vectors[vhel]);
}
}
}
double output=(ME()->contract(_rho)).real()*UnitRemoval::E2/scale;
if(abs(decay[0]->id())<=6) output*=3.;
if(decay[0]->hasColour()) decay[0]->antiColourNeighbour(decay[1]);
else if(decay[1]->hasColour()) decay[1]->antiColourNeighbour(decay[0]);
return output;
}
void SMZDecayer::doinitrun() {
DecayIntegrator::doinitrun();
if(initialize()) {
for(unsigned int ix=0;ix<numberModes();++ix) {
if(ix<5) quarkWeight_ [ix ]=mode(ix)->maxWeight();
else if(ix<11) leptonWeight_[ix-5 ]=mode(ix)->maxWeight();
}
}
}
void SMZDecayer::dataBaseOutput(ofstream & output,
bool header) const {
if(header) output << "update decayers set parameters=\"";
for(unsigned int ix=0;ix<quarkWeight_.size();++ix) {
output << "newdef " << name() << ":QuarkMax " << ix << " "
<< quarkWeight_[ix] << "\n";
}
for(unsigned int ix=0;ix<leptonWeight_.size();++ix) {
output << "newdef " << name() << ":LeptonMax " << ix << " "
<< leptonWeight_[ix] << "\n";
}
// parameters for the DecayIntegrator base class
DecayIntegrator::dataBaseOutput(output,false);
if(header) output << "\n\" where BINARY ThePEGName=\""
<< fullName() << "\";" << endl;
}
InvEnergy2 SMZDecayer::
realEmissionME(unsigned int,const Particle &parent,
ParticleVector &children,
unsigned int iemitter,
double ctheta, double stheta,
const LorentzRotation & rot1,
const LorentzRotation & rot2) {
// check the number of products and parent
assert(children.size()==3 && parent.id()==ParticleID::Z0);
// the electric charge
double e = sqrt(SM().alphaEM()*4.*Constants::pi);
// azimuth of the photon
double phi = children[2]->momentum().phi();
// wavefunctions for the decaying particle in the rotated dipole frame
vector<VectorWaveFunction> vec1 = _vectors;
for(unsigned int ix=0;ix<vec1.size();++ix) {
vec1[ix].transform(rot1);
vec1[ix].transform(rot2);
}
// wavefunctions for the decaying particle in the rotated rest frame
vector<VectorWaveFunction> vec2 = _vectors;
for(unsigned int ix=0;ix<vec1.size();++ix) {
vec2[ix].transform(rot2);
}
// find the outgoing particle and antiparticle
unsigned int iferm(0),ianti(1);
if(children[iferm]->id()<0) swap(iferm,ianti);
// wavefunctions for the particles before the radiation
// wavefunctions for the outgoing fermion
SpinorBarWaveFunction wavebartemp;
Lorentz5Momentum ptemp = - _wavebar[0].momentum();
ptemp *= rot2;
if(ptemp.perp()/ptemp.e()<1e-10) {
ptemp.setX(ZERO);
ptemp.setY(ZERO);
}
wavebartemp = SpinorBarWaveFunction(ptemp,_wavebar[0].particle(),outgoing);
// wavefunctions for the outgoing antifermion
SpinorWaveFunction wavetemp;
ptemp = - _wave[0].momentum();
ptemp *= rot2;
if(ptemp.perp()/ptemp.e()<1e-10) {
ptemp.setX(ZERO);
ptemp.setY(ZERO);
}
wavetemp = SpinorWaveFunction(ptemp,_wave[0].particle(),outgoing);
// loop over helicities
vector<SpinorWaveFunction> wf_old;
vector<SpinorBarWaveFunction> wfb_old;
for(unsigned int ihel=0;ihel<2;++ihel) {
wavetemp.reset(ihel);
wf_old.push_back(wavetemp);
wavebartemp.reset(ihel);
wfb_old.push_back(wavebartemp);
}
// calculate the wave functions for the new fermions
// ensure the momenta have pT=0
for(unsigned int ix=0;ix<2;++ix) {
Lorentz5Momentum ptemp = children[ix]->momentum();
if(ptemp.perp()/ptemp.e()<1e-10) {
ptemp.setX(ZERO);
ptemp.setY(ZERO);
children[ix]->set5Momentum(ptemp);
}
}
// calculate the wavefunctions
vector<SpinorBarWaveFunction> wfb;
SpinorBarWaveFunction::calculateWaveFunctions(wfb,children[iferm],outgoing);
vector<SpinorWaveFunction> wf;
SpinorWaveFunction::calculateWaveFunctions (wf ,children[ianti],outgoing);
// wave functions for the photons
vector<VectorWaveFunction> photon;
VectorWaveFunction::calculateWaveFunctions(photon,children[2],outgoing,true);
// loop to calculate the matrix elements
Complex lome[3][2][2],diffme[3][2][2][2],summe[3][2][2][2];
Energy2 scale(sqr(parent.mass()));
Complex diff[2]={0.,0.};
Complex sum [2]={0.,0.};
for(unsigned int ifm=0;ifm<2;++ifm) {
for(unsigned int ia=0;ia<2;++ia) {
for(unsigned int vhel=0;vhel<3;++vhel) {
// calculation of the leading-order matrix element
Complex loamp = FFZvertex_->evaluate(scale,wf_old[ia],
wfb_old[ifm],vec2[vhel]);
Complex lotemp = FFZvertex_->evaluate(scale,wf[ia],
wfb[ifm],vec1[vhel]);
if(iferm>ianti) lome[vhel][ia][ifm] = loamp;
else lome[vhel][ifm][ia] = loamp;
// photon loop for the real emmision terms
for(unsigned int phel=0;phel<2;++phel) {
// radiation from the antifermion
// normal case with small angle treatment
if(children[2 ]->momentum().z()/
children[iferm]->momentum().z()>=ZERO && iemitter == iferm ) {
Complex dipole = e*double(children[iferm]->dataPtr()->iCharge())/3.*
UnitRemoval::E*loamp*
(children[iferm]->momentum()*photon[2*phel].wave())/
(children[iferm]->momentum()*children[2]->momentum());
// sum and difference
SpinorBarWaveFunction foff =
FFPvertex_->evaluateSmall(ZERO,3,children[iferm]->dataPtr()->CC(),
wfb[ifm],photon[2*phel],
ifm,2*phel,ctheta,phi,stheta,false);
diff[0] = FFZvertex_->evaluate(scale,wf[ia],foff,vec1[vhel]) +
e*double(children[iferm]->dataPtr()->iCharge())/3.*
UnitRemoval::E*(lotemp-loamp)*
(children[iferm]->momentum()*photon[2*phel].wave())/
(children[iferm]->momentum()*children[2]->momentum());
sum [0] = diff[0]+2.*dipole;
}
// special if fermion backwards
else {
SpinorBarWaveFunction foff =
FFPvertex_->evaluate(ZERO,3,children[iferm]->dataPtr()->CC(),
wfb[ifm],photon[2*phel]);
Complex diag =
FFZvertex_->evaluate(scale,wf[ia],foff,vec1[vhel]);
Complex dipole = e*double(children[iferm]->dataPtr()->iCharge())/3.*
UnitRemoval::E*loamp*
(children[iferm]->momentum()*photon[2*phel].wave())/
(children[iferm]->momentum()*children[2]->momentum());
diff[0] = diag-dipole;
sum [0] = diag+dipole;
}
// radiation from the anti fermion
// small angle case in general
if(children[2 ]->momentum().z()/
children[ianti]->momentum().z()>=ZERO && iemitter == ianti ) {
Complex dipole = e*double(children[ianti]->dataPtr()->iCharge())/3.*
UnitRemoval::E*loamp*
(children[ianti]->momentum()*photon[2*phel].wave())/
(children[ianti]->momentum()*children[2]->momentum());
// sum and difference
SpinorWaveFunction foff =
FFPvertex_->evaluateSmall(ZERO,3,children[ianti]->dataPtr()->CC(),
wf[ia],photon[2*phel],
ia,2*phel,ctheta,phi,stheta,false);
diff[1] = FFZvertex_->evaluate(scale,foff ,wfb[ifm],vec1[vhel]) +
e*double(children[ianti]->dataPtr()->iCharge())/3.*
UnitRemoval::E*(lotemp-loamp)*
(children[ianti]->momentum()*photon[2*phel].wave())/
(children[ianti]->momentum()*children[2]->momentum());
sum [1] = diff[1]+2.*dipole;
}
// special if fermion backwards after radiation
else {
SpinorWaveFunction foff =
FFPvertex_->evaluate(ZERO,3,children[ianti]->dataPtr()->CC(),
wf[ia],photon[2*phel]);
Complex diag =
FFZvertex_->evaluate(scale,foff ,wfb[ifm],vec1[vhel]);
Complex dipole = e*double(children[ianti]->dataPtr()->iCharge())/3.*
UnitRemoval::E*loamp*
(children[ianti]->momentum()*photon[2*phel].wave())/
(children[ianti]->momentum()*children[2]->momentum());
// sum and difference
diff[1] = diag - dipole;
sum [1] = diag + dipole;
}
// add to me
if(iferm>ianti) {
diffme[vhel][ia][ifm][phel] = diff[0] + diff[1];
summe [vhel][ia][ifm][phel] = sum[0] + sum[1] ;
}
else {
diffme [vhel][ifm][ia][phel] = diff[0] + diff[1];
summe [vhel][ifm][ia][phel] = sum[0] + sum[1] ;
}
}
}
}
}
// cerr << parent << "\n";
// for(unsigned int ix=0;ix<children.size();++ix) {
// cerr << *children[ix] << "\n";
// }
// _rho = RhoDMatrix(PDT::Spin1);
Complex lo(0.),difference(0.);
for(unsigned int vhel1=0;vhel1<3;++vhel1) {
for(unsigned int vhel2=0;vhel2<3;++vhel2) {
for(unsigned int ifm=0;ifm<2;++ifm) {
for(unsigned int ia=0;ia<2;++ia) {
lo += _rho(vhel1,vhel2)*lome[vhel1][ifm][ia]*conj(lome[vhel2][ifm][ia]);
for(unsigned int phel=0;phel<2;++phel) {
difference +=
_rho(vhel1,vhel2)*diffme[vhel1][ifm][ia][phel]*conj(summe[vhel2][ifm][ia][phel]);
}
}
}
}
}
// // analytic result
// double iCharge = children[0]->dataPtr()->iCharge()*
// children[1]->dataPtr()->iCharge()/9.;
// Energy2 ubar = 2.*children[0]->momentum()*children[2]->momentum();
// Energy2 tbar = 2.*children[1]->momentum()*children[2]->momentum();
// double mu2 = sqr(children[1]->mass()/parent.mass());
// double gL = (FFZvertex_->left() *FFZvertex_->norm()).real();
// double gR = (FFZvertex_->right()*FFZvertex_->norm()).real();
// Energy2 den = sqr(parent.mass())*(((sqr(gL)+sqr(gR))*(1-mu2)+6.*mu2*gL*gR));
// InvEnergy2 anal = -iCharge*( 2.*(ubar/tbar+tbar/ubar)/sqr(parent.mass())+
// 4.*mu2/den*((sqr(gL)+sqr(gR))*(1+ubar/tbar+tbar/ubar)
// -2.*gL*gR*(1.+2.*(ubar/tbar+tbar/ubar))));
// cerr << "testing ratio " << parent.PDGName()
// << " " << difference.real()/sqr(e)/lo.real()*UnitRemoval::InvE2/(anal) << "\n"
// << stheta << " " << ctheta << "\n";
return difference.real()/sqr(e)/lo.real()*UnitRemoval::InvE2;
}
double SMZDecayer::oneLoopVirtualME(unsigned int,
const Particle & parent,
const ParticleVector & children) {
assert(children.size()==2);
// velocities of the particles
double beta = sqrt(1.-4.*sqr(children[0]->mass()/parent.mass()));
double opb = 1.+beta;
double omb = 4.*sqr(children[0]->mass()/parent.mass())/opb;
// couplings
double gL = (FFZvertex_->left() *FFZvertex_->norm()).real();
double gR = (FFZvertex_->right()*FFZvertex_->norm()).real();
double gA = 0.5*(gL-gR);
double gV = 0.5*(gL+gR);
// correction terms
double ln = log(omb/opb);
double f1 = 1. + ln*beta;
double fA = 1. + ln/beta;
InvEnergy f2 = 0.5*sqrt(omb*opb)/parent.mass()/beta*ln;
// momentum difference for the loop
Lorentz5Momentum q = children[0]->momentum()-children[1]->momentum();
if(children[0]->id()<0) q *= -1.;
// spinors
vector<LorentzSpinor <SqrtEnergy> > sp;
vector<LorentzSpinorBar<SqrtEnergy> > sbar;
for(unsigned int ix=0;ix<2;++ix) {
sp .push_back( _wave[ix].dimensionedWave());
sbar.push_back(_wavebar[ix].dimensionedWave());
}
// polarization vectors
vector<LorentzPolarizationVector> pol;
for(unsigned int ix=0;ix<3;++ix)
pol.push_back(_vectors[ix].wave());
// matrix elements
complex<Energy> lome[3][2][2],loopme[3][2][2];
for(unsigned int vhel=0;vhel<3;++vhel) {
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
complex<Energy> vector =
sp[ihel1].generalCurrent(sbar[ihel2], 1.,1.).dot(pol[vhel]);
complex<Energy> axial =
sp[ihel1].generalCurrent(sbar[ihel2],-1.,1.).dot(pol[vhel]);
complex<Energy2> scalar =
sp[ihel1].scalar(sbar[ihel2])*(q*pol[vhel]);
lome [vhel][ihel1][ihel2] = gV* vector-gA* axial;
loopme[vhel][ihel1][ihel2] = gV*f1*vector-gA*fA*axial+scalar*f2*gV;
}
}
}
// sum sums
complex<Energy2> den(ZERO),num(ZERO);
for(unsigned int vhel1=0;vhel1<3;++vhel1) {
for(unsigned int vhel2=0;vhel2<3;++vhel2) {
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
num += _rho(vhel1,vhel2)*
( lome[vhel1][ihel1][ihel2]*conj(loopme[vhel2][ihel1][ihel2])+
loopme[vhel1][ihel1][ihel2]*conj( lome[vhel2][ihel1][ihel2]));
den += _rho(vhel1,vhel2)*
lome[vhel1][ihel1][ihel2]*conj(lome[vhel2][ihel1][ihel2]);
}
}
}
}
// prefactor
double iCharge = children[0]->dataPtr()->iCharge()*
children[1]->dataPtr()->iCharge()/9.;
double pre = 0.5*SM().alphaEM()*iCharge/Constants::pi;
// output
return pre*num.real()/den.real();
}
void SMZDecayer::
-initializeMECorrection(ShowerTreePtr tree, double & initial,
+initializeMECorrection(PerturbativeProcessPtr born, double & initial,
double & final) {
- map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cjt;
// get the quark and antiquark
ParticleVector qq;
- for(cjt=tree->outgoingLines().begin();cjt!=tree->outgoingLines().end();++cjt)
- qq.push_back(cjt->first->copy());
+ for(unsigned int ix=0;ix<born->outgoing().size();++ix)
+ qq.push_back(born->outgoing()[ix].first);
// ensure quark first
if(qq[0]->id()<0) swap(qq[0],qq[1]);
// centre of mass energy
d_Q_ = (qq[0]->momentum() + qq[1]->momentum()).m();
// quark mass
d_m_ = 0.5*(qq[0]->momentum().m()+qq[1]->momentum().m());
// set the other parameters
setRho(sqr(d_m_/d_Q_));
setKtildeSymm();
// otherwise can do it
initial=1.;
final =1.;
}
-void SMZDecayer::
-applyHardMatrixElementCorrection(ShowerTreePtr tree) {
+RealEmissionProcessPtr SMZDecayer::
+applyHardMatrixElementCorrection(PerturbativeProcessPtr born) {
// get the quark and antiquark
ParticleVector qq;
- map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cit;
- for(cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().end();++cit)
- qq.push_back(cit->first->copy());
- if(!qq[0]->dataPtr()->coloured()) return;
+ for(unsigned int ix=0;ix<born->outgoing().size();++ix)
+ qq.push_back(born->outgoing()[ix].first);
+ if(!qq[0]->dataPtr()->coloured()) return RealEmissionProcessPtr();
// ensure quark first
- if(qq[0]->id()<0) swap(qq[0],qq[1]);
+ bool order = qq[0]->id()<0;
+ if(order) swap(qq[0],qq[1]);
// get the momenta
vector<Lorentz5Momentum> newfs = applyHard(qq);
// return if no emission
- if(newfs.size()!=3) return;
+ if(newfs.size()!=3) return RealEmissionProcessPtr();
// perform final check to ensure energy greater than constituent mass
for (int i=0; i<2; i++) {
- if (newfs[i].e() < qq[i]->data().constituentMass()) return;
+ if (newfs[i].e() < qq[i]->data().constituentMass()) return RealEmissionProcessPtr();
}
if (newfs[2].e() < getParticleData(ParticleID::g)->constituentMass())
- return;
+ return RealEmissionProcessPtr();
// set masses
for (int i=0; i<2; i++) newfs[i].setMass(qq[i]->mass());
newfs[2].setMass(ZERO);
// decide which particle emits
bool firstEmits=
newfs[2].vect().perp2(newfs[0].vect())<
newfs[2].vect().perp2(newfs[1].vect());
// create the new quark, antiquark and gluon
PPtr newg = getParticleData(ParticleID::g)->produceParticle(newfs[2]);
- PPtr newq,newa;
- if(firstEmits) {
- newq = getParticleData(abs(qq[0]->id()))->produceParticle(newfs[0]);
- newa = new_ptr(Particle(*qq[1]));
- qq[1]->antiColourLine()->removeAntiColoured(newa);
- newa->set5Momentum(newfs[1]);
+ PPtr newq = qq[0]->dataPtr()->produceParticle(newfs[0]);
+ PPtr newa = qq[1]->dataPtr()->produceParticle(newfs[1]);
+ // create the output real emission process
+ RealEmissionProcessPtr real(new_ptr(RealEmissionProcess(born)));
+ for(unsigned int ix=0;ix<born->incoming().size();++ix) {
+ real->incoming().push_back(born->incoming()[ix]);
+ }
+ if(order) {
+ real->outgoing().push_back(make_pair(newq,PerturbativeProcessPtr()));
+ real->outgoing().push_back(make_pair(newa,PerturbativeProcessPtr()));
+ real->outgoing().push_back(make_pair(newg,PerturbativeProcessPtr()));
}
else {
- newq = new_ptr(Particle(*qq[0]));
- qq[0]->colourLine()->removeColoured(newq);
- newq->set5Momentum(newfs[0]);
- newa = getParticleData(-abs(qq[0]->id()))->produceParticle(newfs[1]);
+ real->outgoing().push_back(make_pair(newa,PerturbativeProcessPtr()));
+ real->outgoing().push_back(make_pair(newq,PerturbativeProcessPtr()));
+ real->outgoing().push_back(make_pair(newg,PerturbativeProcessPtr()));
+ firstEmits = !firstEmits;
}
- // get the original colour line
- ColinePtr col;
- if(qq[0]->id()>0) col=qq[0]->colourLine();
- else col=qq[0]->antiColourLine();
- // set the colour lines
+ // make colour connections
+ newg->colourNeighbour(newq);
+ newa->colourNeighbour(newg);
if(firstEmits) {
- col->addColoured(newq);
- col->addAntiColoured(newg);
- newa->colourNeighbour(newg);
+ real->emitter(1);
+ real->spectator(2);
}
else {
- col->addAntiColoured(newa);
- col->addColoured(newg);
- newq->antiColourNeighbour(newg);
+ real->emitter(2);
+ real->spectator(1);
}
- // change the existing quark and antiquark
- PPtr orig;
- for(cit=tree->outgoingLines().begin();cit!=tree->outgoingLines().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,true)));
- cit->first->progenitor(sp);
- tree->outgoingLines()[cit->first]=sp;
- cit->first->perturbative(!firstEmits);
- if(firstEmits) 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,true)));
- cit->first->progenitor(sp);
- tree->outgoingLines()[cit->first]=sp;
- cit->first->perturbative(firstEmits);
- if(!firstEmits) orig=cit->first->original();
- }
- }
- // 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);
+ return real;
}
vector<Lorentz5Momentum> SMZDecayer::
applyHard(const ParticleVector &p) {
double x, xbar;
vector<Lorentz5Momentum> fs;
// return if no emission
if (getHard(x, xbar) < UseRandom::rnd() || p.size() != 2) return fs;
// centre of mass energy
Lorentz5Momentum pcm = p[0]->momentum() + p[1]->momentum();
// momenta of quark,antiquark and gluon
Lorentz5Momentum pq, pa, pg;
if (p[0]->id() > 0) {
pq = p[0]->momentum();
pa = p[1]->momentum();
} else {
pa = p[0]->momentum();
pq = p[1]->momentum();
}
// boost to boson rest frame
Boost beta = (pcm.findBoostToCM());
pq.boost(beta);
pa.boost(beta);
// return if fails ?????
double xg = 2.-x-xbar;
if((1.-x)*(1.-xbar)*(1.-xg) < d_rho_*xg*xg) return fs;
Axis u1, u2, u3;
// moduli of momenta in units of Q and cos theta
// stick to q direction?
// p1 is the one that is kept, p2 is the other fermion, p3 the gluon.
Energy e1, e2, e3;
Energy pp1, pp2, pp3;
bool keepq = true;
if (UseRandom::rnd() > sqr(x)/(sqr(x)+sqr(xbar)))
keepq = false;
if (keepq) {
pp1 = d_Q_*sqrt(sqr(x)-4.*d_rho_)/2.;
pp2 = d_Q_*sqrt(sqr(xbar)-4.*d_rho_)/2.;
e1 = d_Q_*x/2.;
e2 = d_Q_*xbar/2.;
u1 = pq.vect().unit();
} else {
pp2 = d_Q_*sqrt(sqr(x)-4.*d_rho_)/2.;
pp1 = d_Q_*sqrt(sqr(xbar)-4.*d_rho_)/2.;
e2 = d_Q_*x/2.;
e1 = d_Q_*xbar/2.;
u1 = pa.vect().unit();
}
pp3 = d_Q_*xg/2.;
e3 = pp3;
u2 = u1.orthogonal();
u2 /= u2.mag();
u3 = u1.cross(u2);
u3 /= u3.mag();
double ct2=-2., ct3=-2.;
if (pp1 == ZERO || pp2 == ZERO || pp3 == ZERO) {
bool touched = false;
if (pp1 == ZERO) {
ct2 = 1;
ct3 = -1;
touched = true;
}
if (pp2 == ZERO || pp3 == ZERO) {
ct2 = 1;
ct3 = 1;
touched = true;
}
if (!touched)
throw Exception() << "SMZDecayer::applyHard()"
<< " did not set ct2/3"
<< Exception::abortnow;
} else {
ct3 = (sqr(pp1)+sqr(pp3)-sqr(pp2))/(2.*pp1*pp3);
ct2 = (sqr(pp1)+sqr(pp2)-sqr(pp3))/(2.*pp1*pp2);
}
double phi = Constants::twopi*UseRandom::rnd();
double cphi = cos(phi);
double sphi = sin(phi);
double st2 = sqrt(1.-sqr(ct2));
double st3 = sqrt(1.-sqr(ct3));
ThreeVector<Energy> pv1, pv2, pv3;
pv1 = pp1*u1;
pv2 = -ct2*pp2*u1 + st2*cphi*pp2*u2 + st2*sphi*pp2*u3;
pv3 = -ct3*pp3*u1 - st3*cphi*pp3*u2 - st3*sphi*pp3*u3;
if (keepq) {
pq = Lorentz5Momentum(pv1, e1);
pa = Lorentz5Momentum(pv2, e2);
} else {
pa = Lorentz5Momentum(pv1, e1);
pq = Lorentz5Momentum(pv2, e2);
}
pg = Lorentz5Momentum(pv3, e3);
pq.boost(-beta);
pa.boost(-beta);
pg.boost(-beta);
fs.push_back(pq);
fs.push_back(pa);
fs.push_back(pg);
return fs;
}
double SMZDecayer::getHard(double &x1, double &x2) {
double w = 0.0;
double y1 = UseRandom::rnd(),y2 = UseRandom::rnd();
// simply double MC efficiency
// -> weight has to be divided by two (Jacobian)
if (y1 + y2 > 1) {
y1 = 1.-y1;
y2 = 1.-y2;
}
bool inSoft = false;
if (y1 < 0.25) {
if (y2 < 0.25) {
inSoft = true;
if (y1 < y2) {
y1 = 0.25-y1;
y2 = y1*(1.5 - 2.*y2);
} else {
y2 = 0.25 - y2;
y1 = y2*(1.5 - 2.*y1);
}
} else {
if (y2 < y1 + 2.*sqr(y1)) return w;
}
} else {
if (y2 < 0.25) {
if (y1 < y2 + 2.*sqr(y2)) return w;
}
}
// inside PS?
x1 = 1.-y1;
x2 = 1.-y2;
if(y1*y2*(1.-y1-y2) < d_rho_*sqr(y1+y2)) return w;
double k1 = getKfromX(x1, x2);
double k2 = getKfromX(x2, x1);
// Is it in the quark emission zone?
if (k1 < d_kt1_) return 0.0;
// No...is it in the anti-quark emission zone?
if (k2 < d_kt2_) return 0.0;
// Point is in dead zone: compute q qbar g weight
w = MEV(x1, x2);
// for axial:
// w = MEA(x1, x2);
// Reweight soft region
if (inSoft) {
if (y1 < y2) w *= 2.*y1;
else w *= 2.*y2;
}
// alpha and colour factors
Energy2 pt2 = sqr(d_Q_)*(1.-x1)*(1.-x2);
w *= 1./3./Constants::pi*alpha_->value(pt2);
return w;
}
bool SMZDecayer::
softMatrixElementVeto(ShowerProgenitorPtr initial,ShowerParticlePtr parent,Branching br) {
// check we should be applying the veto
if(parent->id()!=initial->progenitor()->id()||
br.ids[0]->id()!=br.ids[1]->id()||
br.ids[2]->id()!=ParticleID::g) return false;
// calculate pt
double d_z = br.kinematics->z();
Energy d_qt = br.kinematics->scale();
Energy2 d_m2 = parent->momentum().m2();
Energy pPerp = (1.-d_z)*sqrt( sqr(d_z*d_qt) - d_m2);
// if not hardest so far don't apply veto
if(pPerp<initial->highestpT()) return false;
// calculate the weight
double weight = 0.;
if(parent->id()>0) weight = qWeightX(d_qt, d_z);
else weight = qbarWeightX(d_qt, d_z);
// compute veto from weight
bool veto = !UseRandom::rndbool(weight);
// if vetoing reset the scale
if(veto) parent->vetoEmission(br.type,br.kinematics->scale());
// return the veto
return veto;
}
void SMZDecayer::setRho(double r)
{
d_rho_ = r;
d_v_ = sqrt(1.-4.*d_rho_);
}
void SMZDecayer::setKtildeSymm() {
d_kt1_ = (1. + sqrt(1. - 4.*d_rho_))/2.;
setKtilde2();
}
void SMZDecayer::setKtilde2() {
double num = d_rho_ * d_kt1_ + 0.25 * d_v_ *(1.+d_v_)*(1.+d_v_);
double den = d_kt1_ - d_rho_;
d_kt2_ = num/den;
}
double SMZDecayer::getZfromX(double x1, double x2) {
double uval = u(x2);
double num = x1 - (2. - x2)*uval;
double den = sqrt(x2*x2 - 4.*d_rho_);
return uval + num/den;
}
double SMZDecayer::getKfromX(double x1, double x2) {
double zval = getZfromX(x1, x2);
return (1.-x2)/(zval*(1.-zval));
}
double SMZDecayer::MEV(double x1, double x2) {
// Vector part
double num = (x1+2.*d_rho_)*(x1+2.*d_rho_) + (x2+2.*d_rho_)*(x2+2.*d_rho_)
- 8.*d_rho_*(1.+2.*d_rho_);
double den = (1.+2.*d_rho_)*(1.-x1)*(1.-x2);
return (num/den - 2.*d_rho_/((1.-x1)*(1.-x1))
- 2*d_rho_/((1.-x2)*(1.-x2)))/d_v_;
}
double SMZDecayer::MEA(double x1, double x2) {
// Axial part
double num = (x1+2.*d_rho_)*(x1+2.*d_rho_) + (x2+2.*d_rho_)*(x2+2.*d_rho_)
+ 2.*d_rho_*((5.-x1-x2)*(5.-x1-x2) - 19.0 + 4*d_rho_);
double den = d_v_*d_v_*(1.-x1)*(1.-x2);
return (num/den - 2.*d_rho_/((1.-x1)*(1.-x1))
- 2*d_rho_/((1.-x2)*(1.-x2)))/d_v_;
}
double SMZDecayer::u(double x2) {
return 0.5*(1. + d_rho_/(1.-x2+d_rho_));
}
void SMZDecayer::
getXXbar(double kti, double z, double &x, double &xbar) {
double w = sqr(d_v_) + kti*(-1. + z)*z*(2. + kti*(-1. + z)*z);
if (w < 0) {
x = -1.;
xbar = -1;
} else {
x = (1. + sqr(d_v_)*(-1. + z) + sqr(kti*(-1. + z))*z*z*z
+ z*sqrt(w)
- kti*(-1. + z)*z*(2. + z*(-2 + sqrt(w))))/
(1. - kti*(-1. + z)*z + sqrt(w));
xbar = 1. + kti*(-1. + z)*z;
}
}
double SMZDecayer::qWeight(double x, double xbar) {
double rval;
double xg = 2. - xbar - x;
// always return one in the soft gluon region
if(xg < EPS_) return 1.0;
// check it is in the phase space
if((1.-x)*(1.-xbar)*(1.-xg) < d_rho_*xg*xg) return 0.0;
double k1 = getKfromX(x, xbar);
double k2 = getKfromX(xbar, x);
// Is it in the quark emission zone?
if(k1 < d_kt1_) {
rval = MEV(x, xbar)/PS(x, xbar);
// is it also in the anti-quark emission zone?
if(k2 < d_kt2_) rval *= 0.5;
return rval;
}
return 1.0;
}
double SMZDecayer::qbarWeight(double x, double xbar) {
double rval;
double xg = 2. - xbar - x;
// always return one in the soft gluon region
if(xg < EPS_) return 1.0;
// check it is in the phase space
if((1.-x)*(1.-xbar)*(1.-xg) < d_rho_*xg*xg) return 0.0;
double k1 = getKfromX(x, xbar);
double k2 = getKfromX(xbar, x);
// Is it in the antiquark emission zone?
if(k2 < d_kt2_) {
rval = MEV(x, xbar)/PS(xbar, x);
// is it also in the quark emission zone?
if(k1 < d_kt1_) rval *= 0.5;
return rval;
}
return 1.0;
}
double SMZDecayer::qWeightX(Energy qtilde, double z) {
double x, xb;
getXXbar(sqr(qtilde/d_Q_), z, x, xb);
// if exceptionally out of phase space, leave this emission, as there
// is no good interpretation for the soft ME correction.
if (x < 0 || xb < 0) return 1.0;
return qWeight(x, xb);
}
double SMZDecayer::qbarWeightX(Energy qtilde, double z) {
double x, xb;
getXXbar(sqr(qtilde/d_Q_), z, xb, x);
// see above in qWeightX.
if (x < 0 || xb < 0) return 1.0;
return qbarWeight(x, xb);
}
double SMZDecayer::PS(double x, double xbar) {
double u = 0.5*(1. + d_rho_ / (1.-xbar+d_rho_));
double z = u + (x - (2.-xbar)*u)/sqrt(xbar*xbar - 4.*d_rho_);
double brack = (1.+z*z)/(1.-z)- 2.*d_rho_/(1-xbar);
// interesting: the splitting function without the subtraction
// term. Actually gives a much worse approximation in the collinear
// limit. double brack = (1.+z*z)/(1.-z);
double den = (1.-xbar)*sqrt(xbar*xbar - 4.*d_rho_);
return brack/den;
}
diff --git a/Decay/Perturbative/SMZDecayer.h b/Decay/Perturbative/SMZDecayer.h
--- a/Decay/Perturbative/SMZDecayer.h
+++ b/Decay/Perturbative/SMZDecayer.h
@@ -1,456 +1,456 @@
// -*- C++ -*-
//
// SMZDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_SMZDecayer_H
#define HERWIG_SMZDecayer_H
//
// This is the declaration of the SMZDecayer class.
//
#include "Herwig/Decay/DecayIntegrator.h"
#include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h"
#include "Herwig/Decay/DecayPhaseSpaceMode.h"
#include "Herwig/Shower/QTilde/Couplings/ShowerAlpha.fh"
namespace Herwig {
using namespace ThePEG;
using namespace ThePEG::Helicity;
/** \ingroup Decay
*
* The <code>SMZDecayer</code> is designed to perform the decay of the
* Z boson to the Standard Model fermions. In principle it can also
* be used for these decays in any model.
*
* @see DecayIntegrator
*
*/
class SMZDecayer: public DecayIntegrator {
public:
/**
* Default constructor.
*/
SMZDecayer();
/**
* Virtual members to be overridden by inheriting classes
* which implement hard corrections
*/
//@{
/**
* Has an old fashioned ME correction
*/
virtual bool hasMECorrection() {return true;}
/**
* Initialize the ME correction
*/
- virtual void initializeMECorrection(ShowerTreePtr , double & ,
+ virtual void initializeMECorrection(PerturbativeProcessPtr , double & ,
double & );
-
+
/**
* Apply the hard matrix element correction to a given hard process or decay
*/
- virtual void applyHardMatrixElementCorrection(ShowerTreePtr);
+ virtual RealEmissionProcessPtr applyHardMatrixElementCorrection(PerturbativeProcessPtr);
/**
* 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:
/**
* Which of the possible decays is required
* @param cc Is this mode the charge conjugate
* @param parent The decaying particle
* @param children The decay products
*/
virtual int modeNumber(bool & cc, tcPDPtr parent,
const tPDVector & children) const;
/**
* Return the matrix element squared for a given mode and phase-space channel.
* @param ichan The channel we are calculating the matrix element for.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the calculation of the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay,MEOption meopt) const;
/**
* Output the setup information for the particle database
* @param os The stream to output the information to
* @param header Whether or not to output the information for MySQL
*/
virtual void dataBaseOutput(ofstream & os,bool header) const;
/**
* Members for the generation of QED radiation in the decays
*/
//@{
/**
* The one-loop virtual correction.
* @param imode The mode required.
* @param part The decaying particle.
* @param products The decay products including the radiated photon.
* @return Whether the correction is implemented
*/
virtual double oneLoopVirtualME(unsigned int imode,
const Particle & part,
const ParticleVector & products);
/**
* The real emission matrix element
* @param imode The mode required
* @param part The decaying particle
* @param products The decay products including the radiated photon
* @param iemitter The particle which emitted the photon
* @param ctheta The cosine of the polar angle between the photon and the
* emitter
* @param stheta The sine of the polar angle between the photon and the
* emitter
* @param rot1 Rotation from rest frame to frame for real emission
* @param rot2 Rotation to place emitting particle along z
*/
virtual InvEnergy2 realEmissionME(unsigned int imode,
const Particle & part,
ParticleVector & products,
unsigned int iemitter,
double ctheta, double stheta,
const LorentzRotation & rot1,
const LorentzRotation & rot2);
//@}
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);
//@}
/**
* Standard Init function used to initialize the interfaces.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const {return new_ptr(*this);}
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const {return new_ptr(*this);}
//@}
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving and
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
/**
* Initialize this object. Called in the run phase just before
* a run begins.
*/
virtual void doinitrun();
//@}
protected:
/**
* Apply the hard matrix element
*/
vector<Lorentz5Momentum> applyHard(const ParticleVector &p);
/**
* Get the weight for hard emission
*/
double getHard(double &, double &);
/**
* Set the \f$\rho\f$ parameter
*/
void setRho(double);
/**
* Set the \f$\tilde{\kappa}\f$ parameters symmetrically
*/
void setKtildeSymm();
/**
* Set second \f$\tilde{\kappa}\f$, given the first.
*/
void setKtilde2();
/**
* Translate the variables from \f$x_q,x_{\bar{q}}\f$ to \f$\tilde{\kappa},z\f$
*/
//@{
/**
* Calculate \f$z\f$.
*/
double getZfromX(double, double);
/**
* Calculate \f$\tilde{\kappa}\f$.
*/
double getKfromX(double, double);
//@}
/**
* Calculate \f$x_{q},x_{\bar{q}}\f$ from \f$\tilde{\kappa},z\f$.
* @param kt \f$\tilde{\kappa}\f$
* @param z \f$z\f$
* @param x \f$x_{q}\f$
* @param xbar \f$x_{\bar{q}}\f$
*/
void getXXbar(double kt, double z, double & x, double & xbar);
/**
* Soft weight
*/
//@{
/**
* Soft quark weight calculated from \f$x_{q},x_{\bar{q}}\f$
* @param x \f$x_{q}\f$
* @param xbar \f$x_{\bar{q}}\f$
*/
double qWeight(double x, double xbar);
/**
* Soft antiquark weight calculated from \f$x_{q},x_{\bar{q}}\f$
* @param x \f$x_{q}\f$
* @param xbar \f$x_{\bar{q}}\f$
*/
double qbarWeight(double x, double xbar);
/**
* Soft quark weight calculated from \f$\tilde{q},z\f$
* @param qtilde \f$\tilde{q}\f$
* @param z \f$z\f$
*/
double qWeightX(Energy qtilde, double z);
/**
* Soft antiquark weight calculated from \f$\tilde{q},z\f$
* @param qtilde \f$\tilde{q}\f$
* @param z \f$z\f$
*/
double qbarWeightX(Energy qtilde, double z);
//@}
/**
* ????
*/
double u(double);
/**
* Vector and axial vector parts of the matrix element
*/
//@{
/**
* Vector part of the matrix element
*/
double MEV(double, double);
/**
* Axial vector part of the matrix element
*/
double MEA(double, double);
/**
* The matrix element, given \f$x_1\f$, \f$x_2\f$.
* @param x1 \f$x_1\f$
* @param x2 \f$x_2\f$
*/
double PS(double x1, double x2);
/**
* Access to the strong coupling
*/
ShowerAlphaPtr alphaS() const {return alpha_;}
//@}
private:
/**
* Describe a concrete class with persistent data.
*/
static ClassDescription<SMZDecayer> initSMZDecayer;
/**
* Private and non-existent assignment operator.
*/
SMZDecayer & operator=(const SMZDecayer &);
private:
/**
* Pointer to the Z vertex
*/
FFVVertexPtr FFZvertex_;
/**
* Pointer to the photon vertex
*/
AbstractFFVVertexPtr FFPvertex_;
/**
* maximum weights for the different integrations
*/
//@{
/**
* Weights for the Z to quarks decays.
*/
vector<double> quarkWeight_;
/**
* Weights for the Z to leptons decays.
*/
vector<double> leptonWeight_;
//@}
/**
* Spin density matrix for the decay
*/
mutable RhoDMatrix _rho;
/**
* Polarization vectors for the decay
*/
mutable vector<VectorWaveFunction> _vectors;
/**
* Spinors for the decay
*/
mutable vector<SpinorWaveFunction> _wave;
/**
* Barred spinors for the decay
*/
mutable vector<SpinorBarWaveFunction> _wavebar;
private:
/**
* CM energy
*/
Energy d_Q_;
/**
* Quark mass
*/
Energy d_m_;
/**
* The rho parameter
*/
double d_rho_;
/**
* The v parameter
*/
double d_v_;
/**
* The initial kappa-tilde values for radiation from the quark
*/
double d_kt1_;
/**
* The initial kappa-tilde values for radiation from the antiquark
*/
double d_kt2_;
/**
* Cut-off parameter
*/
static const double EPS_;
/**
* Pointer to the coupling
*/
ShowerAlphaPtr alpha_;
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/**
* The following template specialization informs ThePEG about the
* base class of SMZDecayer.
*/
template <>
struct BaseClassTrait<Herwig::SMZDecayer,1> {
/** Typedef of the base class of SMZDecayer. */
typedef Herwig::DecayIntegrator NthBase;
};
/**
* The following template specialization informs ThePEG about the
* name of this class and the shared object where it is defined.
*/
template <>
struct ClassTraits<Herwig::SMZDecayer>
: public ClassTraitsBase<Herwig::SMZDecayer> {
/** Return the class name.*/
static string className() { return "Herwig::SMZDecayer"; }
/**
* Return the name of the shared library to be loaded to get
* access to this class and every other class it uses
* (except the base class).
*/
static string library() { return "HwPerturbativeDecay.so"; }
};
/** @endcond */
}
#endif /* HERWIG_SMZDecayer_H */
diff --git a/Decay/Perturbative/SMZFermionsPOWHEGDecayer.cc b/Decay/Perturbative/SMZFermionsPOWHEGDecayer.cc
--- a/Decay/Perturbative/SMZFermionsPOWHEGDecayer.cc
+++ b/Decay/Perturbative/SMZFermionsPOWHEGDecayer.cc
@@ -1,792 +1,793 @@
//-*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SMZFermionsPOWHEGDecayer class.
//
#include "SMZFermionsPOWHEGDecayer.h"
#include <numeric>
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/PDF/PolarizedBeamParticleData.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
-#include "Herwig/Shower/QTilde/Base/HardTree.h"
-#include "Herwig/Shower/QTilde/Base/ShowerTree.h"
+#include "Herwig/Shower/RealEmissionProcess.h"
#include "Herwig/Shower/QTilde/Base/ShowerProgenitor.h"
#include "Herwig/Shower/QTilde/Base/ShowerParticle.h"
#include "Herwig/Shower/QTilde/Base/Branching.h"
using namespace Herwig;
SMZFermionsPOWHEGDecayer::SMZFermionsPOWHEGDecayer()
: CF_(4./3.), pTmin_(1.*GeV)
{ }
IBPtr SMZFermionsPOWHEGDecayer::clone() const {
return new_ptr(*this);
}
IBPtr SMZFermionsPOWHEGDecayer::fullclone() const {
return new_ptr(*this);
}
void SMZFermionsPOWHEGDecayer::persistentOutput(PersistentOStream & os) const {
os << FFGVertex_ << FFZVertex_ << gluon_ << ounit( pTmin_, GeV );
}
void SMZFermionsPOWHEGDecayer::persistentInput(PersistentIStream & is, int) {
is >> FFGVertex_ >> FFZVertex_ >> gluon_ >> iunit( pTmin_, GeV );
}
ClassDescription<SMZFermionsPOWHEGDecayer>
SMZFermionsPOWHEGDecayer::initSMZFermionsPOWHEGDecayer;
// Definition of the static class description member.
void SMZFermionsPOWHEGDecayer::Init() {
static ClassDocumentation<SMZFermionsPOWHEGDecayer> documentation
("There is no documentation for the SMZFermionsPOWHEGDecayer class");
static Parameter<SMZFermionsPOWHEGDecayer, Energy> interfacePtMin
("minpT",
"The pt cut on hardest emision generation",
&SMZFermionsPOWHEGDecayer::pTmin_, GeV, 1.*GeV, 0*GeV, 100000.0*GeV,
false, false, Interface::limited);
}
-HardTreePtr SMZFermionsPOWHEGDecayer::
-generateHardest(ShowerTreePtr tree) {
- // Get the progenitors: Q and Qbar.
- ShowerProgenitorPtr
- QProgenitor = tree->outgoingLines().begin()->first,
- QbarProgenitor = tree->outgoingLines().rbegin()->first;
- if(QProgenitor->id()<0) swap( QProgenitor, QbarProgenitor );
- partons_.resize(2);
- partons_[0] = QProgenitor->progenitor() ->dataPtr();
- partons_[1] = QbarProgenitor->progenitor()->dataPtr();
- if(!partons_[0]->coloured()) return HardTreePtr();
- // momentum of the partons
- quark_.resize(2);
- quark_[0] = QProgenitor ->copy()->momentum();
- quark_[1] = QbarProgenitor->copy()->momentum();
- // Set the existing mass entries in partons 5 vectors with the
- // once and for all.
- quark_[0].setMass(partons_[0]->mass());
- quark_[1].setMass(partons_[1]->mass());
- gauge_.setMass(0.*MeV);
- // Get the Z boson.
- zboson_ = tree->incomingLines().begin()->first->copy();
- // copy the particle objects
- vector<PPtr> hardProcess (3);
- hardProcess[0] = zboson_;
- hardProcess[1] = QbarProgenitor->copy();
- hardProcess[2] = QProgenitor ->copy();
- // Get the Z boson mass.
- mz2_ = (quark_[0] + quark_[1]).m2();
- // Generate emission and set _quark[0,1] and _gauge to be the
- // momenta of q, qbar and g after the hardest emission:
- if(!getEvent(hardProcess)) {
- QProgenitor ->maximumpT(pTmin_,ShowerInteraction::QCD);
- QbarProgenitor->maximumpT(pTmin_,ShowerInteraction::QCD);
- return HardTreePtr();
- }
- // Ensure the energies are greater than the constituent masses:
- for (int i=0; i<2; i++) {
- if (quark_[i].e() < partons_[i]->constituentMass()) return HardTreePtr();
- if (gauge_.e() < gluon_ ->constituentMass()) return HardTreePtr();
- }
- // set masses
- quark_[0].setMass( partons_[0]->mass() );
- quark_[1].setMass( partons_[1]->mass() );
- gauge_ .setMass( ZERO );
- // assign the emitter based on evolution scales
- unsigned int iemitter = quark_[0]*gauge_ > quark_[1]*gauge_ ? 1 : 0;
- unsigned int ispectator = iemitter==1 ? 0 : 1;
- // Make the particles for the HardTree:
- ShowerParticlePtr emitter (new_ptr(ShowerParticle(partons_[iemitter ],true)));
- ShowerParticlePtr spectator(new_ptr(ShowerParticle(partons_[ispectator],true)));
- ShowerParticlePtr gauge (new_ptr(ShowerParticle(gluon_ ,true)));
- ShowerParticlePtr zboson (new_ptr(ShowerParticle(zboson_->dataPtr() ,false)));
- ShowerParticlePtr parent (new_ptr(ShowerParticle(partons_[iemitter ],true)));
- emitter ->set5Momentum(quark_[iemitter ] );
- spectator->set5Momentum(quark_[ispectator] );
- gauge ->set5Momentum(gauge_ );
- zboson ->set5Momentum(zboson_->momentum());
- Lorentz5Momentum parentMomentum(quark_[iemitter]+gauge_);
- parentMomentum.rescaleMass();
- parent->set5Momentum(parentMomentum);
- // Create the vectors of HardBranchings to create the HardTree:
- vector<HardBranchingPtr> spaceBranchings,allBranchings;
- // Incoming boson:
- spaceBranchings.push_back(new_ptr(HardBranching(zboson,SudakovPtr(),
- HardBranchingPtr(),
- HardBranching::Incoming)));
- // Outgoing particles from hard emission:
- HardBranchingPtr spectatorBranch(new_ptr(HardBranching(spectator,SudakovPtr(),
- HardBranchingPtr(),
- HardBranching::Outgoing)));
- HardBranchingPtr emitterBranch(new_ptr(HardBranching(parent,SudakovPtr(),
- HardBranchingPtr(),
- HardBranching::Outgoing)));
- emitterBranch->addChild(new_ptr(HardBranching(emitter,SudakovPtr(),
- HardBranchingPtr(),
- HardBranching::Outgoing)));
- emitterBranch->addChild(new_ptr(HardBranching(gauge,SudakovPtr(),
- HardBranchingPtr(),
- HardBranching::Outgoing)));
- emitterBranch->type(emitterBranch->branchingParticle()->id()>0 ?
- ShowerPartnerType::QCDColourLine :
- ShowerPartnerType::QCDAntiColourLine);
- allBranchings.push_back(emitterBranch);
- allBranchings.push_back(spectatorBranch);
- if(iemitter==1) swap(allBranchings[0],allBranchings[1]);
- // Add incoming boson to allBranchings
- allBranchings.push_back( spaceBranchings.back() );
- // Make the HardTree from the HardBranching vectors.
- HardTreePtr hardtree = new_ptr(HardTree(allBranchings,spaceBranchings,
- ShowerInteraction::QCD));
- // Set the maximum pt for all other emissions
- Energy ptveto(pT_);
- QProgenitor ->maximumpT(ptveto,ShowerInteraction::QCD);
- QbarProgenitor->maximumpT(ptveto,ShowerInteraction::QCD);
- // Connect the particles with the branchings in the HardTree
- hardtree->connect( QProgenitor->progenitor() , allBranchings[0] );
- hardtree->connect( QbarProgenitor->progenitor(), allBranchings[1] );
- // colour flow
- ColinePtr newline=new_ptr(ColourLine());
- for(set<HardBranchingPtr>::const_iterator cit=hardtree->branchings().begin();
- cit!=hardtree->branchings().end();++cit) {
- if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3)
- newline->addColoured((**cit).branchingParticle());
- else if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3bar)
- newline->addAntiColoured((**cit).branchingParticle());
- }
- ColinePtr newLine2=new_ptr(ColourLine());
- if(emitterBranch->branchingParticle()->dataPtr()->iColour()==PDT::Colour3) {
- emitterBranch->branchingParticle()->colourLine()->addColoured(gauge);
- newLine2->addColoured(emitter);
- newLine2->addAntiColoured(gauge);
- }
- else {
- emitterBranch->branchingParticle()->antiColourLine()->addAntiColoured(gauge);
- newLine2->addAntiColoured(emitter);
- newLine2->addColoured(gauge);
- }
- // return the tree
- return hardtree;
+RealEmissionProcessPtr SMZFermionsPOWHEGDecayer::
+generateHardest(PerturbativeProcessPtr tree) {
+ assert(false);
+ return RealEmissionProcessPtr();
+ // // Get the progenitors: Q and Qbar.
+ // ShowerProgenitorPtr
+ // QProgenitor = tree->outgoingLines().begin()->first,
+ // QbarProgenitor = tree->outgoingLines().rbegin()->first;
+ // if(QProgenitor->id()<0) swap( QProgenitor, QbarProgenitor );
+ // partons_.resize(2);
+ // partons_[0] = QProgenitor->progenitor() ->dataPtr();
+ // partons_[1] = QbarProgenitor->progenitor()->dataPtr();
+ // if(!partons_[0]->coloured()) return HardTreePtr();
+ // // momentum of the partons
+ // quark_.resize(2);
+ // quark_[0] = QProgenitor ->copy()->momentum();
+ // quark_[1] = QbarProgenitor->copy()->momentum();
+ // // Set the existing mass entries in partons 5 vectors with the
+ // // once and for all.
+ // quark_[0].setMass(partons_[0]->mass());
+ // quark_[1].setMass(partons_[1]->mass());
+ // gauge_.setMass(0.*MeV);
+ // // Get the Z boson.
+ // zboson_ = tree->incomingLines().begin()->first->copy();
+ // // copy the particle objects
+ // vector<PPtr> hardProcess (3);
+ // hardProcess[0] = zboson_;
+ // hardProcess[1] = QbarProgenitor->copy();
+ // hardProcess[2] = QProgenitor ->copy();
+ // // Get the Z boson mass.
+ // mz2_ = (quark_[0] + quark_[1]).m2();
+ // // Generate emission and set _quark[0,1] and _gauge to be the
+ // // momenta of q, qbar and g after the hardest emission:
+ // if(!getEvent(hardProcess)) {
+ // QProgenitor ->maximumpT(pTmin_,ShowerInteraction::QCD);
+ // QbarProgenitor->maximumpT(pTmin_,ShowerInteraction::QCD);
+ // return HardTreePtr();
+ // }
+ // // Ensure the energies are greater than the constituent masses:
+ // for (int i=0; i<2; i++) {
+ // if (quark_[i].e() < partons_[i]->constituentMass()) return HardTreePtr();
+ // if (gauge_.e() < gluon_ ->constituentMass()) return HardTreePtr();
+ // }
+ // // set masses
+ // quark_[0].setMass( partons_[0]->mass() );
+ // quark_[1].setMass( partons_[1]->mass() );
+ // gauge_ .setMass( ZERO );
+ // // assign the emitter based on evolution scales
+ // unsigned int iemitter = quark_[0]*gauge_ > quark_[1]*gauge_ ? 1 : 0;
+ // unsigned int ispectator = iemitter==1 ? 0 : 1;
+ // // Make the particles for the HardTree:
+ // ShowerParticlePtr emitter (new_ptr(ShowerParticle(partons_[iemitter ],true)));
+ // ShowerParticlePtr spectator(new_ptr(ShowerParticle(partons_[ispectator],true)));
+ // ShowerParticlePtr gauge (new_ptr(ShowerParticle(gluon_ ,true)));
+ // ShowerParticlePtr zboson (new_ptr(ShowerParticle(zboson_->dataPtr() ,false)));
+ // ShowerParticlePtr parent (new_ptr(ShowerParticle(partons_[iemitter ],true)));
+ // emitter ->set5Momentum(quark_[iemitter ] );
+ // spectator->set5Momentum(quark_[ispectator] );
+ // gauge ->set5Momentum(gauge_ );
+ // zboson ->set5Momentum(zboson_->momentum());
+ // Lorentz5Momentum parentMomentum(quark_[iemitter]+gauge_);
+ // parentMomentum.rescaleMass();
+ // parent->set5Momentum(parentMomentum);
+ // // Create the vectors of HardBranchings to create the HardTree:
+ // vector<HardBranchingPtr> spaceBranchings,allBranchings;
+ // // Incoming boson:
+ // spaceBranchings.push_back(new_ptr(HardBranching(zboson,SudakovPtr(),
+ // HardBranchingPtr(),
+ // HardBranching::Incoming)));
+ // // Outgoing particles from hard emission:
+ // HardBranchingPtr spectatorBranch(new_ptr(HardBranching(spectator,SudakovPtr(),
+ // HardBranchingPtr(),
+ // HardBranching::Outgoing)));
+ // HardBranchingPtr emitterBranch(new_ptr(HardBranching(parent,SudakovPtr(),
+ // HardBranchingPtr(),
+ // HardBranching::Outgoing)));
+ // emitterBranch->addChild(new_ptr(HardBranching(emitter,SudakovPtr(),
+ // HardBranchingPtr(),
+ // HardBranching::Outgoing)));
+ // emitterBranch->addChild(new_ptr(HardBranching(gauge,SudakovPtr(),
+ // HardBranchingPtr(),
+ // HardBranching::Outgoing)));
+ // emitterBranch->type(emitterBranch->branchingParticle()->id()>0 ?
+ // ShowerPartnerType::QCDColourLine :
+ // ShowerPartnerType::QCDAntiColourLine);
+ // allBranchings.push_back(emitterBranch);
+ // allBranchings.push_back(spectatorBranch);
+ // if(iemitter==1) swap(allBranchings[0],allBranchings[1]);
+ // // Add incoming boson to allBranchings
+ // allBranchings.push_back( spaceBranchings.back() );
+ // // Make the HardTree from the HardBranching vectors.
+ // HardTreePtr hardtree = new_ptr(HardTree(allBranchings,spaceBranchings,
+ // ShowerInteraction::QCD));
+ // // Set the maximum pt for all other emissions
+ // Energy ptveto(pT_);
+ // QProgenitor ->maximumpT(ptveto,ShowerInteraction::QCD);
+ // QbarProgenitor->maximumpT(ptveto,ShowerInteraction::QCD);
+ // // Connect the particles with the branchings in the HardTree
+ // hardtree->connect( QProgenitor->progenitor() , allBranchings[0] );
+ // hardtree->connect( QbarProgenitor->progenitor(), allBranchings[1] );
+ // // colour flow
+ // ColinePtr newline=new_ptr(ColourLine());
+ // for(set<HardBranchingPtr>::const_iterator cit=hardtree->branchings().begin();
+ // cit!=hardtree->branchings().end();++cit) {
+ // if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3)
+ // newline->addColoured((**cit).branchingParticle());
+ // else if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3bar)
+ // newline->addAntiColoured((**cit).branchingParticle());
+ // }
+ // ColinePtr newLine2=new_ptr(ColourLine());
+ // if(emitterBranch->branchingParticle()->dataPtr()->iColour()==PDT::Colour3) {
+ // emitterBranch->branchingParticle()->colourLine()->addColoured(gauge);
+ // newLine2->addColoured(emitter);
+ // newLine2->addAntiColoured(gauge);
+ // }
+ // else {
+ // emitterBranch->branchingParticle()->antiColourLine()->addAntiColoured(gauge);
+ // newLine2->addAntiColoured(emitter);
+ // newLine2->addColoured(gauge);
+ // }
+ // // return the tree
+ // return hardtree;
}
double SMZFermionsPOWHEGDecayer::
me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const {
// leading-order result
double output = SMZDecayer::me2(ichan,part,decay,meopt);
// check decay products coloured, otherwise return
if(!decay[0]->dataPtr()->coloured()) return output;
// inital masses, couplings etc
// fermion mass
Energy particleMass = decay[0]->dataPtr()->mass();
// Z mass
mZ_ = part.mass();
// strong coupling
aS_ = SM().alphaS(sqr(mZ_));
// reduced mass
mu_ = particleMass/mZ_;
mu2_ = sqr(mu_);
// scale
scale_ = sqr(mZ_);
// cast the vertices
tcFFVVertexPtr Zvertex = dynamic_ptr_cast<tcFFVVertexPtr>(FFZVertex());
// compute the spinors
vector<SpinorWaveFunction> aout;
vector<SpinorBarWaveFunction> fout;
vector<VectorWaveFunction> vin;
SpinorBarWaveFunction qkout(decay[0]->momentum(),decay[0]->dataPtr(),outgoing);
SpinorWaveFunction qbout(decay[1]->momentum(),decay[1]->dataPtr(),outgoing);
VectorWaveFunction zin (part.momentum() ,part.dataPtr() ,incoming);
for(unsigned int ix=0;ix<2;++ix){
qkout.reset(ix);
fout.push_back(qkout);
qbout.reset(ix);
aout.push_back(qbout);
}
for(unsigned int ix=0;ix<3;++ix){
zin.reset(ix);
vin.push_back(zin);
}
// temporary storage of the different diagrams
// sum over helicities to get the matrix element
double total=0.;
if(mu_!=0.) {
LorentzPolarizationVector momDiff =
(decay[0]->momentum()-decay[1]->momentum())/2./
(decay[0]->momentum().mass()+decay[1]->momentum().mass());
// scalars
Complex scalar1 = zin.wave().dot(momDiff);
for(unsigned int outhel1=0;outhel1<2;++outhel1) {
for(unsigned int outhel2=0;outhel2<2;++outhel2) {
for(unsigned int inhel=0;inhel<3;++inhel) {
// first the LO bit
Complex diag1 = FFZVertex()->evaluate(scale_,aout[outhel2],fout[outhel1],vin[inhel]);
// extra stuff for NLO
LorentzPolarizationVector left =
aout[outhel2].wave().leftCurrent(fout[outhel1].wave());
LorentzPolarizationVector right =
aout[outhel2].wave().rightCurrent(fout[outhel1].wave());
Complex scalar =
aout[outhel2].wave().scalar(fout[outhel1].wave());
// nlo specific pieces
Complex diag3 =
Complex(0.,1.)*Zvertex->norm()*
(Zvertex->right()*( left.dot(zin.wave())) +
Zvertex-> left()*(right.dot(zin.wave())) -
( Zvertex-> left()+Zvertex->right())*scalar1*scalar);
// nlo piece
total += real(diag1*conj(diag3) + diag3*conj(diag1));
}
}
}
// rescale
total *= UnitRemoval::E2/scale_;
}
else {
total = ZERO;
}
// now for the NLO bit
double mu4 = sqr(mu2_);
double lmu = mu_!=0. ? log(mu_) : 0.;
double v = sqrt(1.-4.*mu2_),v2(sqr(v));
double omv = 4.*mu2_/(1.+v);
double f1,f2,fNS,VNS;
double r = omv/(1.+v);
double lr = mu_!=0. ? log(r) : 0.;
// normal form
if(mu_>1e-4) {
f1 = CF_*aS_/Constants::pi*
( +1. + 3.*log(0.5*(1.+v)) - 1.5*log(0.5*(1.+v2)) + sqr(Constants::pi)/6.
- 0.5*sqr(lr) - (1.+v2)/v*(lr*log(1.+v2) + sqr(Constants::pi)/12.
-0.5*log(4.*mu2_)*lr + 0.25*sqr(lr)));
fNS = -0.5*(1.+2.*v2)*lr/v + 1.5*lr - 2./3.*sqr(Constants::pi) + 0.5*sqr(lr)
+ (1.+v2)/v*(Herwig::Math::ReLi2(r) + sqr(Constants::pi)/3. - 0.25*sqr(lr)
+ lr*log((2.*v/ (1.+v))));
VNS = 1.5*log(0.5*(1.+v2))
+ 0.5*(1.+v2)/v*( 2.*lr*log(2.*(1.+v2)/sqr(1.+v))
+ 2.*Herwig::Math::ReLi2(sqr(r))
- 2.*Herwig::Math::ReLi2(2.*v/(1.+v)) - sqr(Constants::pi)/6.)
+ log(1.-mu_) - 2.*log(1.-2.*mu_) - 4.*mu2_/(1.+v2)*log(mu_/(1.-mu_))
- mu_/(1.-mu_)
+ 4.*(2.*mu2_-mu_)/(1.+v2) + 0.5*sqr(Constants::pi);
f2 = CF_*aS_/Constants::pi*mu2_*lr/v;
}
// small mass limit
else {
f1 = -CF_*aS_/Constants::pi/6.*
( - 6. - 24.*lmu*mu2_ - 15.*mu4 - 12.*mu4*lmu - 24.*mu4*sqr(lmu)
+ 2.*mu4*sqr(Constants::pi) - 12.*mu2_*mu4 - 96.*mu2_*mu4*sqr(lmu)
+ 8.*mu2_*mu4*sqr(Constants::pi) - 80.*mu2_*mu4*lmu);
fNS = - mu2_/18.*( + 36.*lmu - 36. - 45.*mu2_ + 216.*lmu*mu2_ - 24.*mu2_*sqr(Constants::pi)
+ 72.*mu2_*sqr(lmu) - 22.*mu4 + 1032.*mu4 * lmu
- 96.*mu4*sqr(Constants::pi) + 288.*mu4*sqr(lmu));
VNS = - mu2_/1260.*(-6930. + 7560.*lmu + 2520.*mu_ - 16695.*mu2_
+ 1260.*mu2_*sqr(Constants::pi)
+ 12600.*lmu*mu2_ + 1344.*mu_*mu2_ - 52780.*mu4 + 36960.*mu4*lmu
+ 5040.*mu4*sqr(Constants::pi) - 12216.*mu_*mu4);
f2 = CF_*aS_*mu2_/Constants::pi*( 2.*lmu + 4.*mu2_*lmu + 2.*mu2_ + 12.*mu4*lmu + 7.*mu4);
}
// add up bits for f1
f1 += CF_*aS_/Constants::pi*(fNS+VNS);
// now for the real correction
double phi = UseRandom::rnd()*Constants::twopi;
// calculate y
double yminus = 0.;
double yplus = 1.-2.*mu_*(1.-mu_)/(1.-2*mu2_);
double y = yminus + UseRandom::rnd()*(yplus-yminus);
// calculate z
double v1 = sqrt(sqr(2.*mu2_+(1.-2.*mu2_)*(1.-y))-4.*mu2_)/(1.-2.*mu2_)/(1.-y);
double zplus = (1.+v1)*(1.-2.*mu2_)*y/2./(mu2_ +(1.-2.*mu2_)*y);
double zminus = (1.-v1)*(1.-2.*mu2_)*y/2./(mu2_ +(1.-2.*mu2_)*y);
double z = zminus + UseRandom::rnd()*(zplus-zminus);
double jac = (1.-y)*(yplus-yminus)*(zplus-zminus);
// calculate x1,x2
double x2 = 1. - y*(1.-2.*mu2_);
double x1 = 1. - z*(x2-2.*mu2_);
// copy the particle objects over for calculateRealEmission
vector<PPtr> hardProcess(3);
hardProcess[0] = const_ptr_cast<PPtr>(&part);
hardProcess[1] = decay[0];
hardProcess[2] = decay[1];
// total real emission contribution
double realFact = 0.25*jac*sqr(1.-2.*mu2_)/
sqrt(1.-4.*mu2_)/Constants::twopi
*2.*CF_*aS_*calculateRealEmission(x1, x2, hardProcess, phi, true);
// the born + virtual + real
output = output*(1. + f1 + realFact) + f2*total;
return output;
}
double SMZFermionsPOWHEGDecayer::meRatio(vector<cPDPtr> partons,
vector<Lorentz5Momentum> momenta,
unsigned int iemitter, bool subtract) const {
Lorentz5Momentum q = momenta[1]+momenta[2]+momenta[3];
Energy2 Q2=q.m2();
Energy2 lambda = sqrt((Q2-sqr(momenta[1].mass()+momenta[2].mass()))*
(Q2-sqr(momenta[1].mass()-momenta[2].mass())));
InvEnergy2 D[2];
double lome[2];
for(unsigned int iemit=0;iemit<2;++iemit) {
unsigned int ispect = iemit==0 ? 1 : 0;
Energy2 pipj = momenta[3 ] * momenta[1+iemit ];
Energy2 pipk = momenta[3 ] * momenta[1+ispect];
Energy2 pjpk = momenta[1+iemit] * momenta[1+ispect];
double y = pipj/(pipj+pipk+pjpk);
double z = pipk/( pipk+pjpk);
Energy mij = sqrt(2.*pipj+sqr(momenta[1+iemit].mass()));
Energy2 lamB = sqrt((Q2-sqr(mij+momenta[1+ispect].mass()))*
(Q2-sqr(mij-momenta[1+ispect].mass())));
Energy2 Qpk = q*momenta[1+ispect];
Lorentz5Momentum pkt =
lambda/lamB*(momenta[1+ispect]-Qpk/Q2*q)
+0.5/Q2*(Q2+sqr(momenta[1+ispect].mass())-sqr(momenta[1+ispect].mass()))*q;
Lorentz5Momentum pijt =
q-pkt;
double muj = momenta[1+iemit ].mass()/sqrt(Q2);
double muk = momenta[1+ispect].mass()/sqrt(Q2);
double vt = sqrt((1.-sqr(muj+muk))*(1.-sqr(muj-muk)))/(1.-sqr(muj)-sqr(muk));
double v = sqrt(sqr(2.*sqr(muk)+(1.-sqr(muj)-sqr(muk))*(1.-y))-4.*sqr(muk))
/(1.-y)/(1.-sqr(muj)-sqr(muk));
// dipole term
D[iemit] = 0.5/pipj*(2./(1.-(1.-z)*(1.-y))
-vt/v*(2.-z+sqr(momenta[1+iemit].mass())/pipj));
// matrix element
vector<Lorentz5Momentum> lomom(3);
lomom[0] = momenta[0];
if(iemit==0) {
lomom[1] = pijt;
lomom[2] = pkt ;
}
else {
lomom[2] = pijt;
lomom[1] = pkt ;
}
lome[iemit] = loME(partons,lomom);
}
InvEnergy2 ratio = realME(partons,momenta)*abs(D[iemitter])
/(abs(D[0]*lome[0])+abs(D[1]*lome[1]));
if(subtract)
return Q2*(ratio-2.*D[iemitter]);
else
return Q2*ratio;
}
double SMZFermionsPOWHEGDecayer::loME(const vector<cPDPtr> & partons,
const vector<Lorentz5Momentum> & momenta) const {
// compute the spinors
vector<VectorWaveFunction> vin;
vector<SpinorWaveFunction> aout;
vector<SpinorBarWaveFunction> fout;
VectorWaveFunction zin (momenta[0],partons[0],incoming);
SpinorBarWaveFunction qkout(momenta[1],partons[1],outgoing);
SpinorWaveFunction qbout(momenta[2],partons[2],outgoing);
for(unsigned int ix=0;ix<2;++ix){
qkout.reset(ix);
fout.push_back(qkout);
qbout.reset(ix);
aout.push_back(qbout);
}
for(unsigned int ix=0;ix<3;++ix){
zin.reset(ix);
vin.push_back(zin);
}
// temporary storage of the different diagrams
// sum over helicities to get the matrix element
double total(0.);
for(unsigned int inhel=0;inhel<3;++inhel) {
for(unsigned int outhel1=0;outhel1<2;++outhel1) {
for(unsigned int outhel2=0;outhel2<2;++outhel2) {
Complex diag1 = FFZVertex()->evaluate(scale_,aout[outhel2],fout[outhel1],vin[inhel]);
total += norm(diag1);
}
}
}
// return the answer
return total;
}
InvEnergy2 SMZFermionsPOWHEGDecayer::realME(const vector<cPDPtr> & partons,
const vector<Lorentz5Momentum> & momenta) const {
// compute the spinors
vector<VectorWaveFunction> vin;
vector<SpinorWaveFunction> aout;
vector<SpinorBarWaveFunction> fout;
vector<VectorWaveFunction> gout;
VectorWaveFunction zin (momenta[0],partons[0],incoming);
SpinorBarWaveFunction qkout(momenta[1],partons[1],outgoing);
SpinorWaveFunction qbout(momenta[2],partons[2],outgoing);
VectorWaveFunction gluon(momenta[3],partons[3],outgoing);
for(unsigned int ix=0;ix<2;++ix){
qkout.reset(ix);
fout.push_back(qkout);
qbout.reset(ix);
aout.push_back(qbout);
gluon.reset(2*ix);
gout.push_back(gluon);
}
for(unsigned int ix=0;ix<3;++ix){
zin.reset(ix);
vin.push_back(zin);
}
vector<Complex> diag(2,0.);
double total(0.);
for(unsigned int inhel1=0;inhel1<3;++inhel1) {
for(unsigned int outhel1=0;outhel1<2;++outhel1) {
for(unsigned int outhel2=0;outhel2<2;++outhel2) {
for(unsigned int outhel3=0;outhel3<2;++outhel3) {
SpinorBarWaveFunction off1 =
FFGVertex()->evaluate(scale_,3,partons[1],fout[outhel1],gout[outhel3]);
diag[0] = FFZVertex()->evaluate(scale_,aout[outhel2],off1,vin[inhel1]);
SpinorWaveFunction off2 =
FFGVertex()->evaluate(scale_,3,partons[2],aout[outhel2],gout[outhel3]);
diag[1] = FFZVertex()->evaluate(scale_,off2,fout[outhel1],vin[inhel1]);
// sum of diagrams
Complex sum = std::accumulate(diag.begin(),diag.end(),Complex(0.));
// me2
total += norm(sum);
}
}
}
}
// divide out the coupling
total /= norm(FFGVertex()->norm());
// return the total
return total*UnitRemoval::InvE2;
}
void SMZFermionsPOWHEGDecayer::doinit() {
// cast the SM pointer to the Herwig SM pointer
tcHwSMPtr hwsm= dynamic_ptr_cast<tcHwSMPtr>(standardModel());
// do the initialisation
if(!hwsm) throw InitException()
<< "Wrong type of StandardModel object in "
<< "SMZFermionsPOWHEGDecayer::doinit() "
<< "the Herwig version must be used."
<< Exception::runerror;
// cast the vertices
FFZVertex_ = hwsm->vertexFFZ();
FFZVertex_->init();
FFGVertex_ = hwsm->vertexFFG();
FFGVertex_->init();
SMZDecayer::doinit();
gluon_ = getParticleData(ParticleID::g);
}
bool SMZFermionsPOWHEGDecayer::getEvent(vector<PPtr> hardProcess) {
Energy particleMass = ZERO;
for(unsigned int ix=0;ix<hardProcess.size();++ix) {
if(hardProcess[ix]->id()==ParticleID::Z0) {
mZ_ = hardProcess[ix]->mass();
}
else {
particleMass = hardProcess[ix]->mass();
}
}
// reduced mass
mu_ = particleMass/mZ_;
mu2_ = sqr(mu_);
// scale
scale_ = sqr(mZ_);
// max pT
Energy pTmax = 0.5*sqrt(mz2_);
if(pTmax<pTmin_) return false;
// Define over valued y_max & y_min according to the associated pt_min cut.
double ymax = acosh(pTmax/pTmin_);
double ymin = -ymax;
// pt of the emmission
pT_ = pTmax;
// prefactor
double overEst = 4.;
double prefactor = overEst*alphaS()->overestimateValue()*CF_*
(ymax-ymin)/Constants::twopi;
// loop to generate the pt and rapidity
bool reject;
//arrays to hold the temporary probabilities whilst the for loop progresses
double probTemp[2][2]={{0.,0.},{0.,0.}};
probTemp[0][0]=probTemp[0][1]=probTemp[1][0]=probTemp[1][1]=0.;
double x1Solution[2][2] = {{0.,0.},{0.,0.}};
double x2Solution[2][2] = {{0.,0.},{0.,0.}};
double x3Solution[2] = {0.,0.};
Energy pT[2] = {pTmax,pTmax};
double yTemp[2] = {0.,0.};
double phi = 0.;
// do the competition
for(int i=0; i<2; i++) {
do {
//generation of phi
phi = UseRandom::rnd() * Constants::twopi;
// reject the emission
reject = true;
// generate pt
pT[i] *= pow(UseRandom::rnd(),1./prefactor);
Energy2 pT2 = sqr(pT[i]);
if(pT[i]<pTmin_) {
pT[i] = -GeV;
break;
}
// generate y
yTemp[i] = ymin + UseRandom::rnd()*(ymax-ymin);
//generate x3 & x1 from pT & y
double x1Plus = 1.;
double x1Minus = 2.*mu_;
x3Solution[i] = 2.*pT[i]*cosh(yTemp[i])/mZ_;
// prefactor
double weightPrefactor = 0.5/sqrt(1.-4.*mu2_)/overEst;
// calculate x1 & x2 solutions
Energy4 discrim2 = (sqr(x3Solution[i]*mZ_) - 4.*pT2)*
(mz2_*(x3Solution[i]-1.)*(4.*mu2_+x3Solution[i]-1.)-4.*mu2_*pT2);
//check discriminant2 is > 0
if( discrim2 < ZERO) continue;
Energy2 discriminant = sqrt(discrim2);
Energy2 fact1 = 3.*mz2_*x3Solution[i]-2.*mz2_+2.*pT2*x3Solution[i]
-4.*pT2-mz2_*sqr(x3Solution[i]);
Energy2 fact2 = 2.*mz2_*(x3Solution[i]-1.)-2.*pT2;
// two solns for x1
x1Solution[i][0] = (fact1 + discriminant)/fact2;
x1Solution[i][1] = (fact1 - discriminant)/fact2;
bool found = false;
for(unsigned int j=0;j<2;++j) {
x2Solution[i][0] = 2.-x3Solution[i]-x1Solution[i][0];
x2Solution[i][1] = 2.-x3Solution[i]-x1Solution[i][1];
// set limits on x2
double root = max(0.,sqr(x1Solution[i][j])-4.*mu2_);
root = sqrt(root);
double x2Plus = 1.-0.5*(1.-x1Solution[i][j])/(1.-x1Solution[i][j]+mu2_)
*(x1Solution[i][j]-2.*mu2_-root);
double x2Minus = 1.-0.5*(1.-x1Solution[i][j])/(1.-x1Solution[i][j]+mu2_)
*(x1Solution[i][j]-2.*mu2_+root);
if(x1Solution[i][j]>=x1Minus && x1Solution[i][j]<=x1Plus &&
x2Solution[i][j]>=x2Minus && x2Solution[i][j]<=x2Plus &&
checkZMomenta(x1Solution[i][j], x2Solution[i][j], x3Solution[i], yTemp[i], pT[i])) {
probTemp[i][j] = weightPrefactor*pT[i]*
calculateJacobian(x1Solution[i][j], x2Solution[i][j], pT[i])*
calculateRealEmission(x1Solution[i][j], x2Solution[i][j],
hardProcess, phi, false, i);
found = true;
}
else {
probTemp[i][j] = 0.;
}
}
if(!found) continue;
// alpha S piece
double wgt = (probTemp[i][0]+probTemp[i][1])*alphaS()->ratio(sqr(pT[i]));
// matrix element weight
reject = UseRandom::rnd()>wgt;
}
while(reject);
} //end of emitter for loop
// no emission
if(pT[0]<ZERO&&pT[1]<ZERO) return false;
//pick the spectator and x1 x2 values
double x1,x2,y;
//particle 1 emits, particle 2 spectates
unsigned int iemit=0;
if(pT[0]>pT[1]){
pT_ = pT[0];
y=yTemp[0];
if(probTemp[0][0]>UseRandom::rnd()*(probTemp[0][0]+probTemp[0][1])) {
x1 = x1Solution[0][0];
x2 = x2Solution[0][0];
}
else {
x1 = x1Solution[0][1];
x2 = x2Solution[0][1];
}
}
// particle 2 emits, particle 1 spectates
else {
iemit=1;
pT_ = pT[1];
y=yTemp[1];
if(probTemp[1][0]>UseRandom::rnd()*(probTemp[1][0]+probTemp[1][1])) {
x1 = x1Solution[1][0];
x2 = x2Solution[1][0];
}
else {
x1 = x1Solution[1][1];
x2 = x2Solution[1][1];
}
}
// find spectator
unsigned int ispect = iemit == 0 ? 1 : 0;
// Find the boost from the lab to the c.o.m with the spectator
// along the -z axis, and then invert it.
LorentzRotation eventFrame( ( quark_[0] + quark_[1] ).findBoostToCM() );
Lorentz5Momentum spectator = eventFrame*quark_[ispect];
eventFrame.rotateZ( -spectator.phi() );
eventFrame.rotateY( -spectator.theta() - Constants::pi );
eventFrame.invert();
// spectator
quark_[ispect].setT( 0.5*x2*mZ_ );
quark_[ispect].setX( ZERO );
quark_[ispect].setY( ZERO );
quark_[ispect].setZ( -sqrt(0.25*mz2_*x2*x2-mz2_*mu2_) );
// gluon
gauge_.setT( pT_*cosh(y) );
gauge_.setX( pT_*cos(phi) );
gauge_.setY( pT_*sin(phi) );
gauge_.setZ( pT_*sinh(y) );
gauge_.setMass(ZERO);
// emitter reconstructed from gluon & spectator
quark_[iemit] = - gauge_ - quark_[ispect];
quark_[iemit].setT( 0.5*mZ_*x1 );
// boost constructed vectors into the event frame
quark_[0] = eventFrame * quark_[0];
quark_[1] = eventFrame * quark_[1];
gauge_ = eventFrame * gauge_;
// need to reset masses because for whatever reason the boost
// touches the mass component of the five-vector and can make
// zero mass objects acquire a floating point negative mass(!).
gauge_.setMass( ZERO );
quark_[iemit] .setMass(partons_[iemit ]->mass());
quark_[ispect].setMass(partons_[ispect]->mass());
return true;
}
InvEnergy SMZFermionsPOWHEGDecayer::calculateJacobian(double x1, double x2, Energy pT) const{
double xPerp = abs(2.*pT/mZ_);
Energy jac = mZ_*fabs((x1*x2-2.*mu2_*(x1+x2)+sqr(x2)-x2)/xPerp/pow(sqr(x2)-4.*mu2_,1.5));
return 1./jac; //jacobian as defined is dptdy=jac*dx1dx2, therefore we have to divide by it
}
bool SMZFermionsPOWHEGDecayer::checkZMomenta(double x1, double x2, double x3, double y, Energy pT) const {
double xPerp2 = 4.*pT*pT/mZ_/mZ_;
static double tolerance = 1e-6;
bool isMomentaReconstructed = false;
if(pT*sinh(y)>ZERO) {
if(abs(-sqrt(sqr(x2)-4.*mu2_)+sqrt(sqr(x3)-xPerp2) + sqrt(sqr(x1)-xPerp2 - 4.*mu2_)) <= tolerance ||
abs(-sqrt(sqr(x2)-4.*mu2_)+sqrt(sqr(x3)-xPerp2) - sqrt(sqr(x1)-xPerp2 - 4.*mu2_)) <= tolerance) isMomentaReconstructed=true;
}
else if(pT*sinh(y) < ZERO){
if(abs(-sqrt(sqr(x2)-4.*mu2_)-sqrt(sqr(x3)-xPerp2) + sqrt(sqr(x1)-xPerp2 - 4.*mu2_)) <= tolerance ||
abs(-sqrt(sqr(x2)-4.*mu2_)-sqrt(sqr(x3)-xPerp2) - sqrt(sqr(x1)-xPerp2 - 4.*mu2_)) <= tolerance) isMomentaReconstructed=true;
}
else
if(abs(-sqrt(sqr(x2)-4.*mu2_)+ sqrt(sqr(x1)-xPerp2 - 4.*mu2_)) <= tolerance) isMomentaReconstructed=true;
return isMomentaReconstructed;
}
double SMZFermionsPOWHEGDecayer::calculateRealEmission(double x1, double x2,
vector<PPtr> hardProcess,
double phi,
bool subtract) const {
// make partons data object for meRatio
vector<cPDPtr> partons (3);
for(int ix=0; ix<3; ++ix)
partons[ix] = hardProcess[ix]->dataPtr();
partons.push_back(gluon_);
// calculate x3
double x3 = 2.-x1-x2;
double xT = sqrt(max(0.,sqr(x3) -0.25*sqr(sqr(x2)+sqr(x3)-sqr(x1))/(sqr(x2)-4.*mu2_)));
// calculate the momenta
Energy M = mZ_;
Lorentz5Momentum pspect(ZERO,ZERO,-0.5*M*sqrt(max(sqr(x2)-4.*mu2_,0.)),0.5*M*x2,M*mu_);
Lorentz5Momentum pemit (-0.5*M*xT*cos(phi),-0.5*M*xT*sin(phi),
0.5*M*sqrt(max(sqr(x1)-sqr(xT)-4.*mu2_,0.)),0.5*M*x1,M*mu_);
Lorentz5Momentum pgluon(0.5*M*xT*cos(phi), 0.5*M*xT*sin(phi),
0.5*M*sqrt(max(sqr(x3)-sqr(xT),0.)),0.5*M*x3,ZERO);
if(abs(pspect.z()+pemit.z()-pgluon.z())/M<1e-6)
pgluon.setZ(-pgluon.z());
else if(abs(pspect.z()-pemit.z()+pgluon.z())/M<1e-6)
pemit .setZ(- pemit.z());
// loop over the possible emitting partons
double realwgt(0.);
for(unsigned int iemit=0;iemit<2;++iemit) {
// boost and rotate momenta
LorentzRotation eventFrame( ( hardProcess[1]->momentum() +
hardProcess[2]->momentum() ).findBoostToCM() );
Lorentz5Momentum spectator = eventFrame*hardProcess[iemit+1]->momentum();
eventFrame.rotateZ( -spectator.phi() );
eventFrame.rotateY( -spectator.theta() );
eventFrame.invert();
vector<Lorentz5Momentum> momenta(3);
momenta[0] = hardProcess[0]->momentum();
if(iemit==0) {
momenta[2] = eventFrame*pspect;
momenta[1] = eventFrame*pemit ;
}
else {
momenta[1] = eventFrame*pspect;
momenta[2] = eventFrame*pemit ;
}
momenta.push_back(eventFrame*pgluon);
// calculate the weight
if(1.-x1>1e-5 && 1.-x2>1e-5)
realwgt += meRatio(partons,momenta,iemit,subtract);
}
// total real emission contribution
return realwgt;
}
double SMZFermionsPOWHEGDecayer::calculateRealEmission(double x1, double x2,
vector<PPtr> hardProcess,
double phi,
bool subtract,
int emitter) const {
// make partons data object for meRatio
vector<cPDPtr> partons (3);
for(int ix=0; ix<3; ++ix)
partons[ix] = hardProcess[ix]->dataPtr();
partons.push_back(gluon_);
// calculate x3
double x3 = 2.-x1-x2;
double xT = sqrt(max(0.,sqr(x3) -0.25*sqr(sqr(x2)+sqr(x3)-sqr(x1))/(sqr(x2)-4.*mu2_)));
// calculate the momenta
Energy M = mZ_;
Lorentz5Momentum pspect(ZERO,ZERO,-0.5*M*sqrt(max(sqr(x2)-4.*mu2_,0.)),0.5*M*x2,M*mu_);
Lorentz5Momentum pemit (-0.5*M*xT*cos(phi),-0.5*M*xT*sin(phi),
0.5*M*sqrt(max(sqr(x1)-sqr(xT)-4.*mu2_,0.)),0.5*M*x1,M*mu_);
Lorentz5Momentum pgluon( 0.5*M*xT*cos(phi), 0.5*M*xT*sin(phi),
0.5*M*sqrt(max(sqr(x3)-sqr(xT),0.)),0.5*M*x3,ZERO);
if(abs(pspect.z()+pemit.z()-pgluon.z())/M<1e-6)
pgluon.setZ(-pgluon.z());
else if(abs(pspect.z()-pemit.z()+pgluon.z())/M<1e-6)
pemit .setZ(- pemit.z());
// loop over the possible emitting partons
double realwgt(0.);
// boost and rotate momenta
LorentzRotation eventFrame( ( hardProcess[1]->momentum() +
hardProcess[2]->momentum() ).findBoostToCM() );
Lorentz5Momentum spectator = eventFrame*hardProcess[emitter+1]->momentum();
eventFrame.rotateZ( -spectator.phi() );
eventFrame.rotateY( -spectator.theta() );
eventFrame.invert();
vector<Lorentz5Momentum> momenta(3);
momenta[0] = hardProcess[0]->momentum();
if(emitter==0) {
momenta[2] = eventFrame*pspect;
momenta[1] = eventFrame*pemit ;
}
else {
momenta[1] = eventFrame*pspect;
momenta[2] = eventFrame*pemit ;
}
momenta.push_back(eventFrame*pgluon);
// calculate the weight
if(1.-x1>1e-5 && 1.-x2>1e-5)
realwgt += meRatio(partons,momenta,emitter,subtract);
// total real emission contribution
return realwgt;
}
diff --git a/Decay/Perturbative/SMZFermionsPOWHEGDecayer.h b/Decay/Perturbative/SMZFermionsPOWHEGDecayer.h
--- a/Decay/Perturbative/SMZFermionsPOWHEGDecayer.h
+++ b/Decay/Perturbative/SMZFermionsPOWHEGDecayer.h
@@ -1,300 +1,300 @@
// -*- C++ -*-
#ifndef HERWIG_SMZFermionsPOWHEGDecayer_H
#define HERWIG_SMZFermionsPOWHEGDecayer_H
//
// This is the declaration of the SMZFermionsPOWHEGDecayer class.
//
#include "SMZDecayer.h"
#include "Herwig/Utilities/Maths.h"
namespace Herwig {
using namespace ThePEG;
/**
* Here is the documentation of the SMZFermionsPOWHEGDecayer class.
*
* @see \ref SMZFermionsPOWHEGDecayerInterfaces "The interfaces"
* defined for SMZFermionsPOWHEGDecayer.
*/
class SMZFermionsPOWHEGDecayer: public SMZDecayer{
public:
/**
* The default constructor.
*/
SMZFermionsPOWHEGDecayer();
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return FSR;}
/**
* Apply the POWHEG style correction
*/
- virtual HardTreePtr generateHardest(ShowerTreePtr);
+ virtual RealEmissionProcessPtr generateHardest(PerturbativeProcessPtr);
/**
* Virtual members to be overridden by inheriting classes
* which implement hard corrections
*/
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const;
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
//@}
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<SMZFermionsPOWHEGDecayer> initSMZFermionsPOWHEGDecayer;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
SMZFermionsPOWHEGDecayer & operator=(const SMZFermionsPOWHEGDecayer &);
/**
* Pointer to the fermion-antifermion Z vertex
*/
AbstractFFVVertexPtr FFZVertex() const {return FFZVertex_;}
/**
* Pointer to the fermion-antifermion Z vertex
*/
AbstractFFVVertexPtr FFGVertex() const {return FFGVertex_;}
/**
* Real emission term, for use in generating the hardest emission
*/
double calculateRealEmission(double x1, double x2,
vector<PPtr> hardProcess,
double phi,
bool subtract,
int emitter) const;
/**
* Real emission term, for use in generating the hardest emission
*/
double calculateRealEmission(double x1, double x2,
vector<PPtr> hardProcess,
double phi,
bool subtract) const;
/**
* Check the sign of the momentum in the \f$z\f$-direction is correct.
*/
bool checkZMomenta(double x1, double x2, double x3, double y, Energy pT) const;
/**
* Calculate the Jacobian
*/
InvEnergy calculateJacobian(double x1, double x2, Energy pT) const;
/**
* Calculate the ratio between NLO & LO ME
*/
double meRatio(vector<cPDPtr> partons,
vector<Lorentz5Momentum> momenta,
unsigned int iemitter,bool subtract) const;
/**
* Calculate the LO ME
*/
double loME(const vector<cPDPtr> & partons,
const vector<Lorentz5Momentum> & momenta) const;
/**
* Calculate the NLO real emission piece of ME
*/
InvEnergy2 realME(const vector<cPDPtr> & partons,
const vector<Lorentz5Momentum> & momenta) const;
/**
* Generate a real emission event
*/
bool getEvent(vector<PPtr> hardProcess);
private:
/**
* Pointer to the fermion-antifermion Z vertex
*/
AbstractFFVVertexPtr FFZVertex_;
/**
* Pointer to the fermion-antifermion G vertex
*/
AbstractFFVVertexPtr FFGVertex_;
/**
* The colour factor
*/
double CF_;
/**
* The Z mass
*/
mutable Energy mZ_;
/**
* The reduced mass
*/
mutable double mu_;
/**
* The square of the reduced mass
*/
mutable double mu2_;
/**
* The strong coupling
*/
mutable double aS_;
/**
* The scale
*/
mutable Energy2 scale_;
/**
* Stuff for the POWHEG correction
*/
//@{
/**
* ParticleData object for the gluon
*/
tcPDPtr gluon_;
/**
* The cut off on pt, assuming massless quarks.
*/
Energy pTmin_;
// radiative variables (pt,y)
Energy pT_;
/**
* The ParticleData objects for the fermions
*/
vector<tcPDPtr> partons_;
/**
* The fermion momenta
*/
vector<Lorentz5Momentum> quark_;
/**
* The momentum of the radiated gauge boson
*/
Lorentz5Momentum gauge_;
/**
* The Z boson
*/
PPtr zboson_;
/**
* Higgs mass squared
*/
Energy2 mz2_;
//@}
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of SMZFermionsPOWHEGDecayer. */
template <>
struct BaseClassTrait<Herwig::SMZFermionsPOWHEGDecayer,1> {
/** Typedef of the first base class of SMZFermionsPOWHEGDecayer. */
typedef Herwig::SMZDecayer NthBase;
};
/** This template specialization informs ThePEG about the name of
* the SMZFermionsPOWHEGDecayer class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::SMZFermionsPOWHEGDecayer>
: public ClassTraitsBase<Herwig::SMZFermionsPOWHEGDecayer> {
/** Return a platform-independent class name */
static string className() { return "Herwig::SMZFermionsPOWHEGDecayer"; }
/**
* The name of a file containing the dynamic library where the class
* SMZFermionsPOWHEGDecayer is implemented. It may also include several, space-separated,
* libraries if the class SMZFermionsPOWHEGDecayer 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 "HwPerturbativeDecay.so"; }
};
/** @endcond */
}
#endif /* HERWIG_SMZFermionsPOWHEGDecayer_H */
diff --git a/MatrixElement/Lepton/MEee2gZ2qq.cc b/MatrixElement/Lepton/MEee2gZ2qq.cc
--- a/MatrixElement/Lepton/MEee2gZ2qq.cc
+++ b/MatrixElement/Lepton/MEee2gZ2qq.cc
@@ -1,1102 +1,1100 @@
// -*- C++ -*-
//
// MEee2gZ2qq.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEee2gZ2qq class.
//
#include "MEee2gZ2qq.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "Herwig/MatrixElement/HardVertex.h"
#include "Herwig/Shower/QTilde/Base/Branching.h"
#include "Herwig/Shower/QTilde/Base/HardTree.h"
#include "ThePEG/PDF/PolarizedBeamParticleData.h"
#include <numeric>
#include "ThePEG/Utilities/DescribeClass.h"
#include "Herwig/Shower/RealEmissionProcess.h"
using namespace Herwig;
const double MEee2gZ2qq::EPS_=0.00000001;
void MEee2gZ2qq::doinit() {
HwMEBase::doinit();
massOption(vector<unsigned int>(2,massopt_));
rescalingOption(3);
if(minflav_>maxflav_)
throw InitException() << "The minimum flavour " << minflav_
<< "must be lower the than maximum flavour " << maxflav_
<< " in MEee2gZ2qq::doinit() "
<< Exception::runerror;
// set the particle data objects
Z0_ = getParticleData(ParticleID::Z0);
gamma_ = getParticleData(ParticleID::gamma);
gluon_ = getParticleData(ParticleID::g);
// cast the SM pointer to the Herwig SM pointer
tcHwSMPtr hwsm= dynamic_ptr_cast<tcHwSMPtr>(standardModel());
// do the initialisation
if(!hwsm) throw InitException()
<< "Wrong type of StandardModel object in "
<< "MEee2gZ2qq::doinit() the Herwig version must be used"
<< Exception::runerror;
FFZVertex_ = hwsm->vertexFFZ();
FFPVertex_ = hwsm->vertexFFP();
FFGVertex_ = hwsm->vertexFFG();
}
void MEee2gZ2qq::getDiagrams() const {
// specific the diagrams
tcPDPtr ep = getParticleData(ParticleID::eplus);
tcPDPtr em = getParticleData(ParticleID::eminus);
tcPDPtr gamma = getParticleData(ParticleID::gamma);
tcPDPtr Z0 = getParticleData(ParticleID::Z0);
// setup the processes
for ( int i =minflav_; i<=maxflav_; ++i ) {
tcPDPtr qk = getParticleData(i);
tcPDPtr qb = qk->CC();
add(new_ptr((Tree2toNDiagram(2), em, ep, 1, gamma, 3, qk, 3, qb, -1)));
add(new_ptr((Tree2toNDiagram(2), em, ep, 1, Z0 , 3, qk, 3, qb, -2)));
}
}
Energy2 MEee2gZ2qq::scale() const {
return sqr(getParticleData(ParticleID::Z0)->mass());
// return sHat();
}
unsigned int MEee2gZ2qq::orderInAlphaS() const {
return 0;
}
unsigned int MEee2gZ2qq::orderInAlphaEW() const {
return 2;
}
Selector<MEBase::DiagramIndex>
MEee2gZ2qq::diagrams(const DiagramVector & diags) const {
double lastCont(0.5),lastBW(0.5);
if ( lastXCombPtr() ) {
lastCont = meInfo()[0];
lastBW = meInfo()[1];
}
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i ) {
if ( diags[i]->id() == -1 ) sel.insert(lastCont, i);
else if ( diags[i]->id() == -2 ) sel.insert(lastBW, i);
}
return sel;
}
Selector<const ColourLines *>
MEee2gZ2qq::colourGeometries(tcDiagPtr ) const {
static const ColourLines c("-5 4");
Selector<const ColourLines *> sel;
sel.insert(1.0, &c);
return sel;
}
void MEee2gZ2qq::persistentOutput(PersistentOStream & os) const {
os << FFZVertex_ << FFPVertex_ << FFGVertex_
<< Z0_ << gamma_ << gluon_ << minflav_
<< maxflav_ << massopt_ << alphaQCD_ << alphaQED_
<< ounit(pTminQED_,GeV) << ounit(pTminQCD_,GeV) << preFactor_
<< spinCorrelations_;
}
void MEee2gZ2qq::persistentInput(PersistentIStream & is, int) {
is >> FFZVertex_ >> FFPVertex_ >> FFGVertex_
>> Z0_ >> gamma_ >> gluon_ >> minflav_
>> maxflav_ >> massopt_ >> alphaQCD_ >> alphaQED_
>> iunit(pTminQED_,GeV) >> iunit(pTminQCD_,GeV) >> preFactor_
>> spinCorrelations_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<MEee2gZ2qq,HwMEBase>
describeMEee2gZ2qq("Herwig::MEee2gZ2qq", "HwMELepton.so");
void MEee2gZ2qq::Init() {
static ClassDocumentation<MEee2gZ2qq> documentation
("The MEee2gZ2qq class implements the matrix element for e+e- -> q qbar");
static Parameter<MEee2gZ2qq,int> interfaceMinimumFlavour
("MinimumFlavour",
"The PDG code of the quark with the lowest PDG code to produce.",
&MEee2gZ2qq::minflav_, 1, 1, 6,
false, false, Interface::limited);
static Parameter<MEee2gZ2qq,int> interfaceMaximumFlavour
("MaximumFlavour",
"The PDG code of the quark with the highest PDG code to produce",
&MEee2gZ2qq::maxflav_, 5, 1, 6,
false, false, Interface::limited);
static Switch<MEee2gZ2qq,unsigned int> interfaceTopMassOption
("TopMassOption",
"Option for the treatment of the top quark mass",
&MEee2gZ2qq::massopt_, 1, false, false);
static SwitchOption interfaceTopMassOptionOnMassShell
(interfaceTopMassOption,
"OnMassShell",
"The top is produced on its mass shell",
1);
static SwitchOption interfaceTopMassOption2
(interfaceTopMassOption,
"OffShell",
"The top is generated off-shell using the mass and width generator.",
2);
static Parameter<MEee2gZ2qq,Energy> interfacepTMinQED
("pTMinQED",
"Minimum pT for hard QED radiation",
&MEee2gZ2qq::pTminQED_, GeV, 1.0*GeV, 0.001*GeV, 10.0*GeV,
false, false, Interface::limited);
static Parameter<MEee2gZ2qq,Energy> interfacepTMinQCD
("pTMinQCD",
"Minimum pT for hard QCD radiation",
&MEee2gZ2qq::pTminQCD_, GeV, 1.0*GeV, 0.001*GeV, 10.0*GeV,
false, false, Interface::limited);
static Parameter<MEee2gZ2qq,double> interfacePrefactor
("Prefactor",
"Prefactor for the overestimate of the emission probability",
&MEee2gZ2qq::preFactor_, 6.0, 1.0, 100.0,
false, false, Interface::limited);
static Reference<MEee2gZ2qq,ShowerAlpha> interfaceQCDCoupling
("AlphaQCD",
"Pointer to the object to calculate the strong coupling for the correction",
&MEee2gZ2qq::alphaQCD_, false, false, true, false, false);
static Reference<MEee2gZ2qq,ShowerAlpha> interfaceEMCoupling
("AlphaQED",
"Pointer to the object to calculate the EM coupling for the correction",
&MEee2gZ2qq::alphaQED_, false, false, true, false, false);
static Switch<MEee2gZ2qq,bool> interfaceSpinCorrelations
("SpinCorrelations",
"Switch the construction of the veretx for spin correlations on/off",
&MEee2gZ2qq::spinCorrelations_, true, false, false);
static SwitchOption interfaceSpinCorrelationsYes
(interfaceSpinCorrelations,
"Yes",
"Swtich On",
true);
static SwitchOption interfaceSpinCorrelationsNo
(interfaceSpinCorrelations,
"No",
"Switch off",
false);
}
double MEee2gZ2qq::me2() const {
return loME(mePartonData(),rescaledMomenta(),true);
}
ProductionMatrixElement MEee2gZ2qq::HelicityME(vector<SpinorWaveFunction> & fin,
vector<SpinorBarWaveFunction> & ain,
vector<SpinorBarWaveFunction> & fout,
vector<SpinorWaveFunction> & aout,
double & me,
double & cont,
double & BW ) const {
// the particles should be in the order
// for the incoming
// 0 incoming fermion (u spinor)
// 1 incoming antifermion (vbar spinor)
// for the outgoing
// 0 outgoing fermion (ubar spinor)
// 1 outgoing antifermion (v spinor)
// me to be returned
ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half);
ProductionMatrixElement gamma (PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half);
ProductionMatrixElement Zboson(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half);
// wavefunctions for the intermediate particles
VectorWaveFunction interZ,interG;
// temporary storage of the different diagrams
Complex diag1,diag2;
// sum over helicities to get the matrix element
unsigned int inhel1,inhel2,outhel1,outhel2;
double total[3]={0.,0.,0.};
for(inhel1=0;inhel1<2;++inhel1) {
for(inhel2=0;inhel2<2;++inhel2) {
// intermediate Z
interZ = FFZVertex_->evaluate(scale(),1,Z0_,fin[inhel1],ain[inhel2]);
// intermediate photon
interG = FFPVertex_->evaluate(scale(),1,gamma_,fin[inhel1],ain[inhel2]);
for(outhel1=0;outhel1<2;++outhel1) {
for(outhel2=0;outhel2<2;++outhel2) {
// first the Z exchange diagram
diag1 = FFZVertex_->evaluate(scale(),aout[outhel2],fout[outhel1],
interZ);
// then the photon exchange diagram
diag2 = FFPVertex_->evaluate(scale(),aout[outhel2],fout[outhel1],
interG);
// add up squares of individual terms
total[1] += norm(diag1);
Zboson(inhel1,inhel2,outhel1,outhel2) = diag1;
total[2] += norm(diag2);
gamma (inhel1,inhel2,outhel1,outhel2) = diag2;
// the full thing including interference
diag1 += diag2;
total[0] += norm(diag1);
output(inhel1,inhel2,outhel1,outhel2)=diag1;
}
}
}
}
for(int ix=0;ix<3;++ix) total[ix] *= 0.25;
tcPolarizedBeamPDPtr beam[2] =
{dynamic_ptr_cast<tcPolarizedBeamPDPtr>(mePartonData()[0]),
dynamic_ptr_cast<tcPolarizedBeamPDPtr>(mePartonData()[1])};
if( beam[0] || beam[1] ) {
RhoDMatrix rho[2] =
{beam[0] ? beam[0]->rhoMatrix() : RhoDMatrix(mePartonData()[0]->iSpin()),
beam[1] ? beam[1]->rhoMatrix() : RhoDMatrix(mePartonData()[1]->iSpin())};
total[0] = output.average(rho[0],rho[1]);
total[1] = Zboson.average(rho[0],rho[1]);
total[2] = gamma .average(rho[0],rho[1]);
}
// results
for(int ix=0;ix<3;++ix) total[ix]*= 3.;
cont = total[2];
BW = total[1];
me = total[0];
return output;
}
void MEee2gZ2qq::constructVertex(tSubProPtr sub) {
if(!spinCorrelations_) return;
// extract the particles in the hard process
ParticleVector hard;
hard.push_back(sub->incoming().first);
hard.push_back(sub->incoming().second);
hard.push_back(sub->outgoing()[0]);
hard.push_back(sub->outgoing()[1]);
if(hard[0]->id()<hard[1]->id()) swap(hard[0],hard[1]);
if(hard[2]->id()<hard[3]->id()) swap(hard[2],hard[3]);
vector<SpinorWaveFunction> fin,aout;
vector<SpinorBarWaveFunction> ain,fout;
// get wave functions for off-shell momenta for later on
SpinorWaveFunction( fin ,hard[0],incoming,false,true);
SpinorBarWaveFunction(ain ,hard[1],incoming,false,true);
SpinorBarWaveFunction(fout,hard[2],outgoing,true ,true);
SpinorWaveFunction( aout,hard[3],outgoing,true ,true);
// now rescale the momenta and compute the matrix element with the
// rescaled momenta for correlations
vector<Lorentz5Momentum> momenta;
cPDVector data;
for(unsigned int ix=0;ix<4;++ix) {
momenta.push_back(hard[ix]->momentum());
data .push_back(hard[ix]->dataPtr());
}
rescaleMomenta(momenta,data);
SpinorWaveFunction ein (rescaledMomenta()[0],data[0],incoming);
SpinorBarWaveFunction pin (rescaledMomenta()[1],data[1],incoming);
SpinorBarWaveFunction qkout(rescaledMomenta()[2],data[2],outgoing);
SpinorWaveFunction qbout(rescaledMomenta()[3],data[3],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
ein.reset(ix) ; fin [ix] = ein ;
pin.reset(ix) ; ain [ix] = pin ;
qkout.reset(ix); fout[ix] = qkout;
qbout.reset(ix); aout[ix] = qbout;
}
// calculate the matrix element
double me,cont,BW;
ProductionMatrixElement prodme=HelicityME(fin,ain,fout,aout,me,cont,BW);
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(prodme);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<4;++ix) {
tSpinPtr spin = hard[ix]->spinInfo();
if(ix<2) {
tcPolarizedBeamPDPtr beam =
dynamic_ptr_cast<tcPolarizedBeamPDPtr>(hard[ix]->dataPtr());
if(beam) spin->rhoMatrix() = beam->rhoMatrix();
}
spin->productionVertex(hardvertex);
}
}
void MEee2gZ2qq::rebind(const TranslationMap & trans) {
FFZVertex_ = trans.translate(FFZVertex_);
FFPVertex_ = trans.translate(FFPVertex_);
FFGVertex_ = trans.translate(FFGVertex_);
Z0_ = trans.translate(Z0_);
gamma_ = trans.translate(gamma_);
gluon_ = trans.translate(gluon_);
HwMEBase::rebind(trans);
}
IVector MEee2gZ2qq::getReferences() {
IVector ret = HwMEBase::getReferences();
ret.push_back(FFZVertex_);
ret.push_back(FFPVertex_);
ret.push_back(FFGVertex_);
ret.push_back(Z0_ );
ret.push_back(gamma_ );
ret.push_back(gluon_ );
return ret;
}
void MEee2gZ2qq::initializeMECorrection(PerturbativeProcessPtr,
double & initial,
double & final) {
d_Q_ = sqrt(sHat());
d_m_ = 0.5*(meMomenta()[2].mass()+meMomenta()[3].mass());
// set the other parameters
d_rho_ = sqr(d_m_/d_Q_);
d_v_ = sqrt(1.-4.*d_rho_);
// maximum evolution scale
d_kt1_ = (1. + sqrt(1. - 4.*d_rho_))/2.;
double num = d_rho_ * d_kt1_ + 0.25 * d_v_ *(1.+d_v_)*(1.+d_v_);
double den = d_kt1_ - d_rho_;
d_kt2_ = num/den;
// maximums for reweighting
initial = 1.;
final = 1.;
}
RealEmissionProcessPtr MEee2gZ2qq::applyHardMatrixElementCorrection(PerturbativeProcessPtr born) {
vector<Lorentz5Momentum> emission;
unsigned int iemit,ispect;
generateHard(born,emission,iemit,ispect,true,ShowerInteraction::QCD);
if(emission.empty()) return RealEmissionProcessPtr();
// get the quark and antiquark
ParticleVector qq;
for(unsigned int ix=0;ix<2;++ix) qq.push_back(born->outgoing()[ix].first);
bool order = qq[0]->id()>0;
if(!order) swap(qq[0],qq[1]);
// perform final check to ensure energy greater than constituent mass
for (int i=0; i<2; i++) {
if (emission[i+2].e() < qq[i]->data().constituentMass())
return RealEmissionProcessPtr();
}
if (emission[4].e() < gluon_->constituentMass())
return RealEmissionProcessPtr();
// set masses
for (int i=0; i<2; i++) emission[i+2].setMass(qq[i]->mass());
emission[4].setMass(ZERO);
// create the new quark, antiquark and gluon
PPtr newq = qq[0]->dataPtr()->produceParticle(emission[2]);
PPtr newa = qq[1]->dataPtr()->produceParticle(emission[3]);
PPtr newg = gluon_->produceParticle(emission[4]);
if(iemit==2) {
}
else {
}
// create the output real emission process
RealEmissionProcessPtr output(new_ptr(RealEmissionProcess(born)));
- cerr << "testing A " << born->incoming().size() << " "
- << output->incoming().size() << "\n";
for(unsigned int ix=0;ix<born->incoming().size();++ix) {
output->incoming().push_back(born->incoming()[ix]);
}
if(order) {
output->outgoing().push_back(make_pair(newq,PerturbativeProcessPtr()));
output->outgoing().push_back(make_pair(newa,PerturbativeProcessPtr()));
output->outgoing().push_back(make_pair(newg,PerturbativeProcessPtr()));
}
else {
output->outgoing().push_back(make_pair(newa,PerturbativeProcessPtr()));
output->outgoing().push_back(make_pair(newq,PerturbativeProcessPtr()));
output->outgoing().push_back(make_pair(newg,PerturbativeProcessPtr()));
swap(iemit,ispect);
}
// set emitter and spectator
output->emitter (iemit);
output->spectator(ispect);
output->emitted(4);
// make colour connections
newg->colourNeighbour(newq);
newa->colourNeighbour(newg);
// return output
return output;
}
bool MEee2gZ2qq::softMatrixElementVeto(ShowerProgenitorPtr initial,
ShowerParticlePtr parent,Branching br) {
// check we should be applying the veto
if(parent->id()!=initial->progenitor()->id()||
br.ids[0]->id()!=br.ids[1]->id()||
br.ids[2]->id()!=ParticleID::g) return false;
// calculate pt
double d_z = br.kinematics->z();
Energy d_qt = br.kinematics->scale();
Energy2 d_m2 = parent->momentum().m2();
Energy pPerp = (1.-d_z)*sqrt( sqr(d_z*d_qt) - d_m2);
// if not hardest so far don't apply veto
if(pPerp<initial->highestpT()) return false;
// calculate x and xb
double kti = sqr(d_qt/d_Q_);
double w = sqr(d_v_) + kti*(-1. + d_z)*d_z*(2. + kti*(-1. + d_z)*d_z);
if (w < 0) return false;
double x = (1. + sqr(d_v_)*(-1. + d_z) + sqr(kti*(-1. + d_z))*d_z*d_z*d_z
+ d_z*sqrt(w)
- kti*(-1. + d_z)*d_z*(2. + d_z*(-2 + sqrt(w))))/
(1. - kti*(-1. + d_z)*d_z + sqrt(w));
double xb = 1. + kti*(-1. + d_z)*d_z;
// calculate the weight
if(parent->id()<0) swap(x,xb);
// if exceptionally out of phase space, leave this emission, as there
// is no good interpretation for the soft ME correction.
if( x<0 || xb<0) return false;
double xg = 2. - xb - x;
// always return one in the soft gluon region
if(xg < EPS_) return false;
// check it is in the phase space
if((1.-x)*(1.-xb)*(1.-xg) < d_rho_*xg*xg) {
parent->vetoEmission(parent->id()>0 ? ShowerPartnerType::QCDColourLine :
ShowerPartnerType::QCDColourLine,br.kinematics->scale());
return true;
}
double k1 = getKfromX(x, xb);
double k2 = getKfromX(xb, x);
double weight = 1.;
// quark emission
if(parent->id() > 0 && k1 < d_kt1_) {
weight = MEV(x, xb)/PS(x, xb);
// is it also in the anti-quark emission zone?
if(k2 < d_kt2_) weight *= 0.5;
}
// antiquark emission
if(parent->id() < 0 && k2 < d_kt2_) {
weight = MEV(x, xb)/PS(xb, x);
// is it also in the quark emission zone?
if(k1 < d_kt1_) weight *= 0.5;
}
// compute veto from weight
bool veto = !UseRandom::rndbool(weight);
// if not vetoed reset max
// if vetoing reset the scale
if(veto) {
parent->vetoEmission(parent->id()>0 ? ShowerPartnerType::QCDColourLine :
ShowerPartnerType::QCDColourLine,br.kinematics->scale());
}
// return the veto
return veto;
}
double MEee2gZ2qq::getKfromX(double x1, double x2) {
double uval = 0.5*(1. + d_rho_/(1.-x2+d_rho_));
double num = x1 - (2. - x2)*uval;
double den = sqrt(x2*x2 - 4.*d_rho_);
double zval = uval + num/den;
return (1.-x2)/(zval*(1.-zval));
}
double MEee2gZ2qq::MEV(double x1, double x2) {
// Vector part
double num = (x1+2.*d_rho_)*(x1+2.*d_rho_) + (x2+2.*d_rho_)*(x2+2.*d_rho_)
- 8.*d_rho_*(1.+2.*d_rho_);
double den = (1.+2.*d_rho_)*(1.-x1)*(1.-x2);
return (num/den - 2.*d_rho_/((1.-x1)*(1.-x1))
- 2*d_rho_/((1.-x2)*(1.-x2)))/d_v_;
}
double MEee2gZ2qq::PS(double x, double xbar) {
double u = 0.5*(1. + d_rho_ / (1.-xbar+d_rho_));
double z = u + (x - (2.-xbar)*u)/sqrt(xbar*xbar - 4.*d_rho_);
double brack = (1.+z*z)/(1.-z)- 2.*d_rho_/(1-xbar);
// interesting: the splitting function without the subtraction
// term. Actually gives a much worse approximation in the collinear
// limit. double brack = (1.+z*z)/(1.-z);
double den = (1.-xbar)*sqrt(xbar*xbar - 4.*d_rho_);
return brack/den;
}
pair<Energy,ShowerInteraction::Type>
MEee2gZ2qq::generateHard(PerturbativeProcessPtr born,
vector<Lorentz5Momentum> & emmision,
unsigned int & iemit, unsigned int & ispect,
bool applyVeto,ShowerInteraction::Type inter) {
vector<ShowerInteraction::Type> interactions;
if(inter==ShowerInteraction::Both) {
interactions.push_back(ShowerInteraction::QED);
interactions.push_back(ShowerInteraction::QCD);
}
else
interactions.push_back(inter);
// incoming particles
tPPtr em = born->incoming()[0].first;
tPPtr ep = born->incoming()[1].first;
if(em->id()<0) swap(em,ep);
// outgoing particles
tPPtr qk = born->outgoing()[0].first;
tPPtr qb = born->outgoing()[1].first;
if(qk->id()<0) swap(qk,qb);
// extract the momenta
loMomenta_.clear();
loMomenta_.push_back(em->momentum());
loMomenta_.push_back(ep->momentum());
loMomenta_.push_back(qk->momentum());
loMomenta_.push_back(qb->momentum());
// and ParticleData objects
partons_.resize(5);
partons_[0]=em->dataPtr();
partons_[1]=ep->dataPtr();
partons_[2]=qk->dataPtr();
partons_[3]=qb->dataPtr();
partons_[4]=cPDPtr();
// boost from lab to CMS frame with outgoing particles
// along the z axis
LorentzRotation eventFrame( ( loMomenta_[2] + loMomenta_[3] ).findBoostToCM() );
Lorentz5Momentum spectator = eventFrame*loMomenta_[2];
eventFrame.rotateZ( -spectator.phi() );
eventFrame.rotateY( -spectator.theta() );
eventFrame.invert();
// mass of the final-state system
Energy2 M2 = (loMomenta_[2]+loMomenta_[3]).m2();
Energy M = sqrt(M2);
double mu1 = loMomenta_[2].mass()/M;
double mu2 = loMomenta_[3].mass()/M;
double mu12 = sqr(mu1), mu22 = sqr(mu2);
double lambda = sqrt(1.+sqr(mu12)+sqr(mu22)-2.*mu12-2.*mu22-2.*mu12*mu22);
// max pT
Energy pTmax = 0.5*sqrt(M2)*
(1.-sqr(loMomenta_[2].mass()+loMomenta_[3].mass())/M2);
// max y
if ( pTmax < pTminQED_ && pTmax < pTminQCD_ ) return make_pair(ZERO,ShowerInteraction::QCD);
vector<Energy> pTemit;
vector<vector<Lorentz5Momentum> > emittedMomenta;;
vector<unsigned int> iemitter,ispectator;
for(unsigned int iinter=0;iinter<interactions.size();++iinter) {
Energy pTmin(ZERO);
double a,ymax;
if(interactions[iinter]==ShowerInteraction::QCD) {
pTmin = pTminQCD_;
ymax = acosh(pTmax/pTmin);
partons_[4] = gluon_;
// prefactor for the overestimate of the Sudakov
a = 4./3.*alphaQCD_->overestimateValue()/Constants::twopi*
2.*ymax*preFactor_;
}
else {
pTmin = pTminQED_;
ymax = acosh(pTmax/pTmin);
partons_[4] = gamma_;
a = alphaQED_->overestimateValue()/Constants::twopi*
2.*ymax*preFactor_*sqr(double(mePartonData()[2]->iCharge())/3.);
}
// variables for the emission
Energy pT[2];
double y[2],phi[2],x3[2],x1[2][2],x2[2][2];
double contrib[2][2];
// storage of the real emission momenta
vector<Lorentz5Momentum> realMomenta[2][2]=
{{vector<Lorentz5Momentum>(5),vector<Lorentz5Momentum>(5)},
{vector<Lorentz5Momentum>(5),vector<Lorentz5Momentum>(5)}};
for(unsigned int ix=0;ix<2;++ix)
for(unsigned int iy=0;iy<2;++iy)
for(unsigned int iz=0;iz<2;++iz)
realMomenta[ix][iy][iz] = loMomenta_[iz];
// generate the emission
for(unsigned int ix=0;ix<2;++ix) {
if(ix==1) {
swap(mu1 ,mu2 );
swap(mu12,mu22);
}
pT[ix] = pTmax;
y [ix] = 0.;
bool reject = true;
do {
// generate pT
pT[ix] *= pow(UseRandom::rnd(),1./a);
if(pT[ix]<pTmin) {
pT[ix] = -GeV;
break;
}
// generate y
y[ix] = -ymax+2.*UseRandom::rnd()*ymax;
// generate phi
phi[ix] = UseRandom::rnd()*Constants::twopi;
// calculate x3 and check in allowed region
x3[ix] = 2.*pT[ix]*cosh(y[ix])/M;
if(x3[ix] < 0. || x3[ix] > 1. -sqr( mu1 + mu2 ) ) continue;
// find the possible solutions for x1
double xT2 = sqr(2./M*pT[ix]);
double root = (-sqr(x3[ix])+xT2)*
(xT2*mu22+2.*x3[ix]-sqr(mu12)+2.*mu22+2.*mu12-sqr(x3[ix])-1.
+2.*mu12*mu22-sqr(mu22)-2.*mu22*x3[ix]-2.*mu12*x3[ix]);
double c1=2.*sqr(x3[ix])-4.*mu22-6.*x3[ix]+4.*mu12-xT2*x3[ix]
+2.*xT2-2.*mu12*x3[ix]+2.*mu22*x3[ix]+4.;
if(root<0.) continue;
x1[ix][0] = 1./(4.-4.*x3[ix]+xT2)*(c1-2.*sqrt(root));
x1[ix][1] = 1./(4.-4.*x3[ix]+xT2)*(c1+2.*sqrt(root));
// change sign of y if 2nd particle emits
if(ix==1) y[ix] *=-1.;
// loop over the solutions
for(unsigned int iy=0;iy<2;++iy) {
contrib[ix][iy]=0.;
// check x1 value allowed
if(x1[ix][iy]<2.*mu1||x1[ix][iy]>1.+mu12-mu22) continue;
// calculate x2 value and check allowed
x2[ix][iy] = 2.-x3[ix]-x1[ix][iy];
double root = max(0.,sqr(x1[ix][iy])-4.*mu12);
root = sqrt(root);
double x2min = 1.+mu22-mu12
-0.5*(1.-x1[ix][iy]+mu12-mu22)/(1.-x1[ix][iy]+mu12)*(x1[ix][iy]-2.*mu12+root);
double x2max = 1.+mu22-mu12
-0.5*(1.-x1[ix][iy]+mu12-mu22)/(1.-x1[ix][iy]+mu12)*(x1[ix][iy]-2.*mu12-root);
if(x2[ix][iy]<x2min||x2[ix][iy]>x2max) continue;
// check the z components
double z1 = sqrt(sqr(x1[ix][iy])-4.*mu12-xT2);
double z2 = -sqrt(sqr(x2[ix][iy])-4.*mu22);
double z3 = pT[ix]*sinh(y[ix])*2./M;
if(ix==1) z3 *=-1.;
if(abs(-z1+z2+z3)<1e-9) z1 *= -1.;
if(abs(z1+z2+z3)>1e-5) continue;
// if using as an ME correction the veto
if(applyVeto) {
double xb = x1[ix][iy], xc = x2[ix][iy];
double b = mu12, c = mu22;
double r = 0.5*(1.+b/(1.+c-xc));
double z1 = r + (xb-(2.-xc)*r)/sqrt(sqr(xc)-4.*c);
double kt1 = (1.-b+c-xc)/z1/(1.-z1);
r = 0.5*(1.+c/(1.+b-xb));
double z2 = r + (xc-(2.-xb)*r)/sqrt(sqr(xb)-4.*b);
double kt2 = (1.-c+b-xb)/z2/(1.-z2);
if(ix==1) {
swap(z1 ,z2);
swap(kt1,kt2);
}
// veto the shower region
if( kt1 < d_kt1_ || kt2 < d_kt2_ ) continue;
}
// construct the momenta
realMomenta[ix][iy][4] =
Lorentz5Momentum(pT[ix]*cos(phi[ix]),pT[ix]*sin(phi[ix]),
pT[ix]*sinh(y[ix]) ,pT[ix]*cosh(y[ix]),ZERO);
if(ix==0) {
realMomenta[ix][iy][2] =
Lorentz5Momentum(-pT[ix]*cos(phi[ix]),-pT[ix]*sin(phi[ix]),
z1*0.5*M,x1[ix][iy]*0.5*M,M*mu1);
realMomenta[ix][iy][3] =
Lorentz5Momentum(ZERO,ZERO, z2*0.5*M,x2[ix][iy]*0.5*M,M*mu2);
}
else {
realMomenta[ix][iy][2] =
Lorentz5Momentum(ZERO,ZERO,-z2*0.5*M,x2[ix][iy]*0.5*M,M*mu2);
realMomenta[ix][iy][3] =
Lorentz5Momentum(-pT[ix]*cos(phi[ix]),-pT[ix]*sin(phi[ix]),
-z1*0.5*M,x1[ix][iy]*0.5*M,M*mu1);
}
// boost the momenta back to the lab
for(unsigned int iz=2;iz<5;++iz)
realMomenta[ix][iy][iz] *= eventFrame;
// jacobian and prefactors for the weight
Energy J = M/sqrt(xT2)*abs(-x1[ix][iy]*x2[ix][iy]+2.*mu22*x1[ix][iy]
+x2[ix][iy]+x2[ix][iy]*mu12+mu22*x2[ix][iy]
-sqr(x2[ix][iy]))
/pow(sqr(x2[ix][iy])-4.*mu22,1.5);
// prefactors etc
contrib[ix][iy] = 0.5*pT[ix]/J/preFactor_/lambda;
// matrix element piece
contrib[ix][iy] *= meRatio(partons_,realMomenta[ix][iy],
ix,interactions[iinter],false);
// coupling piece
if(interactions[iinter]==ShowerInteraction::QCD)
contrib[ix][iy] *= alphaQCD_->ratio(sqr(pT[ix]));
else
contrib[ix][iy] *= alphaQED_->ratio(sqr(pT[ix]));
}
if(contrib[ix][0]+contrib[ix][1]>1.) {
ostringstream s;
s << "MEee2gZ2qq::generateHardest weight for channel " << ix
<< "is " << contrib[ix][0]+contrib[ix][1]
<< " which is greater than 1";
generator()->logWarning( Exception(s.str(), Exception::warning) );
}
reject = UseRandom::rnd() > contrib[ix][0] + contrib[ix][1];
}
while (reject);
if(pT[ix]<pTmin)
pT[ix] = -GeV;
}
// pt of emission
if(pT[0]<ZERO && pT[1]<ZERO) {
pTemit.push_back(-GeV);
emittedMomenta.push_back(vector<Lorentz5Momentum>());
iemitter .push_back(0);
ispectator.push_back(0);
continue;
}
// now pick the emission with highest pT
vector<Lorentz5Momentum> emission;
if(pT[0]>pT[1]) {
iemitter .push_back(2);
ispectator.push_back(3);
pTemit.push_back(pT[0]);
if(UseRandom::rnd()<contrib[0][0]/(contrib[0][0]+contrib[0][1]))
emission = realMomenta[0][0];
else
emission = realMomenta[0][1];
}
else {
iemitter .push_back(3);
ispectator.push_back(2);
pTemit.push_back(pT[1]);
if(UseRandom::rnd()<contrib[1][0]/(contrib[1][0]+contrib[1][1]))
emission = realMomenta[1][0];
else
emission = realMomenta[1][1];
}
emittedMomenta.push_back(emission);
}
// select the type of emission
int iselect=-1;
pTmax = ZERO;
for(unsigned int ix=0;ix<interactions.size();++ix) {
if(pTemit[ix]>pTmax) {
iselect = ix;
pTmax = pTemit[ix];
}
}
// no emission return
if(iselect<0) {
return make_pair(ZERO,ShowerInteraction::QCD);
}
partons_[4] = interactions[iselect]==ShowerInteraction::QCD ? gluon_ : gamma_;
iemit = iemitter[iselect];
ispect = ispectator[iselect];
emmision = emittedMomenta[iselect];
// return pT of emission
return make_pair(pTmax,interactions[iselect]);
}
// HardTreePtr MEee2gZ2qq::generateHardest(ShowerTreePtr tree, ShowerInteraction::Type inter) {
// // generate the momenta for the hard emission
// vector<Lorentz5Momentum> emmision;
// unsigned int iemit,ispect;
// pair<Energy,ShowerInteraction::Type> output
// = generateHard(tree,emmision,iemit,ispect,false,inter);
// Energy pTveto = output.first;
// ShowerInteraction::Type force = output.second;
// // incoming progenitors
// ShowerProgenitorPtr
// ePProgenitor = tree->incomingLines().begin() ->first,
// eMProgenitor = tree->incomingLines().rbegin()->first;
// if(eMProgenitor->id()<0) swap(eMProgenitor,ePProgenitor);
// // outgoing progenitors
// ShowerProgenitorPtr
// qkProgenitor = tree->outgoingLines().begin() ->first,
// qbProgenitor = tree->outgoingLines().rbegin()->first;
// if(qkProgenitor->id()<0) swap(qkProgenitor,qbProgenitor);
// // maximum pT of emission
// if(emmision.empty()) {
// qkProgenitor->maximumpT(pTminQCD_,ShowerInteraction::QCD);
// qbProgenitor->maximumpT(pTminQCD_,ShowerInteraction::QCD);
// qkProgenitor->maximumpT(pTminQED_,ShowerInteraction::QED);
// qbProgenitor->maximumpT(pTminQED_,ShowerInteraction::QED);
// return HardTreePtr();
// }
// else {
// qkProgenitor->maximumpT(pTveto,ShowerInteraction::QCD);
// qbProgenitor->maximumpT(pTveto,ShowerInteraction::QCD);
// qkProgenitor->maximumpT(pTveto,ShowerInteraction::QED);
// qbProgenitor->maximumpT(pTveto,ShowerInteraction::QED);
// }
// // perform final check to ensure energy greater than constituent mass
// if (emmision[2].e() < qkProgenitor->progenitor()->data().constituentMass()) return HardTreePtr();
// if (emmision[3].e() < qbProgenitor->progenitor()->data().constituentMass()) return HardTreePtr();
// if(force!=ShowerInteraction::QED &&
// emmision[4].e() < gluon_->constituentMass()) return HardTreePtr();
// // Make the particles for the hard tree
// ShowerParticleVector hardParticles;
// for(unsigned int ix=0;ix<partons_.size();++ix) {
// hardParticles.push_back(new_ptr(ShowerParticle(partons_[ix],ix>=2)));
// hardParticles.back()->set5Momentum(emmision[ix]);
// }
// ShowerParticlePtr parent(new_ptr(ShowerParticle(partons_[iemit],true)));
// Lorentz5Momentum parentMomentum(emmision[iemit]+emmision[4]);
// parentMomentum.setMass(partons_[iemit]->mass());
// parent->set5Momentum(parentMomentum);
// // Create the vectors of HardBranchings to create the HardTree:
// vector<HardBranchingPtr> spaceBranchings,allBranchings;
// // Incoming boson:
// for(unsigned int ix=0;ix<2;++ix) {
// spaceBranchings.push_back(new_ptr(HardBranching(hardParticles[ix],SudakovPtr(),
// HardBranchingPtr(),
// HardBranching::Incoming)));
// allBranchings.push_back(spaceBranchings.back());
// }
// // Outgoing particles from hard emission:
// HardBranchingPtr spectatorBranch(new_ptr(HardBranching(hardParticles[ispect],
// SudakovPtr(),HardBranchingPtr(),
// HardBranching::Outgoing)));
// HardBranchingPtr emitterBranch(new_ptr(HardBranching(parent,SudakovPtr(),
// HardBranchingPtr(),
// HardBranching::Outgoing)));
// if(force==ShowerInteraction::QED) {
// emitterBranch->type(ShowerPartnerType::QED);
// }
// else {
// emitterBranch->type(emitterBranch->branchingParticle()->id()>0 ?
// ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine);
// }
// emitterBranch->addChild(new_ptr(HardBranching(hardParticles[iemit],
// SudakovPtr(),HardBranchingPtr(),
// HardBranching::Outgoing)));
// emitterBranch->addChild(new_ptr(HardBranching(hardParticles[4],
// SudakovPtr(),HardBranchingPtr(),
// HardBranching::Outgoing)));
// if(iemit==0) {
// allBranchings.push_back(emitterBranch);
// allBranchings.push_back(spectatorBranch);
// }
// else {
// allBranchings.push_back( spectatorBranch );
// allBranchings.push_back( emitterBranch );
// }
// emitterBranch ->branchingParticle()->partner(spectatorBranch->branchingParticle());
// spectatorBranch->branchingParticle()->partner(emitterBranch ->branchingParticle());
// if(force==ShowerInteraction::QED) {
// spaceBranchings[0]->branchingParticle()->partner(spaceBranchings[1]->branchingParticle());
// spaceBranchings[1]->branchingParticle()->partner(spaceBranchings[0]->branchingParticle());
// }
// // Make the HardTree from the HardBranching vectors.
// HardTreePtr hardtree = new_ptr(HardTree(allBranchings,spaceBranchings,
// force));
// hardtree->partnersSet(true);
// // Connect the particles with the branchings in the HardTree
// hardtree->connect( eMProgenitor->progenitor(), allBranchings[0] );
// tPPtr beam = eMProgenitor->original();
// if(!beam->parents().empty()) beam = beam->parents()[0];
// allBranchings[0]->beam(beam);
// hardtree->connect( ePProgenitor->progenitor(), allBranchings[1] );
// beam = ePProgenitor->original();
// if(!beam->parents().empty()) beam = beam->parents()[0];
// allBranchings[1]->beam(beam);
// hardtree->connect( qkProgenitor->progenitor(), allBranchings[2] );
// hardtree->connect( qbProgenitor->progenitor(), allBranchings[3] );
// // colour flow
// ColinePtr newline=new_ptr(ColourLine());
// for(set<HardBranchingPtr>::const_iterator cit=hardtree->branchings().begin();
// cit!=hardtree->branchings().end();++cit) {
// if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3)
// newline->addColoured((**cit).branchingParticle());
// else if((**cit).branchingParticle()->dataPtr()->iColour()==PDT::Colour3bar)
// newline->addAntiColoured((**cit).branchingParticle());
// }
// allBranchings[2]->colourPartner(allBranchings[3]);
// allBranchings[3]->colourPartner(allBranchings[2]);
// if(hardParticles[4]->dataPtr()->iColour()==PDT::Colour8) {
// ColinePtr newLine2=new_ptr(ColourLine());
// if(emitterBranch->branchingParticle()->dataPtr()->iColour()==PDT::Colour3) {
// emitterBranch->branchingParticle()->colourLine()->addColoured(hardParticles[4]);
// newLine2->addColoured(hardParticles[iemit]);
// newLine2->addAntiColoured(hardParticles[4]);
// }
// else {
// emitterBranch->branchingParticle()->antiColourLine()->addAntiColoured(hardParticles[4]);
// newLine2->addAntiColoured(hardParticles[iemit]);
// newLine2->addColoured(hardParticles[4]);
// }
// }
// else {
// if(emitterBranch->branchingParticle()->dataPtr()->iColour()==PDT::Colour3) {
// emitterBranch->branchingParticle()->colourLine()->addColoured(hardParticles[iemit]);
// }
// else {
// emitterBranch->branchingParticle()->antiColourLine()->addAntiColoured(hardParticles[iemit]);
// }
// }
// // Return the HardTree
// return hardtree;
// }
double MEee2gZ2qq::meRatio(vector<cPDPtr> partons,
vector<Lorentz5Momentum> momenta,
unsigned int iemitter,
ShowerInteraction::Type inter,
bool subtract) const {
Lorentz5Momentum q = momenta[2]+momenta[3]+momenta[4];
Energy2 Q2=q.m2();
Energy2 lambda = sqrt((Q2-sqr(momenta[2].mass()+momenta[3].mass()))*
(Q2-sqr(momenta[2].mass()-momenta[3].mass())));
InvEnergy2 D[2];
double lome[2];
for(unsigned int iemit=0;iemit<2;++iemit) {
unsigned int ispect = iemit==0 ? 1 : 0;
Energy2 pipj = momenta[4 ] * momenta[2+iemit ];
Energy2 pipk = momenta[4 ] * momenta[2+ispect];
Energy2 pjpk = momenta[2+iemit] * momenta[2+ispect];
double y = pipj/(pipj+pipk+pjpk);
double z = pipk/( pipk+pjpk);
Energy mij = sqrt(2.*pipj+sqr(momenta[2+iemit].mass()));
Energy2 lamB = sqrt((Q2-sqr(mij+momenta[2+ispect].mass()))*
(Q2-sqr(mij-momenta[2+ispect].mass())));
Energy2 Qpk = q*momenta[2+ispect];
Lorentz5Momentum pkt =
lambda/lamB*(momenta[2+ispect]-Qpk/Q2*q)
+0.5/Q2*(Q2+sqr(momenta[2+ispect].mass())-sqr(momenta[2+ispect].mass()))*q;
Lorentz5Momentum pijt =
q-pkt;
double muj = momenta[2+iemit ].mass()/sqrt(Q2);
double muk = momenta[2+ispect].mass()/sqrt(Q2);
double vt = sqrt((1.-sqr(muj+muk))*(1.-sqr(muj-muk)))/(1.-sqr(muj)-sqr(muk));
double v = sqr(2.*sqr(muk)+(1.-sqr(muj)-sqr(muk))*(1.-y))-4.*sqr(muk);
if(v<=0.) return 0.;
v = sqrt(v)/(1.-y)/(1.-sqr(muj)-sqr(muk));
// dipole term
D[iemit] = 0.5/pipj*(2./(1.-(1.-z)*(1.-y))
-vt/v*(2.-z+sqr(momenta[2+iemit].mass())/pipj));
// matrix element
vector<Lorentz5Momentum> lomom(4);
lomom[0] = momenta[0];
lomom[1] = momenta[1];
if(iemit==0) {
lomom[2] = pijt;
lomom[3] = pkt ;
}
else {
lomom[3] = pijt;
lomom[2] = pkt ;
}
lome[iemit] = loME(partons,lomom,false)/3.;
}
InvEnergy2 ratio = realME(partons,momenta,inter)
*abs(D[iemitter])/(abs(D[0]*lome[0])+abs(D[1]*lome[1]));
double output = Q2*ratio;
if(subtract) output -= 2.*Q2*D[iemitter];
return output;
}
double MEee2gZ2qq::loME(const vector<cPDPtr> & partons,
const vector<Lorentz5Momentum> & momenta,
bool first) const {
// compute the spinors
vector<SpinorWaveFunction> fin,aout;
vector<SpinorBarWaveFunction> ain,fout;
SpinorWaveFunction ein (momenta[0],partons[0],incoming);
SpinorBarWaveFunction pin (momenta[1],partons[1],incoming);
SpinorBarWaveFunction qkout(momenta[2],partons[2],outgoing);
SpinorWaveFunction qbout(momenta[3],partons[3],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
ein.reset(ix) ;
fin.push_back( ein );
pin.reset(ix) ;
ain.push_back( pin );
qkout.reset(ix);
fout.push_back(qkout);
qbout.reset(ix);
aout.push_back(qbout);
}
// compute the matrix element
double me,lastCont,lastBW;
HelicityME(fin,ain,fout,aout,me,lastCont,lastBW);
// save the components
if(first) {
DVector save;
save.push_back(lastCont);
save.push_back(lastBW);
meInfo(save);
}
// return the answer
return me;
}
InvEnergy2 MEee2gZ2qq::realME(const vector<cPDPtr> & partons,
const vector<Lorentz5Momentum> & momenta,
ShowerInteraction::Type inter) const {
// compute the spinors
vector<SpinorWaveFunction> fin,aout;
vector<SpinorBarWaveFunction> ain,fout;
vector<VectorWaveFunction> gout;
SpinorWaveFunction ein (momenta[0],partons[0],incoming);
SpinorBarWaveFunction pin (momenta[1],partons[1],incoming);
SpinorBarWaveFunction qkout(momenta[2],partons[2],outgoing);
SpinorWaveFunction qbout(momenta[3],partons[3],outgoing);
VectorWaveFunction gluon(momenta[4],partons[4],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
ein.reset(ix) ;
fin.push_back( ein );
pin.reset(ix) ;
ain.push_back( pin );
qkout.reset(ix);
fout.push_back(qkout);
qbout.reset(ix);
aout.push_back(qbout);
gluon.reset(2*ix);
gout.push_back(gluon);
}
AbstractFFVVertexPtr vertex = inter == ShowerInteraction::QCD ?
FFGVertex_ : FFPVertex_;
vector<Complex> diag(4,0.);
ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1);
double total(0.);
for(unsigned int inhel1=0;inhel1<2;++inhel1) {
for(unsigned int inhel2=0;inhel2<2;++inhel2) {
// intermediate Z
VectorWaveFunction interZ =
FFZVertex_->evaluate(scale(),1,Z0_,fin[inhel1],ain[inhel2]);
// intermediate photon
VectorWaveFunction interG =
FFPVertex_->evaluate(scale(),1,gamma_,fin[inhel1],ain[inhel2]);
for(unsigned int outhel1=0;outhel1<2;++outhel1) {
for(unsigned int outhel2=0;outhel2<2;++outhel2) {
for(unsigned int outhel3=0;outhel3<2;++outhel3) {
SpinorBarWaveFunction off1 =
vertex->evaluate(scale(),3,partons[2],fout[outhel1],gout[outhel3]);
diag[0] = FFZVertex_->evaluate(scale(),aout[outhel2],off1,interZ);
diag[1] = FFPVertex_->evaluate(scale(),aout[outhel2],off1,interG);
SpinorWaveFunction off2 =
vertex->evaluate(scale(),3,partons[3],aout[outhel2],gout[outhel3]);
diag[2] = FFZVertex_->evaluate(scale(),off2,fout[outhel1],interZ);
diag[3] = FFPVertex_->evaluate(scale(),off2,fout[outhel1],interG);
// sum of diagrams
Complex sum = std::accumulate(diag.begin(),diag.end(),Complex(0.));
// matrix element
output(inhel1,inhel2,outhel1,outhel2,outhel3)=sum;
// me2
total += norm(sum);
}
}
}
}
}
// spin average
total *= 0.25;
tcPolarizedBeamPDPtr beam[2] =
{dynamic_ptr_cast<tcPolarizedBeamPDPtr>(partons[0]),
dynamic_ptr_cast<tcPolarizedBeamPDPtr>(partons[1])};
if( beam[0] || beam[1] ) {
RhoDMatrix rho[2] =
{beam[0] ? beam[0]->rhoMatrix() : RhoDMatrix(mePartonData()[0]->iSpin()),
beam[1] ? beam[1]->rhoMatrix() : RhoDMatrix(mePartonData()[1]->iSpin())};
total = output.average(rho[0],rho[1]);
}
// divide out the coupling
total /= norm(vertex->norm());
// and charge (if needed)
if(inter==ShowerInteraction::QED)
total /= sqr(double(mePartonData()[2]->iCharge())/3.);
// return the total
return total*UnitRemoval::InvE2;
}
diff --git a/Shower/QTilde/QTildeShowerHandler.cc b/Shower/QTilde/QTildeShowerHandler.cc
--- a/Shower/QTilde/QTildeShowerHandler.cc
+++ b/Shower/QTilde/QTildeShowerHandler.cc
@@ -1,3599 +1,3600 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the QTildeShowerHandler class.
//
#include "QTildeShowerHandler.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/RefVector.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/EventRecord/Particle.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Utilities/EnumIO.h"
#include "Herwig/Shower/QTilde/Base/ShowerParticle.h"
#include "Herwig/PDF/MPIPDF.h"
#include "Herwig/PDF/MinBiasPDF.h"
#include "Herwig/Shower/QTilde/Base/ShowerTree.h"
#include "Herwig/Shower/QTilde/Base/KinematicsReconstructor.h"
#include "Herwig/Shower/QTilde/Base/PartnerFinder.h"
#include "Herwig/PDF/HwRemDecayer.h"
#include "Herwig/Shower/QTilde/Base/ShowerVertex.h"
#include "ThePEG/Repository/CurrentGenerator.h"
#include "Herwig/MatrixElement/Matchbox/Base/SubtractedME.h"
#include "Herwig/MatrixElement/Matchbox/MatchboxFactory.h"
#include "ThePEG/PDF/PartonExtractor.h"
#include "Herwig/Shower/RealEmissionProcess.h"
using namespace Herwig;
namespace {
/**
* A struct to order the particles in the same way as in the DecayMode's
*/
struct ParticleOrdering {
/**
* Operator for the ordering
* @param p1 The first ParticleData object
* @param p2 The second ParticleData object
*/
bool operator() (tcPDPtr p1, tcPDPtr p2) {
return abs(p1->id()) > abs(p2->id()) ||
( abs(p1->id()) == abs(p2->id()) && p1->id() > p2->id() ) ||
( p1->id() == p2->id() && p1->fullName() > p2->fullName() );
}
};
typedef multiset<tcPDPtr,ParticleOrdering> OrderedParticles;
/**
* Cached lookup of decay modes.
* Generator::findDecayMode() is not efficient.
*/
tDMPtr findDecayMode(const string & tag) {
static map<string,DMPtr> cache;
map<string,DMPtr>::const_iterator pos = cache.find(tag);
if ( pos != cache.end() )
return pos->second;
tDMPtr dm = CurrentGenerator::current().findDecayMode(tag);
cache[tag] = dm;
return dm;
}
}
bool QTildeShowerHandler::_hardEmissionWarn = true;
bool QTildeShowerHandler::_missingTruncWarn = true;
QTildeShowerHandler::QTildeShowerHandler() :
_maxtry(100), _meCorrMode(1), _reconOpt(0),
_hardVetoReadOption(false),
_iptrms(ZERO), _beta(0.), _gamma(ZERO), _iptmax(),
_limitEmissions(0), _initialenhance(1.), _finalenhance(1.),
interaction_(ShowerInteraction::Both),
_trunc_Mode(true), _hardEmission(1),
_spinOpt(1), _softOpt(2), _hardPOWHEG(false), muPt(ZERO),
_maxTryFSR(100000), _maxFailFSR(100), _fracFSR(0.001),
_nFSR(0), _nFailedFSR(0)
{}
QTildeShowerHandler::~QTildeShowerHandler() {}
IBPtr QTildeShowerHandler::clone() const {
return new_ptr(*this);
}
IBPtr QTildeShowerHandler::fullclone() const {
return new_ptr(*this);
}
void QTildeShowerHandler::persistentOutput(PersistentOStream & os) const {
os << _model << _splittingGenerator << _maxtry
<< _meCorrMode << _hardVetoReadOption
<< _limitEmissions << _spinOpt << _softOpt << _hardPOWHEG
<< ounit(_iptrms,GeV) << _beta << ounit(_gamma,GeV) << ounit(_iptmax,GeV)
<< _vetoes << _trunc_Mode << _hardEmission << _reconOpt
<< ounit(muPt,GeV)
<< oenum(interaction_) << _maxTryFSR << _maxFailFSR << _fracFSR;
}
void QTildeShowerHandler::persistentInput(PersistentIStream & is, int) {
is >> _model >> _splittingGenerator >> _maxtry
>> _meCorrMode >> _hardVetoReadOption
>> _limitEmissions >> _spinOpt >> _softOpt >> _hardPOWHEG
>> iunit(_iptrms,GeV) >> _beta >> iunit(_gamma,GeV) >> iunit(_iptmax,GeV)
>> _vetoes >> _trunc_Mode >> _hardEmission >> _reconOpt
>> iunit(muPt,GeV)
>> ienum(interaction_) >> _maxTryFSR >> _maxFailFSR >> _fracFSR;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<QTildeShowerHandler,ShowerHandler>
describeHerwigQTildeShowerHandler("Herwig::QTildeShowerHandler", "HwShower.so");
void QTildeShowerHandler::Init() {
static ClassDocumentation<QTildeShowerHandler> documentation
("TheQTildeShowerHandler class is the main class"
" for the angular-ordered parton shower",
"The Shower evolution was performed using an algorithm described in "
"\\cite{Marchesini:1983bm,Marchesini:1987cf,Gieseke:2003rz,Bahr:2008pv}.",
"%\\cite{Marchesini:1983bm}\n"
"\\bibitem{Marchesini:1983bm}\n"
" G.~Marchesini and B.~R.~Webber,\n"
" ``Simulation Of QCD Jets Including Soft Gluon Interference,''\n"
" Nucl.\\ Phys.\\ B {\\bf 238}, 1 (1984).\n"
" %%CITATION = NUPHA,B238,1;%%\n"
"%\\cite{Marchesini:1987cf}\n"
"\\bibitem{Marchesini:1987cf}\n"
" G.~Marchesini and B.~R.~Webber,\n"
" ``Monte Carlo Simulation of General Hard Processes with Coherent QCD\n"
" Radiation,''\n"
" Nucl.\\ Phys.\\ B {\\bf 310}, 461 (1988).\n"
" %%CITATION = NUPHA,B310,461;%%\n"
"%\\cite{Gieseke:2003rz}\n"
"\\bibitem{Gieseke:2003rz}\n"
" S.~Gieseke, P.~Stephens and B.~Webber,\n"
" ``New formalism for QCD parton showers,''\n"
" JHEP {\\bf 0312}, 045 (2003)\n"
" [arXiv:hep-ph/0310083].\n"
" %%CITATION = JHEPA,0312,045;%%\n"
);
static Reference<QTildeShowerHandler,SplittingGenerator>
interfaceSplitGen("SplittingGenerator",
"A reference to the SplittingGenerator object",
&Herwig::QTildeShowerHandler::_splittingGenerator,
false, false, true, false);
static Reference<QTildeShowerHandler,ShowerModel> interfaceShowerModel
("ShowerModel",
"The pointer to the object which defines the shower evolution model.",
&QTildeShowerHandler::_model, false, false, true, false, false);
static Parameter<QTildeShowerHandler,unsigned int> interfaceMaxTry
("MaxTry",
"The maximum number of attempts to generate the shower from a"
" particular ShowerTree",
&QTildeShowerHandler::_maxtry, 100, 1, 1000,
false, false, Interface::limited);
static Switch<QTildeShowerHandler, unsigned int> ifaceMECorrMode
("MECorrMode",
"Choice of the ME Correction Mode",
&QTildeShowerHandler::_meCorrMode, 1, false, false);
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<QTildeShowerHandler, bool> ifaceHardVetoReadOption
("HardVetoReadOption",
"Apply read-in scale veto to all collisions or just the primary one?",
&QTildeShowerHandler::_hardVetoReadOption, false, false, false);
static SwitchOption AllCollisions
(ifaceHardVetoReadOption,
"AllCollisions",
"Read-in pT veto applied to primary and secondary collisions.",
false);
static SwitchOption PrimaryCollision
(ifaceHardVetoReadOption,
"PrimaryCollision",
"Read-in pT veto applied to primary but not secondary collisions.",
true);
static Parameter<QTildeShowerHandler, Energy> ifaceiptrms
("IntrinsicPtGaussian",
"RMS of intrinsic pT of Gaussian distribution:\n"
"2*(1-Beta)*exp(-sqr(intrinsicpT/RMS))/sqr(RMS)",
&QTildeShowerHandler::_iptrms, GeV, ZERO, ZERO, 1000000.0*GeV,
false, false, Interface::limited);
static Parameter<QTildeShowerHandler, double> ifacebeta
("IntrinsicPtBeta",
"Proportion of inverse quadratic distribution in generating intrinsic pT.\n"
"(1-Beta) is the proportion of Gaussian distribution",
&QTildeShowerHandler::_beta, 0, 0, 1,
false, false, Interface::limited);
static Parameter<QTildeShowerHandler, Energy> ifacegamma
("IntrinsicPtGamma",
"Parameter for inverse quadratic:\n"
"2*Beta*Gamma/(sqr(Gamma)+sqr(intrinsicpT))",
&QTildeShowerHandler::_gamma,GeV, ZERO, ZERO, 100000.0*GeV,
false, false, Interface::limited);
static Parameter<QTildeShowerHandler, Energy> ifaceiptmax
("IntrinsicPtIptmax",
"Upper bound on intrinsic pT for inverse quadratic",
&QTildeShowerHandler::_iptmax,GeV, ZERO, ZERO, 100000.0*GeV,
false, false, Interface::limited);
static RefVector<QTildeShowerHandler,ShowerVeto> ifaceVetoes
("Vetoes",
"The vetoes to be checked during showering",
&QTildeShowerHandler::_vetoes, -1,
false,false,true,true,false);
static Switch<QTildeShowerHandler,unsigned int> interfaceLimitEmissions
("LimitEmissions",
"Limit the number and type of emissions for testing",
&QTildeShowerHandler::_limitEmissions, 0, false, false);
static SwitchOption interfaceLimitEmissionsNoLimit
(interfaceLimitEmissions,
"NoLimit",
"Allow an arbitrary number of emissions",
0);
static SwitchOption interfaceLimitEmissionsOneInitialStateEmission
(interfaceLimitEmissions,
"OneInitialStateEmission",
"Allow one emission in the initial state and none in the final state",
1);
static SwitchOption interfaceLimitEmissionsOneFinalStateEmission
(interfaceLimitEmissions,
"OneFinalStateEmission",
"Allow one emission in the final state and none in the initial state",
2);
static SwitchOption interfaceLimitEmissionsHardOnly
(interfaceLimitEmissions,
"HardOnly",
"Only allow radiation from the hard ME correction",
3);
static SwitchOption interfaceLimitEmissionsOneEmission
(interfaceLimitEmissions,
"OneEmission",
"Allow one emission in either the final state or initial state, but not both",
4);
static Switch<QTildeShowerHandler,bool> interfaceTruncMode
("TruncatedShower", "Include the truncated shower?",
&QTildeShowerHandler::_trunc_Mode, 1, false, false);
static SwitchOption interfaceTruncMode0
(interfaceTruncMode,"No","Truncated Shower is OFF", 0);
static SwitchOption interfaceTruncMode1
(interfaceTruncMode,"Yes","Truncated Shower is ON", 1);
static Switch<QTildeShowerHandler,int> interfaceHardEmission
("HardEmission",
"Whether to use ME corrections or POWHEG for the hardest emission",
&QTildeShowerHandler::_hardEmission, 0, false, false);
static SwitchOption interfaceHardEmissionNone
(interfaceHardEmission,
"None",
"No Corrections",
0);
static SwitchOption interfaceHardEmissionMECorrection
(interfaceHardEmission,
"MECorrection",
"Old fashioned ME correction",
1);
static SwitchOption interfaceHardEmissionPOWHEG
(interfaceHardEmission,
"POWHEG",
"Powheg style hard emission",
2);
static Switch<QTildeShowerHandler,ShowerInteraction::Type> interfaceInteractions
("Interactions",
"The interactions to be used in the shower",
&QTildeShowerHandler::interaction_, ShowerInteraction::Both, false, false);
static SwitchOption interfaceInteractionsQCD
(interfaceInteractions,
"QCD",
"Only QCD radiation",
ShowerInteraction::QCD);
static SwitchOption interfaceInteractionsQED
(interfaceInteractions,
"QED",
"Only QEd radiation",
ShowerInteraction::QED);
static SwitchOption interfaceInteractionsQCDandQED
(interfaceInteractions,
"QCDandQED",
"Both QED and QCD radiation",
ShowerInteraction::Both);
static Switch<QTildeShowerHandler,unsigned int> interfaceReconstructionOption
("ReconstructionOption",
"Treatment of the reconstruction of the transverse momentum of "
"a branching from the evolution scale.",
&QTildeShowerHandler::_reconOpt, 0, false, false);
static SwitchOption interfaceReconstructionOptionCutOff
(interfaceReconstructionOption,
"CutOff",
"Use the cut-off masses in the calculation",
0);
static SwitchOption interfaceReconstructionOptionOffShell
(interfaceReconstructionOption,
"OffShell",
"Use the off-shell masses in the calculation veto the emission of the parent,"
" no veto in generation of emissions from children",
1);
static SwitchOption interfaceReconstructionOptionOffShell2
(interfaceReconstructionOption,
"OffShell2",
"Use the off-shell masses in the calculation veto the emissions from the children."
" no veto in generation of emissions from children",
2);
static SwitchOption interfaceReconstructionOptionOffShell3
(interfaceReconstructionOption,
"OffShell3",
"Use the off-shell masses in the calculation veto the emissions from the children."
" veto in generation of emissions from children using cut-off for second parton",
3);
static Switch<QTildeShowerHandler,unsigned int> interfaceSpinCorrelations
("SpinCorrelations",
"Treatment of spin correlations in the parton shower",
&QTildeShowerHandler::_spinOpt, 1, false, false);
static SwitchOption interfaceSpinCorrelationsOff
(interfaceSpinCorrelations,
"No",
"No spin correlations",
0);
static SwitchOption interfaceSpinCorrelationsSpin
(interfaceSpinCorrelations,
"Yes",
"Include the azimuthal spin correlations only",
1);
static Switch<QTildeShowerHandler,unsigned int> interfaceSoftCorrelations
("SoftCorrelations",
"Option for the treatment of soft correlations in the parton shower",
&QTildeShowerHandler::_softOpt, 2, false, false);
static SwitchOption interfaceSoftCorrelationsNone
(interfaceSoftCorrelations,
"No",
"No soft correlations",
0);
static SwitchOption interfaceSoftCorrelationsFull
(interfaceSoftCorrelations,
"Full",
"Use the full eikonal",
1);
static SwitchOption interfaceSoftCorrelationsSingular
(interfaceSoftCorrelations,
"Singular",
"Use original Webber-Marchisini form",
2);
static Switch<QTildeShowerHandler,bool> interfaceHardPOWHEG
("HardPOWHEG",
"Treatment of powheg emissions which are too hard to have a shower interpretation",
&QTildeShowerHandler::_hardPOWHEG, false, false, false);
static SwitchOption interfaceHardPOWHEGAsShower
(interfaceHardPOWHEG,
"AsShower",
"Still interpret as shower emissions",
false);
static SwitchOption interfaceHardPOWHEGRealEmission
(interfaceHardPOWHEG,
"RealEmission",
"Generate shower from the real emmission configuration",
true);
static Parameter<QTildeShowerHandler,unsigned int> interfaceMaxTryFSR
("MaxTryFSR",
"The maximum number of attempted FSR emissions in"
" the generation of the FSR",
&QTildeShowerHandler::_maxTryFSR, 100000, 10, 100000000,
false, false, Interface::limited);
static Parameter<QTildeShowerHandler,unsigned int> interfaceMaxFailFSR
("MaxFailFSR",
"Maximum number of failures generating the FSR",
&QTildeShowerHandler::_maxFailFSR, 100, 1, 100000000,
false, false, Interface::limited);
static Parameter<QTildeShowerHandler,double> interfaceFSRFailureFraction
("FSRFailureFraction",
"Maximum fraction of events allowed to fail due to too many FSR emissions",
&QTildeShowerHandler::_fracFSR, 0.001, 1e-10, 1,
false, false, Interface::limited);
}
tPPair QTildeShowerHandler::cascade(tSubProPtr sub,
XCPtr xcomb) {
// use me for reference in tex file etc
useMe();
prepareCascade(sub);
// set things up in the base class
resetWeights();
// check if anything needs doing
if ( !doFSR() && ! doISR() )
return sub->incoming();
// start of the try block for the whole showering process
unsigned int countFailures=0;
while (countFailures<maxtry()) {
try {
decay_.clear();
done_.clear();
PerturbativeProcessPtr hard;
DecayProcessMap decay;
splitHardProcess(firstInteraction() ? tagged() :
tPVector(currentSubProcess()->outgoing().begin(),
currentSubProcess()->outgoing().end()),
hard,decay);
ShowerTree::constructTrees(hard_,decay_,hard,decay);
// if no hard process
if(!hard_) throw Exception() << "Shower starting with a decay"
<< "is not implemented"
<< Exception::runerror;
// perform the shower for the hard process
showerHardProcess(hard_,xcomb);
done_.push_back(hard_);
hard_->updateAfterShower(decay_);
// if no decaying particles to shower break out of the loop
if(decay_.empty()) break;
// shower the decay products
while(!decay_.empty()) {
// find particle whose production process has been showered
ShowerDecayMap::iterator dit = decay_.begin();
while(!dit->second->parent()->hasShowered() && dit!=decay_.end()) ++dit;
assert(dit!=decay_.end());
// get the particle
ShowerTreePtr decayingTree = dit->second;
// remove it from the multimap
decay_.erase(dit);
// make sure the particle has been decayed
QTildeShowerHandler::decay(decayingTree,decay_);
// now shower the decay
showerDecay(decayingTree);
done_.push_back(decayingTree);
decayingTree->updateAfterShower(decay_);
}
// suceeded break out of the loop
break;
}
catch (KinematicsReconstructionVeto) {
resetWeights();
++countFailures;
}
}
// if loop exited because of too many tries, throw event away
if (countFailures >= maxtry()) {
resetWeights();
hard_=ShowerTreePtr();
decay_.clear();
done_.clear();
throw Exception() << "Too many tries for main while loop "
<< "in ShowerHandler::cascade()."
<< Exception::eventerror;
}
//enter the particles in the event record
fillEventRecord();
// clear storage
hard_=ShowerTreePtr();
decay_.clear();
done_.clear();
// non hadronic case return
if (!isResolvedHadron(incomingBeams().first ) &&
!isResolvedHadron(incomingBeams().second) )
return incomingBeams();
// remake the remnants (needs to be after the colours are sorted
// out in the insertion into the event record)
if ( firstInteraction() ) return remakeRemnant(sub->incoming());
//Return the new pair of incoming partons. remakeRemnant is not
//necessary here, because the secondary interactions are not yet
//connected to the remnants.
return make_pair(findFirstParton(sub->incoming().first ),
findFirstParton(sub->incoming().second));
}
void QTildeShowerHandler::fillEventRecord() {
// create a new step
StepPtr pstep = newStep();
assert(!done_.empty());
assert(done_[0]->isHard());
cerr << "testing start of fill \n";
// insert the steps
for(unsigned int ix=0;ix<done_.size();++ix) {
cerr << "testing in fill loop " << ix << "\n";
done_[ix]->fillEventRecord(pstep,doISR(),doFSR());
}
cerr << "testing start of fill \n";
}
HardTreePtr QTildeShowerHandler::generateCKKW(ShowerTreePtr ) const {
return HardTreePtr();
}
void QTildeShowerHandler::doinit() {
ShowerHandler::doinit();
// interactions may have been changed through a setup file so we
// clear it up here
// calculate max no of FSR vetos
_maxFailFSR = max(int(_maxFailFSR), int(_fracFSR*double(generator()->N())));
}
void QTildeShowerHandler::generateIntrinsicpT(vector<ShowerProgenitorPtr> particlesToShower) {
_intrinsic.clear();
if ( !ipTon() || !doISR() ) return;
// don't do anything for the moment for secondary scatters
if( !firstInteraction() ) return;
// generate intrinsic pT
for(unsigned int ix=0;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 QTildeShowerHandler::setupMaximumScales(const vector<ShowerProgenitorPtr> & p,
XCPtr xcomb) {
// let POWHEG events radiate freely
if(_hardEmission==2&&hardTree()) {
vector<ShowerProgenitorPtr>::const_iterator ckt = p.begin();
for (; ckt != p.end(); ckt++) (*ckt)->maxHardPt(Constants::MaxEnergy);
return;
}
// return if no vetos
if (!restrictPhasespace()) return;
// find out if hard partonic subprocess.
bool isPartonic(false);
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit = _currenttree->incomingLines().begin();
Lorentz5Momentum pcm;
for(; cit!=currentTree()->incomingLines().end(); ++cit) {
pcm += cit->first->progenitor()->momentum();
isPartonic |= cit->first->progenitor()->coloured();
}
// find minimum pt from hard process, the maximum pt from all outgoing
// coloured lines (this is simpler and more general than
// 2stu/(s^2+t^2+u^2)). Maximum scale for scattering processes will
// be transverse mass.
Energy ptmax = generator()->maximumCMEnergy();
// general case calculate the scale
if ( !hardScaleIsMuF() || (hardVetoReadOption()&&!firstInteraction()) ) {
// scattering process
if(currentTree()->isHard()) {
assert(xcomb);
// coloured incoming particles
if (isPartonic) {
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt = currentTree()->outgoingLines().begin();
for(; cjt!=currentTree()->outgoingLines().end(); ++cjt) {
if (cjt->first->progenitor()->coloured())
ptmax = min(ptmax,cjt->first->progenitor()->momentum().mt());
}
}
if (ptmax == generator()->maximumCMEnergy() ) ptmax = pcm.m();
if(hardScaleIsMuF()&&hardVetoReadOption()&&
!firstInteraction()) {
ptmax=min(ptmax,sqrt(xcomb->lastShowerScale()));
}
}
// decay, incoming() is the decaying particle.
else {
ptmax = currentTree()->incomingLines().begin()->first
->progenitor()->momentum().mass();
}
}
// hepeup.SCALUP is written into the lastXComb by the
// LesHouchesReader itself - use this by user's choice.
// Can be more general than this.
else {
if(currentTree()->isHard()) {
assert(xcomb);
ptmax = sqrt( xcomb->lastShowerScale() );
}
else {
ptmax = currentTree()->incomingLines().begin()->first
->progenitor()->momentum().mass();
}
}
ptmax *= hardScaleFactor();
// set maxHardPt for all progenitors. For partonic processes this
// is now the max pt in the FS, for non-partonic processes or
// processes with no coloured FS the invariant mass of the IS
vector<ShowerProgenitorPtr>::const_iterator ckt = p.begin();
for (; ckt != p.end(); ckt++) (*ckt)->maxHardPt(ptmax);
}
void QTildeShowerHandler::setupHardScales(const vector<ShowerProgenitorPtr> & p,
XCPtr xcomb) {
if ( hardScaleIsMuF() &&
(!hardVetoReadOption() || firstInteraction()) ) {
Energy hardScale = ZERO;
if(currentTree()->isHard()) {
assert(xcomb);
hardScale = sqrt( xcomb->lastShowerScale() );
}
else {
hardScale = currentTree()->incomingLines().begin()->first
->progenitor()->momentum().mass();
}
hardScale *= hardScaleFactor();
vector<ShowerProgenitorPtr>::const_iterator ckt = p.begin();
for (; ckt != p.end(); ckt++) (*ckt)->hardScale(hardScale);
muPt = hardScale;
}
}
void QTildeShowerHandler::showerHardProcess(ShowerTreePtr hard, XCPtr xcomb) {
_hardme = HwMEBasePtr();
// extract the matrix element
tStdXCombPtr lastXC = dynamic_ptr_cast<tStdXCombPtr>(xcomb);
if(lastXC) {
_hardme = dynamic_ptr_cast<HwMEBasePtr>(lastXC->matrixElement());
}
_decayme = HwDecayerBasePtr();
// set the current tree
currentTree(hard);
hardTree(HardTreePtr());
// work out the type of event
currentTree()->xcombPtr(dynamic_ptr_cast<StdXCombPtr>(xcomb));
currentTree()->identifyEventType();
checkFlags();
// generate the showering
doShowering(true,xcomb);
}
RealEmissionProcessPtr QTildeShowerHandler::hardMatrixElementCorrection(bool hard) {
// set the initial enhancement factors for the soft correction
_initialenhance = 1.;
_finalenhance = 1.;
// see if we can get the correction from the matrix element
// or decayer
RealEmissionProcessPtr real;
if(hard) {
if(_hardme&&_hardme->hasMECorrection()) {
_hardme->initializeMECorrection(_currenttree->perturbativeProcess(),
_initialenhance,_finalenhance);
if(hardMEC())
real =
_hardme->applyHardMatrixElementCorrection(_currenttree->perturbativeProcess());
}
}
else {
- // if(_decayme&&_decayme->hasMECorrection()) {
- // _decayme->initializeMECorrection(_currenttree,
- // _initialenhance,_finalenhance);
- // if(hardMEC())
- // _decayme->applyHardMatrixElementCorrection(_currenttree);
- // }
+ if(_decayme&&_decayme->hasMECorrection()) {
+ _decayme->initializeMECorrection(_currenttree->perturbativeProcess(),
+ _initialenhance,_finalenhance);
+ if(hardMEC())
+ _decayme->applyHardMatrixElementCorrection(_currenttree->perturbativeProcess());
+ }
}
return real;
}
ShowerParticleVector QTildeShowerHandler::createTimeLikeChildren(tShowerParticlePtr, IdList ids) {
// Create the ShowerParticle objects for the two children of
// the emitting particle; set the parent/child relationship
// if same as definition create particles, otherwise create cc
ShowerParticleVector children;
for(unsigned int ix=0;ix<2;++ix) {
children.push_back(new_ptr(ShowerParticle(ids[ix+1],true)));
if(children[ix]->id()==_progenitor->id()&&!ids[ix+1]->stable())
children[ix]->set5Momentum(Lorentz5Momentum(_progenitor->progenitor()->mass()));
else
children[ix]->set5Momentum(Lorentz5Momentum(ids[ix+1]->mass()));
}
return children;
}
bool QTildeShowerHandler::timeLikeShower(tShowerParticlePtr particle,
ShowerInteraction::Type type,
Branching fb, bool first) {
// don't do anything if not needed
if(_limitEmissions == 1 || hardOnly() ||
( _limitEmissions == 2 && _nfs != 0) ||
( _limitEmissions == 4 && _nfs + _nis != 0) ) {
if(particle->spinInfo()) particle->spinInfo()->develop();
return false;
}
// too many tries
if(_nFSR>=_maxTryFSR) {
++_nFailedFSR;
// too many failed events
if(_nFailedFSR>=_maxFailFSR)
throw Exception() << "Too many events have failed due to too many shower emissions, in\n"
<< "QTildeShowerHandler::timeLikeShower(). Terminating run\n"
<< Exception::runerror;
throw Exception() << "Too many attempted emissions in QTildeShowerHandler::timeLikeShower()\n"
<< Exception::eventerror;
}
// generate the emission
ShowerParticleVector children;
int ntry=0;
// generate the emission
if(!fb.kinematics)
fb = selectTimeLikeBranching(particle,type,HardBranchingPtr());
// no emission, return
if(!fb.kinematics) {
if(particle->spinInfo()) particle->spinInfo()->develop();
return false;
}
Branching fc[2];
bool setupChildren = true;
while (ntry<50) {
fc[0] = Branching();
fc[1] = Branching();
++ntry;
assert(fb.kinematics);
// has emitted
// Assign the shower kinematics to the emitting particle.
if(setupChildren) {
++_nFSR;
particle->showerKinematics(fb.kinematics);
// check highest pT
if(fb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(fb.kinematics->pT());
// create the children
children = createTimeLikeChildren(particle,fb.ids);
// update the children
particle->showerKinematics()->
updateChildren(particle, children,fb.type,_reconOpt>=3);
// update number of emissions
++_nfs;
if(_limitEmissions!=0) {
if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
if(particle->spinInfo()) particle->spinInfo()->develop();
return true;
}
setupChildren = false;
}
// select branchings for children
fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr());
fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr());
// old default
if(_reconOpt==0) {
// shower the first particle
if(fc[0].kinematics) timeLikeShower(children[0],type,fc[0],false);
if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
// shower the second particle
if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],false);
if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
break;
}
// Herwig default
else if(_reconOpt==1) {
// shower the first particle
if(fc[0].kinematics) timeLikeShower(children[0],type,fc[0],false);
if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
// shower the second particle
if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],false);
if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
// branching has happened
particle->showerKinematics()->updateParent(particle, children,fb.type);
// clean up the vetoed emission
if(particle->virtualMass()==ZERO) {
particle->showerKinematics(ShoKinPtr());
for(unsigned int ix=0;ix<children.size();++ix)
particle->abandonChild(children[ix]);
children.clear();
if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr());
particle->vetoEmission(fb.type,fb.kinematics->scale());
// generate the new emission
fb = selectTimeLikeBranching(particle,type,HardBranchingPtr());
// no emission, return
if(!fb.kinematics) {
if(particle->spinInfo()) particle->spinInfo()->develop();
return false;
}
setupChildren = true;
continue;
}
else
break;
}
// veto children
else if(_reconOpt>=2) {
// cut-off masses for the branching
const vector<Energy> & virtualMasses = fb.sudakov->virtualMasses(fb.ids);
// compute the masses of the children
Energy masses[3];
for(unsigned int ix=0;ix<2;++ix) {
if(fc[ix].kinematics) {
const vector<Energy> & vm = fc[ix].sudakov->virtualMasses(fc[ix].ids);
Energy2 q2 =
fc[ix].kinematics->z()*(1.-fc[ix].kinematics->z())*sqr(fc[ix].kinematics->scale());
if(fc[ix].ids[0]->id()!=ParticleID::g) q2 += sqr(vm[0]);
masses[ix+1] = sqrt(q2);
}
else {
masses[ix+1] = virtualMasses[ix+1];
}
}
masses[0] = fb.ids[0]->id()!=ParticleID::g ? virtualMasses[0] : ZERO;
double z = fb.kinematics->z();
Energy2 pt2 = z*(1.-z)*(z*(1.-z)*sqr(fb.kinematics->scale()) + sqr(masses[0]))
- sqr(masses[1])*(1.-z) - sqr(masses[2])*z;
if(pt2>=ZERO) {
break;
}
else {
// reset the scales for the children
for(unsigned int ix=0;ix<2;++ix) {
if(fc[ix].kinematics)
children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale());
else
children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO);
children[ix]->virtualMass(ZERO);
}
}
}
};
if(_reconOpt>=2) {
// shower the first particle
if(fc[0].kinematics) timeLikeShower(children[0],type,fc[0],false);
if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
// shower the second particle
if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],false);
if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
// branching has happened
particle->showerKinematics()->updateParent(particle, children,fb.type);
}
if(first&&!children.empty())
particle->showerKinematics()->resetChildren(particle,children);
if(particle->spinInfo()) particle->spinInfo()->develop();
return true;
}
bool
QTildeShowerHandler::spaceLikeShower(tShowerParticlePtr particle, PPtr beam,
ShowerInteraction::Type type) {
//using the pdf's associated with the ShowerHandler assures, that
//modified pdf's are used for the secondary interactions via
//CascadeHandler::resetPDFs(...)
tcPDFPtr pdf;
if(firstPDF().particle() == _beam)
pdf = firstPDF().pdf();
if(secondPDF().particle() == _beam)
pdf = secondPDF().pdf();
Energy freeze = pdfFreezingScale();
// don't do anything if not needed
if(_limitEmissions == 2 || hardOnly() ||
( _limitEmissions == 1 && _nis != 0 ) ||
( _limitEmissions == 4 && _nis + _nfs != 0 ) ) {
if(particle->spinInfo()) particle->spinInfo()->develop();
return false;
}
Branching bb;
// generate branching
while (true) {
bb=_splittingGenerator->chooseBackwardBranching(*particle,beam,
_initialenhance,
_beam,type,
pdf,freeze);
// return if no emission
if(!bb.kinematics) {
if(particle->spinInfo()) particle->spinInfo()->develop();
return false;
}
// if not vetoed break
if(!spaceLikeVetoed(bb,particle)) break;
// otherwise reset scale and continue
particle->vetoEmission(bb.type,bb.kinematics->scale());
if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr());
}
// assign the splitting function and shower kinematics
particle->showerKinematics(bb.kinematics);
if(bb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(bb.kinematics->pT());
// For the time being we are considering only 1->2 branching
// particles as in Sudakov form factor
tcPDPtr part[2]={bb.ids[0],bb.ids[2]};
// Now create the actual particles, make the otherChild a final state
// particle, while the newParent is not
ShowerParticlePtr newParent = new_ptr(ShowerParticle(part[0],false));
ShowerParticlePtr otherChild = new_ptr(ShowerParticle(part[1],true,true));
ShowerParticleVector theChildren;
theChildren.push_back(particle);
theChildren.push_back(otherChild);
//this updates the evolution scale
particle->showerKinematics()->
updateParent(newParent, theChildren,bb.type);
// update the history if needed
_currenttree->updateInitialStateShowerProduct(_progenitor,newParent);
_currenttree->addInitialStateBranching(particle,newParent,otherChild);
// for the reconstruction of kinematics, parent/child
// relationships are according to the branching process:
// now continue the shower
++_nis;
bool emitted = _limitEmissions==0 ?
spaceLikeShower(newParent,beam,type) : false;
if(newParent->spinInfo()) newParent->spinInfo()->develop();
// now reconstruct the momentum
if(!emitted) {
if(_intrinsic.find(_progenitor)==_intrinsic.end()) {
bb.kinematics->updateLast(newParent,ZERO,ZERO);
}
else {
pair<Energy,double> kt=_intrinsic[_progenitor];
bb.kinematics->updateLast(newParent,
kt.first*cos(kt.second),
kt.first*sin(kt.second));
}
}
particle->showerKinematics()->
updateChildren(newParent, theChildren,bb.type,false);
if(_limitEmissions!=0) {
if(particle->spinInfo()) particle->spinInfo()->develop();
return true;
}
// perform the shower of the final-state particle
timeLikeShower(otherChild,type,Branching(),true);
updateHistory(otherChild);
if(theChildren[1]->spinInfo()) theChildren[1]->spinInfo()->develop();
// return the emitted
if(particle->spinInfo()) particle->spinInfo()->develop();
return true;
}
void QTildeShowerHandler::showerDecay(ShowerTreePtr decay) {
// work out the type of event
currentTree()->xcombPtr(StdXCombPtr());
currentTree()->identifyEventType();
_decayme = HwDecayerBasePtr();
_hardme = HwMEBasePtr();
// find the decayer
// try the normal way if possible
tDMPtr dm = decay->incomingLines().begin()->first->original() ->decayMode();
if(!dm) dm = decay->incomingLines().begin()->first->copy() ->decayMode();
if(!dm) dm = decay->incomingLines().begin()->first->progenitor()->decayMode();
// otherwise make a string and look it up
if(!dm) {
string tag = decay->incomingLines().begin()->first->original()->dataPtr()->name()
+ "->";
OrderedParticles outgoing;
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
it=decay->outgoingLines().begin();it!=decay->outgoingLines().end();++it) {
if(abs(decay->incomingLines().begin()->first->original()->id()) == ParticleID::t &&
abs(it->first->original()->id())==ParticleID::Wplus &&
decay->treelinks().size() == 1) {
ShowerTreePtr Wtree = decay->treelinks().begin()->first;
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
it2=Wtree->outgoingLines().begin();it2!=Wtree->outgoingLines().end();++it2) {
outgoing.insert(it2->first->original()->dataPtr());
}
}
else {
outgoing.insert(it->first->original()->dataPtr());
}
}
for(OrderedParticles::const_iterator it=outgoing.begin(); it!=outgoing.end();++it) {
if(it!=outgoing.begin()) tag += ",";
tag +=(**it).name();
}
tag += ";";
dm = findDecayMode(tag);
}
if(dm) _decayme = dynamic_ptr_cast<HwDecayerBasePtr>(dm->decayer());
// set the ShowerTree to be showered
currentTree(decay);
decay->applyTransforms();
hardTree(HardTreePtr());
// generate the showering
doShowering(false,XCPtr());
// if no vetos
// force calculation of spin correlations
SpinPtr spInfo = decay->incomingLines().begin()->first->progenitor()->spinInfo();
if(spInfo) {
if(!spInfo->developed()) spInfo->needsUpdate();
spInfo->develop();
}
}
bool QTildeShowerHandler::spaceLikeDecayShower(tShowerParticlePtr particle,
const ShowerParticle::EvolutionScales & maxScales,
Energy minmass,ShowerInteraction::Type type,
Branching fb) {
// too many tries
if(_nFSR>=_maxTryFSR) {
++_nFailedFSR;
// too many failed events
if(_nFailedFSR>=_maxFailFSR)
throw Exception() << "Too many events have failed due to too many shower emissions, in\n"
<< "QTildeShowerHandler::timeLikeShower(). Terminating run\n"
<< Exception::runerror;
throw Exception() << "Too many attempted emissions in QTildeShowerHandler::timeLikeShower()\n"
<< Exception::eventerror;
}
// generate the emission
ShowerParticleVector children;
int ntry=0;
// generate the emission
if(!fb.kinematics)
fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type,
HardBranchingPtr());
// no emission, return
if(!fb.kinematics) return false;
Branching fc[2];
bool setupChildren = true;
while (ntry<50) {
if(particle->virtualMass()==ZERO)
particle->virtualMass(_progenitor->progenitor()->mass());
fc[0] = Branching();
fc[1] = Branching();
++ntry;
assert(fb.kinematics);
// has emitted
// Assign the shower kinematics to the emitting particle.
if(setupChildren) {
++_nFSR;
// Assign the shower kinematics to the emitting particle.
particle->showerKinematics(fb.kinematics);
if(fb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(fb.kinematics->pT());
// create the ShowerParticle objects for the two children
children = createTimeLikeChildren(particle,fb.ids);
// updateChildren the children
particle->showerKinematics()->
updateChildren(particle, children, fb.type,_reconOpt>=3);
setupChildren = false;
}
// select branchings for children
fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,
type,HardBranchingPtr());
fc[1] = selectTimeLikeBranching (children[1],type,HardBranchingPtr());
// old default
if(_reconOpt==0) {
// shower the first particle
_currenttree->updateInitialStateShowerProduct(_progenitor,children[0]);
_currenttree->addInitialStateBranching(particle,children[0],children[1]);
if(fc[0].kinematics) spaceLikeDecayShower(children[0],maxScales,minmass,type,Branching());
// shower the second particle
if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],true);
updateHistory(children[1]);
// branching has happened
break;
}
// Herwig default
else if(_reconOpt==1) {
// shower the first particle
_currenttree->updateInitialStateShowerProduct(_progenitor,children[0]);
_currenttree->addInitialStateBranching(particle,children[0],children[1]);
if(fc[0].kinematics) spaceLikeDecayShower(children[0],maxScales,minmass,type,Branching());
// shower the second particle
if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],true);
updateHistory(children[1]);
// branching has happened
particle->showerKinematics()->updateParent(particle, children,fb.type);
// clean up the vetoed emission
if(particle->virtualMass()==ZERO) {
particle->showerKinematics(ShoKinPtr());
for(unsigned int ix=0;ix<children.size();++ix)
particle->abandonChild(children[ix]);
children.clear();
particle->vetoEmission(fb.type,fb.kinematics->scale());
// generate the new emission
fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type,
HardBranchingPtr());
// no emission, return
if(!fb.kinematics) {
return false;
}
setupChildren = true;
continue;
}
else
break;
}
else if(_reconOpt>=2) {
// cut-off masses for the branching
const vector<Energy> & virtualMasses = fb.sudakov->virtualMasses(fb.ids);
// compute the masses of the children
Energy masses[3];
// space-like children
masses[1] = children[0]->virtualMass();
// time-like child
if(fc[1].kinematics) {
const vector<Energy> & vm = fc[1].sudakov->virtualMasses(fc[1].ids);
Energy2 q2 =
fc[1].kinematics->z()*(1.-fc[1].kinematics->z())*sqr(fc[1].kinematics->scale());
if(fc[1].ids[0]->id()!=ParticleID::g) q2 += sqr(vm[0]);
masses[2] = sqrt(q2);
}
else {
masses[2] = virtualMasses[2];
}
masses[0]=particle->virtualMass();
double z = fb.kinematics->z();
Energy2 pt2 = (1.-z)*(z*sqr(masses[0])-sqr(masses[1])-z/(1.-z)*sqr(masses[2]));
if(pt2>=ZERO) {
break;
}
else {
// reset the scales for the children
for(unsigned int ix=0;ix<2;++ix) {
if(fc[ix].kinematics)
children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale());
else {
if(ix==0)
children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,Constants::MaxEnergy);
else
children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO);
}
}
children[0]->virtualMass(_progenitor->progenitor()->mass());
children[1]->virtualMass(ZERO);
}
}
};
if(_reconOpt>=2) {
// 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,children[0]);
_currenttree->addInitialStateBranching(particle,children[0],children[1]);
// shower the first particle
if(fc[0].kinematics) spaceLikeDecayShower(children[0],maxScales,minmass,type,Branching());
// shower the second particle
if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],true);
updateHistory(children[1]);
// branching has happened
particle->showerKinematics()->updateParent(particle, children,fb.type);
}
// branching has happened
return true;
}
vector<ShowerProgenitorPtr> QTildeShowerHandler::setupShower(bool hard) {
RealEmissionProcessPtr real;
// generate hard me if needed
if(_hardEmission==1) {
real = hardMatrixElementCorrection(hard);
if(real) setupMECorrection(real);
}
// generate POWHEG hard emission if needed
else if(_hardEmission==2)
hardestEmission(hard);
// set the initial colour partners
setEvolutionPartners(hard,interaction_,false);
// get the particles to be showered
vector<ShowerProgenitorPtr> particlesToShower =
currentTree()->extractProgenitors();
// return the answer
return particlesToShower;
}
void QTildeShowerHandler::setEvolutionPartners(bool hard,ShowerInteraction::Type type,
bool clear) {
// match the particles in the ShowerTree and hardTree
if(hardTree() && !hardTree()->connect(currentTree()))
throw Exception() << "Can't match trees in "
<< "QTildeShowerHandler::setEvolutionPartners()"
<< Exception::eventerror;
// extract the progenitors
vector<ShowerParticlePtr> particles =
currentTree()->extractProgenitorParticles();
// clear the partners if needed
if(clear) {
for(unsigned int ix=0;ix<particles.size();++ix) {
particles[ix]->partner(ShowerParticlePtr());
particles[ix]->clearPartners();
}
}
// sort out the colour partners
if(hardTree()) {
// find the partner
for(unsigned int ix=0;ix<particles.size();++ix) {
tHardBranchingPtr partner =
hardTree()->particles()[particles[ix]]->colourPartner();
if(!partner) continue;
for(map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
it=hardTree()->particles().begin();
it!=hardTree()->particles().end();++it) {
if(it->second==partner) particles[ix]->partner(it->first);
}
if(!particles[ix]->partner())
throw Exception() << "Can't match partners in "
<< "QTildeShowerHandler::setEvolutionPartners()"
<< Exception::eventerror;
}
}
// Set the initial evolution scales
showerModel()->partnerFinder()->
setInitialEvolutionScales(particles,!hard,type,!_hardtree);
if(hardTree() && _hardPOWHEG) {
bool tooHard=false;
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
eit=hardTree()->particles().end();
for(unsigned int ix=0;ix<particles.size();++ix) {
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
mit = hardTree()->particles().find(particles[ix]);
Energy hardScale(ZERO);
ShowerPartnerType::Type type(ShowerPartnerType::Undefined);
// final-state
if(particles[ix]->isFinalState()) {
if(mit!= eit && !mit->second->children().empty()) {
hardScale = mit->second->scale();
type = mit->second->type();
}
}
// initial-state
else {
if(mit!= eit && mit->second->parent()) {
hardScale = mit->second->parent()->scale();
type = mit->second->parent()->type();
}
}
if(type!=ShowerPartnerType::Undefined) {
if(type==ShowerPartnerType::QED) {
tooHard |= particles[ix]->scales().QED_noAO<hardScale;
}
else if(type==ShowerPartnerType::QCDColourLine) {
tooHard |= particles[ix]->scales().QCD_c_noAO<hardScale;
}
else if(type==ShowerPartnerType::QCDAntiColourLine) {
tooHard |= particles[ix]->scales().QCD_ac_noAO<hardScale;
}
}
}
if(tooHard) convertHardTree(hard,type);
}
}
void QTildeShowerHandler::updateHistory(tShowerParticlePtr particle) {
if(!particle->children().empty()) {
ShowerParticleVector theChildren;
for(unsigned int ix=0;ix<particle->children().size();++ix) {
ShowerParticlePtr part = dynamic_ptr_cast<ShowerParticlePtr>
(particle->children()[ix]);
theChildren.push_back(part);
}
// update the history if needed
if(particle==_currenttree->getFinalStateShowerProduct(_progenitor))
_currenttree->updateFinalStateShowerProduct(_progenitor,
particle,theChildren);
_currenttree->addFinalStateBranching(particle,theChildren);
for(unsigned int ix=0;ix<theChildren.size();++ix)
updateHistory(theChildren[ix]);
}
}
bool QTildeShowerHandler::startTimeLikeShower(ShowerInteraction::Type type) {
_nFSR = 0;
// initialize basis vectors etc
progenitor()->progenitor()->initializeFinalState();
if(hardTree()) {
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
eit=hardTree()->particles().end(),
mit = hardTree()->particles().find(progenitor()->progenitor());
if( mit != eit && !mit->second->children().empty() ) {
bool output=truncatedTimeLikeShower(progenitor()->progenitor(),
mit->second ,type,Branching(),true);
if(output) updateHistory(progenitor()->progenitor());
return output;
}
}
// do the shower
bool output = hardOnly() ? false :
timeLikeShower(progenitor()->progenitor() ,type,Branching(),true) ;
if(output) updateHistory(progenitor()->progenitor());
return output;
}
bool QTildeShowerHandler::startSpaceLikeShower(PPtr parent, ShowerInteraction::Type type) {
// initialise the basis vectors
progenitor()->progenitor()->initializeInitialState(parent);
if(hardTree()) {
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
eit =hardTree()->particles().end(),
mit = hardTree()->particles().find(progenitor()->progenitor());
if( mit != eit && mit->second->parent() ) {
return truncatedSpaceLikeShower( progenitor()->progenitor(),
parent, mit->second->parent(), type );
}
}
// perform the shower
return hardOnly() ? false :
spaceLikeShower(progenitor()->progenitor(),parent,type);
}
bool QTildeShowerHandler::
startSpaceLikeDecayShower(const ShowerParticle::EvolutionScales & maxScales,
Energy minimumMass,ShowerInteraction::Type type) {
_nFSR = 0;
// set up the particle basis vectors
progenitor()->progenitor()->initializeDecay();
if(hardTree()) {
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
eit =hardTree()->particles().end(),
mit = hardTree()->particles().find(progenitor()->progenitor());
if( mit != eit && mit->second->parent() ) {
HardBranchingPtr branch=mit->second;
while(branch->parent()) branch=branch->parent();
return truncatedSpaceLikeDecayShower(progenitor()->progenitor(),maxScales,
minimumMass, branch ,type, Branching());
}
}
// perform the shower
return hardOnly() ? false :
spaceLikeDecayShower(progenitor()->progenitor(),maxScales,minimumMass,type,Branching());
}
bool QTildeShowerHandler::timeLikeVetoed(const Branching & fb,
ShowerParticlePtr particle) {
// work out type of interaction
ShowerInteraction::Type type = convertInteraction(fb.type);
// check whether emission was harder than largest pt of hard subprocess
if ( restrictPhasespace() && fb.kinematics->pT() > _progenitor->maxHardPt() )
return true;
// soft matrix element correction veto
if( softMEC()) {
if(_hardme && _hardme->hasMECorrection()) {
if(_hardme->softMatrixElementVeto(_progenitor,particle,fb))
return true;
}
else if(_decayme && _decayme->hasMECorrection()) {
if(_decayme->softMatrixElementVeto(_progenitor,particle,fb))
return true;
}
}
// veto on maximum pt
if(fb.kinematics->pT()>_progenitor->maximumpT(type)) return true;
// general vetos
if (fb.kinematics && !_vetoes.empty()) {
bool vetoed=false;
for (vector<ShowerVetoPtr>::iterator v = _vetoes.begin();
v != _vetoes.end(); ++v) {
bool test = (**v).vetoTimeLike(_progenitor,particle,fb);
switch((**v).vetoType()) {
case ShowerVeto::Emission:
vetoed |= test;
break;
case ShowerVeto::Shower:
if(test) throw VetoShower();
break;
case ShowerVeto::Event:
if(test) throw Veto();
break;
}
}
if(vetoed) return true;
}
if ( firstInteraction() &&
profileScales() ) {
double weight =
profileScales()->
hardScaleProfile(_progenitor->hardScale(),fb.kinematics->pT());
if ( UseRandom::rnd() > weight )
return true;
}
return false;
}
bool QTildeShowerHandler::spaceLikeVetoed(const Branching & bb,
ShowerParticlePtr particle) {
// work out type of interaction
ShowerInteraction::Type type = convertInteraction(bb.type);
// check whether emission was harder than largest pt of hard subprocess
if (restrictPhasespace() && bb.kinematics->pT() > _progenitor->maxHardPt())
return true;
// apply the soft correction
if( softMEC() && _hardme && _hardme->hasMECorrection() ) {
if(_hardme->softMatrixElementVeto(_progenitor,particle,bb))
return true;
}
// the more general vetos
// check vs max pt for the shower
if(bb.kinematics->pT()>_progenitor->maximumpT(type)) return true;
if (!_vetoes.empty()) {
bool vetoed=false;
for (vector<ShowerVetoPtr>::iterator v = _vetoes.begin();
v != _vetoes.end(); ++v) {
bool test = (**v).vetoSpaceLike(_progenitor,particle,bb);
switch ((**v).vetoType()) {
case ShowerVeto::Emission:
vetoed |= test;
break;
case ShowerVeto::Shower:
if(test) throw VetoShower();
break;
case ShowerVeto::Event:
if(test) throw Veto();
break;
}
}
if (vetoed) return true;
}
if ( firstInteraction() &&
profileScales() ) {
double weight =
profileScales()->
hardScaleProfile(_progenitor->hardScale(),bb.kinematics->pT());
if ( UseRandom::rnd() > weight )
return true;
}
return false;
}
bool QTildeShowerHandler::spaceLikeDecayVetoed( const Branching & fb,
ShowerParticlePtr particle) {
// work out type of interaction
ShowerInteraction::Type type = convertInteraction(fb.type);
// apply the soft correction
if( softMEC() && _decayme && _decayme->hasMECorrection() ) {
if(_decayme->softMatrixElementVeto(_progenitor,particle,fb))
return true;
}
// veto on hardest pt in the shower
if(fb.kinematics->pT()> _progenitor->maximumpT(type)) return true;
// general vetos
if (!_vetoes.empty()) {
bool vetoed=false;
for (vector<ShowerVetoPtr>::iterator v = _vetoes.begin();
v != _vetoes.end(); ++v) {
bool test = (**v).vetoSpaceLike(_progenitor,particle,fb);
switch((**v).vetoType()) {
case ShowerVeto::Emission:
vetoed |= test;
break;
case ShowerVeto::Shower:
if(test) throw VetoShower();
break;
case ShowerVeto::Event:
if(test) throw Veto();
break;
}
if (vetoed) return true;
}
}
return false;
}
void QTildeShowerHandler::hardestEmission(bool hard) {
HardTreePtr ISRTree;
if( _hardEmission ==2 &&
(( _hardme && _hardme->hasPOWHEGCorrection()!=0 ) ||
( _decayme && _decayme->hasPOWHEGCorrection()!=0 ) ) ) {
if(_hardme) {
assert(hard);
//_hardtree = _hardme->generateHardest( currentTree(),interaction_);
}
else {
assert(!hard);
- _hardtree = _decayme->generateHardest( currentTree() );
+ // _hardtree = _decayme->generateHardest( currentTree()->perturbativeProcess() );
}
// store initial state POWHEG radiation
if(_hardtree && _hardme && _hardme->hasPOWHEGCorrection()==1)
ISRTree=_hardtree;
}
else if (_hardEmission==2 && hard) {
// Get minimum pT cutoff used in shower approximation
Energy maxpt = 1.*GeV;
int colouredIn = 0;
int colouredOut = 0;
for( map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it
= currentTree()->outgoingLines().begin();
it != currentTree()->outgoingLines().end(); ++it ) {
if( it->second->coloured() ) colouredOut+=1;
}
for( map< ShowerProgenitorPtr, ShowerParticlePtr >::iterator it
= currentTree()->incomingLines().begin();
it != currentTree()->incomingLines().end(); ++it ) {
if( ! it->second->coloured() ) colouredIn+=1;
}
if ( currentTree()->showerApproximation() ){
if ( currentTree()->showerApproximation()->ffPtCut() == currentTree()->showerApproximation()->fiPtCut() &&
currentTree()->showerApproximation()->ffPtCut() == currentTree()->showerApproximation()->iiPtCut() )
maxpt = currentTree()->showerApproximation()->ffPtCut();
else if ( colouredIn == 2 && colouredOut == 0 )
maxpt = currentTree()->showerApproximation()->iiPtCut();
else if ( colouredIn == 0 && colouredOut > 1 )
maxpt = currentTree()->showerApproximation()->ffPtCut();
else if ( colouredIn == 2 && colouredOut == 1 )
maxpt = min(currentTree()->showerApproximation()->iiPtCut(), currentTree()->showerApproximation()->fiPtCut());
else if ( colouredIn == 1 && colouredOut > 1 )
maxpt = min(currentTree()->showerApproximation()->ffPtCut(), currentTree()->showerApproximation()->fiPtCut());
else
maxpt = min(min(currentTree()->showerApproximation()->iiPtCut(), currentTree()->showerApproximation()->fiPtCut()),
currentTree()->showerApproximation()->ffPtCut());
}
// Generate hardtree from born and real emission subprocesses
_hardtree = generateCKKW(currentTree());
// Find transverse momentum of hardest emission
if (_hardtree){
for(set<HardBranchingPtr>::iterator it=_hardtree->branchings().begin();
it!=_hardtree->branchings().end();++it) {
if ((*it)->parent() && (*it)->status()==HardBranching::Incoming)
maxpt=(*it)->branchingParticle()->momentum().perp();
if ((*it)->children().size()==2 && (*it)->status()==HardBranching::Outgoing){
if ((*it)->branchingParticle()->id()!=21 &&
abs((*it)->branchingParticle()->id())>5 ){
if ((*it)->children()[0]->branchingParticle()->id()==21 ||
abs((*it)->children()[0]->branchingParticle()->id())<6)
maxpt=(*it)->children()[0]->branchingParticle()->momentum().perp();
else if ((*it)->children()[1]->branchingParticle()->id()==21 ||
abs((*it)->children()[1]->branchingParticle()->id())<6)
maxpt=(*it)->children()[1]->branchingParticle()->momentum().perp();
}
else {
if ( abs((*it)->branchingParticle()->id())<6){
if (abs((*it)->children()[0]->branchingParticle()->id())<6)
maxpt = (*it)->children()[1]->branchingParticle()->momentum().perp();
else
maxpt = (*it)->children()[0]->branchingParticle()->momentum().perp();
}
else maxpt = (*it)->children()[1]->branchingParticle()->momentum().perp();
}
}
}
}
// Hardest (pt) emission should be the first powheg emission.
maxpt=min(sqrt(lastXCombPtr()->lastShowerScale()),maxpt);
// Set maxpt to pT of emission when showering POWHEG real-emission subprocesses
if (!currentTree()->isPowhegSEvent() && !currentTree()->isPowhegHEvent()){
vector<int> outGluon;
vector<int> outQuark;
map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it;
for( it = currentTree()->outgoingLines().begin();
it != currentTree()->outgoingLines().end(); ++it ) {
if ( abs(it->second->id())< 6) outQuark.push_back(it->second->id());
if ( it->second->id()==21 ) outGluon.push_back(it->second->id());
}
if (outGluon.size() + outQuark.size() == 1){
for( it = currentTree()->outgoingLines().begin();
it != currentTree()->outgoingLines().end(); ++it ) {
if ( abs(it->second->id())< 6 || it->second->id()==21 )
maxpt = it->second->momentum().perp();
}
}
else if (outGluon.size() + outQuark.size() > 1){
// assume qqbar pair from a Z/gamma
if (outGluon.size()==1 && outQuark.size() == 2 && outQuark[0]==-outQuark[1]){
for( it = currentTree()->outgoingLines().begin();
it != currentTree()->outgoingLines().end(); ++it ) {
if ( it->second->id()==21 )
maxpt = it->second->momentum().perp();
}
}
// otherwise take the lowest pT avoiding born DY events
else {
maxpt = generator()->maximumCMEnergy();
for( it = currentTree()->outgoingLines().begin();
it != currentTree()->outgoingLines().end(); ++it ) {
if ( abs(it->second->id())< 6 || it->second->id()==21 )
maxpt = min(maxpt,it->second->momentum().perp());
}
}
}
}
// set maximum pT for subsequent emissions from S events
if ( currentTree()->isPowhegSEvent() || (!currentTree()->isPowhegSEvent() && !currentTree()->isPowhegHEvent())){
for( map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it
= currentTree()->outgoingLines().begin();
it != currentTree()->outgoingLines().end(); ++it ) {
if( ! it->second->coloured() ) continue;
it->first->maximumpT(maxpt, ShowerInteraction::QCD );
}
for( map< ShowerProgenitorPtr, ShowerParticlePtr >::iterator it
= currentTree()->incomingLines().begin();
it != currentTree()->incomingLines().end(); ++it ) {
if( ! it->second->coloured() ) continue;
it->first->maximumpT(maxpt, ShowerInteraction::QCD );
}
}
}
else
_hardtree = generateCKKW(currentTree());
// if hard me doesn't have a FSR powheg
// correction use decay powheg correction
if (_hardme && _hardme->hasPOWHEGCorrection()<2) {
// check for intermediate colour singlet resonance
const ParticleVector inter = _hardme->subProcess()->intermediates();
if (inter.size()!=1 ||
inter[0]->momentum().m2()/GeV2 < 0 ||
inter[0]->dataPtr()->iColour()!=PDT::Colour0){
if(_hardtree) connectTrees(currentTree(),_hardtree,hard);
return;
}
map<ShowerProgenitorPtr, tShowerParticlePtr > out = currentTree()->outgoingLines();
// ignore cases where outgoing particles are not coloured
if (out.size()!=2 ||
out. begin()->second->dataPtr()->iColour()==PDT::Colour0 ||
out.rbegin()->second->dataPtr()->iColour()==PDT::Colour0) {
if(_hardtree) connectTrees(currentTree(),_hardtree,hard);
return;
}
// look up decay mode
tDMPtr dm;
string tag;
string inParticle = inter[0]->dataPtr()->name() + "->";
vector<string> outParticles;
outParticles.push_back(out.begin ()->first->progenitor()->dataPtr()->name());
outParticles.push_back(out.rbegin()->first->progenitor()->dataPtr()->name());
for (int it=0; it<2; ++it){
tag = inParticle + outParticles[it] + "," + outParticles[(it+1)%2] + ";";
dm = generator()->findDecayMode(tag);
if(dm) break;
}
// get the decayer
HwDecayerBasePtr decayer;
if(dm) decayer = dynamic_ptr_cast<HwDecayerBasePtr>(dm->decayer());
// check if decayer has a FSR POWHEG correction
if (!decayer || decayer->hasPOWHEGCorrection()<2){
if(_hardtree) connectTrees(currentTree(),_hardtree,hard);
return;
}
// generate the hardest emission
ShowerDecayMap decay;
PPtr in = new_ptr(*inter[0]);
PerturbativeProcessPtr newProcess(new_ptr(PerturbativeProcess()));
newProcess->incoming().push_back(make_pair(in,PerturbativeProcessPtr()));
ShowerTreePtr decayTree = new_ptr(ShowerTree(newProcess));
- HardTreePtr FSRTree = decayer->generateHardest(decayTree);
+ HardTreePtr FSRTree;
+ //HardTreePtr FSRTree = decayer->generateHardest(decayTree);
if (!FSRTree) {
if(_hardtree) connectTrees(currentTree(),_hardtree,hard);
return;
}
// if there is no ISRTree make _hardtree from FSRTree
if (!ISRTree){
vector<HardBranchingPtr> inBranch,hardBranch;
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit =currentTree()->incomingLines().begin();
cit!=currentTree()->incomingLines().end();++cit ) {
inBranch.push_back(new_ptr(HardBranching(cit->second,SudakovPtr(),
HardBranchingPtr(),
HardBranching::Incoming)));
inBranch.back()->beam(cit->first->original()->parents()[0]);
hardBranch.push_back(inBranch.back());
}
if(inBranch[0]->branchingParticle()->dataPtr()->coloured()) {
inBranch[0]->colourPartner(inBranch[1]);
inBranch[1]->colourPartner(inBranch[0]);
}
for(set<HardBranchingPtr>::iterator it=FSRTree->branchings().begin();
it!=FSRTree->branchings().end();++it) {
if((**it).branchingParticle()->id()!=in->id())
hardBranch.push_back(*it);
}
hardBranch[2]->colourPartner(hardBranch[3]);
hardBranch[3]->colourPartner(hardBranch[2]);
HardTreePtr newTree = new_ptr(HardTree(hardBranch,inBranch,
ShowerInteraction::QCD));
_hardtree = newTree;
}
// Otherwise modify the ISRTree to include the emission in FSRTree
else {
vector<tShowerParticlePtr> FSROut, ISROut;
set<HardBranchingPtr>::iterator itFSR, itISR;
// get outgoing particles
for(itFSR =FSRTree->branchings().begin();
itFSR!=FSRTree->branchings().end();++itFSR){
if ((**itFSR).status()==HardBranching::Outgoing)
FSROut.push_back((*itFSR)->branchingParticle());
}
for(itISR =ISRTree->branchings().begin();
itISR!=ISRTree->branchings().end();++itISR){
if ((**itISR).status()==HardBranching::Outgoing)
ISROut.push_back((*itISR)->branchingParticle());
}
// find COM frame formed by outgoing particles
LorentzRotation eventFrameFSR, eventFrameISR;
eventFrameFSR = ((FSROut[0]->momentum()+FSROut[1]->momentum()).findBoostToCM());
eventFrameISR = ((ISROut[0]->momentum()+ISROut[1]->momentum()).findBoostToCM());
// find rotation between ISR and FSR frames
int j=0;
if (ISROut[0]->id()!=FSROut[0]->id()) j=1;
eventFrameISR.rotateZ( (eventFrameFSR*FSROut[0]->momentum()).phi()-
(eventFrameISR*ISROut[j]->momentum()).phi() );
eventFrameISR.rotateY( (eventFrameFSR*FSROut[0]->momentum()).theta()-
(eventFrameISR*ISROut[j]->momentum()).theta() );
eventFrameISR.invert();
for (itFSR=FSRTree->branchings().begin();
itFSR!=FSRTree->branchings().end();++itFSR){
if ((**itFSR).branchingParticle()->id()==in->id()) continue;
for (itISR =ISRTree->branchings().begin();
itISR!=ISRTree->branchings().end();++itISR){
if ((**itISR).status()==HardBranching::Incoming) continue;
if ((**itFSR).branchingParticle()->id()==
(**itISR).branchingParticle()->id()){
// rotate FSRTree particle to ISRTree event frame
(**itISR).branchingParticle()->setMomentum(eventFrameISR*
eventFrameFSR*
(**itFSR).branchingParticle()->momentum());
(**itISR).branchingParticle()->rescaleMass();
// add the children of the FSRTree particles to the ISRTree
if(!(**itFSR).children().empty()){
(**itISR).addChild((**itFSR).children()[0]);
(**itISR).addChild((**itFSR).children()[1]);
// rotate momenta to ISRTree event frame
(**itISR).children()[0]->branchingParticle()->setMomentum(eventFrameISR*
eventFrameFSR*
(**itFSR).children()[0]->branchingParticle()->momentum());
(**itISR).children()[1]->branchingParticle()->setMomentum(eventFrameISR*
eventFrameFSR*
(**itFSR).children()[1]->branchingParticle()->momentum());
}
}
}
}
_hardtree = ISRTree;
}
}
if(_hardtree){
connectTrees(currentTree(),_hardtree,hard);
}
}
bool QTildeShowerHandler::truncatedTimeLikeShower(tShowerParticlePtr particle,
HardBranchingPtr branch,
ShowerInteraction::Type type,
Branching fb, bool first) {
// select a branching if we don't have one
if(!fb.kinematics)
fb = selectTimeLikeBranching(particle,type,branch);
// must be an emission, the forced one it not a truncated one
assert(fb.kinematics);
ShowerParticleVector children;
int ntry=0;
Branching fc[2];
bool setupChildren = true;
while (ntry<50) {
if(!fc[0].hard) fc[0] = Branching();
if(!fc[1].hard) fc[1] = Branching();
++ntry;
// Assign the shower kinematics to the emitting particle.
if(setupChildren) {
++_nFSR;
// Assign the shower kinematics to the emitting particle.
particle->showerKinematics(fb.kinematics);
if(fb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(fb.kinematics->pT());
// create the children
children = createTimeLikeChildren(particle,fb.ids);
// update the children
particle->showerKinematics()->
updateChildren(particle, children,fb.type,_reconOpt>=3);
setupChildren = false;
}
// select branchings for children
if(!fc[0].kinematics) {
// select branching for first particle
if(!fb.hard && fb.iout ==1 )
fc[0] = selectTimeLikeBranching(children[0],type,branch);
else if(fb.hard && !branch->children()[0]->children().empty() )
fc[0] = selectTimeLikeBranching(children[0],type,branch->children()[0]);
else
fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr());
}
// select branching for the second particle
if(!fc[1].kinematics) {
// select branching for first particle
if(!fb.hard && fb.iout ==2 )
fc[1] = selectTimeLikeBranching(children[1],type,branch);
else if(fb.hard && !branch->children()[1]->children().empty() )
fc[1] = selectTimeLikeBranching(children[1],type,branch->children()[1]);
else
fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr());
}
// old default
if(_reconOpt==0 || (_reconOpt==1 && fb.hard) ) {
// shower the first particle
if(fc[0].kinematics) {
// the parent has truncated emission and following line
if(!fb.hard && fb.iout == 1)
truncatedTimeLikeShower(children[0],branch,type,fc[0],false);
// hard emission and subsquent hard emissions
else if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false);
// normal shower
else
timeLikeShower(children[0],type,fc[0],false);
}
if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
// shower the second particle
if(fc[1].kinematics) {
// the parent has truncated emission and following line
if(!fb.hard && fb.iout == 2)
truncatedTimeLikeShower(children[1],branch,type,fc[1],false);
// hard emission and subsquent hard emissions
else if(fb.hard && !branch->children()[1]->children().empty() )
truncatedTimeLikeShower(children[1],branch->children()[1],type,fc[1],false);
else
timeLikeShower(children[1],type,fc[1],false);
}
if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
// branching has happened
particle->showerKinematics()->updateParent(particle, children,fb.type);
break;
}
// H7 default
else if(_reconOpt==1) {
// shower the first particle
if(fc[0].kinematics) {
// the parent has truncated emission and following line
if(!fb.hard && fb.iout == 1)
truncatedTimeLikeShower(children[0],branch,type,fc[0],false);
else
timeLikeShower(children[0],type,fc[0],false);
}
if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
// shower the second particle
if(fc[1].kinematics) {
// the parent has truncated emission and following line
if(!fb.hard && fb.iout == 2)
truncatedTimeLikeShower(children[1],branch,type,fc[1],false);
else
timeLikeShower(children[1],type,fc[1],false);
}
if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
// branching has happened
particle->showerKinematics()->updateParent(particle, children,fb.type);
// clean up the vetoed emission
if(particle->virtualMass()==ZERO) {
particle->showerKinematics(ShoKinPtr());
for(unsigned int ix=0;ix<children.size();++ix)
particle->abandonChild(children[ix]);
children.clear();
if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr());
particle->vetoEmission(fb.type,fb.kinematics->scale());
// generate the new emission
fb = selectTimeLikeBranching(particle,type,branch);
// must be at least hard emission
assert(fb.kinematics);
setupChildren = true;
continue;
}
else
break;
}
else if(_reconOpt>=2) {
// cut-off masses for the branching
const vector<Energy> & virtualMasses = fb.sudakov->virtualMasses(fb.ids);
// compute the masses of the children
Energy masses[3];
for(unsigned int ix=0;ix<2;++ix) {
if(fc[ix].kinematics) {
const vector<Energy> & vm = fc[ix].sudakov->virtualMasses(fc[ix].ids);
Energy2 q2 =
fc[ix].kinematics->z()*(1.-fc[ix].kinematics->z())*sqr(fc[ix].kinematics->scale());
if(fc[ix].ids[0]->id()!=ParticleID::g) q2 += sqr(vm[0]);
masses[ix+1] = sqrt(q2);
}
else {
masses[ix+1] = virtualMasses[ix+1];
}
}
masses[0] = fb.ids[0]->id()!=ParticleID::g ? virtualMasses[0] : ZERO;
double z = fb.kinematics->z();
Energy2 pt2 = z*(1.-z)*(z*(1.-z)*sqr(fb.kinematics->scale()) + sqr(masses[0]))
- sqr(masses[1])*(1.-z) - sqr(masses[2])*z;
if(pt2>=ZERO) {
break;
}
// if only the hard emission have to accept it
else if ((fc[0].hard && !fc[1].kinematics) ||
(fc[1].hard && !fc[0].kinematics) ) {
break;
}
else {
// reset the scales for the children
for(unsigned int ix=0;ix<2;++ix) {
if(fc[ix].hard) continue;
if(fc[ix].kinematics && ! fc[ix].hard )
children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale());
else
children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO);
children[ix]->virtualMass(ZERO);
}
}
}
};
if(_reconOpt>=2) {
// shower the first particle
if(fc[0].kinematics) {
// the parent has truncated emission and following line
if(!fb.hard && fb.iout == 1)
truncatedTimeLikeShower(children[0],branch,type,fc[0],false);
// hard emission and subsquent hard emissions
else if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false);
// normal shower
else
timeLikeShower(children[0],type,fc[0],false);
}
if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
// shower the second particle
if(fc[1].kinematics) {
// the parent has truncated emission and following line
if(!fb.hard && fb.iout == 2)
truncatedTimeLikeShower(children[1],branch,type,fc[1],false);
// hard emission and subsquent hard emissions
else if(fb.hard && !branch->children()[1]->children().empty() )
truncatedTimeLikeShower(children[1],branch->children()[1],type,fc[1],false);
else
timeLikeShower(children[1],type,fc[1],false);
}
if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
// branching has happened
particle->showerKinematics()->updateParent(particle, children,fb.type);
}
if(first&&!children.empty())
particle->showerKinematics()->resetChildren(particle,children);
if(particle->spinInfo()) particle->spinInfo()->develop();
return true;
}
bool QTildeShowerHandler::truncatedSpaceLikeShower(tShowerParticlePtr particle, PPtr beam,
HardBranchingPtr branch,
ShowerInteraction::Type type) {
tcPDFPtr pdf;
if(firstPDF().particle() == beamParticle())
pdf = firstPDF().pdf();
if(secondPDF().particle() == beamParticle())
pdf = secondPDF().pdf();
Energy freeze = pdfFreezingScale();
Branching bb;
// parameters of the force branching
double z(0.);
HardBranchingPtr timelike;
for( unsigned int ix = 0; ix < branch->children().size(); ++ix ) {
if( branch->children()[ix]->status() ==HardBranching::Outgoing) {
timelike = branch->children()[ix];
}
if( branch->children()[ix]->status() ==HardBranching::Incoming )
z = branch->children()[ix]->z();
}
// generate truncated branching
tcPDPtr part[2];
if(z>=0.&&z<=1.) {
while (true) {
if( !isTruncatedShowerON() || hardOnly() ) break;
bb = splittingGenerator()->chooseBackwardBranching( *particle,
beam, 1., beamParticle(),
type , pdf,freeze);
if( !bb.kinematics || bb.kinematics->scale() < branch->scale() ) {
bb = Branching();
break;
}
// particles as in Sudakov form factor
part[0] = bb.ids[0];
part[1] = bb.ids[2];
double zsplit = bb.kinematics->z();
// apply the vetos for the truncated shower
// if doesn't carry most of momentum
ShowerInteraction::Type type2 = convertInteraction(bb.type);
if(type2==branch->sudakov()->interactionType() &&
zsplit < 0.5) {
particle->vetoEmission(bb.type,bb.kinematics->scale());
continue;
}
// others
if( part[0]->id() != particle->id() || // if particle changes type
bb.kinematics->pT() > progenitor()->maximumpT(type2) || // pt veto
bb.kinematics->scale() < branch->scale()) { // angular ordering veto
particle->vetoEmission(bb.type,bb.kinematics->scale());
continue;
}
// and those from the base class
if(spaceLikeVetoed(bb,particle)) {
particle->vetoEmission(bb.type,bb.kinematics->scale());
continue;
}
break;
}
}
if( !bb.kinematics ) {
//do the hard emission
ShoKinPtr kinematics =
branch->sudakov()->createInitialStateBranching( branch->scale(), z, branch->phi(),
branch->children()[0]->pT() );
// assign the splitting function and shower kinematics
particle->showerKinematics( kinematics );
if(kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(kinematics->pT());
// For the time being we are considering only 1->2 branching
// Now create the actual particles, make the otherChild a final state
// particle, while the newParent is not
ShowerParticlePtr newParent =
new_ptr( ShowerParticle( branch->branchingParticle()->dataPtr(), false ) );
ShowerParticlePtr otherChild =
new_ptr( ShowerParticle( timelike->branchingParticle()->dataPtr(),
true, true ) );
ShowerParticleVector theChildren;
theChildren.push_back( particle );
theChildren.push_back( otherChild );
particle->showerKinematics()->
updateParent( newParent, theChildren, branch->type());
// update the history if needed
currentTree()->updateInitialStateShowerProduct( progenitor(), newParent );
currentTree()->addInitialStateBranching( particle, newParent, otherChild );
// for the reconstruction of kinematics, parent/child
// relationships are according to the branching process:
// now continue the shower
bool emitted=false;
if(!hardOnly()) {
if( branch->parent() ) {
emitted = truncatedSpaceLikeShower( newParent, beam, branch->parent() , type);
}
else {
emitted = spaceLikeShower( newParent, beam , type);
}
}
if( !emitted ) {
if( intrinsicpT().find( progenitor() ) == intrinsicpT().end() ) {
kinematics->updateLast( newParent, ZERO, ZERO );
}
else {
pair<Energy,double> kt = intrinsicpT()[progenitor()];
kinematics->updateLast( newParent,
kt.first*cos( kt.second ),
kt.first*sin( kt.second ) );
}
}
particle->showerKinematics()->
updateChildren( newParent, theChildren,bb.type,false);
if(hardOnly()) return true;
// perform the shower of the final-state particle
if( timelike->children().empty() ) {
timeLikeShower( otherChild , type,Branching(),true);
}
else {
truncatedTimeLikeShower( otherChild, timelike , type,Branching(), true);
}
updateHistory(otherChild);
// return the emitted
return true;
}
// assign the splitting function and shower kinematics
particle->showerKinematics( bb.kinematics );
if(bb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(bb.kinematics->pT());
// For the time being we are considering only 1->2 branching
// Now create the actual particles, make the otherChild a final state
// particle, while the newParent is not
ShowerParticlePtr newParent = new_ptr( ShowerParticle( part[0], false ) );
ShowerParticlePtr otherChild = new_ptr( ShowerParticle( part[1], true, true ) );
ShowerParticleVector theChildren;
theChildren.push_back( particle );
theChildren.push_back( otherChild );
particle->showerKinematics()->
updateParent( newParent, theChildren, bb.type);
// update the history if needed
currentTree()->updateInitialStateShowerProduct( progenitor(), newParent );
currentTree()->addInitialStateBranching( particle, newParent, otherChild );
// for the reconstruction of kinematics, parent/child
// relationships are according to the branching process:
// now continue the shower
bool emitted = truncatedSpaceLikeShower( newParent, beam, branch,type);
// now reconstruct the momentum
if( !emitted ) {
if( intrinsicpT().find( progenitor() ) == intrinsicpT().end() ) {
bb.kinematics->updateLast( newParent, ZERO, ZERO );
}
else {
pair<Energy,double> kt = intrinsicpT()[ progenitor() ];
bb.kinematics->updateLast( newParent,
kt.first*cos( kt.second ),
kt.first*sin( kt.second ) );
}
}
particle->showerKinematics()->
updateChildren( newParent, theChildren, bb.type,false);
// perform the shower of the final-state particle
timeLikeShower( otherChild , type,Branching(),true);
updateHistory(otherChild);
// return the emitted
return true;
}
bool QTildeShowerHandler::
truncatedSpaceLikeDecayShower(tShowerParticlePtr particle,
const ShowerParticle::EvolutionScales & maxScales,
Energy minmass, HardBranchingPtr branch,
ShowerInteraction::Type type, Branching fb) {
// select a branching if we don't have one
if(!fb.kinematics)
fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type,branch);
// must be an emission, the forced one it not a truncated one
assert(fb.kinematics);
ShowerParticleVector children;
int ntry=0;
Branching fc[2];
bool setupChildren = true;
while (ntry<50) {
if(!fc[0].hard) fc[0] = Branching();
if(!fc[1].hard) fc[1] = Branching();
++ntry;
if(setupChildren) {
++_nFSR;
// Assign the shower kinematics to the emitting particle.
particle->showerKinematics(fb.kinematics);
if(fb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(fb.kinematics->pT());
// create the ShowerParticle objects for the two children
children = createTimeLikeChildren(particle,fb.ids);
// updateChildren the children
particle->showerKinematics()->
updateChildren(particle, children, fb.type,_reconOpt>=3);
setupChildren = false;
}
// select branchings for children
if(!fc[0].kinematics) {
if(children[0]->id()==particle->id()) {
// select branching for first particle
if(!fb.hard)
fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type,branch);
else if(fb.hard && ! branch->children()[0]->children().empty() )
fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type,
branch->children()[0]);
else
fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type,
HardBranchingPtr());
}
else {
// select branching for first particle
if(fb.hard && !branch->children()[0]->children().empty() )
fc[0] = selectTimeLikeBranching(children[0],type,branch->children()[0]);
else
fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr());
}
}
// select branching for the second particle
if(!fc[1].kinematics) {
if(children[1]->id()==particle->id()) {
// select branching for first particle
if(!fb.hard)
fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type,branch);
else if(fb.hard && ! branch->children()[1]->children().empty() )
fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type,
branch->children()[1]);
else
fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type,
HardBranchingPtr());
}
else {
if(fb.hard && !branch->children()[1]->children().empty() )
fc[1] = selectTimeLikeBranching(children[1],type,branch->children()[1]);
else
fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr());
}
}
// old default
if(_reconOpt==0 || (_reconOpt==1 && fb.hard) ) {
// update the history if needed
currentTree()->updateInitialStateShowerProduct(progenitor(),children[0]);
currentTree()->addInitialStateBranching(particle,children[0],children[1]);
// shower the first particle
if(fc[0].kinematics) {
if(children[0]->id()==particle->id()) {
if(!fb.hard)
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch,type,fc[0]);
else if(fb.hard && ! branch->children()[0]->children().empty() )
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch->children()[0],type,fc[0]);
else
spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[0]);
}
else {
if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false);
// normal shower
else
timeLikeShower(children[0],type,fc[0],false);
}
}
// shower the second particle
if(fc[1].kinematics) {
if(children[0]->id()==particle->id()) {
if(!fb.hard)
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch,type,fc[1]);
else if(fb.hard && ! branch->children()[0]->children().empty() )
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch->children()[0],type,fc[1]);
else
spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[1]);
}
else {
if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[1],false);
// normal shower
else
timeLikeShower(children[0],type,fc[1],false);
}
}
updateHistory(children[1]);
// branching has happened
break;
}
// H7 default
else if(_reconOpt==1) {
// update the history if needed
currentTree()->updateInitialStateShowerProduct(progenitor(),children[0]);
currentTree()->addInitialStateBranching(particle,children[0],children[1]);
// shower the first particle
if(fc[0].kinematics) {
if(children[0]->id()==particle->id()) {
if(!fb.hard)
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch,type,fc[0]);
else if(fb.hard && ! branch->children()[0]->children().empty() )
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch->children()[0],type,fc[0]);
else
spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[0]);
}
else {
if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false);
// normal shower
else
timeLikeShower(children[0],type,fc[0],false);
}
}
// shower the second particle
if(fc[1].kinematics) {
if(children[0]->id()==particle->id()) {
if(!fb.hard)
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch,type,fc[1]);
else if(fb.hard && ! branch->children()[0]->children().empty() )
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch->children()[0],type,fc[1]);
else
spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[1]);
}
else {
if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[1],false);
// normal shower
else
timeLikeShower(children[0],type,fc[1],false);
}
}
// clean up the vetoed emission
if(particle->virtualMass()==ZERO) {
particle->showerKinematics(ShoKinPtr());
for(unsigned int ix=0;ix<children.size();++ix)
particle->abandonChild(children[ix]);
children.clear();
particle->vetoEmission(fb.type,fb.kinematics->scale());
// generate the new emission
fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type,branch);
// must be at least hard emission
assert(fb.kinematics);
setupChildren = true;
continue;
}
else {
updateHistory(children[1]);
break;
}
}
else if(_reconOpt>=2) {
// cut-off masses for the branching
const vector<Energy> & virtualMasses = fb.sudakov->virtualMasses(fb.ids);
// compute the masses of the children
Energy masses[3];
// space-like children
masses[1] = children[0]->virtualMass();
// time-like child
if(fc[1].kinematics) {
const vector<Energy> & vm = fc[1].sudakov->virtualMasses(fc[1].ids);
Energy2 q2 =
fc[1].kinematics->z()*(1.-fc[1].kinematics->z())*sqr(fc[1].kinematics->scale());
if(fc[1].ids[0]->id()!=ParticleID::g) q2 += sqr(vm[0]);
masses[2] = sqrt(q2);
}
else {
masses[2] = virtualMasses[2];
}
masses[0]=particle->virtualMass();
double z = fb.kinematics->z();
Energy2 pt2 = (1.-z)*(z*sqr(masses[0])-sqr(masses[1])-z/(1.-z)*sqr(masses[2]));
if(pt2>=ZERO) {
break;
}
else {
// reset the scales for the children
for(unsigned int ix=0;ix<2;++ix) {
if(fc[ix].kinematics)
children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale());
else {
if(ix==0)
children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,Constants::MaxEnergy);
else
children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO);
}
}
children[0]->virtualMass(_progenitor->progenitor()->mass());
children[1]->virtualMass(ZERO);
}
}
};
if(_reconOpt>=2) {
// update the history if needed
currentTree()->updateInitialStateShowerProduct(progenitor(),children[0]);
currentTree()->addInitialStateBranching(particle,children[0],children[1]);
// shower the first particle
if(fc[0].kinematics) {
if(children[0]->id()==particle->id()) {
if(!fb.hard)
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch,type,fc[0]);
else if(fb.hard && ! branch->children()[0]->children().empty() )
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch->children()[0],type,fc[0]);
else
spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[0]);
}
else {
if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false);
// normal shower
else
timeLikeShower(children[0],type,fc[0],false);
}
}
// shower the second particle
if(fc[1].kinematics) {
if(children[0]->id()==particle->id()) {
if(!fb.hard)
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch,type,fc[1]);
else if(fb.hard && ! branch->children()[0]->children().empty() )
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch->children()[0],type,fc[1]);
else
spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[1]);
}
else {
if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[1],false);
// normal shower
else
timeLikeShower(children[0],type,fc[1],false);
}
}
updateHistory(children[1]);
}
return true;
}
void QTildeShowerHandler::connectTrees(ShowerTreePtr showerTree,
HardTreePtr hardTree, bool hard ) {
ShowerParticleVector particles;
// find the Sudakovs
for(set<HardBranchingPtr>::iterator cit=hardTree->branchings().begin();
cit!=hardTree->branchings().end();++cit) {
// Sudakovs for ISR
if((**cit).parent()&&(**cit).status()==HardBranching::Incoming) {
++_nis;
vector<long> br(3);
br[0] = (**cit).parent()->branchingParticle()->id();
br[1] = (**cit). branchingParticle()->id();
br[2] = (**cit).parent()->children()[0]==*cit ?
(**cit).parent()->children()[1]->branchingParticle()->id() :
(**cit).parent()->children()[0]->branchingParticle()->id();
BranchingList branchings = splittingGenerator()->initialStateBranchings();
if(br[1]<0&&br[0]==br[1]) {
br[0] = abs(br[0]);
br[1] = abs(br[1]);
}
else if(br[1]<0) {
br[1] = -br[1];
br[2] = -br[2];
}
long index = abs(br[1]);
SudakovPtr sudakov;
for(BranchingList::const_iterator cjt = branchings.lower_bound(index);
cjt != branchings.upper_bound(index); ++cjt ) {
IdList ids = cjt->second.particles;
if(ids[0]->id()==br[0]&&ids[1]->id()==br[1]&&ids[2]->id()==br[2]) {
sudakov=cjt->second.sudakov;
break;
}
}
if(!sudakov) throw Exception() << "Can't find Sudakov for the hard emission in "
<< "QTildeShowerHandler::connectTrees() for ISR"
<< Exception::runerror;
(**cit).parent()->sudakov(sudakov);
}
// Sudakovs for FSR
else if(!(**cit).children().empty()) {
++_nfs;
vector<long> br(3);
br[0] = (**cit) .branchingParticle()->id();
br[1] = (**cit).children()[0]->branchingParticle()->id();
br[2] = (**cit).children()[1]->branchingParticle()->id();
BranchingList branchings = splittingGenerator()->finalStateBranchings();
if(br[0]<0) {
br[0] = abs(br[0]);
br[1] = abs(br[1]);
br[2] = abs(br[2]);
}
long index = br[0];
SudakovPtr sudakov;
for(BranchingList::const_iterator cjt = branchings.lower_bound(index);
cjt != branchings.upper_bound(index); ++cjt ) {
IdList ids = cjt->second.particles;
if(ids[0]->id()==br[0]&&ids[1]->id()==br[1]&&ids[2]->id()==br[2]) {
sudakov=cjt->second.sudakov;
break;
}
}
if(!sudakov) throw Exception() << "Can't find Sudakov for the hard emission in "
<< "QTildeShowerHandler::connectTrees()"
<< Exception::runerror;
(**cit).sudakov(sudakov);
}
}
// calculate the evolution scale
for(set<HardBranchingPtr>::iterator cit=hardTree->branchings().begin();
cit!=hardTree->branchings().end();++cit) {
particles.push_back((*cit)->branchingParticle());
}
showerModel()->partnerFinder()->
setInitialEvolutionScales(particles,!hard,hardTree->interaction(),
!hardTree->partnersSet());
hardTree->partnersSet(true);
// inverse reconstruction
if(hard) {
showerModel()->kinematicsReconstructor()->
deconstructHardJets(hardTree,hardTree->interaction());
}
else
showerModel()->kinematicsReconstructor()->
deconstructDecayJets(hardTree,hardTree->interaction());
// now reset the momenta of the showering particles
vector<ShowerProgenitorPtr> particlesToShower;
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit=showerTree->incomingLines().begin();
cit!=showerTree->incomingLines().end();++cit )
particlesToShower.push_back(cit->first);
// extract the showering particles
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cit=showerTree->outgoingLines().begin();
cit!=showerTree->outgoingLines().end();++cit )
particlesToShower.push_back(cit->first);
// match them
map<ShowerProgenitorPtr,HardBranchingPtr> partners;
for(set<HardBranchingPtr>::const_iterator bit=hardTree->branchings().begin();
bit!=hardTree->branchings().end();++bit) {
Energy2 dmin( 1e30*GeV2 );
ShowerProgenitorPtr partner;
for(vector<ShowerProgenitorPtr>::const_iterator pit=particlesToShower.begin();
pit!=particlesToShower.end();++pit) {
if(partners.find(*pit)!=partners.end()) continue;
if( (**bit).branchingParticle()->id() != (**pit).progenitor()->id() ) continue;
if( (**bit).branchingParticle()->isFinalState() !=
(**pit).progenitor()->isFinalState() ) continue;
if( (**pit).progenitor()->isFinalState() ) {
Energy2 dtest =
sqr( (**pit).progenitor()->momentum().x() - (**bit).showerMomentum().x() ) +
sqr( (**pit).progenitor()->momentum().y() - (**bit).showerMomentum().y() ) +
sqr( (**pit).progenitor()->momentum().z() - (**bit).showerMomentum().z() ) +
sqr( (**pit).progenitor()->momentum().t() - (**bit).showerMomentum().t() );
// add mass difference for identical particles (e.g. Z0 Z0 production)
dtest += 1e10*sqr((**pit).progenitor()->momentum().m()-(**bit).showerMomentum().m());
if( dtest < dmin ) {
partner = *pit;
dmin = dtest;
}
}
else {
// ensure directions are right
if((**pit).progenitor()->momentum().z()/(**bit).showerMomentum().z()>ZERO) {
partner = *pit;
break;
}
}
}
if(!partner) throw Exception() << "Failed to match shower and hard trees in QTildeShowerHandler::hardestEmission"
<< Exception::eventerror;
partners[partner] = *bit;
}
for(vector<ShowerProgenitorPtr>::const_iterator pit=particlesToShower.begin();
pit!=particlesToShower.end();++pit) {
HardBranchingPtr partner = partners[*pit];
if((**pit).progenitor()->dataPtr()->stable()) {
(**pit).progenitor()->set5Momentum(partner->showerMomentum());
(**pit).copy()->set5Momentum(partner->showerMomentum());
}
else {
Lorentz5Momentum oldMomentum = (**pit).progenitor()->momentum();
Lorentz5Momentum newMomentum = partner->showerMomentum();
LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass());
(**pit).progenitor()->transform(boost);
(**pit).copy() ->transform(boost);
boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass());
(**pit).progenitor()->transform(boost);
(**pit).copy() ->transform(boost);
}
}
// correction boosts for daughter trees
for(map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator
tit = showerTree->treelinks().begin();
tit != showerTree->treelinks().end();++tit) {
ShowerTreePtr decayTree = tit->first;
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit = decayTree->incomingLines().begin();
// reset the momentum of the decay particle
Lorentz5Momentum oldMomentum = cit->first->progenitor()->momentum();
Lorentz5Momentum newMomentum = tit->second.second->momentum();
LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass());
decayTree->transform(boost,true);
boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass());
decayTree->transform(boost,true);
}
}
void QTildeShowerHandler::doShowering(bool hard,XCPtr xcomb) {
// zero number of emissions
_nis = _nfs = 0;
// if MC@NLO H event and limited emissions
// indicate both final and initial state emission
if ( currentTree()->isMCatNLOHEvent() && _limitEmissions != 0 ) {
_nis = _nfs = 1;
}
// extract particles to shower
vector<ShowerProgenitorPtr> particlesToShower(setupShower(hard));
// setup the maximum scales for the shower
if (restrictPhasespace()) setupMaximumScales(particlesToShower,xcomb);
// set the hard scales for the profiles
setupHardScales(particlesToShower,xcomb);
// specific stuff for hard processes and decays
Energy minmass(ZERO), mIn(ZERO);
// hard process generate the intrinsic p_T once and for all
if(hard) {
generateIntrinsicpT(particlesToShower);
}
// decay compute the minimum mass of the final-state
else {
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
if(particlesToShower[ix]->progenitor()->isFinalState()) {
if(particlesToShower[ix]->progenitor()->dataPtr()->stable())
minmass += particlesToShower[ix]->progenitor()->dataPtr()->constituentMass();
else
minmass += particlesToShower[ix]->progenitor()->mass();
}
else {
mIn = particlesToShower[ix]->progenitor()->mass();
}
}
// throw exception if decay can't happen
if ( minmass > mIn ) {
throw Exception() << "Evolver.cc: Mass of decaying particle is "
<< "below constituent masses of decay products."
<< Exception::eventerror;
}
}
// create random particle vector (only need to do once)
vector<ShowerProgenitorPtr> tmp;
unsigned int nColouredIncoming = 0;
while(particlesToShower.size()>0){
unsigned int xx=UseRandom::irnd(particlesToShower.size());
tmp.push_back(particlesToShower[xx]);
particlesToShower.erase(particlesToShower.begin()+xx);
}
particlesToShower=tmp;
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
if(!particlesToShower[ix]->progenitor()->isFinalState() &&
particlesToShower[ix]->progenitor()->coloured()) ++nColouredIncoming;
}
bool switchRecon = hard && nColouredIncoming !=1;
// main shower loop
unsigned int ntry(0);
bool reconstructed = false;
do {
// clear results of last attempt if needed
if(ntry!=0) {
currentTree()->clear();
setEvolutionPartners(hard,interaction_,true);
_nis = _nfs = 0;
// if MC@NLO H event and limited emissions
// indicate both final and initial state emission
if ( currentTree()->isMCatNLOHEvent() && _limitEmissions != 0 ) {
_nis = _nfs = 1;
}
for(unsigned int ix=0; ix<particlesToShower.size();++ix) {
SpinPtr spin = particlesToShower[ix]->progenitor()->spinInfo();
if(spin && spin->decayVertex() &&
dynamic_ptr_cast<tcSVertexPtr>(spin->decayVertex())) {
spin->decayVertex(VertexPtr());
}
}
}
// loop over particles
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
// extract the progenitor
progenitor(particlesToShower[ix]);
// final-state radiation
if(progenitor()->progenitor()->isFinalState()) {
if(!doFSR()) continue;
// perform shower
progenitor()->hasEmitted(startTimeLikeShower(interaction_));
}
// initial-state radiation
else {
if(!doISR()) continue;
// hard process
if(hard) {
// get the PDF
setBeamParticle(_progenitor->beam());
assert(beamParticle());
// perform the shower
// set the beam particle
tPPtr beamparticle=progenitor()->original();
if(!beamparticle->parents().empty())
beamparticle=beamparticle->parents()[0];
// generate the shower
progenitor()->hasEmitted(startSpaceLikeShower(beamparticle,
interaction_));
}
// decay
else {
// skip colour and electrically neutral particles
if(!progenitor()->progenitor()->dataPtr()->coloured() &&
!progenitor()->progenitor()->dataPtr()->charged()) {
progenitor()->hasEmitted(false);
continue;
}
// perform shower
// set the scales correctly. The current scale is the maximum scale for
// emission not the starting scale
ShowerParticle::EvolutionScales maxScales(progenitor()->progenitor()->scales());
progenitor()->progenitor()->scales() = ShowerParticle::EvolutionScales();
if(progenitor()->progenitor()->dataPtr()->charged()) {
progenitor()->progenitor()->scales().QED = progenitor()->progenitor()->mass();
progenitor()->progenitor()->scales().QED_noAO = progenitor()->progenitor()->mass();
}
if(progenitor()->progenitor()->hasColour()) {
progenitor()->progenitor()->scales().QCD_c = progenitor()->progenitor()->mass();
progenitor()->progenitor()->scales().QCD_c_noAO = progenitor()->progenitor()->mass();
}
if(progenitor()->progenitor()->hasAntiColour()) {
progenitor()->progenitor()->scales().QCD_ac = progenitor()->progenitor()->mass();
progenitor()->progenitor()->scales().QCD_ac_noAO = progenitor()->progenitor()->mass();
}
// perform the shower
progenitor()->hasEmitted(startSpaceLikeDecayShower(maxScales,minmass,
interaction_));
}
}
}
// do the kinematic reconstruction, checking if it worked
reconstructed = hard ?
showerModel()->kinematicsReconstructor()->
reconstructHardJets (currentTree(),intrinsicpT(),interaction_,
switchRecon && ntry>maximumTries()/2) :
showerModel()->kinematicsReconstructor()->
reconstructDecayJets(currentTree(),interaction_);
}
while(!reconstructed&&maximumTries()>++ntry);
// check if failed to generate the shower
if(ntry==maximumTries()) {
if(hard)
throw ShowerHandler::ShowerTriesVeto(ntry);
else
throw Exception() << "Failed to generate the shower after "
<< ntry << " attempts in QTildeShowerHandler::showerDecay()"
<< Exception::eventerror;
}
// tree has now showered
_currenttree->hasShowered(true);
hardTree(HardTreePtr());
}
void QTildeShowerHandler:: convertHardTree(bool hard,ShowerInteraction::Type type) {
map<ColinePtr,ColinePtr> cmap;
// incoming particles
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit=currentTree()->incomingLines().begin();cit!=currentTree()->incomingLines().end();++cit) {
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
mit = hardTree()->particles().find(cit->first->progenitor());
// put the colour lines in the map
ShowerParticlePtr oldParticle = cit->first->progenitor();
ShowerParticlePtr newParticle = mit->second->branchingParticle();
ColinePtr cLine = oldParticle-> colourLine();
ColinePtr aLine = oldParticle->antiColourLine();
if(newParticle->colourLine() &&
cmap.find(newParticle-> colourLine())==cmap.end())
cmap[newParticle-> colourLine()] = cLine;
if(newParticle->antiColourLine() &&
cmap.find(newParticle->antiColourLine())==cmap.end())
cmap[newParticle->antiColourLine()] = aLine;
// check whether or not particle emits
bool emission = mit->second->parent();
if(emission) {
if(newParticle->colourLine()) {
ColinePtr ctemp = newParticle-> colourLine();
ctemp->removeColoured(newParticle);
}
if(newParticle->antiColourLine()) {
ColinePtr ctemp = newParticle->antiColourLine();
ctemp->removeAntiColoured(newParticle);
}
newParticle = mit->second->parent()->branchingParticle();
}
// get the new colour lines
ColinePtr newCLine,newALine;
// sort out colour lines
if(newParticle->colourLine()) {
ColinePtr ctemp = newParticle-> colourLine();
ctemp->removeColoured(newParticle);
if(cmap.find(ctemp)!=cmap.end()) {
newCLine = cmap[ctemp];
}
else {
newCLine = new_ptr(ColourLine());
cmap[ctemp] = newCLine;
}
}
// and anticolour lines
if(newParticle->antiColourLine()) {
ColinePtr ctemp = newParticle->antiColourLine();
ctemp->removeAntiColoured(newParticle);
if(cmap.find(ctemp)!=cmap.end()) {
newALine = cmap[ctemp];
}
else {
newALine = new_ptr(ColourLine());
cmap[ctemp] = newALine;
}
}
// remove colour lines from old particle
if(aLine) {
aLine->removeAntiColoured(cit->first->copy());
aLine->removeAntiColoured(cit->first->progenitor());
}
if(cLine) {
cLine->removeColoured(cit->first->copy());
cLine->removeColoured(cit->first->progenitor());
}
// add particle to colour lines
if(newCLine) newCLine->addColoured (newParticle);
if(newALine) newALine->addAntiColoured(newParticle);
// insert new particles
cit->first->copy(newParticle);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newParticle,1,false)));
cit->first->progenitor(sp);
currentTree()->incomingLines()[cit->first]=sp;
cit->first->perturbative(!emission);
// and the emitted particle if needed
if(emission) {
ShowerParticlePtr newOut = mit->second->parent()->children()[1]->branchingParticle();
if(newOut->colourLine()) {
ColinePtr ctemp = newOut-> colourLine();
ctemp->removeColoured(newOut);
assert(cmap.find(ctemp)!=cmap.end());
cmap[ctemp]->addColoured (newOut);
}
if(newOut->antiColourLine()) {
ColinePtr ctemp = newOut->antiColourLine();
ctemp->removeAntiColoured(newOut);
assert(cmap.find(ctemp)!=cmap.end());
cmap[ctemp]->addAntiColoured(newOut);
}
ShowerParticlePtr sout=new_ptr(ShowerParticle(*newOut,1,true));
ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(cit->first->original(),newOut,sout));
out->perturbative(false);
currentTree()->outgoingLines().insert(make_pair(out,sout));
}
if(hard) {
// sort out the value of x
if(mit->second->beam()->momentum().z()>ZERO) {
sp->x(newParticle->momentum(). plus()/mit->second->beam()->momentum(). plus());
}
else {
sp->x(newParticle->momentum().minus()/mit->second->beam()->momentum().minus());
}
}
}
// outgoing particles
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cit=currentTree()->outgoingLines().begin();cit!=currentTree()->outgoingLines().end();++cit) {
map<tShowerTreePtr,pair<tShowerProgenitorPtr,
tShowerParticlePtr> >::const_iterator tit;
for(tit = currentTree()->treelinks().begin();
tit != currentTree()->treelinks().end();++tit) {
if(tit->second.first && tit->second.second==cit->first->progenitor())
break;
}
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
mit = hardTree()->particles().find(cit->first->progenitor());
if(mit==hardTree()->particles().end()) continue;
// put the colour lines in the map
ShowerParticlePtr oldParticle = cit->first->progenitor();
ShowerParticlePtr newParticle = mit->second->branchingParticle();
ShowerParticlePtr newOut;
ColinePtr cLine = oldParticle-> colourLine();
ColinePtr aLine = oldParticle->antiColourLine();
if(newParticle->colourLine() &&
cmap.find(newParticle-> colourLine())==cmap.end())
cmap[newParticle-> colourLine()] = cLine;
if(newParticle->antiColourLine() &&
cmap.find(newParticle->antiColourLine())==cmap.end())
cmap[newParticle->antiColourLine()] = aLine;
// check whether or not particle emits
bool emission = !mit->second->children().empty();
if(emission) {
if(newParticle->colourLine()) {
ColinePtr ctemp = newParticle-> colourLine();
ctemp->removeColoured(newParticle);
}
if(newParticle->antiColourLine()) {
ColinePtr ctemp = newParticle->antiColourLine();
ctemp->removeAntiColoured(newParticle);
}
newParticle = mit->second->children()[0]->branchingParticle();
newOut = mit->second->children()[1]->branchingParticle();
if(newParticle->id()!=oldParticle->id()&&newParticle->id()==newOut->id())
swap(newParticle,newOut);
}
// get the new colour lines
ColinePtr newCLine,newALine;
// sort out colour lines
if(newParticle->colourLine()) {
ColinePtr ctemp = newParticle-> colourLine();
ctemp->removeColoured(newParticle);
if(cmap.find(ctemp)!=cmap.end()) {
newCLine = cmap[ctemp];
}
else {
newCLine = new_ptr(ColourLine());
cmap[ctemp] = newCLine;
}
}
// and anticolour lines
if(newParticle->antiColourLine()) {
ColinePtr ctemp = newParticle->antiColourLine();
ctemp->removeAntiColoured(newParticle);
if(cmap.find(ctemp)!=cmap.end()) {
newALine = cmap[ctemp];
}
else {
newALine = new_ptr(ColourLine());
cmap[ctemp] = newALine;
}
}
// remove colour lines from old particle
if(aLine) {
aLine->removeAntiColoured(cit->first->copy());
aLine->removeAntiColoured(cit->first->progenitor());
}
if(cLine) {
cLine->removeColoured(cit->first->copy());
cLine->removeColoured(cit->first->progenitor());
}
// special for unstable particles
if(newParticle->id()==oldParticle->id() &&
(tit!=currentTree()->treelinks().end()||!oldParticle->dataPtr()->stable())) {
Lorentz5Momentum oldMomentum = oldParticle->momentum();
Lorentz5Momentum newMomentum = newParticle->momentum();
LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass());
if(tit!=currentTree()->treelinks().end()) tit->first->transform(boost,false);
oldParticle->transform(boost);
boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass());
oldParticle->transform(boost);
if(tit!=currentTree()->treelinks().end()) tit->first->transform(boost,false);
newParticle=oldParticle;
}
// add particle to colour lines
if(newCLine) newCLine->addColoured (newParticle);
if(newALine) newALine->addAntiColoured(newParticle);
// insert new particles
cit->first->copy(newParticle);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newParticle,1,true)));
cit->first->progenitor(sp);
currentTree()->outgoingLines()[cit->first]=sp;
cit->first->perturbative(!emission);
// and the emitted particle if needed
if(emission) {
if(newOut->colourLine()) {
ColinePtr ctemp = newOut-> colourLine();
ctemp->removeColoured(newOut);
assert(cmap.find(ctemp)!=cmap.end());
cmap[ctemp]->addColoured (newOut);
}
if(newOut->antiColourLine()) {
ColinePtr ctemp = newOut->antiColourLine();
ctemp->removeAntiColoured(newOut);
assert(cmap.find(ctemp)!=cmap.end());
cmap[ctemp]->addAntiColoured(newOut);
}
ShowerParticlePtr sout=new_ptr(ShowerParticle(*newOut,1,true));
ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(cit->first->original(),newOut,sout));
out->perturbative(false);
currentTree()->outgoingLines().insert(make_pair(out,sout));
}
// update any decay products
if(tit!=currentTree()->treelinks().end())
currentTree()->updateLink(tit->first,make_pair(cit->first,sp));
}
// reset the tree
currentTree()->resetShowerProducts();
// reextract the particles and set the colour partners
vector<ShowerParticlePtr> particles =
currentTree()->extractProgenitorParticles();
// clear the partners
for(unsigned int ix=0;ix<particles.size();++ix) {
particles[ix]->partner(ShowerParticlePtr());
particles[ix]->clearPartners();
}
// clear the tree
hardTree(HardTreePtr());
// Set the initial evolution scales
showerModel()->partnerFinder()->
setInitialEvolutionScales(particles,!hard,type,!_hardtree);
}
Branching QTildeShowerHandler::selectTimeLikeBranching(tShowerParticlePtr particle,
ShowerInteraction::Type type,
HardBranchingPtr branch) {
Branching fb;
unsigned int iout=0;
while (true) {
// break if doing truncated shower and no truncated shower needed
if(branch && (!isTruncatedShowerON()||hardOnly())) break;
fb=_splittingGenerator->chooseForwardBranching(*particle,_finalenhance,type);
// no emission break
if(!fb.kinematics) break;
// special for truncated shower
if(branch) {
// check haven't evolved too far
if(fb.kinematics->scale() < branch->scale()) {
fb=Branching();
break;
}
// find the truncated line
iout=0;
if(fb.ids[1]->id()!=fb.ids[2]->id()) {
if(fb.ids[1]->id()==particle->id()) iout=1;
else if (fb.ids[2]->id()==particle->id()) iout=2;
}
else if(fb.ids[1]->id()==particle->id()) {
if(fb.kinematics->z()>0.5) iout=1;
else iout=2;
}
// apply the vetos for the truncated shower
// no flavour changing branchings
if(iout==0) {
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
double zsplit = iout==1 ? fb.kinematics->z() : 1-fb.kinematics->z();
// only if same interaction for forced branching
ShowerInteraction::Type type2 = convertInteraction(fb.type);
// and evolution
if(type2==branch->sudakov()->interactionType()) {
if(zsplit < 0.5 || // hardest line veto
fb.kinematics->scale()*zsplit < branch->scale() ) { // angular ordering veto
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
}
// pt veto
if(fb.kinematics->pT() > progenitor()->maximumpT(type2)) {
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
}
// standard vetos for all emissions
if(timeLikeVetoed(fb,particle)) {
particle->vetoEmission(fb.type,fb.kinematics->scale());
if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr());
continue;
}
// special for already decayed particles
// don't allow flavour changing branchings
bool vetoDecay = false;
for(map<tShowerTreePtr,pair<tShowerProgenitorPtr,
tShowerParticlePtr> >::const_iterator tit = currentTree()->treelinks().begin();
tit != currentTree()->treelinks().end();++tit) {
if(tit->second.first == progenitor()) {
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
it = currentTree()->outgoingLines().find(progenitor());
if(it!=currentTree()->outgoingLines().end() && particle == it->second &&
fb.ids[0]!=fb.ids[1] && fb.ids[1]!=fb.ids[2]) {
vetoDecay = true;
break;
}
}
}
if(vetoDecay) {
cerr << "testing veto\n";
particle->vetoEmission(fb.type,fb.kinematics->scale());
if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr());
continue;
}
break;
}
// normal case
if(!branch) {
if(fb.kinematics) fb.hard = false;
return fb;
}
// truncated emission
if(fb.kinematics) {
fb.hard = false;
fb.iout = iout;
return fb;
}
// otherwise need to return the hard emission
// construct the kinematics for the hard emission
ShoKinPtr showerKin=
branch->sudakov()->createFinalStateBranching(branch->scale(),
branch->children()[0]->z(),
branch->phi(),
branch->children()[0]->pT());
IdList idlist(3);
idlist[0] = particle->dataPtr();
idlist[1] = branch->children()[0]->branchingParticle()->dataPtr();
idlist[2] = branch->children()[1]->branchingParticle()->dataPtr();
fb = Branching( showerKin, idlist, branch->sudakov(),branch->type() );
fb.hard = true;
fb.iout=0;
// return it
return fb;
}
Branching QTildeShowerHandler::selectSpaceLikeDecayBranching(tShowerParticlePtr particle,
const ShowerParticle::EvolutionScales & maxScales,
Energy minmass,ShowerInteraction::Type type,
HardBranchingPtr branch) {
Branching fb;
unsigned int iout=0;
while (true) {
// break if doing truncated shower and no truncated shower needed
if(branch && (!isTruncatedShowerON()||hardOnly())) break;
// select branching
fb=_splittingGenerator->chooseDecayBranching(*particle,maxScales,minmass,
_initialenhance,type);
// return if no radiation
if(!fb.kinematics) break;
// special for truncated shower
if(branch) {
// check haven't evolved too far
if(fb.kinematics->scale() < branch->scale()) {
fb=Branching();
break;
}
// find the truncated line
iout=0;
if(fb.ids[1]->id()!=fb.ids[2]->id()) {
if(fb.ids[1]->id()==particle->id()) iout=1;
else if (fb.ids[2]->id()==particle->id()) iout=2;
}
else if(fb.ids[1]->id()==particle->id()) {
if(fb.kinematics->z()>0.5) iout=1;
else iout=2;
}
// apply the vetos for the truncated shower
// no flavour changing branchings
if(iout==0) {
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
ShowerInteraction::Type type2 = convertInteraction(fb.type);
double zsplit = iout==1 ? fb.kinematics->z() : 1-fb.kinematics->z();
if(type2==branch->sudakov()->interactionType()) {
if(zsplit < 0.5 || // hardest line veto
fb.kinematics->scale()*zsplit < branch->scale() ) { // angular ordering veto
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
}
// pt veto
if(fb.kinematics->pT() > progenitor()->maximumpT(type2)) {
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
}
// if not vetoed break
if(spaceLikeDecayVetoed(fb,particle)) {
// otherwise reset scale and continue
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
break;
}
// normal case
if(!branch) {
if(fb.kinematics) fb.hard = false;
return fb;
}
// truncated emission
if(fb.kinematics) {
fb.hard = false;
fb.iout = iout;
return fb;
}
// otherwise need to return the hard emission
// construct the kinematics for the hard emission
ShoKinPtr showerKin=
branch->sudakov()->createDecayBranching(branch->scale(),
branch->children()[0]->z(),
branch->phi(),
branch->children()[0]->pT());
IdList idlist(3);
idlist[0] = particle->dataPtr();
idlist[1] = branch->children()[0]->branchingParticle()->dataPtr();
idlist[2] = branch->children()[1]->branchingParticle()->dataPtr();
// create the branching
fb = Branching( showerKin, idlist, branch->sudakov(),ShowerPartnerType::QCDColourLine );
fb.hard=true;
fb.iout=0;
// return it
return fb;
}
void QTildeShowerHandler::checkFlags() {
string error = "Inconsistent hard emission set-up in QTildeShowerHandler::showerHardProcess(). ";
if ( ( currentTree()->isMCatNLOSEvent() || currentTree()->isMCatNLOHEvent() ) ) {
if (_hardEmission ==2 )
throw Exception() << error
<< "Cannot generate POWHEG matching with MC@NLO shower "
<< "approximation. Add 'set Evolver:HardEmission 0' to input file."
<< Exception::runerror;
if ( canHandleMatchboxTrunc() )
throw Exception() << error
<< "Cannot use truncated qtilde shower with MC@NLO shower "
<< "approximation. Set LHCGenerator:EventHandler"
<< ":CascadeHandler to '/Herwig/Shower/ShowerHandler' or "
<< "'/Herwig/Shower/Dipole/DipoleShowerHandler'."
<< Exception::runerror;
}
else if ( ((currentTree()->isPowhegSEvent() || currentTree()->isPowhegHEvent()) ) &&
_hardEmission != 2){
if ( canHandleMatchboxTrunc())
throw Exception() << error
<< "Unmatched events requested for POWHEG shower "
<< "approximation. Set Evolver:HardEmission to "
<< "'POWHEG'."
<< Exception::runerror;
else if (_hardEmissionWarn) {
_hardEmissionWarn = false;
_hardEmission=2;
throw Exception() << error
<< "Unmatched events requested for POWHEG shower "
<< "approximation. Changing Evolver:HardEmission from "
<< _hardEmission << " to 2"
<< Exception::warning;
}
}
if ( currentTree()->isPowhegSEvent() || currentTree()->isPowhegHEvent()) {
if (currentTree()->showerApproximation()->needsTruncatedShower() &&
!canHandleMatchboxTrunc() )
throw Exception() << error
<< "Current shower handler cannot generate truncated shower. "
<< "Set Generator:EventHandler:CascadeHandler to "
<< "'/Herwig/Shower/PowhegShowerHandler'."
<< Exception::runerror;
}
else if ( currentTree()->truncatedShower() && _missingTruncWarn) {
_missingTruncWarn=false;
throw Exception() << "Warning: POWHEG shower approximation used without "
<< "truncated shower. Set Generator:EventHandler:"
<< "CascadeHandler to '/Herwig/Shower/PowhegShowerHandler' and "
<< "'MEMatching:TruncatedShower Yes'."
<< Exception::warning;
}
// else if ( !dipme && _hardEmissionMode > 1 &&
// firstInteraction())
// throw Exception() << error
// << "POWHEG matching requested for LO events. Include "
// << "'set Factory:ShowerApproximation MEMatching' in input file."
// << Exception::runerror;
}
tPPair QTildeShowerHandler::remakeRemnant(tPPair oldp){
// get the parton extractor
PartonExtractor & pex = *lastExtractor();
// get the new partons
tPPair newp = make_pair(findFirstParton(oldp.first ),
findFirstParton(oldp.second));
// if the same do nothing
if(newp == oldp) return oldp;
// Creates the new remnants and returns the new PartonBinInstances
// ATTENTION Broken here for very strange configuration
PBIPair newbins = pex.newRemnants(oldp, newp, newStep());
newStep()->addIntermediate(newp.first);
newStep()->addIntermediate(newp.second);
// return the new partons
return newp;
}
PPtr QTildeShowerHandler::findFirstParton(tPPtr seed) const{
if(seed->parents().empty()) return seed;
tPPtr parent = seed->parents()[0];
//if no parent there this is a loose end which will
//be connected to the remnant soon.
if(!parent || parent == incomingBeams().first ||
parent == incomingBeams().second ) return seed;
else return findFirstParton(parent);
}
void QTildeShowerHandler::decay(ShowerTreePtr tree, ShowerDecayMap & decay) {
// must be one incoming particle
assert(tree->incomingLines().size()==1);
// apply any transforms
tree->applyTransforms();
// if already decayed return
if(!tree->outgoingLines().empty()) return;
// now we need to replace the particle with a new copy after the shower
// find particle after the shower
map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator
tit = tree->parent()->treelinks().find(tree);
assert(tit!=tree->parent()->treelinks().end());
ShowerParticlePtr newparent=tit->second.second;
PerturbativeProcessPtr newProcess = new_ptr(PerturbativeProcess());
newProcess->incoming().push_back(make_pair(newparent,PerturbativeProcessPtr()));
DecayProcessMap decayMap;
ShowerHandler::decay(newProcess,decayMap);
ShowerTree::constructTrees(tree,decay,newProcess,decayMap);
}
namespace {
map<ShowerProgenitorPtr,tShowerParticlePtr>::iterator
findFinalStateLine(ShowerTreePtr tree, long id, Lorentz5Momentum momentum) {
map<ShowerProgenitorPtr,tShowerParticlePtr>::iterator partner;
Energy2 dmin(1e30*GeV2);
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::iterator
cit =tree->outgoingLines().begin(); cit!=tree->outgoingLines().end(); ++cit) {
if(cit->second->id()!=id) continue;
Energy2 test =
sqr(cit->second->momentum().x()-momentum.x())+
sqr(cit->second->momentum().y()-momentum.y())+
sqr(cit->second->momentum().z()-momentum.z())+
sqr(cit->second->momentum().t()-momentum.t());
if(test<dmin) {
dmin = test;
partner = cit;
}
}
return partner;
}
map<ShowerProgenitorPtr,ShowerParticlePtr>::iterator
findInitialStateLine(ShowerTreePtr tree, long id, Lorentz5Momentum momentum) {
map<ShowerProgenitorPtr,ShowerParticlePtr>::iterator partner;
Energy2 dmin(1e30*GeV2);
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::iterator
cit =tree->incomingLines().begin(); cit!=tree->incomingLines().end(); ++cit) {
cerr << id << " " << *cit->second << "\n";
if(cit->second->id()!=id) continue;
Energy2 test =
sqr(cit->second->momentum().x()-momentum.x())+
sqr(cit->second->momentum().y()-momentum.y())+
sqr(cit->second->momentum().z()-momentum.z())+
sqr(cit->second->momentum().t()-momentum.t());
if(test<dmin) {
dmin = test;
partner = cit;
}
}
return partner;
}
}
void QTildeShowerHandler::setupMECorrection(RealEmissionProcessPtr real) {
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::iterator it=currentTree()->incomingLines().begin();
it!=currentTree()->incomingLines().end();++it) {
cerr << "BEFORE INCOMING "
<< it->first->progenitor()->colourLine() << " " << it->first->progenitor()->antiColourLine()
<< *it->first->progenitor() << "\n";
}
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::iterator it=currentTree()->outgoingLines().begin();
it!=currentTree()->outgoingLines().end();++it) {
cerr << "BEFORE OUTGOING "
<< it->first->progenitor()->colourLine() << " " << it->first->progenitor()->antiColourLine()
<< *it->first->progenitor() << "\n";
}
assert(real);
currentTree()->hardMatrixElementCorrection(true);
cerr << generator()->currentEvent() << "\n";
cerr << "testing emitter and specator "
<< real->emitter () << " "
<< real->spectator() << " " << real->incoming().size() << "\n";
for(unsigned int ix=0;ix<real->incoming().size();++ix)
cerr << real->incoming()[ix].first-> colourLine() << " "
<< real->incoming()[ix].first->antiColourLine() << " "
<< *real->incoming()[ix].first << "\n";
for(unsigned int ix=0;ix<real->outgoing().size();++ix)
cerr << real->outgoing()[ix].first-> colourLine() << " "
<< real->outgoing()[ix].first->antiColourLine() << " "
<< *real->outgoing()[ix].first << "\n";
// II emission
if(real->emitter() < real->incoming().size() &&
real->spectator() < real->incoming().size()) {
// recoiling system
for( map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt= currentTree()->outgoingLines().begin();
cjt != currentTree()->outgoingLines().end();++cjt ) {
cjt->first->progenitor()->transform(real->transformation());
cjt->first->copy()->transform(real->transformation());
}
// the the radiating system
map<ShowerProgenitorPtr,ShowerParticlePtr>::iterator emitter,spectator;
unsigned int iemit = real->emitter();
unsigned int ispect = real->spectator();
int ig = int(real->emitted())-int(real->incoming().size());
emitter = findInitialStateLine(currentTree(),
real->bornIncoming()[iemit].first->id(),
real->bornIncoming()[iemit].first->momentum());
spectator = findInitialStateLine(currentTree(),
real->bornIncoming()[ispect].first->id(),
real->bornIncoming()[ispect].first->momentum());
// sort out the colours
ColinePair cline,aline;
cline.first = spectator->first->progenitor()->colourLine();
cline.second = real->incoming()[ispect].first->colourLine();
aline.first = spectator->first->progenitor()->antiColourLine();
aline.second = real->incoming()[ispect].first->antiColourLine();
if(cline.first) {
cline.first ->removeColoured(spectator->first->copy());
cline.first ->removeColoured(spectator->first->progenitor());
cline.second->removeColoured(real->incoming()[ispect].first);
cline.first ->addColoured(real->incoming()[ispect].first);
}
if(aline.first) {
aline.first ->removeAntiColoured(spectator->first->copy());
aline.first ->removeAntiColoured(spectator->first->progenitor());
aline.second->removeAntiColoured(real->incoming()[ispect].first);
aline.first ->addAntiColoured(real->incoming()[ispect].first);
}
// update the spectator
spectator->first->copy(real->incoming()[ispect].first);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*real->incoming()[ispect].first,1,false)));
sp->x(ispect ==0 ? real->x().first :real->x().second);
spectator->first->progenitor(sp);
currentTree()->incomingLines()[spectator->first]=sp;
spectator->first->perturbative(true);
// now for the emitter
// sort out the colours
if(real->outgoing()[ig].first->dataPtr()->iColour()==PDT::Colour8) {
// emitter
if(cline.first && cline.first == emitter->first->progenitor()->antiColourLine() &&
cline.second !=real->incoming()[iemit].first->antiColourLine()) {
// sort out not radiating line
ColinePtr col = emitter->first->progenitor()->colourLine();
if(col) {
col->removeColoured(emitter->first->copy());
col->removeColoured(emitter->first->progenitor());
real->incoming()[iemit].first->colourLine()->removeColoured(real->incoming()[iemit].first);
col->addColoured(real->incoming()[iemit].first);
}
}
else if(aline.first && aline.first == emitter->first->progenitor()->colourLine() &&
aline.second !=real->incoming()[iemit].first->colourLine()) {
// sort out not radiating line
ColinePtr anti = emitter->first->progenitor()->antiColourLine();
if(anti) {
anti->removeAntiColoured(emitter->first->copy());
anti->removeAntiColoured(emitter->first->progenitor());
real->incoming()[iemit].first->colourLine()->removeAntiColoured(real->incoming()[iemit].first);
anti->addAntiColoured(real->incoming()[iemit].first);
}
}
else
assert(false);
// emitted
if(cline.first && cline.second==real->outgoing()[ig].first->colourLine()) {
cline.second->removeColoured(real->outgoing()[ig].first);
cline.first->addColoured(real->outgoing()[ig].first);
}
else if(aline.first && aline.second==real->outgoing()[ig].first->antiColourLine()) {
aline.second->removeAntiColoured(real->outgoing()[ig].first);
aline.first->addAntiColoured(real->outgoing()[ig].first);
}
else
assert(false);
}
else {
if(emitter->first->progenitor()->antiColourLine() ) {
ColinePtr col = emitter->first->progenitor()->antiColourLine();
col->removeAntiColoured(emitter->first->copy());
col->removeAntiColoured(emitter->first->progenitor());
if(real->incoming()[iemit].first->antiColourLine()) {
real->incoming()[iemit].first->antiColourLine()->removeAntiColoured(real->incoming()[iemit].first);
col->addAntiColoured(real->incoming()[iemit].first);
}
else if (real->outgoing()[ig].first->colourLine()) {
real->outgoing()[ig].first->colourLine()->removeColoured(real->outgoing()[ig].first);
col->addColoured(real->outgoing()[ig].first);
}
else
assert(false);
}
if(emitter->first->progenitor()->colourLine() ) {
ColinePtr col = emitter->first->progenitor()->colourLine();
col->removeColoured(emitter->first->copy());
col->removeColoured(emitter->first->progenitor());
if(real->incoming()[iemit].first->colourLine()) {
real->incoming()[iemit].first->colourLine()->removeColoured(real->incoming()[iemit].first);
col->addColoured(real->incoming()[iemit].first);
}
else if (real->outgoing()[ig].first->antiColourLine()) {
real->outgoing()[ig].first->antiColourLine()->removeAntiColoured(real->outgoing()[ig].first);
col->addAntiColoured(real->outgoing()[ig].first);
}
else
assert(false);
}
}
// update the emitter
emitter->first->copy(real->incoming()[iemit].first);
sp = new_ptr(ShowerParticle(*real->incoming()[iemit].first,1,false));
sp->x(iemit ==0 ? real->x().first :real->x().second);
emitter->first->progenitor(sp);
currentTree()->incomingLines()[emitter->first]=sp;
emitter->first->perturbative(false);
// add emitted
sp=new_ptr(ShowerParticle(*real->outgoing()[ig].first,1,true));
ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(emitter->first->original(),
real->outgoing()[ig].first,sp));
gluon->perturbative(false);
currentTree()->outgoingLines().insert(make_pair(gluon,sp));
cerr << "II dipole\n";
}
// FF emission
else if(real->emitter() >= real->incoming().size() &&
real->spectator() >= real->incoming().size()) {
assert(real->outgoing()[real->emitted()-2].first->id()==ParticleID::g);
// find the emitter and spectator in the shower tree
map<ShowerProgenitorPtr,tShowerParticlePtr>::iterator emitter,spectator;
int iemit = int(real->emitter())-int(real->incoming().size());
emitter = findFinalStateLine(currentTree(),
real->bornOutgoing()[iemit].first->id(),
real->bornOutgoing()[iemit].first->momentum());
int ispect = int(real->spectator())-int(real->incoming().size());
spectator = findFinalStateLine(currentTree(),
real->bornOutgoing()[ispect].first->id(),
real->bornOutgoing()[ispect].first->momentum());
map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator tit;
// first the spectator
// special case if decayed
for(tit = currentTree()->treelinks().begin(); tit != currentTree()->treelinks().end();++tit) {
if(tit->second.first && tit->second.second==spectator->first->progenitor())
break;
}
// sort out the colours
ColinePair cline,aline;
cline.first = spectator->first->progenitor()->colourLine();
cline.second = real->outgoing()[ispect].first->colourLine();
aline.first = spectator->first->progenitor()->antiColourLine();
aline.second = real->outgoing()[ispect].first->antiColourLine();
if(cline.first) {
cline.first ->removeColoured(spectator->first->copy());
cline.first ->removeColoured(spectator->first->progenitor());
cline.second->removeColoured(real->outgoing()[ispect].first);
cline.first ->addColoured(real->outgoing()[ispect].first);
}
if(aline.first) {
aline.first ->removeAntiColoured(spectator->first->copy());
aline.first ->removeAntiColoured(spectator->first->progenitor());
aline.second->removeAntiColoured(real->outgoing()[ispect].first);
aline.first ->addAntiColoured(real->outgoing()[ispect].first);
}
// update the spectator
spectator->first->copy(real->outgoing()[ispect].first);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*real->outgoing()[ispect].first,1,true)));
spectator->first->progenitor(sp);
currentTree()->outgoingLines()[spectator->first]=sp;
spectator->first->perturbative(true);
// update for decaying particles
if(tit!=currentTree()->treelinks().end())
currentTree()->updateLink(tit->first,make_pair(spectator->first,sp));
// now the emitting particle
// if decaying
for(tit = currentTree()->treelinks().begin(); tit != currentTree()->treelinks().end();++tit) {
if(tit->second.first && tit->second.second==emitter->first->progenitor())
break;
}
// sort out the colour lines
if(cline.first && cline.first == emitter->first->progenitor()->antiColourLine() &&
cline.second !=real->outgoing()[iemit].first->antiColourLine()) {
// sort out not radiating line
ColinePtr col = emitter->first->progenitor()->colourLine();
if(col) {
col->removeColoured(emitter->first->copy());
col->removeColoured(emitter->first->progenitor());
real->outgoing()[iemit].first->colourLine()->removeColoured(real->outgoing()[iemit].first);
col->addColoured(real->outgoing()[iemit].first);
}
}
else if(aline.first && aline.first == emitter->first->progenitor()->colourLine() &&
aline.second !=real->outgoing()[iemit].first->colourLine()) {
cerr << "col line radiates\n";
// sort out not radiating line
ColinePtr anti = emitter->first->progenitor()->antiColourLine();
if(anti) {
anti->removeAntiColoured(emitter->first->copy());
anti->removeAntiColoured(emitter->first->progenitor());
real->outgoing()[iemit].first->colourLine()->removeAntiColoured(real->outgoing()[iemit].first);
anti->addAntiColoured(real->outgoing()[iemit].first);
}
}
else
assert(false);
// update the emitter
emitter->first->copy(real->outgoing()[iemit].first);
sp = new_ptr(ShowerParticle(*real->outgoing()[iemit].first,1,true));
emitter->first->progenitor(sp);
currentTree()->outgoingLines()[emitter->first]=sp;
emitter->first->perturbative(false);
// update for decaying particles
if(tit!=currentTree()->treelinks().end())
currentTree()->updateLink(tit->first,make_pair(emitter->first,sp));
// add the emitted particle
int ig = int(real->emitted())-int(real->incoming().size());
// sort out the colour
if(cline.first && cline.second==real->outgoing()[ig].first->antiColourLine()) {
cline.second->removeAntiColoured(real->outgoing()[ig].first);
cline.first->addAntiColoured(real->outgoing()[ig].first);
}
else if(aline.first && aline.second==real->outgoing()[ig].first->colourLine()) {
aline.second->removeColoured(real->outgoing()[ig].first);
aline.first->addColoured(real->outgoing()[ig].first);
}
else
assert(false);
sp=new_ptr(ShowerParticle(*real->outgoing()[ig].first,1,true));
ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(emitter->first->original(),
real->outgoing()[ig].first,sp));
gluon->perturbative(false);
currentTree()->outgoingLines().insert(make_pair(gluon,sp));
}
// IF emission
else {
cerr << "IF dipole\n";
assert(false);
}
// clean up the shower tree
_currenttree->resetShowerProducts();
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::iterator it=currentTree()->incomingLines().begin();
it!=currentTree()->incomingLines().end();++it) {
cerr << "AFTER INCOMING "
<< it->first->progenitor()->colourLine() << " " << it->first->progenitor()->antiColourLine()
<< *it->first->progenitor() << "\n";
}
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::iterator it=currentTree()->outgoingLines().begin();
it!=currentTree()->outgoingLines().end();++it) {
cerr << "AFTER OUTGOING "
<< it->first->progenitor()->colourLine() << " " << it->first->progenitor()->antiColourLine()
<< *it->first->progenitor() << "\n";
}
}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Feb 23, 2:28 PM (15 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4486606
Default Alt Text
(492 KB)

Event Timeline