Page MenuHomeHEPForge

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/Decay/General/FFSDecayer.cc b/Decay/General/FFSDecayer.cc
--- a/Decay/General/FFSDecayer.cc
+++ b/Decay/General/FFSDecayer.cc
@@ -1,410 +1,405 @@
// -*- C++ -*-
//
// FFSDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FFSDecayer class.
//
#include "FFSDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr FFSDecayer::clone() const {
return new_ptr(*this);
}
IBPtr FFSDecayer::fullclone() const {
return new_ptr(*this);
}
-void FFSDecayer::doinit() {
- perturbativeVertex_ = dynamic_ptr_cast<FFSVertexPtr> (vertex());
- abstractVertex_ = dynamic_ptr_cast<AbstractFFSVertexPtr>(vertex());
- abstractIncomingVertex_ = dynamic_ptr_cast<AbstractFFVVertexPtr>(incomingVertex());
-
- if (outgoingVertices()[0]){
- if (outgoingVertices()[0]->getName()==VertexType::FFV){
- abstractOutgoingVertexF_ = dynamic_ptr_cast<AbstractFFVVertexPtr>(outgoingVertices()[0]);
- abstractOutgoingVertexS_ = dynamic_ptr_cast<AbstractVSSVertexPtr>(outgoingVertices()[1]);
+void FFSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
+ VertexBasePtr vertex,
+ map<ShowerInteraction,VertexBasePtr> & inV,
+ const vector<map<ShowerInteraction,VertexBasePtr> > & outV,
+ map<ShowerInteraction,VertexBasePtr> ) {
+ decayInfo(incoming,outgoing);
+ vertex_ = dynamic_ptr_cast<AbstractFFSVertexPtr>(vertex);
+ perturbativeVertex_ = dynamic_ptr_cast<FFSVertexPtr> (vertex);
+ vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
+ for(auto & inter : itemp) {
+ incomingVertex_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr>(inV.at(inter));
+ if (outV[0].at(inter)->getName()==VertexType::FFV){
+ outgoingVertexF_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr>(outV[0].at(inter));
+ outgoingVertexS_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(outV[1].at(inter));
}
else {
- abstractOutgoingVertexF_ = dynamic_ptr_cast<AbstractFFVVertexPtr>(outgoingVertices()[1]);
- abstractOutgoingVertexS_ = dynamic_ptr_cast<AbstractVSSVertexPtr>(outgoingVertices()[0]);
+ outgoingVertexF_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr>(outV[1].at(inter));
+ outgoingVertexS_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(outV[0].at(inter));
}
}
- else if (outgoingVertices()[1]){
- if (outgoingVertices()[1]->getName()==VertexType::FFV){
- abstractOutgoingVertexF_ = dynamic_ptr_cast<AbstractFFVVertexPtr>(outgoingVertices()[1]);
- abstractOutgoingVertexS_ = dynamic_ptr_cast<AbstractVSSVertexPtr>(outgoingVertices()[0]);
- }
- else {
- abstractOutgoingVertexF_ = dynamic_ptr_cast<AbstractFFVVertexPtr>(outgoingVertices()[0]);
- abstractOutgoingVertexS_ = dynamic_ptr_cast<AbstractVSSVertexPtr>(outgoingVertices()[1]);
- }
- }
- GeneralTwoBodyDecayer::doinit();
}
void FFSDecayer::persistentOutput(PersistentOStream & os) const {
- os << perturbativeVertex_ << abstractVertex_
- << abstractIncomingVertex_ << abstractOutgoingVertexF_
- << abstractOutgoingVertexS_;
+ os << perturbativeVertex_ << vertex_
+ << incomingVertex_ << outgoingVertexF_
+ << outgoingVertexS_;
}
void FFSDecayer::persistentInput(PersistentIStream & is, int) {
- is >> perturbativeVertex_ >> abstractVertex_
- >> abstractIncomingVertex_ >> abstractOutgoingVertexF_
- >> abstractOutgoingVertexS_;
+ is >> perturbativeVertex_ >> vertex_
+ >> incomingVertex_ >> outgoingVertexF_
+ >> outgoingVertexS_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<FFSDecayer,GeneralTwoBodyDecayer>
describeHerwigFFSDecayer("Herwig::FFSDecayer", "Herwig.so");
void FFSDecayer::Init() {
static ClassDocumentation<FFSDecayer> documentation
("The FFSDecayer class implements the decay of a fermion to "
"a fermion and a scalar.");
}
double FFSDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin1Half,PDT::Spin0)));
//Need to use different barred or unbarred spinors depending on
//whether particle is cc or not.
int itype[2];
if(inpart.dataPtr()->CC()) itype[0] = inpart.id() > 0? 0:1;
else itype[0] = 2;
if(decay[0]->dataPtr()->CC()) itype[1] = decay[0]->id() > 0? 0:1;
else itype[1] = 2;
bool ferm(itype[0] == 0 || itype[1] == 0 || (itype[0] == 2 && itype[1] == 2));
if(meopt==Initialize) {
// spinors and rho
if(ferm) {
SpinorWaveFunction ::calculateWaveFunctions(wave_,rho_,
const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wave_[0].wave().Type() != SpinorType::u)
for(unsigned int ix = 0; ix < 2; ++ix) wave_ [ix].conjugate();
}
else {
SpinorBarWaveFunction::calculateWaveFunctions(wavebar_,rho_,
const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wavebar_[0].wave().Type() != SpinorType::v)
for(unsigned int ix = 0; ix < 2; ++ix) wavebar_[ix].conjugate();
}
}
// setup spin info when needed
if(meopt==Terminate) {
// for the decaying particle
if(ferm) {
SpinorWaveFunction::
constructSpinInfo(wave_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
SpinorBarWaveFunction::constructSpinInfo(wavebar_,decay[0],outgoing,true);
}
else {
SpinorBarWaveFunction::
constructSpinInfo(wavebar_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
SpinorWaveFunction::constructSpinInfo(wave_,decay[0],outgoing,true);
}
ScalarWaveFunction::constructSpinInfo(decay[1],outgoing,true);
}
if(ferm)
SpinorBarWaveFunction::
calculateWaveFunctions(wavebar_,decay[0],outgoing);
else
SpinorWaveFunction::
calculateWaveFunctions(wave_ ,decay[0],outgoing);
ScalarWaveFunction scal(decay[1]->momentum(),decay[1]->dataPtr(),outgoing);
Energy2 scale(sqr(inpart.mass()));
for(unsigned int if1 = 0; if1 < 2; ++if1) {
for(unsigned int if2 = 0; if2 < 2; ++if2) {
if(ferm) (*ME())(if1, if2, 0) =
- abstractVertex_->evaluate(scale,wave_[if1],wavebar_[if2],scal);
+ vertex_->evaluate(scale,wave_[if1],wavebar_[if2],scal);
else (*ME())(if2, if1, 0) =
- abstractVertex_->evaluate(scale,wave_[if1],wavebar_[if2],scal);
+ vertex_->evaluate(scale,wave_[if1],wavebar_[if2],scal);
}
}
double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy FFSDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
if(perturbativeVertex_) {
double mu1(0.),mu2(0.);
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
if(outa.first->iSpin() == PDT::Spin1Half) {
mu1 = outa.second/inpart.second;
mu2 = outb.second/inpart.second;
perturbativeVertex_->setCoupling(sqr(inpart.second), in, outa.first, outb.first);
}
else {
mu1 = outb.second/inpart.second;
mu2 = outa.second/inpart.second;
perturbativeVertex_->setCoupling(sqr(inpart.second), in, outb.first, outa.first);
}
double c2 = norm(perturbativeVertex_->norm());
Complex cl = perturbativeVertex_->left();
Complex cr = perturbativeVertex_->right();
double me2 = c2*( (norm(cl) + norm(cr))*(1. + sqr(mu1) - sqr(mu2))
+ 2.*mu1*(conj(cl)*cr + conj(cr)*cl).real() );
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second, outa.second,
outb.second);
Energy output = me2*pcm/16./Constants::pi;
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
double FFSDecayer::threeBodyME(const int , const Particle & inpart,
- const ParticleVector & decay, MEOption meopt) {
+ const ParticleVector & decay,
+ ShowerInteraction inter, MEOption meopt) {
int iscal (0), iferm (1), iglu (2);
// get location of outgoing fermion/scalar
if(decay[1]->dataPtr()->iSpin()==PDT::Spin0) swap(iscal,iferm);
// work out whether inpart is a fermion or antifermion
int itype[2];
if(inpart.dataPtr()->CC()) itype[0] = inpart.id() > 0 ? 0 : 1;
else itype[0] = 2;
if(decay[iferm]->dataPtr()->CC()) itype[1] = decay[iferm]->id() > 0 ? 0 : 1;
else itype[1] = 2;
bool ferm(itype[0] == 0 || itype[1] == 0 ||
(itype[0] == 2 && itype[1] == 2 && decay[iscal]->id() < 0));
if(meopt==Initialize) {
// create spinor (bar) for decaying particle
if(ferm) {
SpinorWaveFunction::calculateWaveFunctions(wave3_, rho3_, const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wave3_[0].wave().Type() != SpinorType::u)
for(unsigned int ix = 0; ix < 2; ++ix) wave3_[ix].conjugate();
}
else {
SpinorBarWaveFunction::calculateWaveFunctions(wavebar3_,rho3_, const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wavebar3_[0].wave().Type() != SpinorType::v)
for(unsigned int ix = 0; ix < 2; ++ix) wavebar3_[ix].conjugate();
}
}
// setup spin information when needed
if(meopt==Terminate) {
if(ferm) {
SpinorWaveFunction::
constructSpinInfo(wave3_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
SpinorBarWaveFunction::constructSpinInfo(wavebar3_,decay[iferm],outgoing,true);
}
else {
SpinorBarWaveFunction::
constructSpinInfo(wavebar3_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
SpinorWaveFunction::constructSpinInfo(wave3_,decay[iferm],outgoing,true);
}
ScalarWaveFunction::constructSpinInfo( decay[iscal],outgoing,true);
VectorWaveFunction::constructSpinInfo(gluon_, decay[iglu ],outgoing,true,false);
return 0.;
}
// calulate colour factors and number of colour flows
unsigned int nflow;
vector<DVector> cfactors = getColourFactors(inpart, decay, nflow);
if(nflow==2) cfactors[0][1] = cfactors[1][0];
vector<GeneralDecayMEPtr> ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half, PDT::Spin0,
PDT::Spin1Half, PDT::Spin1)));
// create wavefunctions
if (ferm) SpinorBarWaveFunction::calculateWaveFunctions(wavebar3_, decay[iferm],outgoing);
else SpinorWaveFunction:: calculateWaveFunctions(wave3_ , decay[iferm],outgoing);
ScalarWaveFunction swave3_(decay[iscal]->momentum(), decay[iscal]->dataPtr(),outgoing);
VectorWaveFunction::calculateWaveFunctions(gluon_, decay[iglu ],outgoing,true);
// // gauge invariance test
// gluon_.clear();
// for(unsigned int ix=0;ix<3;++ix) {
// if(ix==1) gluon_.push_back(VectorWaveFunction());
// else {
// gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(),
// decay[iglu ]->dataPtr(),10,
// outgoing));
// }
// }
- if (! ((abstractIncomingVertex_ && (abstractOutgoingVertexF_ || abstractOutgoingVertexS_)) ||
- (abstractOutgoingVertexF_ && abstractOutgoingVertexS_)))
+ if (! ((incomingVertex_[inter] && (outgoingVertexF_[inter] || outgoingVertexS_[inter])) ||
+ (outgoingVertexF_[inter] && outgoingVertexS_[inter])))
throw Exception()
- << "Invalid vertices for QCD radiation in FFS decay in FFSDecayer::threeBodyME"
+ << "Invalid vertices for radiation in FFS decay in FFSDecayer::threeBodyME"
<< Exception::runerror;
// sort out colour flows
int F(1), S(2);
if (decay[iscal]->dataPtr()->iColour()==PDT::Colour3 &&
decay[iferm]->dataPtr()->iColour()==PDT::Colour8)
swap(F,S);
else if (decay[iferm]->dataPtr()->iColour()==PDT::Colour3bar &&
decay[iscal]->dataPtr()->iColour()==PDT::Colour8)
swap(F,S);
Complex diag;
Energy2 scale(sqr(inpart.mass()));
const GeneralTwoBodyDecayer::CFlow & colourFlow
= colourFlows(inpart, decay);
for(unsigned int ifi = 0; ifi < 2; ++ifi) {
for(unsigned int ifo = 0; ifo < 2; ++ifo) {
for(unsigned int ig = 0; ig < 2; ++ig) {
// radiation from the incoming fermion
if(inpart.dataPtr()->coloured()) {
- assert(abstractIncomingVertex_);
- double gs = abstractIncomingVertex_->strongCoupling(scale);
+ assert(incomingVertex_[inter]);
+ double gs = incomingVertex_[inter]->strongCoupling(scale);
if (ferm){
SpinorWaveFunction spinorInter =
- abstractIncomingVertex_->evaluate(scale,3,inpart.dataPtr(),wave3_[ifi],
+ incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),wave3_[ifi],
gluon_[2*ig],inpart.mass());
if (wave3_[ifi].particle()->PDGName()!=spinorInter.particle()->PDGName())
throw Exception()
<< wave3_[ifi].particle()->PDGName() << " was changed to "
<< spinorInter.particle()->PDGName() << " in FFSDecayer::threeBodyME"
<< Exception::runerror;
- diag = abstractVertex_->evaluate(scale,spinorInter,wavebar3_[ifo],swave3_)/gs;
+ diag = vertex_->evaluate(scale,spinorInter,wavebar3_[ifo],swave3_)/gs;
}
else {
SpinorBarWaveFunction spinorBarInter =
- abstractIncomingVertex_->evaluate(scale,3,inpart.dataPtr(),wavebar3_[ifi],
+ incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),wavebar3_[ifi],
gluon_[2*ig],inpart.mass());
if (wavebar3_[ifi].particle()->PDGName()!=spinorBarInter.particle()->PDGName())
throw Exception()
<< wavebar3_[ifi].particle()->PDGName() << " was changed to "
<< spinorBarInter.particle()->PDGName() << " in FFSDecayer::threeBodyME"
<< Exception::runerror;
- diag = abstractVertex_->evaluate(scale,wave3_[ifo], spinorBarInter,swave3_)/gs;
+ diag = vertex_->evaluate(scale,wave3_[ifo], spinorBarInter,swave3_)/gs;
}
for(unsigned int ix=0;ix<colourFlow[0].size();++ix) {
(*ME[colourFlow[0][ix].first])(ifi, 0, ifo, ig) +=
colourFlow[0][ix].second*diag;
}
}
// radiation from outgoing fermion
if(decay[iferm]->dataPtr()->coloured()) {
- assert(abstractOutgoingVertexF_);
+ assert(outgoingVertexF_[inter]);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[iferm]->dataPtr();
if(off->CC()) off = off->CC();
- double gs = abstractOutgoingVertexF_->strongCoupling(scale);
+ double gs = outgoingVertexF_[inter]->strongCoupling(scale);
if (ferm) {
SpinorBarWaveFunction spinorBarInter =
- abstractOutgoingVertexF_->evaluate(scale,3,off,wavebar3_[ifo],
+ outgoingVertexF_[inter]->evaluate(scale,3,off,wavebar3_[ifo],
gluon_[2*ig],decay[iferm]->mass());
if(wavebar3_[ifo].particle()->PDGName()!=spinorBarInter.particle()->PDGName())
throw Exception()
<< wavebar3_[ifo].particle()->PDGName() << " was changed to "
<< spinorBarInter.particle()->PDGName() << " in FFSDecayer::threeBodyME"
<< Exception::runerror;
- diag = abstractVertex_->evaluate(scale,wave3_[ifi],spinorBarInter,swave3_)/gs;
+ diag = vertex_->evaluate(scale,wave3_[ifi],spinorBarInter,swave3_)/gs;
}
else {
SpinorWaveFunction spinorInter =
- abstractOutgoingVertexF_->evaluate(scale,3,off,wave3_[ifo],
+ outgoingVertexF_[inter]->evaluate(scale,3,off,wave3_[ifo],
gluon_[2*ig],decay[iferm]->mass());
if(wave3_[ifo].particle()->PDGName()!=spinorInter.particle()->PDGName())
throw Exception()
<< wave3_[ifo].particle()->PDGName() << " was changed to "
<< spinorInter.particle()->PDGName() << " in FFSDecayer::threeBodyME"
<< Exception::runerror;
- diag = abstractVertex_->evaluate(scale,spinorInter,wavebar3_[ifi],swave3_)/gs;
+ diag = vertex_->evaluate(scale,spinorInter,wavebar3_[ifi],swave3_)/gs;
}
for(unsigned int ix=0;ix<colourFlow[F].size();++ix) {
(*ME[colourFlow[F][ix].first])(ifi, 0, ifo, ig) +=
colourFlow[F][ix].second*diag;
}
}
// radiation from outgoing scalar
if(decay[iscal]->dataPtr()->coloured()) {
- assert(abstractOutgoingVertexS_);
+ assert(outgoingVertexS_[inter]);
// ensure you get correct ougoing particle from first vertex
tcPDPtr off = decay[iscal]->dataPtr();
if(off->CC()) off = off->CC();
- double gs = abstractOutgoingVertexS_->strongCoupling(scale);
+ double gs = outgoingVertexS_[inter]->strongCoupling(scale);
ScalarWaveFunction scalarInter =
- abstractOutgoingVertexS_->evaluate(scale,3,off,gluon_[2*ig],
+ outgoingVertexS_[inter]->evaluate(scale,3,off,gluon_[2*ig],
swave3_,decay[iscal]->mass());
if(swave3_.particle()->PDGName()!=scalarInter.particle()->PDGName())
throw Exception()
<< swave3_ .particle()->PDGName() << " was changed to "
<< scalarInter.particle()->PDGName() << " in FFSDecayer::threeBodyME"
<< Exception::runerror;
if (ferm){
- diag = abstractVertex_->evaluate(scale,wave3_[ifi],wavebar3_[ifo],scalarInter)/gs;
+ diag = vertex_->evaluate(scale,wave3_[ifi],wavebar3_[ifo],scalarInter)/gs;
}
else {
- diag = abstractVertex_->evaluate(scale,wave3_[ifo],wavebar3_[ifi],scalarInter)/gs;
+ diag = vertex_->evaluate(scale,wave3_[ifo],wavebar3_[ifi],scalarInter)/gs;
}
for(unsigned int ix=0;ix<colourFlow[S].size();++ix) {
(*ME[colourFlow[S][ix].first])(ifi, 0, ifo, ig) +=
colourFlow[S][ix].second*diag;
}
}
}
}
}
// contract matrices
double output=0.;
for(unsigned int ix=0; ix<nflow; ++ix){
for(unsigned int iy=0; iy<nflow; ++iy){
output+=cfactors[ix][iy]*(ME[ix]->contract(*ME[iy],rho3_)).real();
}
}
output*=(4.*Constants::pi);
// return the answer
return output;
}
diff --git a/Decay/General/FFSDecayer.h b/Decay/General/FFSDecayer.h
--- a/Decay/General/FFSDecayer.h
+++ b/Decay/General/FFSDecayer.h
@@ -1,211 +1,208 @@
// -*- C++ -*-
//
// FFSDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_FFSDecayer_H
#define HERWIG_FFSDecayer_H
//
// This is the declaration of the FFSDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Scalar/FFSVertex.h"
#include "ThePEG/Helicity/Vertex/Scalar/VSSVertex.h"
#include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::FFSVertexPtr;
/** \ingroup Decay
* The FFSDecayer class implements the decay of a fermion
* to a fermion and a vector in a general model. It holds an FFVVertex
* pointer that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class FFSDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
FFSDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* 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;
/**
* 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;
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return FSR;}
/**
* Three-body matrix element including additional QCD radiation
*/
virtual double threeBodyME(const int , const Particle & inpart,
- const ParticleVector & decay,MEOption meopt);
+ const ParticleVector & decay,
+ ShowerInteraction inter, MEOption meopt);
+
+ /**
+ * Set the information on the decay
+ */
+ virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr>);
//@}
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 and
- * EventGenerator to disk.
- * @throws InitException if object could not be initialized properly.
- */
- virtual void doinit();
- //@}
-
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
FFSDecayer & operator=(const FFSDecayer &);
private:
/**
* Abstract pointer to AbstractFFSVertex
*/
- AbstractFFSVertexPtr abstractVertex_;
+ AbstractFFSVertexPtr vertex_;
/**
* Pointer to the perturbative vertex
*/
FFSVertexPtr perturbativeVertex_;
/**
* Abstract pointer to AbstractFFVVertex for QCD radiation from incoming (anti)fermion
*/
- AbstractFFVVertexPtr abstractIncomingVertex_;
+ map<ShowerInteraction,AbstractFFVVertexPtr> incomingVertex_;
/**
* Abstract pointer to AbstractFFVVertex for QCD radiation from outgoing (anti)fermion
*/
- AbstractFFVVertexPtr abstractOutgoingVertexF_;
+ map<ShowerInteraction,AbstractFFVVertexPtr> outgoingVertexF_;
/**
* Abstract pointer to AbstractVSSVertex for QCD radiation from outgoing scalar
*/
- AbstractVSSVertexPtr abstractOutgoingVertexS_;
+ map<ShowerInteraction,AbstractVSSVertexPtr> outgoingVertexS_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Spinor wavefunctions
*/
mutable vector<SpinorWaveFunction> wave_ ;
/**
* Barred spinor wavefunctions
*/
mutable vector<SpinorBarWaveFunction> wavebar_;
/**
* Spin density matrix for 3 body decay
*/
mutable RhoDMatrix rho3_;
/**
* Scalar wavefunction for 3 body decay
*/
mutable ScalarWaveFunction swave3_;
/**
* Spinor wavefunction for 3 body decay
*/
mutable vector<SpinorWaveFunction> wave3_;
/**
* Barred spinor wavefunction for 3 body decay
*/
mutable vector<SpinorBarWaveFunction> wavebar3_;
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<VectorWaveFunction> gluon_;
};
}
#endif /* HERWIG_FFSDecayer_H */
diff --git a/Decay/General/FFVDecayer.cc b/Decay/General/FFVDecayer.cc
--- a/Decay/General/FFVDecayer.cc
+++ b/Decay/General/FFVDecayer.cc
@@ -1,431 +1,425 @@
// -*- C++ -*-
//
// FFVDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FFVDecayer class.
//
#include "FFVDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr FFVDecayer::clone() const {
return new_ptr(*this);
}
IBPtr FFVDecayer::fullclone() const {
return new_ptr(*this);
}
-void FFVDecayer::doinit() {
- perturbativeVertex_ = dynamic_ptr_cast<FFVVertexPtr> (vertex());
- abstractVertex_ = dynamic_ptr_cast<AbstractFFVVertexPtr>(vertex());
- abstractIncomingVertex_ = dynamic_ptr_cast<AbstractFFVVertexPtr>(incomingVertex());
-
- if (outgoingVertices()[0]){
- if (outgoingVertices()[0]->getName()==VertexType::FFV){
- abstractOutgoingVertexF_ = dynamic_ptr_cast<AbstractFFVVertexPtr>(outgoingVertices()[0]);
- abstractOutgoingVertexV_ = dynamic_ptr_cast<AbstractVVVVertexPtr>(outgoingVertices()[1]);
+void FFVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
+ VertexBasePtr vertex,
+ map<ShowerInteraction,VertexBasePtr> & inV,
+ const vector<map<ShowerInteraction,VertexBasePtr> > & outV,
+ map<ShowerInteraction,VertexBasePtr> ) {
+ decayInfo(incoming,outgoing);
+ vertex_ = dynamic_ptr_cast<AbstractFFVVertexPtr>(vertex);
+ perturbativeVertex_ = dynamic_ptr_cast<FFVVertexPtr> (vertex);
+ vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
+ for(auto & inter : itemp) {
+ incomingVertex_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr>(inV.at(inter));
+ if (outV[0].at(inter)->getName()==VertexType::FFV){
+ outgoingVertexF_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr>(outV[0].at(inter));
+ outgoingVertexV_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr>(outV[1].at(inter));
}
else {
- abstractOutgoingVertexF_ = dynamic_ptr_cast<AbstractFFVVertexPtr>(outgoingVertices()[1]);
- abstractOutgoingVertexV_ = dynamic_ptr_cast<AbstractVVVVertexPtr>(outgoingVertices()[0]);
+ outgoingVertexF_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr>(outV[1].at(inter));
+ outgoingVertexV_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr>(outV[0].at(inter));
}
}
- else if (outgoingVertices()[1]){
- if (outgoingVertices()[1]->getName()==VertexType::FFV){
- abstractOutgoingVertexF_ = dynamic_ptr_cast<AbstractFFVVertexPtr>(outgoingVertices()[1]);
- abstractOutgoingVertexV_ = dynamic_ptr_cast<AbstractVVVVertexPtr>(outgoingVertices()[0]);
- }
- else {
- abstractOutgoingVertexF_ = dynamic_ptr_cast<AbstractFFVVertexPtr>(outgoingVertices()[0]);
- abstractOutgoingVertexV_ = dynamic_ptr_cast<AbstractVVVVertexPtr>(outgoingVertices()[1]);
- }
- }
-
- GeneralTwoBodyDecayer::doinit();
}
void FFVDecayer::persistentOutput(PersistentOStream & os) const {
- os << abstractVertex_ << perturbativeVertex_
- << abstractIncomingVertex_ << abstractOutgoingVertexF_
- << abstractOutgoingVertexV_;
+ os << vertex_ << perturbativeVertex_
+ << incomingVertex_ << outgoingVertexF_
+ << outgoingVertexV_;
}
void FFVDecayer::persistentInput(PersistentIStream & is, int) {
- is >> abstractVertex_ >> perturbativeVertex_
- >> abstractIncomingVertex_ >> abstractOutgoingVertexF_
- >> abstractOutgoingVertexV_;
+ is >> vertex_ >> perturbativeVertex_
+ >> incomingVertex_ >> outgoingVertexF_
+ >> outgoingVertexV_;
}
double FFVDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin1Half,PDT::Spin1)));
// type of process
int itype[2];
if(inpart.dataPtr()->CC()) itype[0] = inpart.id() > 0 ? 0 : 1;
else itype[0] = 2;
if(decay[0]->dataPtr()->CC()) itype[1] = decay[0]->id() > 0 ? 0 : 1;
else itype[1] = 2;
//Need to use different barred or unbarred spinors depending on
//whether particle is cc or not.
bool ferm(itype[0] == 0 || itype[1] == 0 || (itype[0] == 2 && itype[1] == 2));
if(meopt==Initialize) {
// spinors and rho
if(ferm) {
SpinorWaveFunction ::calculateWaveFunctions(wave_,rho_,
const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wave_[0].wave().Type() != SpinorType::u)
for(unsigned int ix = 0; ix < 2; ++ix) wave_ [ix].conjugate();
}
else {
SpinorBarWaveFunction::calculateWaveFunctions(wavebar_,rho_,
const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wavebar_[0].wave().Type() != SpinorType::v)
for(unsigned int ix = 0; ix < 2; ++ix) wavebar_[ix].conjugate();
}
}
// setup spin info when needed
if(meopt==Terminate) {
// for the decaying particle
if(ferm) {
SpinorWaveFunction::
constructSpinInfo(wave_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
SpinorBarWaveFunction::constructSpinInfo(wavebar_,decay[0],outgoing,true);
}
else {
SpinorBarWaveFunction::
constructSpinInfo(wavebar_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
SpinorWaveFunction::constructSpinInfo(wave_,decay[0],outgoing,true);
}
VectorWaveFunction::
constructSpinInfo(vector_,decay[1],outgoing,true,false);
}
Energy2 scale(sqr(inpart.mass()));
if(ferm)
SpinorBarWaveFunction::
calculateWaveFunctions(wavebar_,decay[0],outgoing);
else
SpinorWaveFunction::
calculateWaveFunctions(wave_ ,decay[0],outgoing);
bool massless = decay[1]->dataPtr()->mass()==ZERO;
VectorWaveFunction::
calculateWaveFunctions(vector_,decay[1],outgoing,massless);
for(unsigned int if1 = 0; if1 < 2; ++if1) {
for(unsigned int if2 = 0; if2 < 2; ++if2) {
for(unsigned int vhel = 0; vhel < 3; ++vhel) {
if(massless && vhel == 1) ++vhel;
if(ferm)
(*ME())(if1, if2,vhel) =
- abstractVertex_->evaluate(scale,wave_[if1],wavebar_[if2],vector_[vhel]);
+ vertex_->evaluate(scale,wave_[if1],wavebar_[if2],vector_[vhel]);
else
(*ME())(if2, if1, vhel) =
- abstractVertex_->evaluate(scale,wave_[if1],wavebar_[if2],vector_[vhel]);
+ vertex_->evaluate(scale,wave_[if1],wavebar_[if2],vector_[vhel]);
}
}
}
double output=(ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),decay[1]->dataPtr());
// return the answer
return output;
}
Energy FFVDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
if(perturbativeVertex_) {
double mu1(outa.second/inpart.second),mu2(outb.second/inpart.second);
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
if( outa.first->iSpin() == PDT::Spin1Half)
perturbativeVertex_->setCoupling(sqr(inpart.second), in,
outa.first, outb.first);
else {
swap(mu1,mu2);
perturbativeVertex_->setCoupling(sqr(inpart.second),in,
outb.first,outa.first);
}
Complex cl(perturbativeVertex_->left()),cr(perturbativeVertex_->right());
double me2(0.);
if( mu2 > 0. ) {
me2 = (norm(cl) + norm(cr))*(1. + sqr(mu1*mu2) + sqr(mu2)
- 2.*sqr(mu1) - 2.*sqr(mu2*mu2)
+ sqr(mu1*mu1))
- 6.*mu1*sqr(mu2)*(conj(cl)*cr + conj(cr)*cl).real();
me2 /= sqr(mu2);
}
else
me2 = 2.*( (norm(cl) + norm(cr))*(sqr(mu1) + 1.)
- 4.*mu1*(conj(cl)*cr + conj(cr)*cl).real() );
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second, outa.second,
outb.second);
Energy output = norm(perturbativeVertex_->norm())*me2*pcm/16./Constants::pi;
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<FFVDecayer,GeneralTwoBodyDecayer>
describeHerwigFFVDecayer("Herwig::FFVDecayer", "Herwig.so");
void FFVDecayer::Init() {
static ClassDocumentation<FFVDecayer> documentation
("There is no documentation for the FFVDecayer class");
}
double FFVDecayer::threeBodyME(const int , const Particle & inpart,
- const ParticleVector & decay, MEOption meopt) {
+ const ParticleVector & decay,
+ ShowerInteraction inter, MEOption meopt) {
int iferm (0), ivect (1), iglu (2);
// get location of outgoing lepton/vector
if(decay[1]->dataPtr()->iSpin()==PDT::Spin1Half) swap(iferm,ivect);
// work out whether inpart is a fermion or antifermion
int itype[2];
if(inpart.dataPtr()->CC()) itype[0] = inpart.id() > 0 ? 0 : 1;
else itype[0] = 2;
if(decay[iferm]->dataPtr()->CC()) itype[1] = decay[iferm]->id() > 0 ? 0 : 1;
else itype[1] = 2;
bool ferm(itype[0] == 0 || itype[1] == 0 ||
(itype[0] == 2 && itype[1] == 2 && decay[ivect]->id() < 0));
// no emissions from massive vectors
bool massless = decay[ivect]->dataPtr()->mass()==ZERO;
- if (abstractOutgoingVertexV_ && (! massless))
+ if (outgoingVertexV_[inter] && (! massless))
throw Exception()
<< "No dipoles available for massive vectors in FFVDecayer::threeBodyME"
<< Exception::runerror;
if(meopt==Initialize) {
// create spinor (bar) for decaying particle
if(ferm) {
SpinorWaveFunction::calculateWaveFunctions(wave3_, rho3_, const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wave3_[0].wave().Type() != SpinorType::u)
for(unsigned int ix = 0; ix < 2; ++ix) wave3_[ix].conjugate();
}
else {
SpinorBarWaveFunction::calculateWaveFunctions(wavebar3_,rho3_, const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wavebar3_[0].wave().Type() != SpinorType::v)
for(unsigned int ix = 0; ix < 2; ++ix) wavebar3_[ix].conjugate();
}
}
// setup spin information when needed
if(meopt==Terminate) {
if(ferm) {
SpinorWaveFunction::
constructSpinInfo(wave3_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
SpinorBarWaveFunction::constructSpinInfo(wavebar3_,decay[iferm],outgoing,true);
}
else {
SpinorBarWaveFunction::
constructSpinInfo(wavebar3_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
SpinorWaveFunction::constructSpinInfo(wave3_,decay[iferm],outgoing,true);
}
VectorWaveFunction::constructSpinInfo(vector3_, decay[ivect],outgoing,true,massless);
VectorWaveFunction::constructSpinInfo(gluon_, decay[iglu ],outgoing,true,false);
return 0.;
}
// calulate colour factors and number of colour flows
unsigned int nflow;
vector<DVector> cfactors = getColourFactors(inpart, decay, nflow);
if(nflow==2) cfactors[0][1] = cfactors[1][0];
vector<GeneralDecayMEPtr> ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half, PDT::Spin1Half,
PDT::Spin1, PDT::Spin1)));
// create wavefunctions
if (ferm) SpinorBarWaveFunction::calculateWaveFunctions(wavebar3_, decay[iferm],outgoing);
else SpinorWaveFunction:: calculateWaveFunctions(wave3_ , decay[iferm],outgoing);
VectorWaveFunction::calculateWaveFunctions(vector3_, decay[ivect],outgoing,massless);
VectorWaveFunction::calculateWaveFunctions(gluon_, decay[iglu ],outgoing,true );
// // gauge invariance test
// gluon_.clear();
// for(unsigned int ix=0;ix<3;++ix) {
// if(ix==1) gluon_.push_back(VectorWaveFunction());
// else {
// gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(),
// decay[iglu ]->dataPtr(),10,
// outgoing));
// }
// }
- if (! ((abstractIncomingVertex_ && (abstractOutgoingVertexF_ || abstractOutgoingVertexV_)) ||
- (abstractOutgoingVertexF_ && abstractOutgoingVertexV_)))
+ if (! ((incomingVertex_[inter] && (outgoingVertexF_[inter] || outgoingVertexV_[inter])) ||
+ (outgoingVertexF_[inter] && outgoingVertexV_[inter])))
throw Exception()
<< "Invalid vertices for QCD radiation in FFV decay in FFVDecayer::threeBodyME"
<< Exception::runerror;
// sort out colour flows
int F(1), V(2);
if (decay[iferm]->dataPtr()->iColour()==PDT::Colour3bar &&
decay[ivect]->dataPtr()->iColour()==PDT::Colour8)
swap(F,V);
else if (decay[ivect]->dataPtr()->iColour()==PDT::Colour3 &&
decay[iferm]->dataPtr()->iColour()==PDT::Colour8)
swap(F,V);
Complex diag;
Energy2 scale(sqr(inpart.mass()));
const GeneralTwoBodyDecayer::CFlow & colourFlow
= colourFlows(inpart, decay);
for(unsigned int ifi = 0; ifi < 2; ++ifi) {
for(unsigned int ifo = 0; ifo < 2; ++ifo) {
for(unsigned int iv = 0; iv < 3; ++iv) {
for(unsigned int ig = 0; ig < 2; ++ig) {
// radiation from the incoming fermion
if(inpart.dataPtr()->coloured()) {
- assert(abstractIncomingVertex_);
- double gs = abstractIncomingVertex_->strongCoupling(scale);
+ assert(incomingVertex_[inter]);
+ double gs = incomingVertex_[inter]->strongCoupling(scale);
if (ferm){
SpinorWaveFunction spinorInter =
- abstractIncomingVertex_->evaluate(scale,3,inpart.dataPtr(),wave3_[ifi],
+ incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),wave3_[ifi],
gluon_[2*ig],inpart.mass());
if (wave3_[ifi].particle()->PDGName()!=spinorInter.particle()->PDGName())
throw Exception()
<< wave3_[ifi].particle()->PDGName() << " was changed to "
<< spinorInter.particle()->PDGName() << " in FFVDecayer::threeBodyME"
<< Exception::runerror;
- diag = abstractVertex_->evaluate(scale,spinorInter,wavebar3_[ifo],vector3_[iv])/gs;
+ diag = vertex_->evaluate(scale,spinorInter,wavebar3_[ifo],vector3_[iv])/gs;
}
else {
SpinorBarWaveFunction spinorBarInter =
- abstractIncomingVertex_->evaluate(scale,3,inpart.dataPtr(),wavebar3_[ifi],
+ incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),wavebar3_[ifi],
gluon_[2*ig],inpart.mass());
if (wavebar3_[ifi].particle()->PDGName()!=spinorBarInter.particle()->PDGName())
throw Exception()
<< wavebar3_[ifi].particle()->PDGName() << " was changed to "
<< spinorBarInter.particle()->PDGName() << " in FFVDecayer::threeBodyME"
<< Exception::runerror;
- diag = abstractVertex_->evaluate(scale,wave3_[ifo], spinorBarInter,vector3_[iv])/gs;
+ diag = vertex_->evaluate(scale,wave3_[ifo], spinorBarInter,vector3_[iv])/gs;
}
for(unsigned int ix=0;ix<colourFlow[0].size();++ix) {
(*ME[colourFlow[0][ix].first])(ifi, ifo, iv, ig) +=
colourFlow[0][ix].second*diag;
}
}
// radiation from outgoing fermion
if(decay[iferm]->dataPtr()->coloured()) {
- assert(abstractOutgoingVertexF_);
+ assert(outgoingVertexF_[inter]);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[iferm]->dataPtr();
if(off->CC()) off = off->CC();
- double gs = abstractOutgoingVertexF_->strongCoupling(scale);
+ double gs = outgoingVertexF_[inter]->strongCoupling(scale);
if (ferm) {
SpinorBarWaveFunction spinorBarInter =
- abstractOutgoingVertexF_->evaluate(scale,3,off,wavebar3_[ifo],
+ outgoingVertexF_[inter]->evaluate(scale,3,off,wavebar3_[ifo],
gluon_[2*ig],decay[iferm]->mass());
if(wavebar3_[ifo].particle()->PDGName()!=spinorBarInter.particle()->PDGName())
throw Exception()
<< wavebar3_[ifo].particle()->PDGName() << " was changed to "
<< spinorBarInter.particle()->PDGName() << " in FFVDecayer::threeBodyME"
<< Exception::runerror;
- diag = abstractVertex_->evaluate(scale,wave3_[ifi],spinorBarInter,vector3_[iv])/gs;
+ diag = vertex_->evaluate(scale,wave3_[ifi],spinorBarInter,vector3_[iv])/gs;
}
else {
SpinorWaveFunction spinorInter =
- abstractOutgoingVertexF_->evaluate(scale,3,off,wave3_[ifo],
+ outgoingVertexF_[inter]->evaluate(scale,3,off,wave3_[ifo],
gluon_[2*ig],decay[iferm]->mass());
if(wave3_[ifo].particle()->PDGName()!=spinorInter.particle()->PDGName())
throw Exception()
<< wave3_[ifo].particle()->PDGName() << " was changed to "
<< spinorInter.particle()->PDGName() << " in FFVDecayer::threeBodyME"
<< Exception::runerror;
- diag = abstractVertex_->evaluate(scale,spinorInter,wavebar3_[ifi],vector3_[iv])/gs;
+ diag = vertex_->evaluate(scale,spinorInter,wavebar3_[ifi],vector3_[iv])/gs;
}
for(unsigned int ix=0;ix<colourFlow[F].size();++ix) {
(*ME[colourFlow[F][ix].first])(ifi, ifo, iv, ig) +=
colourFlow[F][ix].second*diag;
}
}
// radiation from outgoing vector
if(decay[ivect]->dataPtr()->coloured()) {
- assert(abstractOutgoingVertexV_);
+ assert(outgoingVertexV_[inter]);
// ensure you get correct ougoing particle from first vertex
tcPDPtr off = decay[ivect]->dataPtr();
if(off->CC()) off = off->CC();
double sign = decay[iferm]->id()>0 ? -1:1;
- double gs = abstractOutgoingVertexV_->strongCoupling(scale);
+ double gs = outgoingVertexV_[inter]->strongCoupling(scale);
VectorWaveFunction vectorInter =
- abstractOutgoingVertexV_->evaluate(scale,3,off,gluon_[2*ig],
+ outgoingVertexV_[inter]->evaluate(scale,3,off,gluon_[2*ig],
vector3_[iv],decay[ivect]->mass());
if(vector3_[iv].particle()->PDGName()!=vectorInter.particle()->PDGName())
throw Exception()
<< vector3_[iv].particle()->PDGName() << " was changed to "
<< vectorInter. particle()->PDGName() << " in FFVDecayer::threeBodyME"
<< Exception::runerror;
if (ferm){
- diag = sign*abstractVertex_->evaluate(scale,wave3_[ifi],wavebar3_[ifo],vectorInter)/gs;
+ diag = sign*vertex_->evaluate(scale,wave3_[ifi],wavebar3_[ifo],vectorInter)/gs;
}
else {
- diag = sign*abstractVertex_->evaluate(scale,wave3_[ifo],wavebar3_[ifi],vectorInter)/gs;
+ diag = sign*vertex_->evaluate(scale,wave3_[ifo],wavebar3_[ifi],vectorInter)/gs;
}
for(unsigned int ix=0;ix<colourFlow[V].size();++ix) {
(*ME[colourFlow[V][ix].first])(ifi, ifo, iv, ig) +=
colourFlow[V][ix].second*diag;
}
}
}
if(massless) ++iv;
}
}
}
// contract matrices
double output=0.;
for(unsigned int ix=0; ix<nflow; ++ix){
for(unsigned int iy=0; iy<nflow; ++iy){
output+=cfactors[ix][iy]*(ME[ix]->contract(*ME[iy],rho3_)).real();
}
}
output*=(4.*Constants::pi);
// return the answer
return output;
}
diff --git a/Decay/General/FFVDecayer.h b/Decay/General/FFVDecayer.h
--- a/Decay/General/FFVDecayer.h
+++ b/Decay/General/FFVDecayer.h
@@ -1,217 +1,214 @@
// -*- C++ -*-
//
// FFVDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_FFVDecayer_H
#define HERWIG_FFVDecayer_H
//
// This is the declaration of the FFVDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h"
#include "ThePEG/Helicity/Vertex/Vector/VVVVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::FFVVertexPtr;
/** \ingroup Decay
* The FFVDecayer class implements the decay of a fermion
* to a fermion and a vector in a general model. It holds an FFVVertex
* pointer that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class FFVDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
FFVDecayer() {}
public:
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* 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 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;
/**
* 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;
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return FSR;}
/**
* Three-body matrix element including additional QCD radiation
*/
virtual double threeBodyME(const int , const Particle & inpart,
- const ParticleVector & decay,MEOption meopt);
+ const ParticleVector & decay,
+ ShowerInteraction inter, MEOption meopt);
+
+ /**
+ * Set the information on the decay
+ */
+ virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr>);
//@}
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
-protected:
-
- /** @name Standard Interfaced functions. */
- //@{
- /**
- * Initialize this object after the setup phase before saving an
- * EventGenerator to disk.
- * @throws InitException if object could not be initialized properly.
- */
- virtual void doinit();
- //@}
-
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
FFVDecayer & operator=(const FFVDecayer &);
private:
/**
* Abstract pointer to AbstractFFVVertex
*/
- AbstractFFVVertexPtr abstractVertex_;
+ AbstractFFVVertexPtr vertex_;
/**
* Pointer to the perturbative vertex
*/
FFVVertexPtr perturbativeVertex_;
/**
* Abstract pointer to AbstractFFVVertex for QCD radiation from incoming (anti)fermion
*/
- AbstractFFVVertexPtr abstractIncomingVertex_;
+ map<ShowerInteraction,AbstractFFVVertexPtr> incomingVertex_;
/**
* Abstract pointer to AbstractFFVVertex for QCD radiation from outgoing (anti)fermion
*/
- AbstractFFVVertexPtr abstractOutgoingVertexF_;
+ map<ShowerInteraction,AbstractFFVVertexPtr> outgoingVertexF_;
/**
* Abstract pointer to AbstractVVVVertex for QCD radiation from outgoing vector
*/
- AbstractVVVVertexPtr abstractOutgoingVertexV_;
+ map<ShowerInteraction,AbstractVVVVertexPtr> outgoingVertexV_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Spinor wavefunction
*/
mutable vector<SpinorWaveFunction> wave_ ;
/**
* Barred spinor wavefunction
*/
mutable vector<SpinorBarWaveFunction> wavebar_;
/**
* Polarization vectors
*/
mutable vector<VectorWaveFunction> vector_;
/**
* Spin density matrix for 3 body decay
*/
mutable RhoDMatrix rho3_;
/**
* vector wavefunction for 3 body decay
*/
mutable vector<VectorWaveFunction> vector3_;
/**
* Spinor wavefunction for 3 body decay
*/
mutable vector<SpinorWaveFunction> wave3_;
/**
* Barred spinor wavefunction for 3 body decay
*/
mutable vector<SpinorBarWaveFunction> wavebar3_;
/**
* Vector wavefunction for gluon in 3 body decay
*/
mutable vector<VectorWaveFunction> gluon_;
};
}
#endif /* HERWIG_FFVDecayer_H */
diff --git a/Decay/General/FRSDecayer.cc b/Decay/General/FRSDecayer.cc
--- a/Decay/General/FRSDecayer.cc
+++ b/Decay/General/FRSDecayer.cc
@@ -1,179 +1,183 @@
// -*- C++ -*-
//
// FRSDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FRSDecayer class.
//
#include "FRSDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr FRSDecayer::clone() const {
return new_ptr(*this);
}
IBPtr FRSDecayer::fullclone() const {
return new_ptr(*this);
}
-void FRSDecayer::doinit() {
- perturbativeVertex_ = dynamic_ptr_cast<RFSVertexPtr> (vertex());
- abstractVertex_ = dynamic_ptr_cast<AbstractRFSVertexPtr>(vertex());
- GeneralTwoBodyDecayer::doinit();
+void FRSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
+ VertexBasePtr vertex,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr>) {
+ decayInfo(incoming,outgoing);
+ vertex_ = dynamic_ptr_cast<AbstractRFSVertexPtr>(vertex);
+ perturbativeVertex_ = dynamic_ptr_cast<RFSVertexPtr> (vertex);
}
void FRSDecayer::persistentOutput(PersistentOStream & os) const {
- os << perturbativeVertex_ << abstractVertex_;
+ os << perturbativeVertex_ << vertex_;
}
void FRSDecayer::persistentInput(PersistentIStream & is, int) {
- is >> perturbativeVertex_ >> abstractVertex_;
+ is >> perturbativeVertex_ >> vertex_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<FRSDecayer,GeneralTwoBodyDecayer>
describeHerwigFRSDecayer("Herwig::FRSDecayer", "Herwig.so");
void FRSDecayer::Init() {
static ClassDocumentation<FRSDecayer> documentation
("The FRSDecayer class implements the decay of a fermion to "
"a spin-3/2 fermion and a scalar.");
}
double FRSDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
bool ferm = inpart.id() > 0;
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin3Half,PDT::Spin0)));
if(meopt==Initialize) {
// spinors and rho
if(ferm) {
SpinorWaveFunction ::calculateWaveFunctions(wave_,rho_,
const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wave_[0].wave().Type() != SpinorType::u)
for(unsigned int ix = 0; ix < 2; ++ix) wave_ [ix].conjugate();
}
else {
SpinorBarWaveFunction::calculateWaveFunctions(wavebar_,rho_,
const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wavebar_[0].wave().Type() != SpinorType::v)
for(unsigned int ix = 0; ix < 2; ++ix) wavebar_[ix].conjugate();
}
}
// setup spin info when needed
if(meopt==Terminate) {
// for the decaying particle
if(ferm) {
SpinorWaveFunction::
constructSpinInfo(wave_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
RSSpinorBarWaveFunction::constructSpinInfo(RSwavebar_,decay[0],outgoing,true);
}
else {
SpinorBarWaveFunction::
constructSpinInfo(wavebar_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
RSSpinorWaveFunction::constructSpinInfo(RSwave_,decay[0],outgoing,true);
}
ScalarWaveFunction::constructSpinInfo(decay[1],outgoing,true);
}
if(ferm)
RSSpinorBarWaveFunction::
calculateWaveFunctions(RSwavebar_,decay[0],outgoing);
else
RSSpinorWaveFunction::
calculateWaveFunctions(RSwave_ ,decay[0],outgoing);
ScalarWaveFunction scal(decay[1]->momentum(),decay[1]->dataPtr(),outgoing);
Energy2 scale(sqr(inpart.mass()));
for(unsigned int if1 = 0; if1 < 2; ++if1) {
for(unsigned int if2 = 0; if2 < 4; ++if2) {
if(ferm) (*ME())(if1, if2, 0) =
- abstractVertex_->evaluate(scale,wave_[if1],RSwavebar_[if2],scal);
+ vertex_->evaluate(scale,wave_[if1],RSwavebar_[if2],scal);
else (*ME())(if1, if2, 0) =
- abstractVertex_->evaluate(scale,RSwave_[if2],wavebar_[if1],scal);
+ vertex_->evaluate(scale,RSwave_[if2],wavebar_[if1],scal);
}
}
double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// test code
// Energy q = inpart.mass();
// Energy m1 = decay[0]->mass();
// Energy m2 = decay[1]->mass();
// Energy2 q2(q*q),m12(m1*m1),m22(m2*m2);
// Energy2 pcm2(0.25*(q2*(q2-2.*m12-2.*m22)+(m12-m22)*(m12-m22))/q2);
// Energy pcm(sqrt(pcm2));
// Energy Qp(sqrt((q+m1)*(q+m1)-m22)),Qm(sqrt((q-m1)*(q-m1)-m22));
// double r23(sqrt(2./3.));
// // couplings
// Complex left = perturbativeVertex_-> left()*perturbativeVertex_-> norm();
// Complex right = perturbativeVertex_->right()*perturbativeVertex_-> norm();
// complex<InvEnergy> A1 = 0.5*(left+right)*UnitRemoval::InvE;
// complex<InvEnergy> B1 = 0.5*(right-left)*UnitRemoval::InvE;
// complex<Energy> h1(-2.*r23*pcm*q/m1*Qm*B1);
// complex<Energy> h2( 2.*r23*pcm*q/m1*Qp*A1);
// cout << "testing 1/2->3/2 0 "
// << output*scale/GeV2 << " "
// << real(h1*conj(h1)+h2*conj(h2))/4./GeV2 << " "
// << real(h1*conj(h1)+h2*conj(h2))/4./(output*scale) << endl;
// return the answer
return output;
}
Energy FRSDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
if(perturbativeVertex_) {
Energy q = inpart.second;
Energy m1 = outa.second;
Energy m2 = outb.second;
Energy2 q2(q*q),m12(m1*m1),m22(m2*m2);
Energy2 pcm2(0.25*(q2*(q2-2.*m12-2.*m22)+(m12-m22)*(m12-m22))/q2);
Energy pcm(sqrt(pcm2));
Energy Qp(sqrt((q+m1)*(q+m1)-m22)),Qm(sqrt((q-m1)*(q-m1)-m22));
double r23(sqrt(2./3.));
// couplings
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
perturbativeVertex_->setCoupling(sqr(inpart.second), outa.first,
in, outb.first);
Complex left = perturbativeVertex_-> left()*perturbativeVertex_-> norm();
Complex right = perturbativeVertex_->right()*perturbativeVertex_-> norm();
complex<InvEnergy> A1 = 0.5*(left+right)*UnitRemoval::InvE;
complex<InvEnergy> B1 = 0.5*(right-left)*UnitRemoval::InvE;
complex<Energy> h1(-2.*r23*pcm*q/m1*Qm*B1);
complex<Energy> h2( 2.*r23*pcm*q/m1*Qp*A1);
double me2 = real(h1*conj(h1)+h2*conj(h2))/4./sqr(inpart.second);
Energy output = me2*pcm/8./Constants::pi;
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
diff --git a/Decay/General/FRSDecayer.h b/Decay/General/FRSDecayer.h
--- a/Decay/General/FRSDecayer.h
+++ b/Decay/General/FRSDecayer.h
@@ -1,167 +1,163 @@
// -*- C++ -*-
//
// FRSDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_FRSDecayer_H
#define HERWIG_FRSDecayer_H
//
// This is the declaration of the FRSDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Scalar/RFSVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::RFSVertexPtr;
/** \ingroup Decay
* The FRSDecayer class implements the decay of a fermion
* to a spin-3/2 fermion and a vector in a general model. It holds an RFVVertex
* pointer that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class FRSDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
FRSDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* 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;
/**
* 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;
+
+ /**
+ * Set the information on the decay
+ */
+ virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr>);
//@}
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 and
- * EventGenerator to disk.
- * @throws InitException if object could not be initialized properly.
- */
- virtual void doinit();
- //@}
-
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
FRSDecayer & operator=(const FRSDecayer &);
private:
/**
* Abstract pointer to AbstractFRSVertex
*/
- AbstractRFSVertexPtr abstractVertex_;
+ AbstractRFSVertexPtr vertex_;
/**
* Pointer to the perturbative vertex
*/
RFSVertexPtr perturbativeVertex_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Spinor wavefunctions
*/
mutable vector<SpinorWaveFunction> wave_ ;
/**
* Barred spinor wavefunctions
*/
mutable vector<SpinorBarWaveFunction> wavebar_;
/**
* RS Spinor wavefunctions
*/
mutable vector<RSSpinorWaveFunction> RSwave_ ;
/**
* Barred RS spinor wavefunctions
*/
mutable vector<RSSpinorBarWaveFunction> RSwavebar_;
};
}
#endif /* HERWIG_FRSDecayer_H */
diff --git a/Decay/General/FRVDecayer.cc b/Decay/General/FRVDecayer.cc
--- a/Decay/General/FRVDecayer.cc
+++ b/Decay/General/FRVDecayer.cc
@@ -1,210 +1,213 @@
// -*- C++ -*-
//
// FRVDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FRVDecayer class.
//
#include "FRVDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr FRVDecayer::clone() const {
return new_ptr(*this);
}
IBPtr FRVDecayer::fullclone() const {
return new_ptr(*this);
}
-void FRVDecayer::doinit() {
- perturbativeVertex_ = dynamic_ptr_cast<RFVVertexPtr> (vertex());
- abstractVertex_ = dynamic_ptr_cast<AbstractRFVVertexPtr>(vertex());
- GeneralTwoBodyDecayer::doinit();
+void FRVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
+ VertexBasePtr vertex,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr>) {
+ decayInfo(incoming,outgoing);
+ vertex_ = dynamic_ptr_cast<AbstractRFVVertexPtr>(vertex);
+ perturbativeVertex_ = dynamic_ptr_cast<RFVVertexPtr> (vertex);
}
void FRVDecayer::persistentOutput(PersistentOStream & os) const {
- os << abstractVertex_ << perturbativeVertex_;
+ os << vertex_ << perturbativeVertex_;
}
void FRVDecayer::persistentInput(PersistentIStream & is, int) {
- is >> abstractVertex_ >> perturbativeVertex_;
+ is >> vertex_ >> perturbativeVertex_;
}
double FRVDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin3Half,PDT::Spin1)));
// decaying fermion or antifermion
bool ferm = inpart.id() > 0;
// initialize
if(meopt==Initialize) {
// spinors and rho
if(ferm) {
SpinorWaveFunction ::calculateWaveFunctions(wave_,rho_,
const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wave_[0].wave().Type() != SpinorType::u)
for(unsigned int ix = 0; ix < 2; ++ix) wave_ [ix].conjugate();
}
else {
SpinorBarWaveFunction::calculateWaveFunctions(wavebar_,rho_,
const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wavebar_[0].wave().Type() != SpinorType::v)
for(unsigned int ix = 0; ix < 2; ++ix) wavebar_[ix].conjugate();
}
}
// setup spin info when needed
if(meopt==Terminate) {
// for the decaying particle
if(ferm) {
SpinorWaveFunction::
constructSpinInfo(wave_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
RSSpinorBarWaveFunction::constructSpinInfo(RSwavebar_,decay[0],outgoing,true);
}
else {
SpinorBarWaveFunction::
constructSpinInfo(wavebar_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
RSSpinorWaveFunction::constructSpinInfo(RSwave_,decay[0],outgoing,true);
}
VectorWaveFunction::
constructSpinInfo(vector_,decay[1],outgoing,true,false);
}
Energy2 scale(sqr(inpart.mass()));
if(ferm)
RSSpinorBarWaveFunction::
calculateWaveFunctions(RSwavebar_,decay[0],outgoing);
else
RSSpinorWaveFunction::
calculateWaveFunctions(RSwave_ ,decay[0],outgoing);
bool massless = decay[1]->dataPtr()->mass()==ZERO;
VectorWaveFunction::
calculateWaveFunctions(vector_,decay[1],outgoing,massless);
// loop over helicities
for(unsigned int if1 = 0; if1 < 2; ++if1) {
for(unsigned int if2 = 0; if2 < 4; ++if2) {
for(unsigned int vhel = 0; vhel < 3; ++vhel) {
if(massless && vhel == 1) ++vhel;
if(ferm)
(*ME())(if1, if2,vhel) =
- abstractVertex_->evaluate(scale,wave_[if1],
- RSwavebar_[if2],vector_[vhel]);
+ vertex_->evaluate(scale,wave_[if1],
+ RSwavebar_[if2],vector_[vhel]);
else
(*ME())(if1, if2, vhel) =
- abstractVertex_->evaluate(scale,RSwave_[if2],
- wavebar_[if1],vector_[vhel]);
-
+ vertex_->evaluate(scale,RSwave_[if2],
+ wavebar_[if1],vector_[vhel]);
}
}
}
double output=(ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// test
// Energy m1(inpart.mass()),m2(decay[0]->mass()),m3(decay[1]->mass());
// Energy2 m12(m1*m1),m22(m2*m2),m32(m3*m3);
// Energy Qp(sqrt(sqr(m1+m2)-sqr(m3))),Qm(sqrt(sqr(m1-m2)-sqr(m3)));
// double r2(sqrt(2.)),r3(sqrt(3.));
// Energy pcm(Kinematics::pstarTwoBodyDecay(m1,m2,m3));
// vector<Complex> left = perturbativeVertex_-> left();
// vector<Complex> right = perturbativeVertex_->right();
// Complex A1 = 0.5*(left [0]+right[0])*perturbativeVertex_-> norm();
// Complex B1 = 0.5*(right[0]- left[0])*perturbativeVertex_-> norm();
// complex<InvEnergy> A2 = 0.5*(left [1]+right[1])*perturbativeVertex_-> norm()*UnitRemoval::InvE;
// complex<InvEnergy> B2 = 0.5*(right[1]- left[1])*perturbativeVertex_-> norm()*UnitRemoval::InvE;
// complex<InvEnergy2> A3 = 0.5*(left [2]+right[2])*perturbativeVertex_-> norm()*UnitRemoval::InvE2;
// complex<InvEnergy2> B3 = 0.5*(right[2]- left[2])*perturbativeVertex_-> norm()*UnitRemoval::InvE2;
// complex<Energy> h1(-2.*Qp*A1),h2(2.*Qm*B1);
// complex<Energy> h3(-2./r3*Qp*(A1-Qm*Qm/m2*A2));
// complex<Energy> h4( 2./r3*Qm*(B1-Qp*Qp/m2*B2));
// complex<Energy> h5(ZERO),h6(ZERO);
// if(decay[1]->mass()>ZERO) {
// h5 = -2.*r2/r3/m2/m3*Qp*(0.5*(m12-m22-m32)*A1+0.5*Qm*Qm*(m1+m2)*A2
// +m12*pcm*pcm*A3);
// h6 = 2.*r2/r3/m2/m3*Qm*(0.5*(m12-m22-m32)*B1-0.5*Qp*Qp*(m1-m2)*B2
// +m12*pcm*pcm*B3);
// }
// cout << "testing 1/2->3/2 1 " << inpart.id() << " "
// << output << " "
// << 0.25*(h1*conj(h1)+h2*conj(h2)+h3*conj(h3)+
// h4*conj(h4)+h5*conj(h5)+h6*conj(h6))/sqr(inpart.mass()) << " "
// << 0.25*(h1*conj(h1)+h2*conj(h2)+h3*conj(h3)+
// h4*conj(h4)+h5*conj(h5)+h6*conj(h6))/sqr(inpart.mass())/output << endl;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),decay[1]->dataPtr());
// return the answer
return output;
}
Energy FRVDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
if(perturbativeVertex_) {
Energy m1(inpart.second),m2(outa.second),m3(outb.second);
Energy2 m12(m1*m1),m22(m2*m2),m32(m3*m3);
Energy Qp(sqrt(sqr(m1+m2)-sqr(m3))),Qm(sqrt(sqr(m1-m2)-sqr(m3)));
double r2(sqrt(2.)),r3(sqrt(3.));
Energy pcm(Kinematics::pstarTwoBodyDecay(m1,m2,m3));
// couplings
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
perturbativeVertex_->setCoupling(sqr(inpart.second), outa.first,
in, outb.first);
vector<Complex> left = perturbativeVertex_-> left();
vector<Complex> right = perturbativeVertex_->right();
Complex A1 = 0.5*(left [0]+right[0])*perturbativeVertex_-> norm();
Complex B1 = 0.5*(right[0]- left[0])*perturbativeVertex_-> norm();
complex<InvEnergy> A2 = 0.5*(left [1]+right[1])*perturbativeVertex_-> norm()*UnitRemoval::InvE;
complex<InvEnergy> B2 = 0.5*(right[1]- left[1])*perturbativeVertex_-> norm()*UnitRemoval::InvE;
complex<InvEnergy2> A3 = 0.5*(left [2]+right[2])*perturbativeVertex_-> norm()*UnitRemoval::InvE2;
complex<InvEnergy2> B3 = 0.5*(right[2]- left[2])*perturbativeVertex_-> norm()*UnitRemoval::InvE2;
complex<Energy> h1(-2.*Qp*A1),h2(2.*Qm*B1);
complex<Energy> h3(-2./r3*Qp*(A1-Qm*Qm/m2*A2));
complex<Energy> h4( 2./r3*Qm*(B1-Qp*Qp/m2*B2));
complex<Energy> h5(ZERO),h6(ZERO);
if(outb.second>ZERO) {
h5 = -2.*r2/r3/m2/m3*Qp*(0.5*(m12-m22-m32)*A1+0.5*Qm*Qm*(m1+m2)*A2
+m12*pcm*pcm*A3);
h6 = 2.*r2/r3/m2/m3*Qm*(0.5*(m12-m22-m32)*B1-0.5*Qp*Qp*(m1-m2)*B2
+m12*pcm*pcm*B3);
}
double me2 = 0.25*real(h1*conj(h1)+h2*conj(h2)+h3*conj(h3)+
h4*conj(h4)+h5*conj(h5)+h6*conj(h6))/sqr(inpart.second);
Energy output = me2*pcm/8./Constants::pi;
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<FRVDecayer,GeneralTwoBodyDecayer>
describeHerwigFRVDecayer("Herwig::FRVDecayer", "Herwig.so");
void FRVDecayer::Init() {
static ClassDocumentation<FRVDecayer> documentation
("The FRVDecayer class handles the decay of a fermion to "
"a spin-3/2 particle and a vector boson.");
}
diff --git a/Decay/General/FRVDecayer.h b/Decay/General/FRVDecayer.h
--- a/Decay/General/FRVDecayer.h
+++ b/Decay/General/FRVDecayer.h
@@ -1,174 +1,170 @@
// -*- C++ -*-
//
// FRVDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_FRVDecayer_H
#define HERWIG_FRVDecayer_H
//
// This is the declaration of the FRVDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Vector/RFVVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::RFVVertexPtr;
/** \ingroup Decay
* The FRVDecayer class implements the decay of a fermion
* to a spin-3/2 fermion and a vector in a general model. It holds an RFVVertex
* pointer that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class FRVDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
FRVDecayer() {}
public:
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* 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 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;
/**
* 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;
+
+ /**
+ * Set the information on the decay
+ */
+ virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr>);
//@}
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
-protected:
-
- /** @name Standard Interfaced functions. */
- //@{
- /**
- * Initialize this object after the setup phase before saving an
- * EventGenerator to disk.
- * @throws InitException if object could not be initialized properly.
- */
- virtual void doinit();
- //@}
-
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
FRVDecayer & operator=(const FRVDecayer &);
private:
/**
* Abstract pointer to AbstractFRVVertex
*/
- AbstractRFVVertexPtr abstractVertex_;
+ AbstractRFVVertexPtr vertex_;
/**
* Pointer to the perturbative vertex
*/
RFVVertexPtr perturbativeVertex_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Spinor wavefunction
*/
mutable vector<SpinorWaveFunction> wave_ ;
/**
* Barred spinor wavefunction
*/
mutable vector<SpinorBarWaveFunction> wavebar_;
/**
* RS Spinor wavefunction
*/
mutable vector<RSSpinorWaveFunction> RSwave_ ;
/**
* Barred RS spinor wavefunction
*/
mutable vector<RSSpinorBarWaveFunction> RSwavebar_;
/**
* Polarization vectors
*/
mutable vector<VectorWaveFunction> vector_;
};
}
#endif /* HERWIG_FRVDecayer_H */
diff --git a/Decay/General/GeneralTwoBodyDecayer.cc b/Decay/General/GeneralTwoBodyDecayer.cc
--- a/Decay/General/GeneralTwoBodyDecayer.cc
+++ b/Decay/General/GeneralTwoBodyDecayer.cc
@@ -1,724 +1,719 @@
// -*- C++ -*-
//
// GeneralTwoBodyDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the GeneralTwoBodyDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Utilities/Exception.h"
#include "Herwig/Shower/RealEmissionProcess.h"
using namespace Herwig;
ParticleVector GeneralTwoBodyDecayer::decay(const Particle & parent,
const tPDVector & children) const {
// return empty vector if products heavier than parent
Energy mout(ZERO);
for(tPDVector::const_iterator it=children.begin();
it!=children.end();++it) mout+=(**it).massMin();
if(mout>parent.mass()) return ParticleVector();
// generate the decay
bool cc;
int imode=modeNumber(cc,parent.dataPtr(),children);
// generate the kinematics
ParticleVector decay=generate(generateIntermediates(),cc,imode,parent);
// make the colour connections
colourConnections(parent, decay);
// return the answer
return decay;
}
void GeneralTwoBodyDecayer::doinit() {
PerturbativeDecayer::doinit();
- assert( vertex_ );
assert( incoming_ && outgoing_.size()==2);
- vertex_->init();
//create phase space mode
tPDVector extpart(3);
extpart[0] = incoming_;
extpart[1] = outgoing_[0];
extpart[2] = outgoing_[1];
addMode(new_ptr(DecayPhaseSpaceMode(extpart, this)), maxWeight_, vector<double>());
}
int GeneralTwoBodyDecayer::modeNumber(bool & cc, tcPDPtr parent,
const tPDVector & children) const {
long parentID = parent->id();
long id1 = children[0]->id();
long id2 = children[1]->id();
cc = false;
long out1 = outgoing_[0]->id();
long out2 = outgoing_[1]->id();
if( parentID == incoming_->id() &&
((id1 == out1 && id2 == out2) ||
(id1 == out2 && id2 == out1)) ) {
return 0;
}
else if(incoming_->CC() && parentID == incoming_->CC()->id()) {
cc = true;
if( outgoing_[0]->CC()) out1 = outgoing_[0]->CC()->id();
if( outgoing_[1]->CC()) out2 = outgoing_[1]->CC()->id();
if((id1 == out1 && id2 == out2) ||
(id1 == out2 && id2 == out1)) return 0;
}
return -1;
}
void GeneralTwoBodyDecayer::
colourConnections(const Particle & parent,
const ParticleVector & out) const {
PDT::Colour incColour(parent.data().iColour());
PDT::Colour outaColour(out[0]->data().iColour());
PDT::Colour outbColour(out[1]->data().iColour());
//incoming colour singlet
if(incColour == PDT::Colour0) {
// colour triplet-colourantitriplet
if((outaColour == PDT::Colour3 && outbColour == PDT::Colour3bar) ||
(outaColour == PDT::Colour3bar && outbColour == PDT::Colour3)) {
bool ac(out[0]->id() < 0);
out[0]->colourNeighbour(out[1],!ac);
}
//colour octet
else if(outaColour == PDT::Colour8 && outbColour == PDT::Colour8) {
out[0]->colourNeighbour(out[1]);
out[0]->antiColourNeighbour(out[1]);
}
// colour singlets
else if(outaColour == PDT::Colour0 && outbColour == PDT::Colour0) {
}
// unknown
else
throw Exception() << "Unknown outgoing colours for decaying "
<< "colour singlet in "
<< "GeneralTwoBodyDecayer::colourConnections "
<< outaColour << " " << outbColour
<< Exception::runerror;
}
//incoming colour triplet
else if(incColour == PDT::Colour3) {
// colour triplet + singlet
if(outaColour == PDT::Colour3 && outbColour == PDT::Colour0) {
out[0]->incomingColour(const_ptr_cast<tPPtr>(&parent));
}
//opposite order
else if(outaColour == PDT::Colour0 && outbColour == PDT::Colour3) {
out[1]->incomingColour(const_ptr_cast<tPPtr>(&parent));
}
// octet + triplet
else if(outaColour == PDT::Colour8 && outbColour == PDT::Colour3) {
out[0]->incomingColour(const_ptr_cast<tPPtr>(&parent));
out[1]->antiColourNeighbour(out[0]);
}
//opposite order
else if(outaColour == PDT::Colour3 && outbColour == PDT::Colour8) {
out[1]->incomingColour(const_ptr_cast<tPPtr>(&parent));
out[0]->antiColourNeighbour(out[1]);
}
else if(outaColour == PDT::Colour3bar && outaColour == PDT::Colour3bar) {
tColinePtr col[2] = {ColourLine::create(out[0],true),
ColourLine::create(out[1],true)};
parent.colourLine()->setSinkNeighbours(col[0],col[1]);
}
else
throw Exception() << "Unknown outgoing colours for decaying "
<< "colour triplet in "
<< "GeneralTwoBodyDecayer::colourConnections() "
<< outaColour << " " << outbColour
<< Exception::runerror;
}
// incoming colour anti triplet
else if(incColour == PDT::Colour3bar) {
// colour antitriplet +singlet
if(outaColour == PDT::Colour3bar && outbColour == PDT::Colour0) {
out[0]->incomingAntiColour(const_ptr_cast<tPPtr>(&parent));
}
//opposite order
else if(outaColour == PDT::Colour0 && outbColour == PDT::Colour3bar) {
out[1]->incomingAntiColour(const_ptr_cast<tPPtr>(&parent));
}
//octet + antitriplet
else if(outaColour == PDT::Colour3bar && outbColour == PDT::Colour8) {
out[1]->incomingAntiColour(const_ptr_cast<tPPtr>(&parent));
out[0]->colourNeighbour(out[1]);
}
//opposite order
else if(outaColour == PDT::Colour8 && outbColour == PDT::Colour3bar) {
out[0]->incomingAntiColour(const_ptr_cast<tPPtr>(&parent));
out[1]->colourNeighbour(out[0]);
}
else if(outaColour == PDT::Colour3 && outbColour == PDT::Colour3) {
tColinePtr col[2] = {ColourLine::create(out[0]),
ColourLine::create(out[1])};
parent.antiColourLine()->setSourceNeighbours(col[0],col[1]);
}
else
throw Exception() << "Unknown outgoing colours for decaying "
<< "colour antitriplet "
<< "in GeneralTwoBodyDecayer::colourConnections() "
<< outaColour << " " << outbColour
<< Exception::runerror;
}
//incoming colour octet
else if(incColour == PDT::Colour8) {
// triplet-antitriplet
if(outaColour == PDT::Colour3&&outbColour == PDT::Colour3bar) {
out[0]->incomingColour(const_ptr_cast<tPPtr>(&parent));
out[1]->incomingAntiColour(const_ptr_cast<tPPtr>(&parent));
}
// opposite order
else if(outbColour == PDT::Colour3&&outaColour == PDT::Colour3bar) {
out[0]->incomingAntiColour(const_ptr_cast<tPPtr>(&parent));
out[1]->incomingColour(const_ptr_cast<tPPtr>(&parent));
}
// neutral octet
else if(outaColour == PDT::Colour0&&outbColour == PDT::Colour8) {
out[1]->incomingColour(const_ptr_cast<tPPtr>(&parent));
out[1]->incomingAntiColour(const_ptr_cast<tPPtr>(&parent));
}
else if(outbColour == PDT::Colour0&&outaColour == PDT::Colour8) {
out[0]->incomingColour(const_ptr_cast<tPPtr>(&parent));
out[0]->incomingAntiColour(const_ptr_cast<tPPtr>(&parent));
}
else
throw Exception() << "Unknown outgoing colours for decaying "
<< "colour octet "
<< "in GeneralTwoBodyDecayer::colourConnections() "
<< outaColour << " " << outbColour
<< Exception::runerror;
}
else if(incColour == PDT::Colour6) {
if(outaColour == PDT::Colour3 && outbColour == PDT::Colour3) {
tPPtr tempParent = const_ptr_cast<tPPtr>(&parent);
Ptr<MultiColour>::pointer parentColour =
dynamic_ptr_cast<Ptr<MultiColour>::pointer>
(tempParent->colourInfo());
tColinePtr line1 = const_ptr_cast<tColinePtr>(parentColour->colourLines()[0]);
line1->addColoured(dynamic_ptr_cast<tPPtr>(out[0]));
tColinePtr line2 = const_ptr_cast<tColinePtr>(parentColour->colourLines()[1]);
line2->addColoured(dynamic_ptr_cast<tPPtr>(out[1]));
}
else
throw Exception() << "Unknown outgoing colours for decaying "
<< "colour sextet "
<< "in GeneralTwoBodyDecayer::colourConnections() "
<< outaColour << " " << outbColour
<< Exception::runerror;
}
else if(incColour == PDT::Colour6bar) {
if(outaColour == PDT::Colour3bar && outbColour == PDT::Colour3bar) {
tPPtr tempParent = const_ptr_cast<tPPtr>(&parent);
Ptr<MultiColour>::pointer parentColour =
dynamic_ptr_cast<Ptr<MultiColour>::pointer>
(tempParent->colourInfo());
tColinePtr line1 = const_ptr_cast<tColinePtr>(parentColour->antiColourLines()[0]);
line1->addAntiColoured(dynamic_ptr_cast<tPPtr>(out[0]));
tColinePtr line2 = const_ptr_cast<tColinePtr>(parentColour->antiColourLines()[1]);
line2->addAntiColoured(dynamic_ptr_cast<tPPtr>(out[1]));
}
else
throw Exception() << "Unknown outgoing colours for decaying "
<< "colour anti-sextet "
<< "in GeneralTwoBodyDecayer::colourConnections() "
<< outaColour << " " << outbColour
<< Exception::runerror;
}
else
throw Exception() << "Unknown incoming colour in "
<< "GeneralTwoBodyDecayer::colourConnections() "
<< incColour
<< Exception::runerror;
}
bool GeneralTwoBodyDecayer::twoBodyMEcode(const DecayMode & dm, int & mecode,
double & coupling) const {
assert(dm.parent()->id() == incoming_->id());
ParticleMSet::const_iterator pit = dm.products().begin();
long id1 = (*pit)->id();
++pit;
long id2 = (*pit)->id();
long id1t(outgoing_[0]->id()), id2t(outgoing_[1]->id());
mecode = -1;
coupling = 1.;
if( id1 == id1t && id2 == id2t ) {
return true;
}
else if( id1 == id2t && id2 == id1t ) {
return false;
}
else
assert(false);
return false;
}
void GeneralTwoBodyDecayer::persistentOutput(PersistentOStream & os) const {
- os << vertex_ << incoming_ << outgoing_ << maxWeight_
- << incomingVertex_ << outgoingVertices_ << fourPointVertex_;
+ os << incoming_ << outgoing_ << maxWeight_;
}
void GeneralTwoBodyDecayer::persistentInput(PersistentIStream & is, int) {
- is >> vertex_ >> incoming_ >> outgoing_ >> maxWeight_
- >> incomingVertex_ >> outgoingVertices_ >> fourPointVertex_;
+ is >> incoming_ >> outgoing_ >> maxWeight_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeAbstractClass<GeneralTwoBodyDecayer,PerturbativeDecayer>
describeHerwigGeneralTwoBodyDecayer("Herwig::GeneralTwoBodyDecayer", "Herwig.so");
void GeneralTwoBodyDecayer::Init() {
static ClassDocumentation<GeneralTwoBodyDecayer> documentation
("This class is designed to be a base class for all 2 body decays"
"in a general model");
}
double GeneralTwoBodyDecayer::brat(const DecayMode &, const Particle & p,
double oldbrat) const {
ParticleVector children = p.children();
if( children.size() != 2 || !p.data().widthGenerator() )
return oldbrat;
// partial width for this mode
Energy scale = p.mass();
Energy pwidth =
partialWidth( make_pair(p.dataPtr(), scale),
make_pair(children[0]->dataPtr(), children[0]->mass()),
make_pair(children[1]->dataPtr(), children[1]->mass()) );
Energy width = p.data().widthGenerator()->width(p.data(), scale);
return pwidth/width;
}
void GeneralTwoBodyDecayer::doinitrun() {
- vertex_->initrun();
PerturbativeDecayer::doinitrun();
for(unsigned int ix=0;ix<numberModes();++ix) {
double fact = pow(1.5,int(mode(ix)->externalParticles(0)->iSpin())-1);
mode(ix)->setMaxWeight(fact*mode(ix)->maxWeight());
}
}
double GeneralTwoBodyDecayer::colourFactor(tcPDPtr in, tcPDPtr out1,
tcPDPtr out2) const {
// identical particle symmetry factor
double output = out1->id()==out2->id() ? 0.5 : 1.;
// colour neutral incoming particle
if(in->iColour()==PDT::Colour0) {
// both colour neutral
if(out1->iColour()==PDT::Colour0 && out2->iColour()==PDT::Colour0)
output *= 1.;
// colour triplet/ antitriplet
else if((out1->iColour()==PDT::Colour3 && out2->iColour()==PDT::Colour3bar) ||
(out1->iColour()==PDT::Colour3bar && out2->iColour()==PDT::Colour3 ) ) {
output *= 3.;
}
// colour octet colour octet
else if(out1->iColour()==PDT::Colour8 && out2->iColour()==PDT::Colour8 ) {
output *= 8.;
}
else
throw Exception() << "Unknown colour for the outgoing particles"
<< " for decay colour neutral particle in "
<< "GeneralTwoBodyDecayer::colourFactor() for "
<< in->PDGName() << " -> "
<< out1->PDGName() << " " << out2->PDGName()
<< Exception::runerror;
}
// triplet
else if(in->iColour()==PDT::Colour3) {
// colour triplet + neutral
if((out1->iColour()==PDT::Colour0 && out2->iColour()==PDT::Colour3) ||
(out1->iColour()==PDT::Colour3 && out2->iColour()==PDT::Colour0) ) {
output *= 1.;
}
// colour triplet + octet
else if((out1->iColour()==PDT::Colour8 && out2->iColour()==PDT::Colour3) ||
(out1->iColour()==PDT::Colour3 && out2->iColour()==PDT::Colour8) ) {
output *= 4./3.;
}
// colour anti triplet anti triplet
else if(out1->iColour()==PDT::Colour3bar &&
out2->iColour()==PDT::Colour3bar) {
output *= 2.;
}
else
throw Exception() << "Unknown colour for the outgoing particles"
<< " for decay colour triplet particle in "
<< "GeneralTwoBodyDecayer::colourFactor() for "
<< in->PDGName() << " -> "
<< out1->PDGName() << " " << out2->PDGName()
<< Exception::runerror;
}
// anti triplet
else if(in->iColour()==PDT::Colour3bar) {
// colour anti triplet + neutral
if((out1->iColour()==PDT::Colour0 && out2->iColour()==PDT::Colour3bar ) ||
(out1->iColour()==PDT::Colour3bar && out2->iColour()==PDT::Colour0 ) ) {
output *= 1.;
}
// colour anti triplet + octet
else if((out1->iColour()==PDT::Colour8 && out2->iColour()==PDT::Colour3bar ) ||
(out1->iColour()==PDT::Colour3bar && out2->iColour()==PDT::Colour8 ) ) {
output *= 4./3.;
}
// colour triplet triplet
else if(out1->iColour()==PDT::Colour3 &&
out2->iColour()==PDT::Colour3) {
output *= 2.;
}
else
throw Exception() << "Unknown colour for the outgoing particles"
<< " for decay colour anti triplet particle in "
<< "GeneralTwoBodyDecayer::colourFactor() for "
<< in->PDGName() << " -> "
<< out1->PDGName() << " " << out2->PDGName()
<< Exception::runerror;
}
else if(in->iColour()==PDT::Colour8) {
// colour octet + neutral
if((out1->iColour()==PDT::Colour0 && out2->iColour()==PDT::Colour8 ) ||
(out1->iColour()==PDT::Colour8 && out2->iColour()==PDT::Colour0 ) ) {
output *= 1.;
}
// colour triplet/antitriplet
else if((out1->iColour()==PDT::Colour3 && out2->iColour()==PDT::Colour3bar) ||
(out1->iColour()==PDT::Colour3bar && out2->iColour()==PDT::Colour3 ) ) {
output *= 0.5;
}
else
throw Exception() << "Unknown colour for the outgoing particles"
<< " for decay colour octet particle in "
<< "GeneralTwoBodyDecayer::colourFactor() for "
<< in->PDGName() << " -> "
<< out1->PDGName() << " " << out2->PDGName()
<< Exception::runerror;
}
else if(in->iColour()==PDT::Colour6) {
// colour sextet -> triplet triplet
if( out1->iColour()==PDT::Colour3 && out2->iColour()==PDT::Colour3 ) {
output *= 1.;
}
else
throw Exception() << "Unknown colour for the outgoing particles"
<< " for decay colour sextet particle in "
<< "GeneralTwoBodyDecayer::colourFactor() for "
<< in->PDGName() << " -> "
<< out1->PDGName() << " " << out2->PDGName()
<< Exception::runerror;
}
else if(in->iColour()==PDT::Colour6bar) {
// colour sextet -> triplet triplet
if( out1->iColour()==PDT::Colour3bar && out2->iColour()==PDT::Colour3bar ) {
output *= 1.;
}
else
throw Exception() << "Unknown colour for the outgoing particles"
<< " for decay colour anti-sextet particle in "
<< "GeneralTwoBodyDecayer::colourFactor() for "
<< in->PDGName() << " -> "
<< out1->PDGName() << " " << out2->PDGName()
<< Exception::runerror;
}
else
throw Exception() << "Unknown colour "
<< in->iColour() << " for the decaying particle in "
<< "GeneralTwoBodyDecayer::colourFactor() for "
<< in->PDGName() << " -> "
<< out1->PDGName() << " " << out2->PDGName()
<< Exception::runerror;
return output;
}
Energy GeneralTwoBodyDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
// select the number of the mode
tPDVector children;
children.push_back(const_ptr_cast<PDPtr>(outa.first));
children.push_back(const_ptr_cast<PDPtr>(outb.first));
bool cc;
int nmode=modeNumber(cc,inpart.first,children);
tcPDPtr newchild[2] = {mode(nmode)->externalParticles(1),
mode(nmode)->externalParticles(2)};
// make the particles
Lorentz5Momentum pparent = Lorentz5Momentum(inpart.second);
PPtr parent = inpart.first->produceParticle(pparent);
Lorentz5Momentum pout[2];
double ctheta,phi;
Kinematics::generateAngles(ctheta,phi);
Kinematics::twoBodyDecay(pparent, outa.second, outb.second,
ctheta, phi,pout[0],pout[1]);
if( ( !cc && outa.first!=newchild[0]) ||
( cc && !(( outa.first->CC() && outa.first->CC() == newchild[0])||
( !outa.first->CC() && outa.first == newchild[0]) )))
swap(pout[0],pout[1]);
ParticleVector decay;
decay.push_back(newchild[0]->produceParticle(pout[0]));
decay.push_back(newchild[1]->produceParticle(pout[1]));
double me = me2(-1,*parent,decay,Initialize);
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,
outa.second, outb.second);
return me/(8.*Constants::pi)*pcm;
}
-void GeneralTwoBodyDecayer::setDecayInfo(PDPtr incoming,PDPair outgoing,
- VertexBasePtr vertex, VertexBasePtr inV,
- const vector<VertexBasePtr> & outV,
- VertexBasePtr fourV) {
+void GeneralTwoBodyDecayer::decayInfo(PDPtr incoming, PDPair outgoing) {
incoming_=incoming;
outgoing_.clear();
outgoing_.push_back(outgoing.first );
outgoing_.push_back(outgoing.second);
- vertex_ = vertex;
- incomingVertex_ = inV;
- outgoingVertices_ = outV;
- fourPointVertex_ = fourV;
-
}
double GeneralTwoBodyDecayer::matrixElementRatio(const Particle & inpart,
const ParticleVector & decay2,
const ParticleVector & decay3,
MEOption meopt,
ShowerInteraction inter) {
- if(inter!=ShowerInteraction::QCD) return 0.;
// calculate R/B
double B = me2 (0, inpart, decay2, meopt);
- double R = threeBodyME(0, inpart, decay3, meopt);
+ double R = threeBodyME(0, inpart, decay3, inter, meopt);
return R/B;
}
const vector<DVector> & GeneralTwoBodyDecayer::getColourFactors(const Particle & inpart,
const ParticleVector & decay,
unsigned int & nflow){
// calculate the colour factors for the three-body decay
vector<int> sing,trip,atrip,oct;
for(unsigned int it=0;it<decay.size();++it) {
if (decay[it]->dataPtr()->iColour() == PDT::Colour0 ) sing. push_back(it);
else if(decay[it]->dataPtr()->iColour() == PDT::Colour3 ) trip. push_back(it);
else if(decay[it]->dataPtr()->iColour() == PDT::Colour3bar ) atrip.push_back(it);
else if(decay[it]->dataPtr()->iColour() == PDT::Colour8 ) oct. push_back(it);
}
// require at least one gluon
assert(oct.size()>=1);
// identical particle symmetry factor
double symFactor=1.;
if (( sing.size()==2 && decay[ sing[0]]->id()==decay[ sing[1]]->id()) ||
( trip.size()==2 && decay[ trip[0]]->id()==decay[ trip[1]]->id()) ||
(atrip.size()==2 && decay[atrip[0]]->id()==decay[atrip[1]]->id()) ||
( oct.size()==2 && decay[ oct[0]]->id()==decay[ oct[1]]->id()))
symFactor/=2.;
else if (oct.size()==3 &&
decay[oct[0]]->id()==decay[oct[1]]->id() &&
decay[oct[0]]->id()==decay[oct[2]]->id())
symFactor/=6.;
colour_ = vector<DVector>(1,DVector(1,symFactor*1.));
// decaying colour singlet
if(inpart.dataPtr()->iColour() == PDT::Colour0) {
if(trip.size()==1 && atrip.size()==1 && oct.size()==1) {
nflow = 1;
colour_ = vector<DVector>(1,DVector(1,symFactor*4.));
}
else if (oct.size()==3){
nflow = 1.;
colour_ = vector<DVector>(1,DVector(1,symFactor*24.));
}
else
throw Exception() << "Unknown colour for the outgoing particles"
<< " for decay colour scalar particle in "
<< "GeneralTwoBodyDecayer::getColourFactors() for "
<< inpart. dataPtr()->PDGName() << " -> "
<< decay[0]->dataPtr()->PDGName() << " "
<< decay[1]->dataPtr()->PDGName() << " "
<< decay[2]->dataPtr()->PDGName()
<< Exception::runerror;
}
// decaying colour triplet
else if(inpart.dataPtr()->iColour() == PDT::Colour3) {
if(trip.size()==1 && sing.size()==1 && oct.size()==1) {
nflow = 1;
colour_ = vector<DVector>(1,DVector(1,symFactor*4./3.));
}
else if(trip.size()==1 && oct.size()==2) {
nflow = 2;
colour_.clear();
colour_.resize(2,DVector(2,0.));
colour_[0][0] = symFactor*16./9.; colour_[0][1] = -symFactor*2./9.;
colour_[1][0] = -symFactor*2./9.; colour_[1][1] = symFactor*16./9.;
}
else
throw Exception() << "Unknown colour for the outgoing particles"
<< " for decay colour triplet particle in "
<< "GeneralTwoBodyDecayer::getColourFactors() for "
<< inpart. dataPtr()->PDGName() << " -> "
<< decay[0]->dataPtr()->PDGName() << " "
<< decay[1]->dataPtr()->PDGName() << " "
<< decay[2]->dataPtr()->PDGName()
<< Exception::runerror;
}
// decaying colour anti-triplet
else if(inpart.dataPtr()->iColour() == PDT::Colour3bar) {
if(atrip.size()==1 && sing.size()==1 && oct.size()==1) {
nflow = 1;
colour_ = vector<DVector>(1,DVector(1,symFactor*4./3.));
}
else if(atrip.size()==1 && oct.size()==2){
nflow = 2;
colour_.clear();
colour_ .resize(2,DVector(2,0.));
colour_[0][0] = symFactor*16./9.; colour_[0][1] = -symFactor*2./9.;
colour_[1][0] = -symFactor*2./9.; colour_[1][1] = symFactor*16./9.;
}
else
throw Exception() << "Unknown colour for the outgoing particles"
<< " for decay colour anti-triplet particle in "
<< "GeneralTwoBodyDecayer::getColourFactors() for "
<< inpart. dataPtr()->PDGName() << " -> "
<< decay[0]->dataPtr()->PDGName() << " "
<< decay[1]->dataPtr()->PDGName() << " "
<< decay[2]->dataPtr()->PDGName()
<< Exception::runerror;
}
// decaying colour octet
else if(inpart.dataPtr()->iColour() == PDT::Colour8) {
if(oct.size()==1 && trip.size()==1 && atrip.size()==1) {
nflow = 2;
colour_.clear();
colour_.resize(2,DVector(2,0.));
colour_[0][0] = symFactor*2./3. ; colour_[0][1] = -symFactor*1./12.;
colour_[1][0] = -symFactor*1./12.; colour_[1][1] = symFactor*2./3. ;
}
else if (oct.size()==2 && sing.size()==1){
nflow = 1;
colour_ = vector<DVector>(1,DVector(1,symFactor*3.));
}
else
throw Exception() << "Unknown colour for the outgoing particles"
<< " for decay colour octet particle in "
<< "GeneralTwoBodyDecayer::getColourFactors() for "
<< inpart. dataPtr()->PDGName() << " -> "
<< decay[0]->dataPtr()->PDGName() << " "
<< decay[1]->dataPtr()->PDGName() << " "
<< decay[2]->dataPtr()->PDGName()
<< Exception::runerror;
}
else
throw Exception() << "Unknown colour for the decaying particle in "
<< "GeneralTwoBodyDecayer::getColourFactors() for "
<< inpart. dataPtr()->PDGName() << " -> "
<< decay[0]->dataPtr()->PDGName() << " "
<< decay[1]->dataPtr()->PDGName() << " "
<< decay[2]->dataPtr()->PDGName()
<< Exception::runerror;
return colour_;
}
const GeneralTwoBodyDecayer::CFlow &
GeneralTwoBodyDecayer::colourFlows(const Particle & inpart,
const ParticleVector & decay) {
// static initialization of commonly used colour structures
static const CFlow init = CFlow(3, CFlowPairVec(1, make_pair(0, 1.)));
static CFlow tripflow = init;
static CFlow atripflow = init;
static CFlow octflow = init;
static const CFlow fpflow = CFlow(4, CFlowPairVec(1, make_pair(0, 1.)));
static bool initialized = false;
if (! initialized) {
tripflow[2].resize(2, make_pair(0,1.));
tripflow[2][0] = make_pair(0, 1.);
tripflow[2][1] = make_pair(1,-1.);
tripflow[1][0] = make_pair(1, 1.);
atripflow[1].resize(2, make_pair(0,1.));
atripflow[1][0] = make_pair(0, 1.);
atripflow[1][1] = make_pair(1,-1.);
atripflow[2][0] = make_pair(1, 1.);
octflow[0].resize(2, make_pair(0,1.));
octflow[0][0] = make_pair(0,-1.);
octflow[0][1] = make_pair(1, 1.);
octflow[2][0] = make_pair(1, 1.);
initialized = true;
}
// main function body
int sing=0,trip=0,atrip=0,oct=0;
for (size_t it=0; it<decay.size(); ++it) {
switch ( decay[it]->dataPtr()->iColour() ) {
case PDT::Colour0: ++sing; break;
case PDT::Colour3: ++trip; break;
case PDT::Colour3bar: ++atrip; break;
case PDT::Colour8: ++oct; break;
/// @todo: handle these better
case PDT::ColourUndefined: break;
case PDT::Coloured: break;
case PDT::Colour6: break;
case PDT::Colour6bar: break;
}
}
// require a gluon
assert(oct>=1);
const CFlow * retval = 0;
bool inconsistent4PV = true;
// decaying colour triplet
if(inpart.dataPtr()->iColour() == PDT::Colour3 &&
trip==1 && oct==2) {
retval = &tripflow;
}
// decaying colour anti-triplet
else if(inpart.dataPtr()->iColour() == PDT::Colour3bar &&
atrip==1 && oct==2){
retval = &atripflow;
}
// decaying colour octet
else if(inpart.dataPtr()->iColour() == PDT::Colour8 &&
oct==1 && trip==1 && atrip==1) {
retval = &octflow;
}
else {
inconsistent4PV = false;
retval = &init;
}
- // if a 4 point vertex exists, add a colour flow for it
- if ( fourPointVertex_ ) {
- if ( inconsistent4PV )
- throw Exception() << "Unknown colour flows for 4 point vertex in "
- << "GeneralTwoBodyDecayer::colourFlows()"
- << Exception::runerror;
- else {
- retval = &fpflow;
- }
- }
+ // // if a 4 point vertex exists, add a colour flow for it
+ // if ( fourPointVertex_.find(ShowerInteraction::QCD)!=fourPointVertex_.end() ) {
+ // if ( inconsistent4PV )
+ // throw Exception() << "Unknown colour flows for 4 point vertex in "
+ // << "GeneralTwoBodyDecayer::colourFlows()"
+ // << Exception::runerror;
+ // else {
+ // retval = &fpflow;
+ // }
+ // }
return *retval;
}
+
+double GeneralTwoBodyDecayer::threeBodyME(const int , const Particle &,
+ const ParticleVector &,
+ ShowerInteraction, MEOption) {
+ throw Exception() << "Base class PerturbativeDecayer::threeBodyME() "
+ << "called, should have an implementation in the inheriting class"
+ << Exception::runerror;
+ return 0.;
+}
diff --git a/Decay/General/GeneralTwoBodyDecayer.h b/Decay/General/GeneralTwoBodyDecayer.h
--- a/Decay/General/GeneralTwoBodyDecayer.h
+++ b/Decay/General/GeneralTwoBodyDecayer.h
@@ -1,303 +1,305 @@
// -*- C++ -*-
//
// GeneralTwoBodyDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_GeneralTwoBodyDecayer_H
#define HERWIG_GeneralTwoBodyDecayer_H
//
// This is the declaration of the GeneralTwoBodyDecayer class.
//
#include "Herwig/Decay/PerturbativeDecayer.h"
#include "Herwig/Decay/DecayPhaseSpaceMode.h"
#include "ThePEG/Helicity/Vertex/VertexBase.h"
#include "GeneralTwoBodyDecayer.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
* PerturbativeDecayer 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 PerturbativeDecayer
*/
class GeneralTwoBodyDecayer: public PerturbativeDecayer {
public:
/** A ParticleData ptr and (possible) mass pair.*/
typedef pair<tcPDPtr, Energy> PMPair;
public:
/**
* The default constructor.
*/
GeneralTwoBodyDecayer() : maxWeight_(1.), 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;
//@}
/**
* Set the information on the decay
*/
- void setDecayInfo(PDPtr incoming,PDPair outgoing,
- VertexBasePtr,VertexBasePtr,
- const vector<VertexBasePtr> &,
- VertexBasePtr);
+ virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr>) =0;
protected:
/** @name Functions used by inheriting decayers. */
//@{
-
- /**
- * Get vertex pointer
- * @return a pointer to the vertex
- */
- VertexBasePtr vertex() const { return vertex_; }
-
- /**
- * Get vertex pointer
- * @return a pointer to the vertex for QCD radiation off the decaying particle
- */
- VertexBasePtr incomingVertex() const { return incomingVertex_; }
-
- /**
- * Get vertex pointer
- * @return a pointer to the vertex for QCD radiation off the decay products
- */
- vector<VertexBasePtr> outgoingVertices() 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(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;
/**
* 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,
ShowerInteraction inter);
+
+ /**
+ * Set the information on the decay
+ */
+ void decayInfo(PDPtr incoming, PDPair outgoing);
//@}
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);
+ /**
+ * Three-body matrix element including additional QCD radiation
+ */
+ virtual double threeBodyME(const int , const Particle & inpart,
+ const ParticleVector & decay,
+ ShowerInteraction inter, MEOption meopt);
+
//@}
private:
/**
* 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_;
/**
* Store colour factors for ME calc.
*/
vector<DVector> colour_;
};
+
+/**
+ * Write a map with ShowerInteraction as the key
+ */
+template<typename T, typename Cmp, typename A>
+inline PersistentOStream & operator<<(PersistentOStream & os,
+ const map<ShowerInteraction,T,Cmp,A> & m) {
+ os << m.size();
+ if(m.find(ShowerInteraction::QCD)!=m.end()) {
+ os << 0 << m.at(ShowerInteraction::QCD);
+ }
+ if(m.find(ShowerInteraction::QED)!=m.end()) {
+ os << 1 << m.at(ShowerInteraction::QED);
+ }
+ return os;
+}
+
+/**
+ * Read a map with ShowerInteraction as the key
+ */
+template <typename T, typename Cmp, typename A>
+inline PersistentIStream & operator>>(PersistentIStream & is, map<ShowerInteraction,T,Cmp,A> & m) {
+ m.clear();
+ long size;
+ int k;
+ is >> size;
+ while ( size-- && is ) {
+ is >> k;
+ if(k==0)
+ is >> m[ShowerInteraction::QCD];
+ else if(k==1)
+ is >> m[ShowerInteraction::QED];
+ else
+ assert(false);
+ }
+ return is;
+}
}
#endif /* HERWIG_GeneralTwoBodyDecayer_H */
diff --git a/Decay/General/SFFDecayer.cc b/Decay/General/SFFDecayer.cc
--- a/Decay/General/SFFDecayer.cc
+++ b/Decay/General/SFFDecayer.cc
@@ -1,394 +1,404 @@
// -*- C++ -*-
//
// SFFDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SFFDecayer class.
//
#include "SFFDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr SFFDecayer::clone() const {
return new_ptr(*this);
}
IBPtr SFFDecayer::fullclone() const {
return new_ptr(*this);
}
-void SFFDecayer::doinit() {
- perturbativeVertex_ = dynamic_ptr_cast<FFSVertexPtr> (vertex());
- abstractVertex_ = dynamic_ptr_cast<AbstractFFSVertexPtr>(vertex());
- abstractIncomingVertex_ = dynamic_ptr_cast<AbstractVSSVertexPtr>(incomingVertex());
- abstractOutgoingVertex1_ = dynamic_ptr_cast<AbstractFFVVertexPtr>(outgoingVertices()[0]);
- abstractOutgoingVertex2_ = dynamic_ptr_cast<AbstractFFVVertexPtr>(outgoingVertices()[1]);
- GeneralTwoBodyDecayer::doinit();
+void SFFDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
+ VertexBasePtr vertex,
+ map<ShowerInteraction,VertexBasePtr> & inV,
+ const vector<map<ShowerInteraction,VertexBasePtr> > & outV,
+ map<ShowerInteraction,VertexBasePtr> ) {
+ decayInfo(incoming,outgoing);
+ vertex_ = dynamic_ptr_cast<AbstractFFSVertexPtr>(vertex);
+ perturbativeVertex_ = dynamic_ptr_cast<FFSVertexPtr> (vertex);
+ vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
+ for(auto & inter : itemp) {
+ incomingVertex_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(inV.at(inter));
+ outgoingVertex1_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr>(outV[0].at(inter));
+ outgoingVertex2_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr>(outV[1].at(inter));
+ }
}
void SFFDecayer::persistentOutput(PersistentOStream & os) const {
- os << abstractVertex_ << perturbativeVertex_
- << abstractIncomingVertex_ << abstractOutgoingVertex1_
- << abstractOutgoingVertex2_;
+ os << vertex_ << perturbativeVertex_
+ << incomingVertex_ << outgoingVertex1_
+ << outgoingVertex2_;
}
void SFFDecayer::persistentInput(PersistentIStream & is, int) {
- is >> abstractVertex_ >> perturbativeVertex_
- >> abstractIncomingVertex_ >> abstractOutgoingVertex1_
- >> abstractOutgoingVertex2_;
+ is >> vertex_ >> perturbativeVertex_
+ >> incomingVertex_ >> outgoingVertex1_
+ >> outgoingVertex2_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SFFDecayer,GeneralTwoBodyDecayer>
describeHerwigSFFDecayer("Herwig::SFFDecayer", "Herwig.so");
void SFFDecayer::Init() {
static ClassDocumentation<SFFDecayer> documentation
("This class implements to decay of a scalar to 2 fermions");
}
double SFFDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin1Half,PDT::Spin1Half)));
// work out which is the fermion and antifermion
int iferm(1),ianti(0);
int itype[2];
for(unsigned int ix=0;ix<2;++ix) {
if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1;
else itype[ix] = 2;
}
if(itype[0]==0||itype[1]==1||(itype[0]==2&&itype[1]==2)) swap(iferm,ianti);
if(meopt==Initialize) {
ScalarWaveFunction::
calculateWaveFunctions(rho_,const_ptr_cast<tPPtr>(&inpart),incoming);
swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming);
}
if(meopt==Terminate) {
ScalarWaveFunction::
constructSpinInfo(const_ptr_cast<tPPtr>(&inpart),incoming,true);
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);
Energy2 scale(sqr(inpart.mass()));
for(unsigned int ifm = 0; ifm < 2; ++ifm){
for(unsigned int ia = 0; ia < 2; ++ia) {
if(iferm > ianti){
- (*ME())(0, ia, ifm) = abstractVertex_->evaluate(scale,wave_[ia],
+ (*ME())(0, ia, ifm) = vertex_->evaluate(scale,wave_[ia],
wavebar_[ifm],swave_);
}
else {
- (*ME())(0, ifm, ia) = abstractVertex_->evaluate(scale,wave_[ia],
+ (*ME())(0, ifm, ia) = vertex_->evaluate(scale,wave_[ia],
wavebar_[ifm],swave_);
}
}
}
double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy SFFDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
if(perturbativeVertex_) {
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
perturbativeVertex_->setCoupling(sqr(inpart.second), outb.first, outa.first,
in);
double mu1(outa.second/inpart.second),mu2(outb.second/inpart.second);
double c2 = norm(perturbativeVertex_->norm());
Complex al(perturbativeVertex_->left()), ar(perturbativeVertex_->right());
double me2 = -c2*( (norm(al) + norm(ar))*( sqr(mu1) + sqr(mu2) - 1.)
+ 2.*(ar*conj(al) + al*conj(ar)).real()*mu1*mu2 );
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second, outa.second,
outb.second);
Energy output = me2*pcm/(8*Constants::pi);
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
double SFFDecayer::threeBodyME(const int , const Particle & inpart,
- const ParticleVector & decay, MEOption meopt) {
+ const ParticleVector & decay,
+ ShowerInteraction inter, MEOption meopt) {
// work out which is the fermion and antifermion
int ianti(0), iferm(1), iglu(2);
int itype[2];
for(unsigned int ix=0;ix<2;++ix) {
if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1;
else itype[ix] = 2;
}
if(itype[0]==0 && itype[1]!=0) swap(iferm, ianti);
if(itype[0]==2 && itype[1]==1) swap(iferm, ianti);
if(itype[0]==0 && itype[1]==0 && decay[0]->dataPtr()->id()<decay[1]->dataPtr()->id())
swap(iferm, ianti);
if(itype[0]==1 && itype[1]==1 && decay[0]->dataPtr()->id()<decay[1]->dataPtr()->id())
swap(iferm, ianti);
if(meopt==Initialize) {
// create scalar wavefunction for decaying particle
ScalarWaveFunction::
calculateWaveFunctions(rho3_,const_ptr_cast<tPPtr>(&inpart),incoming);
swave3_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming);
}
// setup spin information when needed
if(meopt==Terminate) {
ScalarWaveFunction::
constructSpinInfo(const_ptr_cast<tPPtr>(&inpart),incoming,true);
SpinorBarWaveFunction::
constructSpinInfo(wavebar3_ ,decay[iferm],outgoing,true);
SpinorWaveFunction::
constructSpinInfo(wave3_ ,decay[ianti],outgoing,true);
VectorWaveFunction::
constructSpinInfo(gluon_ ,decay[iglu ],outgoing,true,false);
return 0.;
}
// calculate colour factors and number of colour flows
unsigned int nflow;
vector<DVector> cfactors = getColourFactors(inpart, decay, nflow);
if(nflow==2) cfactors[0][1]=cfactors[1][0];
vector<GeneralDecayMEPtr> ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, PDT::Spin1Half,
PDT::Spin1Half, PDT::Spin1)));
// create wavefunctions
SpinorBarWaveFunction::
calculateWaveFunctions(wavebar3_, decay[iferm],outgoing);
SpinorWaveFunction::
calculateWaveFunctions(wave3_ , decay[ianti],outgoing);
VectorWaveFunction::
calculateWaveFunctions(gluon_ , decay[iglu ],outgoing,true);
// // gauge invariance test
// gluon_.clear();
// for(unsigned int ix=0;ix<3;++ix) {
// if(ix==1) gluon_.push_back(VectorWaveFunction());
// else {
// gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(),
// decay[iglu ]->dataPtr(),10,
// outgoing));
// }
// }
// identify fermion and/or anti-fermion vertex
- AbstractFFVVertexPtr abstractOutgoingVertexF;
- AbstractFFVVertexPtr abstractOutgoingVertexA;
- identifyVertices(iferm, ianti, inpart, decay, abstractOutgoingVertexF, abstractOutgoingVertexA);
+ AbstractFFVVertexPtr outgoingVertexF;
+ AbstractFFVVertexPtr outgoingVertexA;
+ identifyVertices(iferm, ianti, inpart, decay, outgoingVertexF, outgoingVertexA,
+ inter);
const GeneralTwoBodyDecayer::CFlow & colourFlow
= colourFlows(inpart, decay);
Energy2 scale(sqr(inpart.mass()));
for(unsigned int ifm = 0; ifm < 2; ++ifm) {
for(unsigned int ia = 0; ia < 2; ++ia) {
for(unsigned int ig = 0; ig < 2; ++ig) {
// radiation from the incoming scalar
if(inpart.dataPtr()->coloured()) {
- assert(abstractIncomingVertex_);
+ assert(incomingVertex_[inter]);
ScalarWaveFunction scalarInter =
- abstractIncomingVertex_->evaluate(scale,3,inpart.dataPtr(),
+ incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),
gluon_[2*ig],swave3_,inpart.mass());
if (swave3_.particle()->PDGName()!=scalarInter.particle()->PDGName())
throw Exception()
<< swave3_ .particle()->PDGName() << " was changed to "
<< scalarInter.particle()->PDGName() << " in SFFDecayer::threeBodyME"
<< Exception::runerror;
- double gs = abstractIncomingVertex_->strongCoupling(scale);
- Complex diag = abstractVertex_->evaluate(scale,wave3_[ia], wavebar3_[ifm],
+ double gs = incomingVertex_[inter]->strongCoupling(scale);
+ Complex diag = vertex_->evaluate(scale,wave3_[ia], wavebar3_[ifm],
scalarInter)/gs;
for(unsigned int ix=0;ix<colourFlow[0].size();++ix) {
(*ME[colourFlow[0][ix].first])(0, ia, ifm, ig) +=
colourFlow[0][ix].second*diag;
}
}
// radiation from outgoing fermion
if(decay[iferm]->dataPtr()->coloured()) {
- assert(abstractOutgoingVertexF);
+ assert(outgoingVertexF);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[iferm]->dataPtr();
if(off->CC()) off = off->CC();
SpinorBarWaveFunction interS =
- abstractOutgoingVertexF->evaluate(scale,3,off,wavebar3_[ifm],
+ outgoingVertexF->evaluate(scale,3,off,wavebar3_[ifm],
gluon_[2*ig],decay[iferm]->mass());
if(wavebar3_[ifm].particle()->PDGName()!=interS.particle()->PDGName())
throw Exception()
<< wavebar3_[ifm].particle()->PDGName() << " was changed to "
<< interS .particle()->PDGName() << " in SFFDecayer::threeBodyME"
<< Exception::runerror;
- double gs = abstractOutgoingVertexF->strongCoupling(scale);
- Complex diag = abstractVertex_->evaluate(scale,wave3_[ia], interS,swave3_)/gs;
+ double gs = outgoingVertexF->strongCoupling(scale);
+ Complex diag = vertex_->evaluate(scale,wave3_[ia], interS,swave3_)/gs;
for(unsigned int ix=0;ix<colourFlow[1].size();++ix) {
(*ME[colourFlow[1][ix].first])(0, ia, ifm, ig) +=
colourFlow[1][ix].second*diag;
}
}
// radiation from outgoing antifermion
if(decay[ianti]->dataPtr()->coloured()) {
- assert(abstractOutgoingVertexA);
+ assert(outgoingVertexA);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[ianti]->dataPtr();
if(off->CC()) off = off->CC();
SpinorWaveFunction interS =
- abstractOutgoingVertexA->evaluate(scale,3,off,wave3_[ia],
+ outgoingVertexA->evaluate(scale,3,off,wave3_[ia],
gluon_[2*ig],decay[ianti]->mass());
if(wave3_[ia].particle()->PDGName()!=interS.particle()->PDGName())
throw Exception()
<< wave3_[ia].particle()->PDGName() << " was changed to "
<< interS .particle()->PDGName() << " in SFFDecayer::threeBodyME"
<< Exception::runerror;
- double gs = abstractOutgoingVertexA->strongCoupling(scale);
- Complex diag = abstractVertex_->evaluate(scale,interS,wavebar3_[ifm],swave3_)/gs;
+ double gs = outgoingVertexA->strongCoupling(scale);
+ Complex diag = vertex_->evaluate(scale,interS,wavebar3_[ifm],swave3_)/gs;
for(unsigned int ix=0;ix<colourFlow[2].size();++ix) {
(*ME[colourFlow[2][ix].first])(0, ia, ifm, ig) +=
colourFlow[2][ix].second*diag;
}
}
}
}
}
// contract matrices
double output=0.;
for(unsigned int ix=0; ix<nflow; ++ix){
for(unsigned int iy=0; iy<nflow; ++iy){
output+=cfactors[ix][iy]*(ME[ix]->contract(*ME[iy],rho3_)).real();
}
}
output*=(4.*Constants::pi);
// return the answer
return output;
}
void SFFDecayer::identifyVertices(const int iferm, const int ianti,
const Particle & inpart, const ParticleVector & decay,
- AbstractFFVVertexPtr & abstractOutgoingVertexF,
- AbstractFFVVertexPtr & abstractOutgoingVertexA){
+ AbstractFFVVertexPtr & outgoingVertexF,
+ AbstractFFVVertexPtr & outgoingVertexA,
+ ShowerInteraction inter) {
// work out which fermion each outgoing vertex corresponds to
// two outgoing vertices
if( inpart.dataPtr() ->iColour()==PDT::Colour0 &&
((decay[iferm]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar) ||
(decay[iferm]->dataPtr()->iColour()==PDT::Colour8 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour8))){
- if(abstractOutgoingVertex1_==abstractOutgoingVertex2_){
- abstractOutgoingVertexF = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){
+ outgoingVertexF = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
- else if (abstractOutgoingVertex1_->isIncoming(getParticleData(decay[iferm]->id()))){
- abstractOutgoingVertexF = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iferm]->id()))){
+ outgoingVertexF = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
- else if (abstractOutgoingVertex2_->isIncoming(getParticleData(decay[iferm]->id()))){
- abstractOutgoingVertexF = abstractOutgoingVertex2_;
- abstractOutgoingVertexA = abstractOutgoingVertex1_;
+ else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[iferm]->id()))){
+ outgoingVertexF = outgoingVertex2_[inter];
+ outgoingVertexA = outgoingVertex1_[inter];
}
}
else if(inpart.dataPtr() ->iColour()==PDT::Colour8 &&
decay[iferm]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){
- if(abstractOutgoingVertex1_==abstractOutgoingVertex2_){
- abstractOutgoingVertexF = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){
+ outgoingVertexF = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
- else if (abstractOutgoingVertex1_->isIncoming(getParticleData(decay[iferm]->id()))){
- abstractOutgoingVertexF = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iferm]->id()))){
+ outgoingVertexF = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
- else if (abstractOutgoingVertex2_->isIncoming(getParticleData(decay[iferm]->id()))){
- abstractOutgoingVertexF = abstractOutgoingVertex2_;
- abstractOutgoingVertexA = abstractOutgoingVertex1_;
+ else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[iferm]->id()))){
+ outgoingVertexF = outgoingVertex2_[inter];
+ outgoingVertexA = outgoingVertex1_[inter];
}
}
// one outgoing vertex
else if(inpart.dataPtr()->iColour()==PDT::Colour3){
if(decay[iferm]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour0){
- if (abstractOutgoingVertex1_) abstractOutgoingVertexF = abstractOutgoingVertex1_;
- else if(abstractOutgoingVertex2_) abstractOutgoingVertexF = abstractOutgoingVertex2_;
+ if (outgoingVertex1_[inter]) outgoingVertexF = outgoingVertex1_[inter];
+ else if(outgoingVertex2_[inter]) outgoingVertexF = outgoingVertex2_[inter];
}
else if (decay[iferm]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour8){
- if (abstractOutgoingVertex1_->isIncoming(getParticleData(decay[ianti]->dataPtr()->id()))){
- abstractOutgoingVertexF = abstractOutgoingVertex2_;
- abstractOutgoingVertexA = abstractOutgoingVertex1_;
+ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[ianti]->dataPtr()->id()))){
+ outgoingVertexF = outgoingVertex2_[inter];
+ outgoingVertexA = outgoingVertex1_[inter];
}
else {
- abstractOutgoingVertexF = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ outgoingVertexF = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
}
}
else if(inpart.dataPtr()->iColour()==PDT::Colour3bar){
if(decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar &&
decay[iferm]->dataPtr()->iColour()==PDT::Colour0){
- if (abstractOutgoingVertex1_) abstractOutgoingVertexA = abstractOutgoingVertex1_;
- else if(abstractOutgoingVertex2_) abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ if (outgoingVertex1_[inter]) outgoingVertexA = outgoingVertex1_[inter];
+ else if(outgoingVertex2_[inter]) outgoingVertexA = outgoingVertex2_[inter];
}
else if (decay[iferm]->dataPtr()->iColour()==PDT::Colour8 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){
- if (abstractOutgoingVertex1_->isIncoming(getParticleData(decay[iferm]->dataPtr()->id()))){
- abstractOutgoingVertexF = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iferm]->dataPtr()->id()))){
+ outgoingVertexF = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
else {
- abstractOutgoingVertexF = abstractOutgoingVertex2_;
- abstractOutgoingVertexA = abstractOutgoingVertex1_;
+ outgoingVertexF = outgoingVertex2_[inter];
+ outgoingVertexA = outgoingVertex1_[inter];
}
}
}
- if (! ((abstractIncomingVertex_ && (abstractOutgoingVertexF || abstractOutgoingVertexA)) ||
- ( abstractOutgoingVertexF && abstractOutgoingVertexA)))
+ if (! ((incomingVertex_[inter] && (outgoingVertexF || outgoingVertexA)) ||
+ ( outgoingVertexF && outgoingVertexA)))
throw Exception()
<< "Invalid vertices for QCD radiation in SFF decay in SFFDecayer::identifyVertices"
<< Exception::runerror;
}
diff --git a/Decay/General/SFFDecayer.h b/Decay/General/SFFDecayer.h
--- a/Decay/General/SFFDecayer.h
+++ b/Decay/General/SFFDecayer.h
@@ -1,225 +1,224 @@
// -*- C++ -*-
//
// SFFDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_SFFDecayer_H
#define HERWIG_SFFDecayer_H
//
// This is the declaration of the SFFDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Scalar/FFSVertex.h"
#include "ThePEG/Helicity/Vertex/Scalar/VSSVertex.h"
#include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::FFSVertexPtr;
/** \ingroup Decay
* The SFFDecayer class implements the decay of a scalar to 2
* fermions in a general model. It holds an FFSVertex pointer that
* must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class SFFDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
SFFDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* 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;
/**
* 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;
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return FSR;}
/**
* Three-body matrix element including additional QCD radiation
*/
virtual double threeBodyME(const int , const Particle & inpart,
- const ParticleVector & decay,MEOption meopt);
+ const ParticleVector & decay,
+ ShowerInteraction inter,
+ MEOption meopt);
/**
* Indentify outgoing vertices for the fermion and antifermion
*/
void identifyVertices(const int iferm, const int ianti,
const Particle & inpart, const ParticleVector & decay,
- AbstractFFVVertexPtr & abstractOutgoingVertexF,
- AbstractFFVVertexPtr & abstractOutgoingVertexA);
+ AbstractFFVVertexPtr & outgoingVertexF,
+ AbstractFFVVertexPtr & outgoingVertexA,
+ ShowerInteraction inter);
+
+ /**
+ * Set the information on the decay
+ */
+ virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr>);
//@}
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 and
- * EventGenerator to disk.
- * @throws InitException if object could not be initialized properly.
- */
- virtual void doinit();
- //@}
-
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
SFFDecayer & operator=(const SFFDecayer &);
private:
/**
* Abstract pointer to AbstractFFSVertex
*/
- AbstractFFSVertexPtr abstractVertex_;
+ AbstractFFSVertexPtr vertex_;
/**
* Pointer to the perturbative vertex
*/
FFSVertexPtr perturbativeVertex_;
/**
* Abstract pointer to AbstractVSSVertex for QCD radiation from incoming scalar
*/
- AbstractVSSVertexPtr abstractIncomingVertex_;
+ map<ShowerInteraction,AbstractVSSVertexPtr> incomingVertex_;
/**
* Abstract pointer to AbstractFFVVertex for QCD radiation from outgoing (anti)fermion
*/
- AbstractFFVVertexPtr abstractOutgoingVertex1_;
+ map<ShowerInteraction,AbstractFFVVertexPtr> outgoingVertex1_;
/**
* Abstract pointer to AbstractFFVVertex for QCD radiation from outgoing (anti)fermion
*/
- AbstractFFVVertexPtr abstractOutgoingVertex2_;
+ map<ShowerInteraction,AbstractFFVVertexPtr> outgoingVertex2_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Scalar wavefunction
*/
mutable ScalarWaveFunction swave_;
/**
* Spinor wavefunction
*/
mutable vector<SpinorWaveFunction> wave_;
/**
* Barred spinor wavefunction
*/
mutable vector<SpinorBarWaveFunction> wavebar_;
/**
* Spin density matrix for 3 body decay
*/
mutable RhoDMatrix rho3_;
/**
* Scalar wavefunction for 3 body decay
*/
mutable ScalarWaveFunction swave3_;
/**
* Spinor wavefunction for 3 body decay
*/
mutable vector<SpinorWaveFunction> wave3_;
/**
* Barred spinor wavefunction for 3 body decay
*/
mutable vector<SpinorBarWaveFunction> wavebar3_;
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<VectorWaveFunction> gluon_;
};
}
#endif /* HERWIG_SFFDecayer_H */
diff --git a/Decay/General/SRFDecayer.cc b/Decay/General/SRFDecayer.cc
--- a/Decay/General/SRFDecayer.cc
+++ b/Decay/General/SRFDecayer.cc
@@ -1,177 +1,181 @@
// -*- C++ -*-
//
// SRFDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SRFDecayer class.
//
#include "SRFDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr SRFDecayer::clone() const {
return new_ptr(*this);
}
IBPtr SRFDecayer::fullclone() const {
return new_ptr(*this);
}
-void SRFDecayer::doinit() {
- perturbativeVertex_ = dynamic_ptr_cast<RFSVertexPtr> (vertex());
- abstractVertex_ = dynamic_ptr_cast<AbstractRFSVertexPtr>(vertex());
- GeneralTwoBodyDecayer::doinit();
+void SRFDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
+ VertexBasePtr vertex,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr>) {
+ decayInfo(incoming,outgoing);
+ vertex_ = dynamic_ptr_cast<AbstractRFSVertexPtr>(vertex);
+ perturbativeVertex_ = dynamic_ptr_cast<RFSVertexPtr> (vertex);
}
void SRFDecayer::persistentOutput(PersistentOStream & os) const {
- os << abstractVertex_ << perturbativeVertex_;
+ os << vertex_ << perturbativeVertex_;
}
void SRFDecayer::persistentInput(PersistentIStream & is, int) {
- is >> abstractVertex_ >> perturbativeVertex_;
+ is >> vertex_ >> perturbativeVertex_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SRFDecayer,GeneralTwoBodyDecayer>
describeHerwigSRFDecayer("Herwig::SRFDecayer", "Herwig.so");
void SRFDecayer::Init() {
static ClassDocumentation<SRFDecayer> documentation
("This class implements to decay of a scalar to a spin-3/2 and"
" spin-1/2 fermion");
}
double SRFDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,MEOption meopt) const {
unsigned int irs=0,ifm=1;
if(decay[0]->dataPtr()->iSpin()==PDT::Spin1Half) swap(irs,ifm);
if(!ME()) {
if(irs==0)
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin3Half,PDT::Spin1Half)));
else
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin1Half,PDT::Spin3Half)));
}
bool ferm = decay[ifm]->id()<0;
if(meopt==Initialize) {
ScalarWaveFunction::
calculateWaveFunctions(rho_,const_ptr_cast<tPPtr>(&inpart),incoming);
swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming);
}
if(meopt==Terminate) {
ScalarWaveFunction::
constructSpinInfo(const_ptr_cast<tPPtr>(&inpart),incoming,true);
if(ferm) {
RSSpinorBarWaveFunction::
constructSpinInfo(RSwavebar_,decay[irs],outgoing,true);
SpinorWaveFunction::
constructSpinInfo(wave_ ,decay[ifm],outgoing,true);
}
else {
RSSpinorWaveFunction::
constructSpinInfo(RSwave_ ,decay[irs],outgoing,true);
SpinorBarWaveFunction::
constructSpinInfo(wavebar_,decay[ifm],outgoing,true);
}
return 0.;
}
if(ferm) {
RSSpinorBarWaveFunction::
calculateWaveFunctions(RSwavebar_,decay[irs],outgoing);
SpinorWaveFunction::
calculateWaveFunctions(wave_ ,decay[ifm],outgoing);
}
else {
RSSpinorWaveFunction::
calculateWaveFunctions(RSwave_ ,decay[irs],outgoing);
SpinorBarWaveFunction::
calculateWaveFunctions(wavebar_,decay[ifm],outgoing);
}
Energy2 scale(sqr(inpart.mass()));
for(unsigned int ifm = 0; ifm < 4; ++ifm){
for(unsigned int ia = 0; ia < 2; ++ia) {
if(irs==0) {
if(ferm)
- (*ME())(0, ifm, ia) = abstractVertex_->evaluate(scale,wave_[ia],
+ (*ME())(0, ifm, ia) = vertex_->evaluate(scale,wave_[ia],
RSwavebar_[ifm],swave_);
else
- (*ME())(0, ifm, ia) = abstractVertex_->evaluate(scale,RSwave_[ifm],
+ (*ME())(0, ifm, ia) = vertex_->evaluate(scale,RSwave_[ifm],
wavebar_[ia],swave_);
}
else {
if(ferm)
- (*ME())(0, ia, ifm) = abstractVertex_->evaluate(scale,wave_[ia],
+ (*ME())(0, ia, ifm) = vertex_->evaluate(scale,wave_[ia],
RSwavebar_[ifm],swave_);
else
- (*ME())(0, ia, ifm) = abstractVertex_->evaluate(scale,RSwave_[ifm],
+ (*ME())(0, ia, ifm) = vertex_->evaluate(scale,RSwave_[ifm],
wavebar_[ia],swave_);
}
}
}
double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[irs]->dataPtr(),
decay[ifm]->dataPtr());
// return the answer
return output;
}
Energy SRFDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
if(perturbativeVertex_) {
Energy q = inpart.second;
Energy m1 = outa.second, m2 = outb.second;
// couplings
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
if(outa.first->iSpin()==PDT::Spin1Half) {
swap(m1,m2);
perturbativeVertex_->setCoupling(sqr(inpart.second),outb.first,
outa.first, in);
}
else {
perturbativeVertex_->setCoupling(sqr(inpart.second),outa.first,
outb.first, in);
}
Complex left = perturbativeVertex_-> left()*perturbativeVertex_-> norm();
Complex right = perturbativeVertex_->right()*perturbativeVertex_-> norm();
complex<InvEnergy> A1 = 0.5*(left+right)*UnitRemoval::InvE;
complex<InvEnergy> B1 = 0.5*(right-left)*UnitRemoval::InvE;
Energy2 q2(q*q),m12(m1*m1),m22(m2*m2);
Energy2 pcm2(0.25*(q2*(q2-2.*m12-2.*m22)+(m12-m22)*(m12-m22))/q2);
Energy pcm(sqrt(pcm2));
Energy Qp(sqrt(-sqr(m2+m1)+q2)),Qm(sqrt(-sqr(m2-m1)+q2));
double r23(sqrt(2./3.));
complex<Energy> h1(-2.*r23*pcm*q/m1*Qm*B1);
complex<Energy> h2( 2.*r23*pcm*q/m1*Qp*A1);
double me2 = real(h1*conj(h1)+h2*conj(h2))/2./sqr(inpart.second);
Energy output = me2*pcm/8./Constants::pi;
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
diff --git a/Decay/General/SRFDecayer.h b/Decay/General/SRFDecayer.h
--- a/Decay/General/SRFDecayer.h
+++ b/Decay/General/SRFDecayer.h
@@ -1,174 +1,170 @@
// -*- C++ -*-
//
// SRFDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_SRFDecayer_H
#define HERWIG_SRFDecayer_H
//
// This is the declaration of the SRFDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Scalar/RFSVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::RFSVertexPtr;
/** \ingroup Decay
* The SRFDecayer class implements the decay of a scalar to spin-3/2
* and spin-1/2 fermion in a general model. It holds an RFSVertex pointer that
* must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class SRFDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
SRFDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* 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;
/**
* 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;
+
+ /**
+ * Set the information on the decay
+ */
+ virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr>);
//@}
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 and
- * EventGenerator to disk.
- * @throws InitException if object could not be initialized properly.
- */
- virtual void doinit();
- //@}
-
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
SRFDecayer & operator=(const SRFDecayer &);
private:
/**
* Abstract pointer to AbstractFFSVertex
*/
- AbstractRFSVertexPtr abstractVertex_;
+ AbstractRFSVertexPtr vertex_;
/**
* Pointer to the perturbative vertex
*/
RFSVertexPtr perturbativeVertex_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Scalar wavefunction
*/
mutable ScalarWaveFunction swave_;
/**
* Spinor wavefunction
*/
mutable vector<SpinorWaveFunction> wave_;
/**
* Barred spinor wavefunction
*/
mutable vector<SpinorBarWaveFunction> wavebar_;
/**
* RS Spinor wavefunction
*/
mutable vector<RSSpinorWaveFunction> RSwave_;
/**
* Barred RS spinor wavefunction
*/
mutable vector<RSSpinorBarWaveFunction> RSwavebar_;
};
}
#endif /* HERWIG_SRFDecayer_H */
diff --git a/Decay/General/SSSDecayer.cc b/Decay/General/SSSDecayer.cc
--- a/Decay/General/SSSDecayer.cc
+++ b/Decay/General/SSSDecayer.cc
@@ -1,350 +1,358 @@
// -*- C++ -*-
//
// SSSDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSSDecayer class.
//
#include "SSSDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr SSSDecayer::clone() const {
return new_ptr(*this);
}
IBPtr SSSDecayer::fullclone() const {
return new_ptr(*this);
}
-void SSSDecayer::doinit() {
- perturbativeVertex_ = dynamic_ptr_cast<SSSVertexPtr> (vertex());
- abstractVertex_ = dynamic_ptr_cast<AbstractSSSVertexPtr>(vertex());
- abstractIncomingVertex_ = dynamic_ptr_cast<AbstractVSSVertexPtr>(incomingVertex());
- abstractOutgoingVertex1_ = dynamic_ptr_cast<AbstractVSSVertexPtr>(outgoingVertices()[0]);
- abstractOutgoingVertex2_ = dynamic_ptr_cast<AbstractVSSVertexPtr>(outgoingVertices()[1]);
-
- GeneralTwoBodyDecayer::doinit();
+void SSSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
+ VertexBasePtr vertex,
+ map<ShowerInteraction,VertexBasePtr> & inV,
+ const vector<map<ShowerInteraction,VertexBasePtr> > & outV,
+ map<ShowerInteraction,VertexBasePtr> ) {
+ decayInfo(incoming,outgoing);
+ vertex_ = dynamic_ptr_cast<AbstractSSSVertexPtr>(vertex);
+ perturbativeVertex_ = dynamic_ptr_cast<SSSVertexPtr> (vertex);
+ vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
+ for(auto & inter : itemp) {
+ incomingVertex_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(inV.at(inter));
+ outgoingVertex1_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(outV[0].at(inter));
+ outgoingVertex2_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(outV[1].at(inter));
+ }
}
void SSSDecayer::persistentOutput(PersistentOStream & os) const {
- os << abstractVertex_ << perturbativeVertex_
- << abstractIncomingVertex_ << abstractOutgoingVertex1_
- << abstractOutgoingVertex2_;
+ os << vertex_ << perturbativeVertex_
+ << incomingVertex_ << outgoingVertex1_
+ << outgoingVertex2_;
}
void SSSDecayer::persistentInput(PersistentIStream & is, int) {
- is >> abstractVertex_ >> perturbativeVertex_
- >> abstractIncomingVertex_ >> abstractOutgoingVertex1_
- >> abstractOutgoingVertex2_;
+ is >> vertex_ >> perturbativeVertex_
+ >> incomingVertex_ >> outgoingVertex1_
+ >> outgoingVertex2_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SSSDecayer,GeneralTwoBodyDecayer>
describeHerwigSSSDecayer("Herwig::SSSDecayer", "Herwig.so");
void SSSDecayer::Init() {
static ClassDocumentation<SSSDecayer> documentation
("This class implements the decay of a scalar to 2 scalars.");
}
double SSSDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin0,PDT::Spin0)));
if(meopt==Initialize) {
ScalarWaveFunction::
calculateWaveFunctions(rho_,const_ptr_cast<tPPtr>(&inpart),incoming);
swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming);
}
if(meopt==Terminate) {
ScalarWaveFunction::
constructSpinInfo(const_ptr_cast<tPPtr>(&inpart),incoming,true);
for(unsigned int ix=0;ix<2;++ix)
ScalarWaveFunction::
constructSpinInfo(decay[ix],outgoing,true);
}
ScalarWaveFunction s1(decay[0]->momentum(),decay[0]->dataPtr(),outgoing);
ScalarWaveFunction s2(decay[1]->momentum(),decay[1]->dataPtr(),outgoing);
Energy2 scale(sqr(inpart.mass()));
- (*ME())(0,0,0) = abstractVertex_->evaluate(scale,s1,s2,swave_);
+ (*ME())(0,0,0) = vertex_->evaluate(scale,s1,s2,swave_);
double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy SSSDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
if(perturbativeVertex_ && !perturbativeVertex_->kinematics()) {
Energy2 scale(sqr(inpart.second));
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
perturbativeVertex_->setCoupling(scale, in, outa.first, outb.first);
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second, outa.second,
outb.second);
double c2 = norm(perturbativeVertex_->norm());
Energy pWidth = c2*pcm/8./Constants::pi/scale*UnitRemoval::E2;
// colour factor
pWidth *= colourFactor(inpart.first,outa.first,outb.first);
return pWidth;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
double SSSDecayer::threeBodyME(const int , const Particle & inpart,
- const ParticleVector & decay, MEOption meopt) {
+ const ParticleVector & decay,
+ ShowerInteraction inter, MEOption meopt) {
// work out which is the scalar and anti scalar
int ianti(0), iscal(1), iglu(2);
int itype[2];
for(unsigned int ix=0;ix<2;++ix) {
if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1;
else itype[ix] = 2;
}
if(itype[0]==0 && itype[1]!=0) swap(ianti, iscal);
if(itype[0]==2 && itype[1]==1) swap(ianti, iscal);
if(itype[0]==0 && itype[1]==0 && abs(decay[0]->dataPtr()->id())>abs(decay[1]->dataPtr()->id()))
swap(iscal, ianti);
if(itype[0]==1 && itype[1]==1 && abs(decay[0]->dataPtr()->id())<abs(decay[1]->dataPtr()->id()))
swap(iscal, ianti);
if(meopt==Initialize) {
// create scalar wavefunction for decaying particle
ScalarWaveFunction::calculateWaveFunctions(rho3_,const_ptr_cast<tPPtr>(&inpart),incoming);
swave3_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming);
}
// setup spin information when needed
if(meopt==Terminate) {
ScalarWaveFunction::
constructSpinInfo(const_ptr_cast<tPPtr>(&inpart),incoming,true);
ScalarWaveFunction::
constructSpinInfo(decay[iscal],outgoing,true);
ScalarWaveFunction::
constructSpinInfo(decay[ianti],outgoing,true);
VectorWaveFunction::
constructSpinInfo(gluon_,decay[iglu ],outgoing,true,false);
return 0.;
}
// calculate colour factors and number of colour flows
unsigned int nflow;
vector<DVector> cfactors = getColourFactors(inpart, decay, nflow);
if(nflow==2) cfactors[0][1]=cfactors[1][0];
vector<GeneralDecayMEPtr> ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, PDT::Spin0,
PDT::Spin0, PDT::Spin1)));
// create wavefunctions
ScalarWaveFunction scal(decay[iscal]->momentum(), decay[iscal]->dataPtr(),outgoing);
ScalarWaveFunction anti(decay[ianti]->momentum(), decay[ianti]->dataPtr(),outgoing);
VectorWaveFunction::calculateWaveFunctions(gluon_,decay[iglu ],outgoing,true);
// // gauge invariance test
// gluon_.clear();
// for(unsigned int ix=0;ix<3;++ix) {
// if(ix==1) gluon_.push_back(VectorWaveFunction());
// else {
// gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(),
// decay[iglu ]->dataPtr(),10,
// outgoing));
// }
// }
- AbstractVSSVertexPtr abstractOutgoingVertexS;
- AbstractVSSVertexPtr abstractOutgoingVertexA;
- identifyVertices(iscal, ianti, inpart, decay, abstractOutgoingVertexS, abstractOutgoingVertexA);
+ AbstractVSSVertexPtr outgoingVertexS;
+ AbstractVSSVertexPtr outgoingVertexA;
+ identifyVertices(iscal, ianti, inpart, decay, outgoingVertexS, outgoingVertexA,inter);
Energy2 scale(sqr(inpart.mass()));
const GeneralTwoBodyDecayer::CFlow & colourFlow
= colourFlows(inpart, decay);
for(unsigned int ig = 0; ig < 2; ++ig) {
// radiation from the incoming scalar
if(inpart.dataPtr()->coloured()) {
- assert(abstractIncomingVertex_);
+ assert(incomingVertex_[inter]);
ScalarWaveFunction scalarInter =
- abstractIncomingVertex_->evaluate(scale,3,inpart.dataPtr(),
+ incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),
gluon_[2*ig],swave3_,inpart.mass());
if (swave3_.particle()->PDGName()!=scalarInter.particle()->PDGName())
throw Exception()
<< swave3_ .particle()->PDGName() << " was changed to "
<< scalarInter.particle()->PDGName() << " in SSSDecayer::threeBodyME"
<< Exception::runerror;
- double gs = abstractIncomingVertex_->strongCoupling(scale);
- Complex diag = abstractVertex_->evaluate(scale,scal,anti,scalarInter)/gs;
+ double gs = incomingVertex_[inter]->strongCoupling(scale);
+ Complex diag = vertex_->evaluate(scale,scal,anti,scalarInter)/gs;
for(unsigned int ix=0;ix<colourFlow[0].size();++ix) {
(*ME[colourFlow[0][ix].first])(0, 0, 0, ig) +=
colourFlow[0][ix].second*diag;
}
}
// radiation from the outgoing scalar
if(decay[iscal]->dataPtr()->coloured()) {
- assert(abstractOutgoingVertexS);
+ assert(outgoingVertexS);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[iscal]->dataPtr();
if(off->CC()) off = off->CC();
ScalarWaveFunction scalarInter =
- abstractOutgoingVertexS->evaluate(scale,3,off,gluon_[2*ig],scal,decay[iscal]->mass());
+ outgoingVertexS->evaluate(scale,3,off,gluon_[2*ig],scal,decay[iscal]->mass());
if (scal.particle()->PDGName()!=scalarInter.particle()->PDGName())
throw Exception()
<< scal .particle()->PDGName() << " was changed to "
<< scalarInter.particle()->PDGName() << " in SSSDecayer::threeBodyME"
<< Exception::runerror;
- double gs = abstractOutgoingVertexS->strongCoupling(scale);
- Complex diag = abstractVertex_->evaluate(scale,swave3_,anti,scalarInter)/gs;
+ double gs = outgoingVertexS->strongCoupling(scale);
+ Complex diag = vertex_->evaluate(scale,swave3_,anti,scalarInter)/gs;
for(unsigned int ix=0;ix<colourFlow[1].size();++ix) {
(*ME[colourFlow[1][ix].first])(0, 0, 0, ig) +=
colourFlow[1][ix].second*diag;
}
}
// radiation from the outgoing anti scalar
if(decay[ianti]->dataPtr()->coloured()) {
- assert(abstractOutgoingVertexA);
+ assert(outgoingVertexA);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[ianti]->dataPtr();
if(off->CC()) off = off->CC();
ScalarWaveFunction scalarInter =
- abstractOutgoingVertexA->evaluate(scale,3,off, gluon_[2*ig],anti,decay[ianti]->mass());
+ outgoingVertexA->evaluate(scale,3,off, gluon_[2*ig],anti,decay[ianti]->mass());
if (anti.particle()->PDGName()!=scalarInter.particle()->PDGName())
throw Exception()
<< anti .particle()->PDGName() << " was changed to "
<< scalarInter.particle()->PDGName() << " in SSSDecayer::threeBodyME"
<< Exception::runerror;
- double gs = abstractOutgoingVertexA->strongCoupling(scale);
- Complex diag = abstractVertex_->evaluate(scale,swave3_,scal,scalarInter)/gs;
+ double gs = outgoingVertexA->strongCoupling(scale);
+ Complex diag = vertex_->evaluate(scale,swave3_,scal,scalarInter)/gs;
for(unsigned int ix=0;ix<colourFlow[2].size();++ix) {
(*ME[colourFlow[2][ix].first])(0, 0, 0, ig) +=
colourFlow[2][ix].second*diag;
}
}
}
// contract matrices
double output=0.;
for(unsigned int ix=0; ix<nflow; ++ix){
for(unsigned int iy=0; iy<nflow; ++iy){
output+=cfactors[ix][iy]*(ME[ix]->contract(*ME[iy],rho3_)).real();
}
}
output*=(4.*Constants::pi);
// return the answer
return output;
}
void SSSDecayer::identifyVertices(const int iscal, const int ianti,
const Particle & inpart, const ParticleVector & decay,
- AbstractVSSVertexPtr & abstractOutgoingVertexS,
- AbstractVSSVertexPtr & abstractOutgoingVertexA){
+ AbstractVSSVertexPtr & outgoingVertexS,
+ AbstractVSSVertexPtr & outgoingVertexA,
+ ShowerInteraction inter){
// work out which scalar each outgoing vertex corresponds to
// two outgoing vertices
if( inpart.dataPtr() ->iColour()==PDT::Colour0 &&
((decay[iscal]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar) ||
(decay[iscal]->dataPtr()->iColour()==PDT::Colour8 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour8))){
- if(abstractOutgoingVertex1_==abstractOutgoingVertex2_){
- abstractOutgoingVertexS = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){
+ outgoingVertexS = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
- else if (abstractOutgoingVertex1_->isIncoming(getParticleData(decay[iscal]->id()))){
- abstractOutgoingVertexS = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){
+ outgoingVertexS = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
- else if (abstractOutgoingVertex2_->isIncoming(getParticleData(decay[iscal]->id()))){
- abstractOutgoingVertexS = abstractOutgoingVertex2_;
- abstractOutgoingVertexA = abstractOutgoingVertex1_;
+ else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){
+ outgoingVertexS = outgoingVertex2_[inter];
+ outgoingVertexA = outgoingVertex1_[inter];
}
}
else if(inpart.dataPtr() ->iColour()==PDT::Colour8 &&
decay[iscal]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){
- if(abstractOutgoingVertex1_==abstractOutgoingVertex2_){
- abstractOutgoingVertexS = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){
+ outgoingVertexS = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
- else if (abstractOutgoingVertex1_->isIncoming(getParticleData(decay[iscal]->id()))){
- abstractOutgoingVertexS = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){
+ outgoingVertexS = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
- else if (abstractOutgoingVertex2_->isIncoming(getParticleData(decay[iscal]->id()))){
- abstractOutgoingVertexS = abstractOutgoingVertex2_;
- abstractOutgoingVertexA = abstractOutgoingVertex1_;
+ else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){
+ outgoingVertexS = outgoingVertex2_[inter];
+ outgoingVertexA = outgoingVertex1_[inter];
}
}
// one outgoing vertex
else if(inpart.dataPtr() ->iColour()==PDT::Colour3){
if(decay[iscal]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour0){
- if (abstractOutgoingVertex1_) abstractOutgoingVertexS = abstractOutgoingVertex1_;
- else if(abstractOutgoingVertex2_) abstractOutgoingVertexS = abstractOutgoingVertex2_;
+ if (outgoingVertex1_[inter]) outgoingVertexS = outgoingVertex1_[inter];
+ else if(outgoingVertex2_[inter]) outgoingVertexS = outgoingVertex2_[inter];
}
else if (decay[iscal]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour8){
- if (abstractOutgoingVertex1_->isIncoming(getParticleData(decay[ianti]->dataPtr()->id()))){
- abstractOutgoingVertexS = abstractOutgoingVertex2_;
- abstractOutgoingVertexA = abstractOutgoingVertex1_;
+ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[ianti]->dataPtr()->id()))){
+ outgoingVertexS = outgoingVertex2_[inter];
+ outgoingVertexA = outgoingVertex1_[inter];
}
else {
- abstractOutgoingVertexS = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ outgoingVertexS = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
}
}
else if(inpart.dataPtr() ->iColour()==PDT::Colour3bar){
if(decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar &&
decay[iscal]->dataPtr()->iColour()==PDT::Colour0){
- if (abstractOutgoingVertex1_) abstractOutgoingVertexA = abstractOutgoingVertex1_;
- else if(abstractOutgoingVertex2_) abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ if (outgoingVertex1_[inter]) outgoingVertexA = outgoingVertex1_[inter];
+ else if(outgoingVertex2_[inter]) outgoingVertexA = outgoingVertex2_[inter];
}
else if (decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar &&
decay[iscal]->dataPtr()->iColour()==PDT::Colour8){
- if (abstractOutgoingVertex1_->isIncoming(getParticleData(decay[iscal]->dataPtr()->id()))){
- abstractOutgoingVertexS = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->dataPtr()->id()))){
+ outgoingVertexS = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
else {
- abstractOutgoingVertexS = abstractOutgoingVertex2_;
- abstractOutgoingVertexA = abstractOutgoingVertex1_;
+ outgoingVertexS = outgoingVertex2_[inter];
+ outgoingVertexA = outgoingVertex1_[inter];
}
}
}
- if (! ((abstractIncomingVertex_ && (abstractOutgoingVertexS || abstractOutgoingVertexA)) ||
- ( abstractOutgoingVertexS && abstractOutgoingVertexA)))
+ if (! ((incomingVertex_[inter] && (outgoingVertexS || outgoingVertexA)) ||
+ ( outgoingVertexS && outgoingVertexA)))
throw Exception()
<< "Invalid vertices for QCD radiation in SSS decay in SSSDecayer::identifyVertices"
<< Exception::runerror;
}
diff --git a/Decay/General/SSSDecayer.h b/Decay/General/SSSDecayer.h
--- a/Decay/General/SSSDecayer.h
+++ b/Decay/General/SSSDecayer.h
@@ -1,203 +1,201 @@
// -*- C++ -*-
//
// SSSDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_SSSDecayer_H
#define HERWIG_SSSDecayer_H
//
// This is the declaration of the SSSDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Scalar/SSSVertex.h"
#include "ThePEG/Helicity/Vertex/Scalar/VSSVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::SSSVertexPtr;
/** \ingroup Decay
* The SSDecayer class implements the decay of a scalar
* to 2 scalars in a general model. It holds a SSSVertex
* pointer that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class SSSDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
SSSDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* 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;
/**
* 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;
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return FSR;}
/**
* Three-body matrix element including additional QCD radiation
*/
virtual double threeBodyME(const int , const Particle & inpart,
- const ParticleVector & decay,MEOption meopt);
+ const ParticleVector & decay,
+ ShowerInteraction inter, MEOption meopt);
/**
* Indentify outgoing vertices for the scalar and anti scalar
*/
void identifyVertices(const int iscal, const int ianti,
const Particle & inpart, const ParticleVector & decay,
AbstractVSSVertexPtr & abstractOutgoingVertexS,
- AbstractVSSVertexPtr & abstractOutgoingVertexA);
+ AbstractVSSVertexPtr & abstractOutgoingVertexA,
+ ShowerInteraction inter);
+
+ /**
+ * Set the information on the decay
+ */
+ virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr>);
//@}
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 and
- * EventGenerator to disk.
- * @throws InitException if object could not be initialized properly.
- */
- virtual void doinit();
- //@}
-
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
SSSDecayer & operator=(const SSSDecayer &);
private:
/**
* Abstract pointer to AbstractSSSVertex
*/
- AbstractSSSVertexPtr abstractVertex_;
+ AbstractSSSVertexPtr vertex_;
/**
* Pointer to the perturbative vertex
*/
SSSVertexPtr perturbativeVertex_;
/**
* Abstract pointer to AbstractVSSVertex for QCD radiation from incoming scalar
*/
- AbstractVSSVertexPtr abstractIncomingVertex_;
+ map<ShowerInteraction,AbstractVSSVertexPtr> incomingVertex_;
/**
* Abstract pointer to AbstractVSSVertex for QCD radiation from outgoing scalar
*/
- AbstractVSSVertexPtr abstractOutgoingVertex1_;
+ map<ShowerInteraction,AbstractVSSVertexPtr> outgoingVertex1_;
/**
* Abstract pointer to AbstractVSSVertex for QCD radiation from outgoing scalar
*/
- AbstractVSSVertexPtr abstractOutgoingVertex2_;
+ map<ShowerInteraction,AbstractVSSVertexPtr> outgoingVertex2_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Scalar wavefunctions
*/
mutable Helicity::ScalarWaveFunction swave_;
/**
* Spin density matrix for 3 body decay
*/
mutable RhoDMatrix rho3_;
/**
* Scalar wavefunction for 3 body decay
*/
mutable Helicity::ScalarWaveFunction swave3_;
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<Helicity::VectorWaveFunction> gluon_;
};
}
#endif /* HERWIG_SSSDecayer_H */
diff --git a/Decay/General/SSVDecayer.cc b/Decay/General/SSVDecayer.cc
--- a/Decay/General/SSVDecayer.cc
+++ b/Decay/General/SSVDecayer.cc
@@ -1,338 +1,333 @@
// -*- C++ -*-
//
// SSVDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSVDecayer class.
//
#include "SSVDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "Herwig/Utilities/Kinematics.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr SSVDecayer::clone() const {
return new_ptr(*this);
}
IBPtr SSVDecayer::fullclone() const {
return new_ptr(*this);
}
-void SSVDecayer::doinit() {
- perturbativeVertex_ = dynamic_ptr_cast<VSSVertexPtr> (vertex());
- abstractVertex_ = dynamic_ptr_cast<AbstractVSSVertexPtr> (vertex());
- abstractIncomingVertex_ = dynamic_ptr_cast<AbstractVSSVertexPtr> (incomingVertex());
- abstractFourPointVertex_ = dynamic_ptr_cast<AbstractVVSSVertexPtr>(getFourPointVertex());
-
- if (outgoingVertices()[0]){
- if (outgoingVertices()[0]->getName()==VertexType::VSS){
- abstractOutgoingVertexS_ = dynamic_ptr_cast<AbstractVSSVertexPtr>(outgoingVertices()[0]);
- abstractOutgoingVertexV_ = dynamic_ptr_cast<AbstractVVVVertexPtr>(outgoingVertices()[1]);
+void SSVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
+ VertexBasePtr vertex,
+ map<ShowerInteraction,VertexBasePtr> & inV,
+ const vector<map<ShowerInteraction,VertexBasePtr> > & outV,
+ map<ShowerInteraction,VertexBasePtr> fourV) {
+ decayInfo(incoming,outgoing);
+ vertex_ = dynamic_ptr_cast<AbstractVSSVertexPtr>(vertex);
+ perturbativeVertex_ = dynamic_ptr_cast<VSSVertexPtr> (vertex);
+ vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
+ for(auto & inter : itemp) {
+ incomingVertex_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(inV.at(inter));
+ fourPointVertex_[inter] = dynamic_ptr_cast<AbstractVVSSVertexPtr>(fourV.at(inter));
+ if (outV[0].at(inter)->getName()==VertexType::VSS){
+ outgoingVertexS_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(outV[0].at(inter));
+ outgoingVertexV_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr>(outV[1].at(inter));
}
else {
- abstractOutgoingVertexS_ = dynamic_ptr_cast<AbstractVSSVertexPtr>(outgoingVertices()[1]);
- abstractOutgoingVertexV_ = dynamic_ptr_cast<AbstractVVVVertexPtr>(outgoingVertices()[0]);
+ outgoingVertexS_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(outV[1].at(inter));
+ outgoingVertexV_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr>(outV[0].at(inter));
}
}
- else if (outgoingVertices()[1]){
- if (outgoingVertices()[1]->getName()==VertexType::VSS){
- abstractOutgoingVertexS_ = dynamic_ptr_cast<AbstractVSSVertexPtr>(outgoingVertices()[1]);
- abstractOutgoingVertexV_ = dynamic_ptr_cast<AbstractVVVVertexPtr>(outgoingVertices()[0]);
- }
- else {
- abstractOutgoingVertexS_ = dynamic_ptr_cast<AbstractVSSVertexPtr>(outgoingVertices()[0]);
- abstractOutgoingVertexV_ = dynamic_ptr_cast<AbstractVVVVertexPtr>(outgoingVertices()[1]);
- }
- }
- GeneralTwoBodyDecayer::doinit();
}
void SSVDecayer::persistentOutput(PersistentOStream & os) const {
- os << abstractVertex_ << perturbativeVertex_
- << abstractIncomingVertex_ << abstractOutgoingVertexS_
- << abstractOutgoingVertexV_ << abstractFourPointVertex_;
+ os << vertex_ << perturbativeVertex_
+ << incomingVertex_ << outgoingVertexS_
+ << outgoingVertexV_ << fourPointVertex_;
}
void SSVDecayer::persistentInput(PersistentIStream & is, int) {
- is >> abstractVertex_ >> perturbativeVertex_
- >> abstractIncomingVertex_ >> abstractOutgoingVertexS_
- >> abstractOutgoingVertexV_ >> abstractFourPointVertex_;
+ is >> vertex_ >> perturbativeVertex_
+ >> incomingVertex_ >> outgoingVertexS_
+ >> outgoingVertexV_ >> fourPointVertex_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SSVDecayer,GeneralTwoBodyDecayer>
describeHerwigSSVDecayer("Herwig::SSVDecayer", "Herwig.so");
void SSVDecayer::Init() {
static ClassDocumentation<SSVDecayer> documentation
("This implements the decay of a scalar to a vector and a scalar");
}
double SSVDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
unsigned int isc(0),ivec(1);
if(decay[0]->dataPtr()->iSpin() != PDT::Spin0) swap(isc,ivec);
if(!ME()) {
if(ivec==1)
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin0,PDT::Spin1)));
else
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin1,PDT::Spin0)));
}
if(meopt==Initialize) {
ScalarWaveFunction::
calculateWaveFunctions(rho_,const_ptr_cast<tPPtr>(&inpart),incoming);
swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming);
}
if(meopt==Terminate) {
ScalarWaveFunction::
constructSpinInfo(const_ptr_cast<tPPtr>(&inpart),incoming,true);
ScalarWaveFunction::
constructSpinInfo(decay[isc],outgoing,true);
VectorWaveFunction::
constructSpinInfo(vector_,decay[ivec],outgoing,true,false);
}
VectorWaveFunction::
calculateWaveFunctions(vector_,decay[ivec],outgoing,false);
ScalarWaveFunction sca(decay[isc]->momentum(),decay[isc]->dataPtr(),outgoing);
Energy2 scale(sqr(inpart.mass()));
//make sure decay matrix element is in the correct order
double output(0.);
if(ivec == 0) {
for(unsigned int ix = 0; ix < 3; ++ix)
- (*ME())(0, ix, 0) = abstractVertex_->evaluate(scale,vector_[ix],sca, swave_);
+ (*ME())(0, ix, 0) = vertex_->evaluate(scale,vector_[ix],sca, swave_);
}
else {
for(unsigned int ix = 0; ix < 3; ++ix)
- (*ME())(0, 0, ix) = abstractVertex_->evaluate(scale,vector_[ix],sca,swave_);
+ (*ME())(0, 0, ix) = vertex_->evaluate(scale,vector_[ix],sca,swave_);
}
output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy SSVDecayer:: partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
if(perturbativeVertex_) {
double mu1sq(sqr(outa.second/inpart.second)),
mu2sq(sqr(outb.second/inpart.second));
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
if(outa.first->iSpin() == PDT::Spin0) {
perturbativeVertex_->setCoupling(sqr(inpart.second), outb.first, outa.first,in);
}
else {
swap(mu1sq,mu2sq);
perturbativeVertex_->setCoupling(sqr(inpart.second), outa.first, outb.first,in);
}
double me2(0.);
if(mu2sq == 0.)
me2 = -2.*mu1sq - 2.;
else
me2 = ( sqr(mu2sq - mu1sq) - 2.*(mu2sq + mu1sq) + 1. )/mu2sq;
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second, outa.second,
outb.second);
Energy output = pcm*me2*norm(perturbativeVertex_->norm())/8./Constants::pi;
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
double SSVDecayer::threeBodyME(const int , const Particle & inpart,
- const ParticleVector & decay, MEOption meopt) {
+ const ParticleVector & decay,
+ ShowerInteraction inter, MEOption meopt) {
int iscal (0), ivect (1), iglu (2);
// get location of outgoing scalar/vector
if(decay[1]->dataPtr()->iSpin()==PDT::Spin0) swap(iscal,ivect);
// no emissions from massive vectors
- if (abstractOutgoingVertexV_ && decay[ivect]->dataPtr()->mass()!=ZERO)
+ if (outgoingVertexV_[inter] && decay[ivect]->dataPtr()->mass()!=ZERO)
throw Exception()
<< "No dipoles available for massive vectors in SSVDecayer::threeBodyME"
<< Exception::runerror;
if(meopt==Initialize) {
// create scalar wavefunction for decaying particle
ScalarWaveFunction::calculateWaveFunctions(rho3_,const_ptr_cast<tPPtr>(&inpart),incoming);
swave3_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming);
}
// setup spin information when needed
if(meopt==Terminate) {
ScalarWaveFunction::
constructSpinInfo(const_ptr_cast<tPPtr>(&inpart),incoming,true);
ScalarWaveFunction::
constructSpinInfo(decay[iscal],outgoing,true);
VectorWaveFunction::
constructSpinInfo(vector3_,decay[ivect],outgoing,true,false);
VectorWaveFunction::
constructSpinInfo(gluon_, decay[iglu ],outgoing,true,false);
return 0.;
}
// calculate colour factors and number of colour flows
unsigned int nflow;
vector<DVector> cfactors = getColourFactors(inpart, decay, nflow);
if(nflow==2) cfactors[0][1]=cfactors[1][0];
vector<GeneralDecayMEPtr> ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, PDT::Spin0,
PDT::Spin1, PDT::Spin1)));
// create wavefunctions
ScalarWaveFunction scal_(decay[iscal]->momentum(), decay[iscal]->dataPtr(),outgoing);
VectorWaveFunction::calculateWaveFunctions(vector3_,decay[ivect],outgoing,false);
VectorWaveFunction::calculateWaveFunctions(gluon_, decay[iglu ],outgoing,true );
// // gauge invariance test
// gluon_.clear();
// for(unsigned int ix=0;ix<3;++ix) {
// if(ix==1) gluon_.push_back(VectorWaveFunction());
// else {
// gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(),
// decay[iglu ]->dataPtr(),10,
// outgoing));
// }
// }
- if (! ((abstractIncomingVertex_ && (abstractOutgoingVertexS_ || abstractOutgoingVertexV_)) ||
- (abstractOutgoingVertexS_ && abstractOutgoingVertexV_)))
+ if (! ((incomingVertex_[inter] && (outgoingVertexS_[inter] || outgoingVertexV_[inter])) ||
+ (outgoingVertexS_[inter] && outgoingVertexV_[inter])))
throw Exception()
<< "Invalid vertices for QCD radiation in SSV decay in SSVDecayer::threeBodyME"
<< Exception::runerror;
// sort out colour flows
int S(1), V(2);
if (decay[iscal]->dataPtr()->iColour()==PDT::Colour3bar &&
decay[ivect]->dataPtr()->iColour()==PDT::Colour8)
swap(S,V);
else if (decay[ivect]->dataPtr()->iColour()==PDT::Colour3 &&
decay[iscal]->dataPtr()->iColour()==PDT::Colour8)
swap(S,V);
Energy2 scale(sqr(inpart.mass()));
const GeneralTwoBodyDecayer::CFlow & colourFlow
= colourFlows(inpart, decay);
for(unsigned int iv = 0; iv < 3; ++iv) {
for(unsigned int ig = 0; ig < 2; ++ig) {
// radiation from the incoming scalar
if(inpart.dataPtr()->coloured()) {
- assert(abstractIncomingVertex_);
+ assert(incomingVertex_[inter]);
ScalarWaveFunction scalarInter =
- abstractIncomingVertex_->evaluate(scale,3,inpart.dataPtr(),
+ incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),
gluon_[2*ig],swave3_,inpart.mass());
if (swave3_.particle()->PDGName()!=scalarInter.particle()->PDGName())
throw Exception()
<< swave3_ .particle()->PDGName() << " was changed to "
<< scalarInter.particle()->PDGName() << " in SSVDecayer::threeBodyME"
<< Exception::runerror;
- double gs = abstractIncomingVertex_->strongCoupling(scale);
+ double gs = incomingVertex_[inter]->strongCoupling(scale);
double sign = 1.;//inpart.dataPtr()->id()>0 ? 1:-1;
- Complex diag = sign * abstractVertex_->evaluate(scale,vector3_[iv],scal_,scalarInter)/gs;
+ Complex diag = sign * vertex_->evaluate(scale,vector3_[iv],scal_,scalarInter)/gs;
for(unsigned int ix=0;ix<colourFlow[0].size();++ix) {
(*ME[colourFlow[0][ix].first])(0, 0, iv, ig) +=
colourFlow[0][ix].second*diag;
}
}
// radiation from the outgoing scalar
if(decay[iscal]->dataPtr()->coloured()) {
- assert(abstractOutgoingVertexS_);
+ assert(outgoingVertexS_[inter]);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[iscal]->dataPtr();
if(off->CC()) off = off->CC();
ScalarWaveFunction scalarInter =
- abstractOutgoingVertexS_->evaluate(scale,3,off,gluon_[2*ig],scal_,decay[iscal]->mass());
+ outgoingVertexS_[inter]->evaluate(scale,3,off,gluon_[2*ig],scal_,decay[iscal]->mass());
if (scal_.particle()->PDGName()!=scalarInter.particle()->PDGName())
throw Exception()
<< scal_ .particle()->PDGName() << " was changed to "
<< scalarInter.particle()->PDGName() << " in SSVDecayer::threeBodyME"
<< Exception::runerror;
- double gs = abstractOutgoingVertexS_->strongCoupling(scale);
+ double gs = outgoingVertexS_[inter]->strongCoupling(scale);
double sign = 1.;//decay[iscal]->dataPtr()->id()>0 ? -1:1;
- Complex diag = sign*abstractVertex_->evaluate(scale,vector3_[iv],scalarInter,swave3_)/gs;
+ Complex diag = sign*vertex_->evaluate(scale,vector3_[iv],scalarInter,swave3_)/gs;
for(unsigned int ix=0;ix<colourFlow[S].size();++ix) {
(*ME[colourFlow[S][ix].first])(0, 0, iv, ig) +=
colourFlow[S][ix].second*diag;
}
}
// radiation from outgoing vector
if(decay[ivect]->dataPtr()->coloured()) {
- assert(abstractOutgoingVertexV_);
+ assert(outgoingVertexV_[inter]);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[ivect]->dataPtr();
if(off->CC()) off = off->CC();
VectorWaveFunction vectorInter =
- abstractOutgoingVertexV_->evaluate(scale,3,off,gluon_[2*ig],
+ outgoingVertexV_[inter]->evaluate(scale,3,off,gluon_[2*ig],
vector3_[iv],decay[ivect]->mass());
if(vector3_[iv].particle()->PDGName()!=vectorInter.particle()->PDGName())
throw Exception()
<< vector3_[iv].particle()->PDGName() << " was changed to "
<< vectorInter. particle()->PDGName() << " in SSVDecayer::threeBodyME"
<< Exception::runerror;
double sign = 1.;//decay[iscal]->id()>0 ? -1:1;
- double gs = abstractOutgoingVertexV_->strongCoupling(scale);
- Complex diag = sign*abstractVertex_->evaluate(scale,vectorInter,scal_,swave3_)/gs;
+ double gs = outgoingVertexV_[inter]->strongCoupling(scale);
+ Complex diag = sign*vertex_->evaluate(scale,vectorInter,scal_,swave3_)/gs;
for(unsigned int ix=0;ix<colourFlow[V].size();++ix) {
(*ME[colourFlow[V][ix].first])(0, 0, iv, ig) +=
colourFlow[V][ix].second*diag;
}
}
// radiation from 4 point vertex
- if (abstractFourPointVertex_){
- double gs = abstractFourPointVertex_->strongCoupling(scale);
+ if (fourPointVertex_[inter]){
+ double gs = fourPointVertex_[inter]->strongCoupling(scale);
double sign = decay[iscal]->id()>0 ? -1:-1;
- Complex diag = sign*abstractFourPointVertex_->evaluate(scale, gluon_[2*ig], vector3_[iv],
+ Complex diag = sign*fourPointVertex_[inter]->evaluate(scale, gluon_[2*ig], vector3_[iv],
scal_, swave3_)/gs;
for(unsigned int ix=0;ix<colourFlow[3].size();++ix) {
(*ME[colourFlow[3][ix].first])(0, 0, iv, ig) +=
colourFlow[3][ix].second*diag;
}
}
}
}
// contract matrices
double output=0.;
for(unsigned int ix=0; ix<nflow; ++ix){
for(unsigned int iy=0; iy<nflow; ++iy){
output+=cfactors[ix][iy]*(ME[ix]->contract(*ME[iy],rho3_)).real();
}
}
output*=(4.*Constants::pi);
// return the answer
return output;
}
diff --git a/Decay/General/SSVDecayer.h b/Decay/General/SSVDecayer.h
--- a/Decay/General/SSVDecayer.h
+++ b/Decay/General/SSVDecayer.h
@@ -1,217 +1,214 @@
// -*- C++ -*-
//
// SSVDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_SSVDecayer_H
#define HERWIG_SSVDecayer_H
//
// This is the declaration of the SSVDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Helicity/Vertex/Scalar/VSSVertex.h"
#include "ThePEG/Helicity/Vertex/Vector/VVVVertex.h"
#include "ThePEG/Helicity/Vertex/Scalar/VVSSVertex.h"
#include "ThePEG/Repository/EventGenerator.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::VSSVertexPtr;
/** \ingroup Decay
* The SSVDecayer class implements the decay of a scalar to a vector
* and a scalar in a general model. It holds an VSSVertex pointer
* that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class SSVDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
SSVDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* 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;
/**
* 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;
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return FSR;}
/**
* Three-body matrix element including additional QCD radiation
*/
virtual double threeBodyME(const int , const Particle & inpart,
- const ParticleVector & decay,MEOption meopt);
+ const ParticleVector & decay,
+ ShowerInteraction inter,
+ MEOption meopt);
+
+ /**
+ * Set the information on the decay
+ */
+ virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr>);
//@}
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
-
-protected:
-
- /** @name Standard Interfaced functions. */
- //@{
- /**
- * Initialize this object after the setup phase before saving an
- * EventGenerator to disk.
- * @throws InitException if object could not be initialized properly.
- */
- virtual void doinit();
- //@}
-
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
SSVDecayer & operator=(const SSVDecayer &);
private:
/**
* Abstract pointer to AbstractFFVVertex
*/
- AbstractVSSVertexPtr abstractVertex_;
+ AbstractVSSVertexPtr vertex_;
/**
* Pointer to the perturbative vertex
*/
VSSVertexPtr perturbativeVertex_;
/**
* Abstract pointer to AbstractVSSVertex for QCD radiation from incoming scalar
*/
- AbstractVSSVertexPtr abstractIncomingVertex_;
+ map<ShowerInteraction,AbstractVSSVertexPtr> incomingVertex_;
/**
* Abstract pointer to AbstractVSSVertex for QCD radiation from outgoing scalar
*/
- AbstractVSSVertexPtr abstractOutgoingVertexS_;
+ map<ShowerInteraction,AbstractVSSVertexPtr> outgoingVertexS_;
/**
* Abstract pointer to AbstractVVVVertex for QCD radiation from outgoing vector
*/
- AbstractVVVVertexPtr abstractOutgoingVertexV_;
+ map<ShowerInteraction,AbstractVVVVertexPtr> outgoingVertexV_;
/**
* Abstract pointer to AbstractVVSSVertex for QCD radiation from 4 point vertex
*/
- AbstractVVSSVertexPtr abstractFourPointVertex_;
+ map<ShowerInteraction,AbstractVVSSVertexPtr> fourPointVertex_;
/**
* Spinor density matrix
*/
mutable RhoDMatrix rho_;
/**
* Scalar wavefunction
*/
mutable Helicity::ScalarWaveFunction swave_;
/**
* Vector wavefunction
*/
mutable vector<Helicity::VectorWaveFunction> vector_;
/**
* Spin density matrix for 3 body decay
*/
mutable RhoDMatrix rho3_;
/**
* Scalar wavefunction for 3 body decay
*/
mutable Helicity::ScalarWaveFunction swave3_;
/**
* Scalar wavefunction for 3 body decay
*/
mutable Helicity::ScalarWaveFunction scal_;
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<Helicity::VectorWaveFunction> vector3_;
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<Helicity::VectorWaveFunction> gluon_;
};
}
#endif /* HERWIG_SSVDecayer_H */
diff --git a/Decay/General/SVVDecayer.cc b/Decay/General/SVVDecayer.cc
--- a/Decay/General/SVVDecayer.cc
+++ b/Decay/General/SVVDecayer.cc
@@ -1,142 +1,141 @@
// -*- C++ -*-
//
// SVVDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SVVDecayer class.
//
#include "SVVDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/Vertex/Scalar/VVSVertex.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr SVVDecayer::clone() const {
return new_ptr(*this);
}
IBPtr SVVDecayer::fullclone() const {
return new_ptr(*this);
}
-void SVVDecayer::doinit() {
- GeneralTwoBodyDecayer::doinit();
- abstractVertex_ = dynamic_ptr_cast<AbstractVVSVertexPtr>(vertex());
- perturbativeVertex_ = dynamic_ptr_cast<VVSVertexPtr >(vertex());
-}
-
-void SVVDecayer::doinitrun() {
- vertex()->initrun();
- GeneralTwoBodyDecayer::doinitrun();
+void SVVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
+ VertexBasePtr vertex,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr> ) {
+ decayInfo(incoming,outgoing);
+ vertex_ = dynamic_ptr_cast<AbstractVVSVertexPtr>(vertex);
+ perturbativeVertex_ = dynamic_ptr_cast<VVSVertexPtr> (vertex);
}
void SVVDecayer::persistentOutput(PersistentOStream & os) const {
- os << abstractVertex_ << perturbativeVertex_;
+ os << vertex_ << perturbativeVertex_;
}
void SVVDecayer::persistentInput(PersistentIStream & is, int) {
- is >> abstractVertex_ >> perturbativeVertex_;
+ is >> vertex_ >> perturbativeVertex_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SVVDecayer,GeneralTwoBodyDecayer>
describeHerwigSVVDecayer("Herwig::SVVDecayer", "Herwig.so");
void SVVDecayer::Init() {
static ClassDocumentation<SVVDecayer> documentation
("This implements the decay of a scalar to 2 vector bosons.");
}
double SVVDecayer::me2(const int , const Particle & inpart,
const ParticleVector& decay,
MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin1,PDT::Spin1)));
bool photon[2];
for(unsigned int ix=0;ix<2;++ix)
photon[ix] = decay[ix]->mass()==ZERO;
if(meopt==Initialize) {
ScalarWaveFunction::
calculateWaveFunctions(rho_,const_ptr_cast<tPPtr>(&inpart),incoming);
swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming);
}
if(meopt==Terminate) {
ScalarWaveFunction::
constructSpinInfo(const_ptr_cast<tPPtr>(&inpart),incoming,true);
for(unsigned int ix=0;ix<2;++ix)
VectorWaveFunction::
constructSpinInfo(vectors_[ix],decay[ix],outgoing,true,photon[ix]);
}
for(unsigned int ix=0;ix<2;++ix)
VectorWaveFunction::
calculateWaveFunctions(vectors_[ix],decay[ix],outgoing,photon[ix]);
Energy2 scale(sqr(inpart.mass()));
unsigned int iv1,iv2;
for(iv2 = 0; iv2 < 3; ++iv2) {
if( photon[1] && iv2 == 1 ) ++iv2;
for(iv1=0;iv1<3;++iv1) {
if( photon[0] && iv1 == 1) ++iv1;
- (*ME())(0, iv1, iv2) = abstractVertex_->evaluate(scale,vectors_[0][iv1],
- vectors_[1][iv2],swave_);
+ (*ME())(0, iv1, iv2) = vertex_->evaluate(scale,vectors_[0][iv1],
+ vectors_[1][iv2],swave_);
}
}
double output = ME()->contract(rho_).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy SVVDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
if(perturbativeVertex_) {
Energy2 scale(sqr(inpart.second));
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
perturbativeVertex_->setCoupling(scale, outa.first ,
outb.first, in);
double mu1sq = sqr(outa.second/inpart.second);
double mu2sq = sqr(outb.second/inpart.second);
double m1pm2 = mu1sq + mu2sq;
double me2(0.);
if( mu1sq > 0. && mu2sq > 0.)
me2 = ( m1pm2*(m1pm2 - 2.) + 8.*mu1sq*mu2sq + 1.)/4./mu1sq/mu2sq;
else if( mu1sq == 0. || mu2sq == 0. )
me2 = 3.;
else
me2 = 4.;
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second,
outb.second);
Energy output = norm(perturbativeVertex_->norm())*
me2*pcm/(8*Constants::pi)/scale*UnitRemoval::E2;
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
diff --git a/Decay/General/SVVDecayer.h b/Decay/General/SVVDecayer.h
--- a/Decay/General/SVVDecayer.h
+++ b/Decay/General/SVVDecayer.h
@@ -1,167 +1,157 @@
// -*- C++ -*-
//
// SVVDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_SVVDecayer_H
#define HERWIG_SVVDecayer_H
//
// This is the declaration of the SVVDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/AbstractVVSVertex.fh"
#include "ThePEG/Helicity/Vertex/Scalar/VVSVertex.fh"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::VVSVertexPtr;
/** \ingroup Decay
* This SVVDecayer class implements the decay of a scalar to
* 2 vector bosons using either the tree level VVSVertex or the loop vertex.
* It inherits from
* GeneralTwoBodyDecayer and implements the virtual member functions me2()
* and partialWidth(). It also stores a pointer to the VVSVertex.
*
* @see GeneralTwoBodyDecayer
*
*/
class SVVDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
SVVDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* 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;
/**
* 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;
+
+ /**
+ * Set the information on the decay
+ */
+ virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr>);
//@}
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 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();
- //@}
-
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
SVVDecayer & operator=(const SVVDecayer &);
private:
/**
* Abstract pointer to general VVS vertex
*/
- AbstractVVSVertexPtr abstractVertex_;
+ AbstractVVSVertexPtr vertex_;
/**
* Pointer to the perturbative form
*/
VVSVertexPtr perturbativeVertex_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Scalar wavefunction
*/
mutable Helicity::ScalarWaveFunction swave_;
/**
* Vector wavefunctions
*/
mutable vector<Helicity::VectorWaveFunction> vectors_[2];
};
}
#endif /* HERWIG_SVVDecayer_H */
diff --git a/Decay/General/TFFDecayer.cc b/Decay/General/TFFDecayer.cc
--- a/Decay/General/TFFDecayer.cc
+++ b/Decay/General/TFFDecayer.cc
@@ -1,314 +1,321 @@
// -*- C++ -*-
//
// TFFDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the TFFDecayer class.
//
#include "TFFDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/WaveFunction/TensorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr TFFDecayer::clone() const {
return new_ptr(*this);
}
IBPtr TFFDecayer::fullclone() const {
return new_ptr(*this);
}
-void TFFDecayer::doinit() {
- perturbativeVertex_ = dynamic_ptr_cast<FFTVertexPtr> (vertex());
- abstractVertex_ = dynamic_ptr_cast<AbstractFFTVertexPtr> (vertex());
- abstractOutgoingVertex1_ = dynamic_ptr_cast<AbstractFFVVertexPtr> (outgoingVertices()[0]);
- abstractOutgoingVertex2_ = dynamic_ptr_cast<AbstractFFVVertexPtr> (outgoingVertices()[1]);
- abstractFourPointVertex_ = dynamic_ptr_cast<AbstractFFVTVertexPtr>(getFourPointVertex());
-
- GeneralTwoBodyDecayer::doinit();
+void TFFDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
+ VertexBasePtr vertex,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > & outV,
+ map<ShowerInteraction,VertexBasePtr> fourV) {
+ decayInfo(incoming,outgoing);
+ vertex_ = dynamic_ptr_cast<AbstractFFTVertexPtr>(vertex);
+ perturbativeVertex_ = dynamic_ptr_cast<FFTVertexPtr> (vertex);
+ vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
+ for(auto & inter : itemp) {
+ fourPointVertex_[inter] = dynamic_ptr_cast<AbstractFFVTVertexPtr>(fourV.at(inter));
+ outgoingVertex1_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr> (outV[0].at(inter));
+ outgoingVertex2_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr> (outV[1].at(inter));
+ }
}
void TFFDecayer::persistentOutput(PersistentOStream & os) const {
- os << abstractVertex_ << perturbativeVertex_
- << abstractOutgoingVertex1_ << abstractOutgoingVertex2_
- << abstractFourPointVertex_;
+ os << vertex_ << perturbativeVertex_
+ << outgoingVertex1_ << outgoingVertex2_
+ << fourPointVertex_;
}
void TFFDecayer::persistentInput(PersistentIStream & is, int) {
- is >> abstractVertex_ >> perturbativeVertex_
- >> abstractOutgoingVertex1_ >> abstractOutgoingVertex2_
- >> abstractFourPointVertex_;
+ is >> vertex_ >> perturbativeVertex_
+ >> outgoingVertex1_ >> outgoingVertex2_
+ >> fourPointVertex_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<TFFDecayer,GeneralTwoBodyDecayer>
describeHerwigTFFDecayer("Herwig::TFFDecayer", "Herwig.so");
void TFFDecayer::Init() {
static ClassDocumentation<TFFDecayer> documentation
("The TFFDecayer class implements the decay of a tensor particle "
"to 2 fermions ");
}
double TFFDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
unsigned int iferm(0),ianti(1);
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin2,PDT::Spin1Half,PDT::Spin1Half)));
if(decay[0]->id()>=0) swap(iferm,ianti);
if(meopt==Initialize) {
TensorWaveFunction::
- calculateWaveFunctions(ten_sors,rho_,const_ptr_cast<tPPtr>(&inpart),
+ calculateWaveFunctions(tensors_,rho_,const_ptr_cast<tPPtr>(&inpart),
incoming,false);
}
if(meopt==Terminate) {
TensorWaveFunction::
- constructSpinInfo(ten_sors,const_ptr_cast<tPPtr>(&inpart),
+ constructSpinInfo(tensors_,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);
Energy2 scale(sqr(inpart.mass()));
unsigned int thel,fhel,ahel;
for(thel=0;thel<5;++thel) {
for(fhel=0;fhel<2;++fhel) {
for(ahel=0;ahel<2;++ahel) {
if(iferm > ianti) {
(*ME())(thel,fhel,ahel) =
- abstractVertex_->evaluate(scale,wave_[ahel],
- wavebar_[fhel],ten_sors[thel]);
+ vertex_->evaluate(scale,wave_[ahel],
+ wavebar_[fhel],tensors_[thel]);
}
else {
(*ME())(thel,ahel,fhel) =
- abstractVertex_->evaluate(scale,wave_[ahel],
- wavebar_[fhel],ten_sors[thel]);
+ vertex_->evaluate(scale,wave_[ahel],
+ wavebar_[fhel],tensors_[thel]);
}
}
}
}
double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy TFFDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
if(perturbativeVertex_) {
Energy2 scale = sqr(inpart.second);
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
perturbativeVertex_->setCoupling(scale, in, outa.first, outb.first);
double musq = sqr(outa.second/inpart.second);
double b = sqrt(1- 4.*musq);
double me2 = b*b*(5-2*b*b)*scale/120.*UnitRemoval::InvE2;
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second,
outb.second);
Energy output = norm(perturbativeVertex_->norm())*me2*pcm/(8.*Constants::pi);
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
double TFFDecayer::threeBodyME(const int , const Particle & inpart,
- const ParticleVector & decay, MEOption meopt) {
+ const ParticleVector & decay,
+ ShowerInteraction inter, MEOption meopt) {
// work out which is the fermion and antifermion
int ianti(0), iferm(1), iglu(2);
int itype[2];
for(unsigned int ix=0;ix<2;++ix) {
if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1;
else itype[ix] = 2;
}
if(itype[0]==0 && itype[1]!=0) swap(iferm, ianti);
if(itype[0]==2 && itype[1]==1) swap(iferm, ianti);
if(itype[0]==0 && itype[1]==0 && decay[0]->dataPtr()->id()<decay[1]->dataPtr()->id())
swap(iferm, ianti);
if(itype[0]==1 && itype[1]==1 && decay[0]->dataPtr()->id()<decay[1]->dataPtr()->id())
swap(iferm, ianti);
if(meopt==Initialize) {
// create tensor wavefunction for decaying particle
TensorWaveFunction::
calculateWaveFunctions(tensors3_, rho3_, const_ptr_cast<tPPtr>(&inpart), incoming, false);
}
// setup spin information when needed
if(meopt==Terminate) {
TensorWaveFunction::
constructSpinInfo(tensors3_, const_ptr_cast<tPPtr>(&inpart),incoming,true, false);
SpinorBarWaveFunction::
constructSpinInfo(wavebar3_ ,decay[iferm],outgoing,true);
SpinorWaveFunction::
constructSpinInfo(wave3_ ,decay[ianti],outgoing,true);
VectorWaveFunction::
constructSpinInfo(gluon_ ,decay[iglu ],outgoing,true,false);
return 0.;
}
// calculate colour factors and number of colour flows
unsigned int nflow;
vector<DVector> cfactors = getColourFactors(inpart, decay, nflow);
if(nflow==2) cfactors[0][1]=cfactors[1][0];
vector<GeneralDecayMEPtr> ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin2, PDT::Spin1Half,
PDT::Spin1Half, PDT::Spin1)));
// create wavefunctions
SpinorBarWaveFunction::
calculateWaveFunctions(wavebar3_, decay[iferm],outgoing);
SpinorWaveFunction::
calculateWaveFunctions(wave3_ , decay[ianti],outgoing);
VectorWaveFunction::
calculateWaveFunctions(gluon_ , decay[iglu ],outgoing,true);
// // gauge invariance test
// gluon_.clear();
// for(unsigned int ix=0;ix<3;++ix) {
// if(ix==1) gluon_.push_back(VectorWaveFunction());
// else {
// gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(),
// decay[iglu ]->dataPtr(),10,
// outgoing));
// }
// }
- if (! (abstractOutgoingVertex1_ && abstractOutgoingVertex2_))
+ if (! (outgoingVertex1_[inter] && outgoingVertex2_[inter]))
throw Exception()
<< "Invalid vertices for QCD radiation in TFF decay in TFFDecayer::threeBodyME"
<< Exception::runerror;
// identify fermion and/or anti-fermion vertex
- AbstractFFVVertexPtr abstractOutgoingVertexF = abstractOutgoingVertex1_;
- AbstractFFVVertexPtr abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ AbstractFFVVertexPtr outgoingVertexF = outgoingVertex1_[inter];
+ AbstractFFVVertexPtr outgoingVertexA = outgoingVertex2_[inter];
- if(abstractOutgoingVertex1_!=abstractOutgoingVertex2_ &&
- abstractOutgoingVertex1_->isIncoming(getParticleData(decay[ianti]->id())))
- swap (abstractOutgoingVertexF, abstractOutgoingVertexA);
+ if(outgoingVertex1_[inter]!=outgoingVertex2_[inter] &&
+ outgoingVertex1_[inter]->isIncoming(getParticleData(decay[ianti]->id())))
+ swap (outgoingVertexF, outgoingVertexA);
if(! (inpart.dataPtr()->iColour()==PDT::Colour0)){
throw Exception()
<< "Invalid vertices for QCD radiation in TFF decay in TFFDecayer::threeBodyME"
<< Exception::runerror;
}
Energy2 scale(sqr(inpart.mass()));
const GeneralTwoBodyDecayer::CFlow & colourFlow
= colourFlows(inpart, decay);
for(unsigned int it = 0; it < 5; ++it) {
for(unsigned int ifm = 0; ifm < 2; ++ifm) {
for(unsigned int ia = 0; ia < 2; ++ia) {
for(unsigned int ig = 0; ig < 2; ++ig) {
// radiation from outgoing fermion
if(decay[iferm]->dataPtr()->coloured()) {
- assert(abstractOutgoingVertexF);
+ assert(outgoingVertexF);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[iferm]->dataPtr();
if(off->CC()) off = off->CC();
SpinorBarWaveFunction interS =
- abstractOutgoingVertexF->evaluate(scale,3,off,wavebar3_[ifm],
+ outgoingVertexF->evaluate(scale,3,off,wavebar3_[ifm],
gluon_[2*ig],decay[iferm]->mass());
if(wavebar3_[ifm].particle()->PDGName()!=interS.particle()->PDGName())
throw Exception()
<< wavebar3_[ifm].particle()->PDGName() << " was changed to "
<< interS .particle()->PDGName() << " in TFFDecayer::threeBodyME"
<< Exception::runerror;
- double gs = abstractOutgoingVertexF->strongCoupling(scale);
- Complex diag = abstractVertex_->evaluate(scale,wave3_[ia], interS,tensors3_[it])/gs;
+ double gs = outgoingVertexF->strongCoupling(scale);
+ Complex diag = vertex_->evaluate(scale,wave3_[ia], interS,tensors3_[it])/gs;
for(unsigned int ix=0;ix<colourFlow[1].size();++ix) {
(*ME[colourFlow[1][ix].first])(it, ifm, ia, ig) +=
colourFlow[1][ix].second*diag;
}
}
// radiation from outgoing antifermion
if(decay[ianti]->dataPtr()->coloured()) {
- assert(abstractOutgoingVertexA);
+ assert(outgoingVertexA);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[ianti]->dataPtr();
if(off->CC()) off = off->CC();
SpinorWaveFunction interS =
- abstractOutgoingVertexA->evaluate(scale,3,off,wave3_[ia],
+ outgoingVertexA->evaluate(scale,3,off,wave3_[ia],
gluon_[2*ig],decay[ianti]->mass());
if(wave3_[ia].particle()->PDGName()!=interS.particle()->PDGName())
throw Exception()
<< wave3_[ia].particle()->PDGName() << " was changed to "
<< interS .particle()->PDGName() << " in TFFDecayer::threeBodyME"
<< Exception::runerror;
- double gs = abstractOutgoingVertexA->strongCoupling(scale);
- Complex diag = abstractVertex_->evaluate(scale,interS,wavebar3_[ifm],tensors3_[it])/gs;
+ double gs = outgoingVertexA->strongCoupling(scale);
+ Complex diag = vertex_->evaluate(scale,interS,wavebar3_[ifm],tensors3_[it])/gs;
for(unsigned int ix=0;ix<colourFlow[2].size();++ix) {
(*ME[colourFlow[2][ix].first])(it, ifm, ia, ig) +=
colourFlow[2][ix].second*diag;
}
}
// radiation from 4 point vertex
- if (abstractFourPointVertex_){
- double gs = abstractFourPointVertex_->strongCoupling(scale);
- Complex diag = abstractFourPointVertex_->evaluate(scale, wave3_[ia], wavebar3_[ifm],
- gluon_[2*ig], tensors3_[it])/gs;
+ if (fourPointVertex_[inter]){
+ double gs = fourPointVertex_[inter]->strongCoupling(scale);
+ Complex diag = fourPointVertex_[inter]->evaluate(scale, wave3_[ia], wavebar3_[ifm],
+ gluon_[2*ig], tensors3_[it])/gs;
for(unsigned int ix=0;ix<colourFlow[3].size();++ix) {
(*ME[colourFlow[3][ix].first])(it, ifm, ia, ig) +=
colourFlow[3][ix].second*diag;
}
}
}
}
}
}
// contract matrices
double output=0.;
for(unsigned int ix=0; ix<nflow; ++ix){
for(unsigned int iy=0; iy<nflow; ++iy){
output+=cfactors[ix][iy]*(ME[ix]->contract(*ME[iy],rho3_)).real();
}
}
output*=(4.*Constants::pi);
// return the answer
return output;
}
diff --git a/Decay/General/TFFDecayer.h b/Decay/General/TFFDecayer.h
--- a/Decay/General/TFFDecayer.h
+++ b/Decay/General/TFFDecayer.h
@@ -1,216 +1,213 @@
// -*- C++ -*-
//
// TFFDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_TFFDecayer_H
#define HERWIG_TFFDecayer_H
//
// This is the declaration of the TFFDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Tensor/FFTVertex.h"
#include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h"
#include "ThePEG/Helicity/Vertex/Tensor/FFVTVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::FFTVertexPtr;
/** \ingroup Decay
* The TFFDecayer class implements the decay of a tensor
* to 2 fermions in a general model. It holds an FFTVertex pointer
* that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class TFFDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
TFFDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* 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 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;
/**
* 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;
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return FSR;}
/**
* Three-body matrix element including additional QCD radiation
*/
virtual double threeBodyME(const int , const Particle & inpart,
- const ParticleVector & decay,MEOption meopt);
+ const ParticleVector & decay,
+ ShowerInteraction inter, MEOption meopt);
+
+ /**
+ * Set the information on the decay
+ */
+ virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr>);
//@}
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 and
- * EventGenerator to disk.
- * @throws InitException if object could not be initialized properly.
- */
- virtual void doinit();
- //@}
-
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
TFFDecayer & operator=(const TFFDecayer &);
private:
/**
* Abstract pointer to AbstractFFTVertex
*/
- AbstractFFTVertexPtr abstractVertex_;
+ AbstractFFTVertexPtr vertex_;
/**
* Pointer to the perturbative vertex
*/
FFTVertexPtr perturbativeVertex_;
/**
* Abstract pointer to AbstractFFVVertex for QCD radiation from outgoing (anti)fermion
*/
- AbstractFFVVertexPtr abstractOutgoingVertex1_;
+ map<ShowerInteraction,AbstractFFVVertexPtr> outgoingVertex1_;
/**
* Abstract pointer to AbstractFFVVertex for QCD radiation from outgoing (anti)fermion
*/
- AbstractFFVVertexPtr abstractOutgoingVertex2_;
+ map<ShowerInteraction,AbstractFFVVertexPtr> outgoingVertex2_;
/**
* Abstract pointer to AbstractFFVTVertex for QCD radiation from 4 point vertex
*/
- AbstractFFVTVertexPtr abstractFourPointVertex_;
+ map<ShowerInteraction,AbstractFFVTVertexPtr> fourPointVertex_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Polarization tensors for the decaying particle
*/
- mutable vector<TensorWaveFunction> ten_sors;
+ mutable vector<TensorWaveFunction> tensors_;
/**
* Spinors for the decay products
*/
mutable vector<SpinorWaveFunction> wave_;
/**
* Barred spinors for the decay products
*/
mutable vector<SpinorBarWaveFunction> wavebar_;
/**
* Spin density matrix for 3 body decay
*/
mutable RhoDMatrix rho3_;
/**
* Tensor wavefunction for 3 body decay
*/
mutable vector<TensorWaveFunction> tensors3_;
/**
* Spinor wavefunction for 3 body decay
*/
mutable vector<SpinorWaveFunction> wave3_;
/**
* Barred spinor wavefunction for 3 body decay
*/
mutable vector<SpinorBarWaveFunction> wavebar3_;
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<VectorWaveFunction> gluon_;
};
}
#endif /* HERWIG_TFFDecayer_H */
diff --git a/Decay/General/TSSDecayer.cc b/Decay/General/TSSDecayer.cc
--- a/Decay/General/TSSDecayer.cc
+++ b/Decay/General/TSSDecayer.cc
@@ -1,119 +1,125 @@
// -*- C++ -*-
//
// TSSDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the TSSDecayer class.
//
#include "TSSDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Utilities/Kinematics.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/TensorWaveFunction.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr TSSDecayer::clone() const {
return new_ptr(*this);
}
IBPtr TSSDecayer::fullclone() const {
return new_ptr(*this);
}
-void TSSDecayer::doinit() {
- GeneralTwoBodyDecayer::doinit();
- perturbativeVertex_ = dynamic_ptr_cast<SSTVertexPtr> (vertex());
- abstractVertex_ = dynamic_ptr_cast<AbstractSSTVertexPtr>(vertex());
+
+void TSSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
+ VertexBasePtr vertex,
+ map<ShowerInteraction,VertexBasePtr> & ,
+ const vector<map<ShowerInteraction,VertexBasePtr> > & ,
+ map<ShowerInteraction,VertexBasePtr> ) {
+ decayInfo(incoming,outgoing);
+ vertex_ = dynamic_ptr_cast<AbstractSSTVertexPtr>(vertex);
+ perturbativeVertex_ = dynamic_ptr_cast<SSTVertexPtr> (vertex);
}
+
void TSSDecayer::persistentOutput(PersistentOStream & os) const {
- os << abstractVertex_ << perturbativeVertex_;
+ os << vertex_ << perturbativeVertex_;
}
void TSSDecayer::persistentInput(PersistentIStream & is, int) {
- is >> abstractVertex_ >> perturbativeVertex_;
+ is >> vertex_ >> perturbativeVertex_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<TSSDecayer,GeneralTwoBodyDecayer>
describeHerwigTSSDecayer("Herwig::TSSDecayer", "Herwig.so");
void TSSDecayer::Init() {
static ClassDocumentation<TSSDecayer> documentation
("This class implements the decay of a tensor particle into "
"2 scalars.");
}
double TSSDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin2,PDT::Spin0,PDT::Spin0)));
if(meopt==Initialize) {
TensorWaveFunction::
- calculateWaveFunctions(ten_sors,rho_,const_ptr_cast<tPPtr>(&inpart),
+ calculateWaveFunctions(tensors_,rho_,const_ptr_cast<tPPtr>(&inpart),
incoming,false);
}
if(meopt==Terminate) {
TensorWaveFunction::
- constructSpinInfo(ten_sors,const_ptr_cast<tPPtr>(&inpart),
+ constructSpinInfo(tensors_,const_ptr_cast<tPPtr>(&inpart),
incoming,true,false);
for(unsigned int ix=0;ix<2;++ix)
ScalarWaveFunction::
constructSpinInfo(decay[ix],outgoing,true);
return 0.;
}
ScalarWaveFunction sca1(decay[0]->momentum(),decay[0]->dataPtr(),outgoing);
ScalarWaveFunction sca2(decay[1]->momentum(),decay[1]->dataPtr(),outgoing);
Energy2 scale(sqr(inpart.mass()));
for(unsigned int thel=0;thel<5;++thel) {
- (*ME())(thel,0,0) =abstractVertex_->evaluate(scale,sca1,sca2,ten_sors[thel]);
+ (*ME())(thel,0,0) = vertex_->evaluate(scale,sca1,sca2,tensors_[thel]);
}
double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy TSSDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
if(perturbativeVertex_) {
Energy2 scale(sqr(inpart.second));
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
perturbativeVertex_->setCoupling(scale, outa.first, outb.first, in);
double musq = sqr(outa.second/inpart.second);
double b = sqrt(1. - 4.*musq);
double me2 = scale*pow(b,4)/120*UnitRemoval::InvE2;
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second,
outb.second);
Energy output = norm(perturbativeVertex_->norm())*me2*pcm/(8.*Constants::pi);
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
diff --git a/Decay/General/TSSDecayer.h b/Decay/General/TSSDecayer.h
--- a/Decay/General/TSSDecayer.h
+++ b/Decay/General/TSSDecayer.h
@@ -1,154 +1,150 @@
// -*- C++ -*-
//
// TSSDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_TSSDecayer_H
#define HERWIG_TSSDecayer_H
//
// This is the declaration of the TSSDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Tensor/SSTVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::SSTVertexPtr;
/** \ingroup Decay
* The TSSDecayer class implements the decay of a tensor
* to 2 scalars in a general model. It holds an SSTVertex pointer
* that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class TSSDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
TSSDecayer() {}
public:
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* 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 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;
/**
* 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;
-//@}
+
+ /**
+ * Set the information on the decay
+ */
+ virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr>);
+ //@}
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 and
- * EventGenerator to disk.
- * @throws InitException if object could not be initialized properly.
- */
- virtual void doinit();
- //@}
-
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
TSSDecayer & operator=(const TSSDecayer &);
private:
/**
* Abstract pointer to AbstractSSTVertex
*/
- AbstractSSTVertexPtr abstractVertex_;
+ AbstractSSTVertexPtr vertex_;
/**
* Pointer to the perturbative vertex
*/
SSTVertexPtr perturbativeVertex_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Polarization tensors of the decaying particle
*/
- mutable vector<Helicity::TensorWaveFunction> ten_sors;
+ mutable vector<Helicity::TensorWaveFunction> tensors_;
};
}
#endif /* HERWIG_TSSDecayer_H */
diff --git a/Decay/General/TVVDecayer.cc b/Decay/General/TVVDecayer.cc
--- a/Decay/General/TVVDecayer.cc
+++ b/Decay/General/TVVDecayer.cc
@@ -1,310 +1,317 @@
// -*- C++ -*-
//
// TVVDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the TVVDecayer class.
//
#include "TVVDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/TensorWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "ThePEG/Helicity/LorentzTensor.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr TVVDecayer::clone() const {
return new_ptr(*this);
}
IBPtr TVVDecayer::fullclone() const {
return new_ptr(*this);
}
-void TVVDecayer::doinit() {
- GeneralTwoBodyDecayer::doinit();
- perturbativeVertex_ = dynamic_ptr_cast<VVTVertexPtr> (vertex());
- abstractVertex_ = dynamic_ptr_cast<AbstractVVTVertexPtr> (vertex());
- abstractOutgoingVertex1_ = dynamic_ptr_cast<AbstractVVVVertexPtr> (outgoingVertices()[0]);
- abstractOutgoingVertex2_ = dynamic_ptr_cast<AbstractVVVVertexPtr> (outgoingVertices()[1]);
- abstractFourPointVertex_ = dynamic_ptr_cast<AbstractVVVTVertexPtr>(getFourPointVertex());
-
+void TVVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
+ VertexBasePtr vertex,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > & outV,
+ map<ShowerInteraction,VertexBasePtr> fourV) {
+ decayInfo(incoming,outgoing);
+ vertex_ = dynamic_ptr_cast<AbstractVVTVertexPtr>(vertex);
+ perturbativeVertex_ = dynamic_ptr_cast<VVTVertexPtr> (vertex);
+ vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
+ for(auto & inter : itemp) {
+ fourPointVertex_[inter] = dynamic_ptr_cast<AbstractVVVTVertexPtr>(fourV.at(inter));
+ outgoingVertex1_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr> (outV[0].at(inter));
+ outgoingVertex2_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr> (outV[1].at(inter));
+ }
}
void TVVDecayer::persistentOutput(PersistentOStream & os) const {
- os << abstractVertex_ << perturbativeVertex_
- << abstractOutgoingVertex1_ << abstractOutgoingVertex2_
- << abstractFourPointVertex_;
+ os << vertex_ << perturbativeVertex_
+ << outgoingVertex1_ << outgoingVertex2_
+ << fourPointVertex_;
}
void TVVDecayer::persistentInput(PersistentIStream & is, int) {
- is >> abstractVertex_ >> perturbativeVertex_
- >> abstractOutgoingVertex1_ >> abstractOutgoingVertex2_
- >> abstractFourPointVertex_;
+ is >> vertex_ >> perturbativeVertex_
+ >> outgoingVertex1_ >> outgoingVertex2_
+ >> fourPointVertex_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<TVVDecayer,GeneralTwoBodyDecayer>
describeHerwigTVVDecayer("Herwig::TVVDecayer", "Herwig.so");
void TVVDecayer::Init() {
static ClassDocumentation<TVVDecayer> documentation
("This class implements the decay of a tensor to 2 vector bosons");
}
double TVVDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin2,PDT::Spin1,PDT::Spin1)));
bool photon[2];
for(unsigned int ix=0;ix<2;++ix)
photon[ix] = decay[ix]->mass()==ZERO;
if(meopt==Initialize) {
TensorWaveFunction::
- calculateWaveFunctions(ten_sors,rho_,const_ptr_cast<tPPtr>(&inpart),
+ calculateWaveFunctions(tensors_,rho_,const_ptr_cast<tPPtr>(&inpart),
incoming,false);
}
if(meopt==Terminate) {
TensorWaveFunction::
- constructSpinInfo(ten_sors,const_ptr_cast<tPPtr>(&inpart),
+ constructSpinInfo(tensors_,const_ptr_cast<tPPtr>(&inpart),
incoming,true,false);
for(unsigned int ix=0;ix<2;++ix)
VectorWaveFunction::
constructSpinInfo(vectors_[ix],decay[ix],outgoing,true,photon[ix]);
return 0.;
}
for(unsigned int ix=0;ix<2;++ix)
VectorWaveFunction::
calculateWaveFunctions(vectors_[ix],decay[ix],outgoing,photon[ix]);
Energy2 scale(sqr(inpart.mass()));
unsigned int thel,v1hel,v2hel;
for(thel=0;thel<5;++thel) {
for(v1hel=0;v1hel<3;++v1hel) {
for(v2hel=0;v2hel<3;++v2hel) {
- (*ME())(thel,v1hel,v2hel) = abstractVertex_->evaluate(scale,
+ (*ME())(thel,v1hel,v2hel) = vertex_->evaluate(scale,
vectors_[0][v1hel],
vectors_[1][v2hel],
- ten_sors[thel]);
+ tensors_[thel]);
if(photon[1]) ++v2hel;
}
if(photon[0]) ++v1hel;
}
}
double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy TVVDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
if(perturbativeVertex_) {
Energy2 scale(sqr(inpart.second));
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
perturbativeVertex_->setCoupling(scale, outa.first, outb.first, in);
double mu2 = sqr(outa.second/inpart.second);
double b = sqrt(1 - 4.*mu2);
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second,
outb.second);
Energy2 me2;
if(outa.second > ZERO && outb.second > ZERO)
me2 = scale*(30 - 20.*b*b + 3.*pow(b,4))/120.;
else
me2 = scale/10.;
Energy output = norm(perturbativeVertex_->norm())*me2*pcm
/(8.*Constants::pi)*UnitRemoval::InvE2;
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
double TVVDecayer::threeBodyME(const int , const Particle & inpart,
- const ParticleVector & decay, MEOption meopt) {
+ const ParticleVector & decay,
+ ShowerInteraction inter, MEOption meopt) {
bool massless[2];
for(unsigned int ix=0;ix<2;++ix)
massless[ix] = decay[ix]->mass()==ZERO;
// no emissions from massive vectors
if (! (massless[0] && massless[1]))
throw Exception()
<< "No dipoles available for massive vectors in TVVDecayer::threeBodyME"
<< Exception::runerror;
int iglu(2);
if(meopt==Initialize) {
// create tensor wavefunction for decaying particle
TensorWaveFunction::
calculateWaveFunctions(tensors3_, rho3_, const_ptr_cast<tPPtr>(&inpart), incoming, false);
}
// setup spin information when needed
if(meopt==Terminate) {
TensorWaveFunction::
constructSpinInfo(tensors3_, const_ptr_cast<tPPtr>(&inpart),incoming,true, false);
for(unsigned int ix=0;ix<2;++ix)
VectorWaveFunction::
constructSpinInfo(vectors3_[ix],decay[ix ],outgoing,true, massless[ix]);
VectorWaveFunction::
constructSpinInfo(gluon_ ,decay[iglu ],outgoing,true,false);
return 0.;
}
// calculate colour factors and number of colour flows
unsigned int nflow;
vector<DVector> cfactors = getColourFactors(inpart, decay, nflow);
if(nflow==2) cfactors[0][1]=cfactors[1][0];
vector<GeneralDecayMEPtr> ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin2, PDT::Spin1,
PDT::Spin1, PDT::Spin1)));
// create wavefunctions
for(unsigned int ix=0;ix<2;++ix)
VectorWaveFunction::
calculateWaveFunctions(vectors3_[ix],decay[ix ],outgoing,massless[ix]);
VectorWaveFunction::
calculateWaveFunctions(gluon_ ,decay[iglu ],outgoing,true);
// // gauge test
// gluon_.clear();
// for(unsigned int ix=0;ix<3;++ix) {
// if(ix==1) gluon_.push_back(VectorWaveFunction());
// else {
// gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(),
// decay[iglu ]->dataPtr(),10,
// outgoing));
// }
// }
// work out which vector each outgoing vertex corresponds to
- if(abstractOutgoingVertex1_!=abstractOutgoingVertex2_ &&
- abstractOutgoingVertex1_->isIncoming(getParticleData(decay[1]->id())))
- swap(abstractOutgoingVertex1_, abstractOutgoingVertex2_);
+ if(outgoingVertex1_[inter]!=outgoingVertex2_[inter] &&
+ outgoingVertex1_[inter]->isIncoming(getParticleData(decay[1]->id())))
+ swap(outgoingVertex1_[inter], outgoingVertex2_[inter]);
- if (! (abstractOutgoingVertex1_ && abstractOutgoingVertex2_))
+ if (! (outgoingVertex1_[inter] && outgoingVertex2_[inter]))
throw Exception()
<< "Invalid vertices for QCD radiation in TVV decay in TVVDecayer::threeBodyME"
<< Exception::runerror;
if( !(inpart.dataPtr()->iColour()==PDT::Colour0))
throw Exception()
<< "Invalid vertices for QCD radiation in TVV decay in TVVDecayer::threeBodyME"
<< Exception::runerror;
Energy2 scale(sqr(inpart.mass()));
const GeneralTwoBodyDecayer::CFlow & colourFlow
= colourFlows(inpart, decay);
for(unsigned int it = 0; it < 5; ++it) {
for(unsigned int iv0 = 0; iv0 < 3; ++iv0) {
for(unsigned int iv1 = 0; iv1 < 3; ++iv1) {
for(unsigned int ig = 0; ig < 2; ++ig) {
// radiation from first outgoing vector
if(decay[0]->dataPtr()->coloured()) {
- assert(abstractOutgoingVertex1_);
+ assert(outgoingVertex1_[inter]);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[0]->dataPtr();
if(off->CC()) off = off->CC();
VectorWaveFunction vectInter =
- abstractOutgoingVertex1_->evaluate(scale,3,off,gluon_[2*ig],
+ outgoingVertex1_[inter]->evaluate(scale,3,off,gluon_[2*ig],
vectors3_[0][iv0],decay[0]->mass());
if(vectors3_[0][iv0].particle()->PDGName()!=vectInter.particle()->PDGName())
throw Exception()
<< vectors3_[0][iv0].particle()->PDGName() << " was changed to "
<< vectInter .particle()->PDGName() << " in TVVDecayer::threeBodyME"
<< Exception::runerror;
- double gs = abstractOutgoingVertex1_->strongCoupling(scale);
- Complex diag = abstractVertex_->evaluate(scale,vectors3_[1][iv1],
- vectInter,tensors3_[it])/gs;
+ double gs = outgoingVertex1_[inter]->strongCoupling(scale);
+ Complex diag = vertex_->evaluate(scale,vectors3_[1][iv1],
+ vectInter,tensors3_[it])/gs;
for(unsigned int ix=0;ix<colourFlow[1].size();++ix) {
(*ME[colourFlow[1][ix].first])(it, iv0, iv1, ig) +=
colourFlow[1][ix].second*diag;
}
}
// radiation from second outgoing vector
if(decay[1]->dataPtr()->coloured()) {
- assert(abstractOutgoingVertex2_);
+ assert(outgoingVertex2_[inter]);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[1]->dataPtr();
if(off->CC()) off = off->CC();
VectorWaveFunction vectInter =
- abstractOutgoingVertex2_->evaluate(scale,3,off,vectors3_[1][iv1],
+ outgoingVertex2_[inter]->evaluate(scale,3,off,vectors3_[1][iv1],
gluon_[2*ig],decay[1]->mass());
if(vectors3_[1][iv1].particle()->PDGName()!=vectInter.particle()->PDGName())
throw Exception()
<< vectors3_[1][iv1].particle()->PDGName() << " was changed to "
<< vectInter .particle()->PDGName() << " in TVVDecayer::threeBodyME"
<< Exception::runerror;
- double gs = abstractOutgoingVertex2_->strongCoupling(scale);
- Complex diag = abstractVertex_->evaluate(scale,vectInter,vectors3_[0][iv0],
+ double gs = outgoingVertex2_[inter]->strongCoupling(scale);
+ Complex diag = vertex_->evaluate(scale,vectInter,vectors3_[0][iv0],
tensors3_[it])/gs;
for(unsigned int ix=0;ix<colourFlow[2].size();++ix) {
(*ME[colourFlow[2][ix].first])(it, iv0, iv1, ig) +=
colourFlow[2][ix].second*diag;
}
}
// radiation from 4 point vertex
- if (abstractFourPointVertex_){
- double gs = abstractFourPointVertex_->strongCoupling(scale);
- Complex diag = abstractFourPointVertex_->evaluate(scale, vectors3_[0][iv0],
+ if (fourPointVertex_[inter]){
+ double gs = fourPointVertex_[inter]->strongCoupling(scale);
+ Complex diag = fourPointVertex_[inter]->evaluate(scale, vectors3_[0][iv0],
vectors3_[1][iv1],gluon_[2*ig],
tensors3_[it])/gs;
for(unsigned int ix=0;ix<colourFlow[3].size();++ix) {
(*ME[colourFlow[3][ix].first])(it, iv0, iv1, ig) +=
colourFlow[3][ix].second*diag;
}
}
}
if(massless[1]) ++iv1;
}
if(massless[0]) ++iv0;
}
}
// contract matrices
double output=0.;
for(unsigned int ix=0; ix<nflow; ++ix){
for(unsigned int iy=0; iy<nflow; ++iy){
output+=cfactors[ix][iy]*(ME[ix]->contract(*ME[iy],rho3_)).real();
}
}
output*=(4.*Constants::pi);
// return the answer
return output;
}
diff --git a/Decay/General/TVVDecayer.h b/Decay/General/TVVDecayer.h
--- a/Decay/General/TVVDecayer.h
+++ b/Decay/General/TVVDecayer.h
@@ -1,206 +1,203 @@
// -*- C++ -*-
//
// TVVDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_TVVDecayer_H
#define HERWIG_TVVDecayer_H
//
// This is the declaration of the TVVDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Vector/VVVVertex.h"
#include "ThePEG/Helicity/Vertex/Tensor/VVTVertex.h"
#include "ThePEG/Helicity/Vertex/Tensor/VVVTVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::VVTVertexPtr;
/** \ingroup Decay
* The TVVDecayer class implements the decay of a tensor
* to 2 vector bosons in a general model. It holds a VVTVertex pointer
* that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class TVVDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
TVVDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* 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 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;
/**
* 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;
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return FSR;}
/**
* Three-body matrix element including additional QCD radiation
*/
virtual double threeBodyME(const int , const Particle & inpart,
- const ParticleVector & decay,MEOption meopt);
+ const ParticleVector & decay,
+ ShowerInteraction inter, MEOption meopt);
+
+ /**
+ * Set the information on the decay
+ */
+ virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr>);
//@}
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 and
- * EventGenerator to disk.
- * @throws InitException if object could not be initialized properly.
- */
- virtual void doinit();
- //@}
-
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
TVVDecayer & operator=(const TVVDecayer &);
private:
/**
* Abstract pointer to AbstractVVTVertex
*/
- AbstractVVTVertexPtr abstractVertex_;
+ AbstractVVTVertexPtr vertex_;
/**
* Pointer to the perturbative vertex
*/
VVTVertexPtr perturbativeVertex_;
/**
* Abstract pointer to AbstractVVVVertex for QCD radiation from outgoing vector
*/
- AbstractVVVVertexPtr abstractOutgoingVertex1_;
+ map<ShowerInteraction,AbstractVVVVertexPtr> outgoingVertex1_;
/**
* Abstract pointer to AbstractVVVVertex for QCD radiation from outgoing vector
*/
- AbstractVVVVertexPtr abstractOutgoingVertex2_;
+ map<ShowerInteraction,AbstractVVVVertexPtr> outgoingVertex2_;
/**
* Abstract pointer to AbstractVVVTVertex for QCD radiation from 4 point vertex
*/
- AbstractVVVTVertexPtr abstractFourPointVertex_;
+ map<ShowerInteraction,AbstractVVVTVertexPtr> fourPointVertex_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Polarization tensors of decaying particle
*/
- mutable vector<Helicity::TensorWaveFunction> ten_sors;
+ mutable vector<Helicity::TensorWaveFunction> tensors_;
/**
* Polarization vectors of outgoing vector bosons
*/
mutable vector<Helicity::VectorWaveFunction> vectors_[2];
/**
* Spin density matrix for 3 body decay
*/
mutable RhoDMatrix rho3_;
/**
* Tensor wavefunction for 3 body decay
*/
mutable vector<Helicity::TensorWaveFunction> tensors3_;
/**
* Polarization vectors of outgoing vector bosons
*/
mutable vector<Helicity::VectorWaveFunction> vectors3_[2];
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<Helicity::VectorWaveFunction> gluon_;
};
}
#endif /* HERWIG_TVVDecayer_H */
diff --git a/Decay/General/VFFDecayer.cc b/Decay/General/VFFDecayer.cc
--- a/Decay/General/VFFDecayer.cc
+++ b/Decay/General/VFFDecayer.cc
@@ -1,402 +1,411 @@
// -*- C++ -*-
//
// VFFDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the VFFDecayer class.
//
#include "VFFDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr VFFDecayer::clone() const {
return new_ptr(*this);
}
IBPtr VFFDecayer::fullclone() const {
return new_ptr(*this);
}
-void VFFDecayer::doinit() {
- perturbativeVertex_ = dynamic_ptr_cast<FFVVertexPtr> (vertex());
- abstractVertex_ = dynamic_ptr_cast<AbstractFFVVertexPtr>(vertex());
- abstractIncomingVertex_ = dynamic_ptr_cast<AbstractVVVVertexPtr>(incomingVertex());
- abstractOutgoingVertex1_ = dynamic_ptr_cast<AbstractFFVVertexPtr>(outgoingVertices()[0]);
- abstractOutgoingVertex2_ = dynamic_ptr_cast<AbstractFFVVertexPtr>(outgoingVertices()[1]);
- GeneralTwoBodyDecayer::doinit();
+void VFFDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
+ VertexBasePtr vertex,
+ map<ShowerInteraction,VertexBasePtr> & inV,
+ const vector<map<ShowerInteraction,VertexBasePtr> > & outV,
+ map<ShowerInteraction,VertexBasePtr> ) {
+ decayInfo(incoming,outgoing);
+ vertex_ = dynamic_ptr_cast<AbstractFFVVertexPtr>(vertex);
+ perturbativeVertex_ = dynamic_ptr_cast<FFVVertexPtr> (vertex);
+ vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
+ for(auto & inter : itemp) {
+ incomingVertex_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr>(inV.at(inter));
+ outgoingVertex1_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr>(outV[0].at(inter));
+ outgoingVertex2_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr>(outV[1].at(inter));
+ }
}
void VFFDecayer::persistentOutput(PersistentOStream & os) const {
- os << abstractVertex_ << perturbativeVertex_
- << abstractIncomingVertex_ << abstractOutgoingVertex1_
- << abstractOutgoingVertex2_;
+ os << vertex_ << perturbativeVertex_
+ << incomingVertex_ << outgoingVertex1_
+ << outgoingVertex2_;
}
void VFFDecayer::persistentInput(PersistentIStream & is, int) {
- is >> abstractVertex_ >> perturbativeVertex_
- >> abstractIncomingVertex_ >> abstractOutgoingVertex1_
- >> abstractOutgoingVertex2_;
+ is >> vertex_ >> perturbativeVertex_
+ >> incomingVertex_ >> outgoingVertex1_
+ >> outgoingVertex2_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<VFFDecayer,GeneralTwoBodyDecayer>
describeHerwigVFFDecayer("Herwig::VFFDecayer", "Herwig.so");
void VFFDecayer::Init() {
static ClassDocumentation<VFFDecayer> documentation
("The VFFDecayer implements the matrix element for the"
" decay of a vector to fermion-antifermion pair");
}
double VFFDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
int iferm(1),ianti(0);
if(decay[0]->id()>0) swap(iferm,ianti);
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1Half,PDT::Spin1Half)));
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(inpart.mass()*inpart.mass());
for(unsigned int ifm = 0; ifm < 2; ++ifm) { //loop over fermion helicities
for(unsigned int ia = 0; ia < 2; ++ia) {// loop over antifermion helicities
for(unsigned int vhel = 0; vhel < 3; ++vhel) {//loop over vector helicities
if(iferm > ianti) {
(*ME())(vhel, ia, ifm) =
- abstractVertex_->evaluate(scale,wave_[ia],
+ vertex_->evaluate(scale,wave_[ia],
wavebar_[ifm],vectors_[vhel]);
}
else
(*ME())(vhel,ifm,ia)=
- abstractVertex_->evaluate(scale,wave_[ia],
+ vertex_->evaluate(scale,wave_[ia],
wavebar_[ifm],vectors_[vhel]);
}
}
}
double output=(ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy VFFDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
if(perturbativeVertex_) {
double mu1(outa.second/inpart.second), mu2(outb.second/inpart.second);
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
perturbativeVertex_->setCoupling(sqr(inpart.second), outa.first, outb.first,in);
Complex cl(perturbativeVertex_->left()), cr(perturbativeVertex_->right());
double me2 = (norm(cl) + norm(cr))*( sqr(sqr(mu1) - sqr(mu2))
+ sqr(mu1) + sqr(mu2) - 2.)
- 6.*(cl*conj(cr) + cr*conj(cl)).real()*mu1*mu2;
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second,
outb.second);
Energy output = -norm(perturbativeVertex_->norm())*me2*pcm /
(24.*Constants::pi);
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
double VFFDecayer::threeBodyME(const int , const Particle & inpart,
- const ParticleVector & decay, MEOption meopt) {
+ const ParticleVector & decay,
+ ShowerInteraction inter, MEOption meopt) {
bool massless = inpart.mass()==ZERO;
// work out which is the fermion and antifermion
int ianti(0), iferm(1), iglu(2);
int itype[2];
for(unsigned int ix=0;ix<2;++ix) {
if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1;
else itype[ix] = 2;
}
if(itype[0]==0 && itype[1]!=0) swap(iferm, ianti);
if(itype[0]==2 && itype[1]==1) swap(iferm, ianti);
if(itype[0]==0 && itype[1]==0 && decay[0]->dataPtr()->id()<decay[1]->dataPtr()->id())
swap(iferm, ianti);
if(itype[0]==1 && itype[1]==1 && decay[0]->dataPtr()->id()<decay[1]->dataPtr()->id())
swap(iferm, ianti);
if(meopt==Initialize) {
// create vector wavefunction for decaying particle
VectorWaveFunction::calculateWaveFunctions(vector3_, rho3_, const_ptr_cast<tPPtr>(&inpart),
incoming, massless);
}
// setup spin information when needed
if(meopt==Terminate) {
VectorWaveFunction::
constructSpinInfo(vector3_ ,const_ptr_cast<tPPtr>(&inpart),outgoing,true,massless);
SpinorBarWaveFunction::
constructSpinInfo(wavebar3_,decay[iferm],outgoing,true);
SpinorWaveFunction::
constructSpinInfo(wave3_ ,decay[ianti],outgoing,true);
VectorWaveFunction::
constructSpinInfo(gluon_ ,decay[iglu ],outgoing,true,false);
return 0.;
}
// calculate colour factors and number of colour flows
unsigned int nflow;
vector<DVector> cfactors = getColourFactors(inpart, decay, nflow);
if(nflow==2) cfactors[0][1]=cfactors[1][0];
vector<GeneralDecayMEPtr> ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin1, PDT::Spin1Half,
PDT::Spin1Half, PDT::Spin1)));
// create wavefunctions
SpinorBarWaveFunction::
calculateWaveFunctions(wavebar3_, decay[iferm],outgoing);
SpinorWaveFunction::
calculateWaveFunctions(wave3_ , decay[ianti],outgoing);
VectorWaveFunction::
calculateWaveFunctions(gluon_ , decay[iglu ],outgoing,true);
// // gauge invariance test
// gluon_.clear();
// for(unsigned int ix=0;ix<3;++ix) {
// if(ix==1) gluon_.push_back(VectorWaveFunction());
// else {
// gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(),
// decay[iglu ]->dataPtr(),10,
// outgoing));
// }
// }
// identify fermion and/or anti-fermion vertex
- AbstractFFVVertexPtr abstractOutgoingVertexF;
- AbstractFFVVertexPtr abstractOutgoingVertexA;
- identifyVertices(iferm, ianti, inpart, decay, abstractOutgoingVertexF, abstractOutgoingVertexA);
+ AbstractFFVVertexPtr outgoingVertexF;
+ AbstractFFVVertexPtr outgoingVertexA;
+ identifyVertices(iferm, ianti, inpart, decay, outgoingVertexF, outgoingVertexA,inter);
Energy2 scale(sqr(inpart.mass()));
const GeneralTwoBodyDecayer::CFlow & colourFlow
= colourFlows(inpart, decay);
for(unsigned int iv = 0; iv < 3; ++iv) {
for(unsigned int ifm = 0; ifm < 2; ++ifm) {
for(unsigned int ia = 0; ia < 2; ++ia) {
for(unsigned int ig = 0; ig < 2; ++ig) {
// radiation from the incoming vector
if(inpart.dataPtr()->coloured()) {
- assert(abstractIncomingVertex_);
+ assert(incomingVertex_[inter]);
VectorWaveFunction vectorInter =
- abstractIncomingVertex_->evaluate(scale,3,inpart.dataPtr(),vector3_[iv],
+ incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),vector3_[iv],
gluon_[2*ig],inpart.mass());
if (vector3_[iv].particle()->PDGName()!=vectorInter.particle()->PDGName())
throw Exception()
<< vector3_[iv].particle()->PDGName() << " was changed to "
<< vectorInter .particle()->PDGName() << " in VFFDecayer::threeBodyME"
<< Exception::runerror;
- double gs = abstractIncomingVertex_->strongCoupling(scale);
- Complex diag = abstractVertex_->evaluate(scale,wave3_[ia],wavebar3_[ifm],vectorInter)/gs;
+ double gs = incomingVertex_[inter]->strongCoupling(scale);
+ Complex diag = vertex_->evaluate(scale,wave3_[ia],wavebar3_[ifm],vectorInter)/gs;
for(unsigned int ix=0;ix<colourFlow[0].size();++ix) {
(*ME[colourFlow[0][ix].first])(iv, ia, ifm, ig) +=
colourFlow[0][ix].second*diag;
}
}
// radiation from outgoing fermion
if(decay[iferm]->dataPtr()->coloured()) {
- assert(abstractOutgoingVertexF);
+ assert(outgoingVertexF);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[iferm]->dataPtr();
if(off->CC()) off = off->CC();
SpinorBarWaveFunction interS =
- abstractOutgoingVertexF->evaluate(scale,3,off,wavebar3_[ifm],
+ outgoingVertexF->evaluate(scale,3,off,wavebar3_[ifm],
gluon_[2*ig],decay[iferm]->mass());
if(wavebar3_[ifm].particle()->PDGName()!=interS.particle()->PDGName())
throw Exception()
<< wavebar3_[ifm].particle()->PDGName() << " was changed to "
<< interS .particle()->PDGName() << " in VFFDecayer::threeBodyME"
<< Exception::runerror;
- double gs = abstractOutgoingVertexF->strongCoupling(scale);
- Complex diag = abstractVertex_->evaluate(scale,wave3_[ia], interS,vector3_[iv])/gs;
+ double gs = outgoingVertexF->strongCoupling(scale);
+ Complex diag = vertex_->evaluate(scale,wave3_[ia], interS,vector3_[iv])/gs;
for(unsigned int ix=0;ix<colourFlow[1].size();++ix) {
(*ME[colourFlow[1][ix].first])(iv, ia, ifm, ig) +=
colourFlow[1][ix].second*diag;
}
}
// radiation from outgoing antifermion
if(decay[ianti]->dataPtr()->coloured()) {
- assert(abstractOutgoingVertexA);
+ assert(outgoingVertexA);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[ianti]->dataPtr();
if(off->CC()) off = off->CC();
SpinorWaveFunction interS =
- abstractOutgoingVertexA->evaluate(scale,3,off,wave3_[ia],
+ outgoingVertexA->evaluate(scale,3,off,wave3_[ia],
gluon_[2*ig],decay[ianti]->mass());
if(wave3_[ia].particle()->PDGName()!=interS.particle()->PDGName())
throw Exception()
<< wave3_[ia].particle()->PDGName() << " was changed to "
<< interS .particle()->PDGName() << " in VFFDecayer::threeBodyME"
<< Exception::runerror;
- double gs = abstractOutgoingVertexA->strongCoupling(scale);
- Complex diag = abstractVertex_->evaluate(scale,interS,wavebar3_[ifm],vector3_[iv])/gs;
+ double gs = outgoingVertexA->strongCoupling(scale);
+ Complex diag = vertex_->evaluate(scale,interS,wavebar3_[ifm],vector3_[iv])/gs;
for(unsigned int ix=0;ix<colourFlow[2].size();++ix) {
(*ME[colourFlow[2][ix].first])(iv, ia, ifm, ig) +=
colourFlow[2][ix].second*diag;
}
}
}
}
}
if(massless) ++iv;
}
// contract matrices
double output=0.;
for(unsigned int ix=0; ix<nflow; ++ix){
for(unsigned int iy=0; iy<nflow; ++iy){
output+=cfactors[ix][iy]*(ME[ix]->contract(*ME[iy],rho3_)).real();
}
}
output*=(4.*Constants::pi);
//return output
return output;
}
void VFFDecayer::identifyVertices(const int iferm, const int ianti,
const Particle & inpart, const ParticleVector & decay,
- AbstractFFVVertexPtr & abstractOutgoingVertexF,
- AbstractFFVVertexPtr & abstractOutgoingVertexA){
+ AbstractFFVVertexPtr & outgoingVertexF,
+ AbstractFFVVertexPtr & outgoingVertexA,
+ ShowerInteraction inter){
// work out which fermion each outgoing vertex corresponds to
// two outgoing vertices
if( inpart.dataPtr() ->iColour()==PDT::Colour0 &&
((decay[iferm]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar) ||
(decay[iferm]->dataPtr()->iColour()==PDT::Colour8 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour8))){
- if(abstractOutgoingVertex1_==abstractOutgoingVertex2_){
- abstractOutgoingVertexF = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){
+ outgoingVertexF = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
- else if (abstractOutgoingVertex1_->isIncoming(getParticleData(decay[iferm]->id()))){
- abstractOutgoingVertexF = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iferm]->id()))){
+ outgoingVertexF = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
- else if (abstractOutgoingVertex2_->isIncoming(getParticleData(decay[iferm]->id()))){
- abstractOutgoingVertexF = abstractOutgoingVertex2_;
- abstractOutgoingVertexA = abstractOutgoingVertex1_;
+ else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[iferm]->id()))){
+ outgoingVertexF = outgoingVertex2_[inter];
+ outgoingVertexA = outgoingVertex1_[inter];
}
}
else if(inpart.dataPtr() ->iColour()==PDT::Colour8 &&
decay[iferm]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){
- if(abstractOutgoingVertex1_==abstractOutgoingVertex2_){
- abstractOutgoingVertexF = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){
+ outgoingVertexF = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
- else if (abstractOutgoingVertex1_->isIncoming(getParticleData(decay[iferm]->id()))){
- abstractOutgoingVertexF = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iferm]->id()))){
+ outgoingVertexF = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
- else if (abstractOutgoingVertex2_->isIncoming(getParticleData(decay[iferm]->id()))){
- abstractOutgoingVertexF = abstractOutgoingVertex2_;
- abstractOutgoingVertexA = abstractOutgoingVertex1_;
+ else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[iferm]->id()))){
+ outgoingVertexF = outgoingVertex2_[inter];
+ outgoingVertexA = outgoingVertex1_[inter];
}
}
// one outgoing vertex
else if(inpart.dataPtr()->iColour()==PDT::Colour3){
if(decay[iferm]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour0){
- if (abstractOutgoingVertex1_) abstractOutgoingVertexF = abstractOutgoingVertex1_;
- else if(abstractOutgoingVertex2_) abstractOutgoingVertexF = abstractOutgoingVertex2_;
+ if (outgoingVertex1_[inter]) outgoingVertexF = outgoingVertex1_[inter];
+ else if(outgoingVertex2_[inter]) outgoingVertexF = outgoingVertex2_[inter];
}
else if (decay[iferm]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour8){
- if (abstractOutgoingVertex1_->isIncoming(getParticleData(decay[ianti]->dataPtr()->id()))){
- abstractOutgoingVertexF = abstractOutgoingVertex2_;
- abstractOutgoingVertexA = abstractOutgoingVertex1_;
+ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[ianti]->dataPtr()->id()))){
+ outgoingVertexF = outgoingVertex2_[inter];
+ outgoingVertexA = outgoingVertex1_[inter];
}
else {
- abstractOutgoingVertexF = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ outgoingVertexF = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
}
}
else if(inpart.dataPtr()->iColour()==PDT::Colour3bar){
if(decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar &&
decay[iferm]->dataPtr()->iColour()==PDT::Colour0){
- if (abstractOutgoingVertex1_) abstractOutgoingVertexA = abstractOutgoingVertex1_;
- else if(abstractOutgoingVertex2_) abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ if (outgoingVertex1_[inter]) outgoingVertexA = outgoingVertex1_[inter];
+ else if(outgoingVertex2_[inter]) outgoingVertexA = outgoingVertex2_[inter];
}
else if (decay[iferm]->dataPtr()->iColour()==PDT::Colour8 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){
- if (abstractOutgoingVertex1_->isIncoming(getParticleData(decay[iferm]->dataPtr()->id()))){
- abstractOutgoingVertexF = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iferm]->dataPtr()->id()))){
+ outgoingVertexF = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
else {
- abstractOutgoingVertexF = abstractOutgoingVertex2_;
- abstractOutgoingVertexA = abstractOutgoingVertex1_;
+ outgoingVertexF = outgoingVertex2_[inter];
+ outgoingVertexA = outgoingVertex1_[inter];
}
}
}
- if (! ((abstractIncomingVertex_ && (abstractOutgoingVertexF || abstractOutgoingVertexA)) ||
- ( abstractOutgoingVertexF && abstractOutgoingVertexA)))
+ if (! ((incomingVertex_[inter] && (outgoingVertexF || outgoingVertexA)) ||
+ ( outgoingVertexF && outgoingVertexA)))
throw Exception()
<< "Invalid vertices for QCD radiation in VFF decay in VFFDecayer::identifyVertices"
<< Exception::runerror;
}
diff --git a/Decay/General/VFFDecayer.h b/Decay/General/VFFDecayer.h
--- a/Decay/General/VFFDecayer.h
+++ b/Decay/General/VFFDecayer.h
@@ -1,224 +1,222 @@
// -*- C++ -*-
//
// VFFDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_VFFDecayer_H
#define HERWIG_VFFDecayer_H
//
// This is the declaration of the VFFDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h"
#include "ThePEG/Helicity/Vertex/Vector/VVVVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::FFVVertexPtr;
/** \ingroup Decay
* The VFFDecayer class implements the decay of a vector
* to 2 fermions in a general model. It holds an FFVVertex pointer
* that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class VFFDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
VFFDecayer() {}
public:
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* 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 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;
/**
* 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;
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return FSR;}
/**
* Three-body matrix element including additional QCD radiation
*/
virtual double threeBodyME(const int , const Particle & inpart,
- const ParticleVector & decay,MEOption meopt);
+ const ParticleVector & decay,
+ ShowerInteraction inter, MEOption meopt);
/**
* Indentify outgoing vertices for the fermion and antifermion
*/
void identifyVertices(const int iferm, const int ianti,
const Particle & inpart, const ParticleVector & decay,
AbstractFFVVertexPtr & abstractOutgoingVertexF,
- AbstractFFVVertexPtr & abstractOutgoingVertexA);
+ AbstractFFVVertexPtr & abstractOutgoingVertexA,
+ ShowerInteraction inter);
+
+ /**
+ * Set the information on the decay
+ */
+ virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr>);
//@}
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 and
- * EventGenerator to disk.
- * @throws InitException if object could not be initialized properly.
- */
- virtual void doinit();
- //@}
-
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
VFFDecayer & operator=(const VFFDecayer &);
private:
/**
* Abstract pointer to AbstractFFVVertex
*/
- AbstractFFVVertexPtr abstractVertex_;
+ AbstractFFVVertexPtr vertex_;
/**
* Pointer to the perturbative vertex
*/
FFVVertexPtr perturbativeVertex_;
/**
* Abstract pointer to AbstractVVVVertex for QCD radiation from incoming vector
*/
- AbstractVVVVertexPtr abstractIncomingVertex_;
+ map<ShowerInteraction,AbstractVVVVertexPtr> incomingVertex_;
/**
* Abstract pointer to AbstractFFVVertex for QCD radiation from outgoing (anti)fermion
*/
- AbstractFFVVertexPtr abstractOutgoingVertex1_;
+ map<ShowerInteraction,AbstractFFVVertexPtr> outgoingVertex1_;
/**
* Abstract pointer to AbstractFFVVertex for QCD radiation from outgoing (anti)fermion
*/
- AbstractFFVVertexPtr abstractOutgoingVertex2_;
+ map<ShowerInteraction,AbstractFFVVertexPtr> outgoingVertex2_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Polarization vectors for the decaying particle
*/
mutable vector<VectorWaveFunction> vectors_;
/**
* Spinors for the decay products
*/
mutable vector<SpinorWaveFunction> wave_;
/**
* Barred spinors for the decay products
*/
mutable vector<SpinorBarWaveFunction> wavebar_;
/**
* Spin density matrix for 3 body decay
*/
mutable RhoDMatrix rho3_;
/**
* Scalar wavefunction for 3 body decay
*/
mutable vector<VectorWaveFunction> vector3_;
/**
* Spinor wavefunction for 3 body decay
*/
mutable vector<SpinorWaveFunction> wave3_;
/**
* Barred spinor wavefunction for 3 body decay
*/
mutable vector<SpinorBarWaveFunction> wavebar3_;
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<VectorWaveFunction> gluon_;
};
}
#endif /* HERWIG_VFFDecayer_H */
diff --git a/Decay/General/VSSDecayer.cc b/Decay/General/VSSDecayer.cc
--- a/Decay/General/VSSDecayer.cc
+++ b/Decay/General/VSSDecayer.cc
@@ -1,369 +1,378 @@
// -*- C++ -*-
//
// VSSDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
// This is the implementation of the non-inlined, non-templated member
// functions of the VSSDecayer class.
//
#include "VSSDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "Herwig/Utilities/Kinematics.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr VSSDecayer::clone() const {
return new_ptr(*this);
}
IBPtr VSSDecayer::fullclone() const {
return new_ptr(*this);
}
-void VSSDecayer::doinit() {
- perturbativeVertex_ = dynamic_ptr_cast<VSSVertexPtr> (vertex());
- abstractVertex_ = dynamic_ptr_cast<AbstractVSSVertexPtr>(vertex());
- abstractIncomingVertex_ = dynamic_ptr_cast<AbstractVVVVertexPtr>(incomingVertex());
- abstractOutgoingVertex1_ = dynamic_ptr_cast<AbstractVSSVertexPtr>(outgoingVertices()[0]);
- abstractOutgoingVertex2_ = dynamic_ptr_cast<AbstractVSSVertexPtr>(outgoingVertices()[1]);
- GeneralTwoBodyDecayer::doinit();
+void VSSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
+ VertexBasePtr vertex,
+ map<ShowerInteraction,VertexBasePtr> & inV,
+ const vector<map<ShowerInteraction,VertexBasePtr> > & outV,
+ map<ShowerInteraction,VertexBasePtr> ) {
+ decayInfo(incoming,outgoing);
+ vertex_ = dynamic_ptr_cast<AbstractVSSVertexPtr>(vertex);
+ perturbativeVertex_ = dynamic_ptr_cast<VSSVertexPtr> (vertex);
+ vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
+ for(auto & inter : itemp) {
+ incomingVertex_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr>(inV.at(inter));
+ outgoingVertex1_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(outV[0].at(inter));
+ outgoingVertex2_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(outV[1].at(inter));
+ }
}
void VSSDecayer::persistentOutput(PersistentOStream & os) const {
- os << abstractVertex_ << perturbativeVertex_
- << abstractIncomingVertex_ << abstractOutgoingVertex1_
- << abstractOutgoingVertex2_;
+ os << vertex_ << perturbativeVertex_
+ << incomingVertex_ << outgoingVertex1_
+ << outgoingVertex2_;
}
void VSSDecayer::persistentInput(PersistentIStream & is, int) {
- is >> abstractVertex_ >> perturbativeVertex_
- >> abstractIncomingVertex_ >> abstractOutgoingVertex1_
- >> abstractOutgoingVertex2_;
+ is >> vertex_ >> perturbativeVertex_
+ >> incomingVertex_ >> outgoingVertex1_
+ >> outgoingVertex2_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<VSSDecayer,GeneralTwoBodyDecayer>
describeHerwigVSSDecayer("Herwig::VSSDecayer", "Herwig.so");
void VSSDecayer::Init() {
static ClassDocumentation<VSSDecayer> documentation
("This implements the decay of a vector to 2 scalars");
}
double VSSDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin0,PDT::Spin0)));
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);
for(unsigned int ix=0;ix<2;++ix)
ScalarWaveFunction::
constructSpinInfo(decay[ix],outgoing,true);
return 0.;
}
ScalarWaveFunction sca1(decay[0]->momentum(),decay[0]->dataPtr(),outgoing);
ScalarWaveFunction sca2(decay[1]->momentum(),decay[1]->dataPtr(),outgoing);
Energy2 scale(sqr(inpart.mass()));
for(unsigned int ix=0;ix<3;++ix) {
- (*ME())(ix,0,0) = abstractVertex_->evaluate(scale,vectors_[ix],sca1,sca2);
+ (*ME())(ix,0,0) = vertex_->evaluate(scale,vectors_[ix],sca1,sca2);
}
double output=(ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy VSSDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
if(perturbativeVertex_) {
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
perturbativeVertex_->setCoupling(sqr(inpart.second), in, outa.first,
outb.first);
double mu1sq = sqr(outa.second/inpart.second);
double mu2sq = sqr(outb.second/inpart.second);
double me2 = sqr(mu1sq - mu2sq) - 2.*(mu1sq + mu2sq);
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second,
outb.second);
Energy output = -norm(perturbativeVertex_->norm())*me2*pcm /
(24.*Constants::pi);
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
double VSSDecayer::threeBodyME(const int , const Particle & inpart,
- const ParticleVector & decay, MEOption meopt) {
+ const ParticleVector & decay,
+ ShowerInteraction inter, MEOption meopt) {
bool massless = inpart.mass()==ZERO;
// work out which is the scalar and anti-scalar
int ianti(0), iscal(1), iglu(2);
int itype[2];
for(unsigned int ix=0;ix<2;++ix) {
if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1;
else itype[ix] = 2;
}
if(itype[0]==0 && itype[1]!=0) swap(ianti, iscal);
if(itype[0]==2 && itype[1]==1) swap(ianti, iscal);
if(itype[0]==0 && itype[1]==0 && abs(decay[0]->dataPtr()->id())>abs(decay[1]->dataPtr()->id()))
swap(iscal, ianti);
if(itype[0]==1 && itype[1]==1 && abs(decay[0]->dataPtr()->id())<abs(decay[1]->dataPtr()->id()))
swap(iscal, ianti);
if(meopt==Initialize) {
// create vector wavefunction for decaying particle
VectorWaveFunction::calculateWaveFunctions(vector3_, rho3_, const_ptr_cast<tPPtr>(&inpart),
incoming, massless);
}
// setup spin information when needed
if(meopt==Terminate) {
VectorWaveFunction::
constructSpinInfo(vector3_ ,const_ptr_cast<tPPtr>(&inpart),outgoing,true,massless);
ScalarWaveFunction::constructSpinInfo( decay[iscal],outgoing,true);
ScalarWaveFunction::constructSpinInfo( decay[ianti],outgoing,true);
VectorWaveFunction::constructSpinInfo(gluon_,decay[iglu ],outgoing,true,false);
return 0.;
}
// calculate colour factors and number of colour flows
unsigned int nflow;
vector<DVector> cfactors = getColourFactors(inpart, decay, nflow);
if(nflow==2) cfactors[0][1]=cfactors[1][0];
vector<GeneralDecayMEPtr> ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin1, PDT::Spin0,
PDT::Spin0, PDT::Spin1)));
// create wavefunctions
ScalarWaveFunction scal(decay[iscal]->momentum(), decay[iscal]->dataPtr(),outgoing);
ScalarWaveFunction anti(decay[ianti]->momentum(), decay[ianti]->dataPtr(),outgoing);
VectorWaveFunction::calculateWaveFunctions(gluon_,decay[iglu ],outgoing,true);
// gauge test
// gluon_.clear();
// for(unsigned int ix=0;ix<3;++ix) {
// if(ix==1) gluon_.push_back(VectorWaveFunction());
// else {
// gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(),
// decay[iglu ]->dataPtr(),10,
// outgoing));
// }
// }
// identify scalar and/or anti-scalar vertex
- AbstractVSSVertexPtr abstractOutgoingVertexS;
- AbstractVSSVertexPtr abstractOutgoingVertexA;
- identifyVertices(iscal, ianti, inpart, decay, abstractOutgoingVertexS, abstractOutgoingVertexA);
+ AbstractVSSVertexPtr outgoingVertexS;
+ AbstractVSSVertexPtr outgoingVertexA;
+ identifyVertices(iscal, ianti, inpart, decay, outgoingVertexS, outgoingVertexA,inter);
Energy2 scale(sqr(inpart.mass()));
const GeneralTwoBodyDecayer::CFlow & colourFlow
= colourFlows(inpart, decay);
for(unsigned int iv = 0; iv < 3; ++iv) {
for(unsigned int ig = 0; ig < 2; ++ig) {
// radiation from the incoming vector
if(inpart.dataPtr()->coloured()) {
- assert(abstractIncomingVertex_);
+ assert(incomingVertex_[inter]);
VectorWaveFunction vectorInter =
- abstractIncomingVertex_->evaluate(scale,3,inpart.dataPtr(),vector3_[iv],
+ incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),vector3_[iv],
gluon_[2*ig],inpart.mass());
if (vector3_[iv].particle()->PDGName()!=vectorInter.particle()->PDGName())
throw Exception()
<< vector3_[iv].particle()->PDGName() << " was changed to "
<< vectorInter .particle()->PDGName() << " in VSSDecayer::threeBodyME"
<< Exception::runerror;
- double gs = abstractIncomingVertex_->strongCoupling(scale);
- Complex diag = abstractVertex_->evaluate(scale,vectorInter,scal,anti)/gs;
+ double gs = incomingVertex_[inter]->strongCoupling(scale);
+ Complex diag = vertex_->evaluate(scale,vectorInter,scal,anti)/gs;
for(unsigned int ix=0;ix<colourFlow[0].size();++ix) {
(*ME[colourFlow[0][ix].first])(iv, 0, 0, ig) +=
colourFlow[0][ix].second*diag;
}
}
// radiation from the outgoing scalar
if(decay[iscal]->dataPtr()->coloured()) {
- assert(abstractOutgoingVertexS);
+ assert(outgoingVertexS);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[iscal]->dataPtr();
if(off->CC()) off = off->CC();
ScalarWaveFunction scalarInter =
- abstractOutgoingVertexS->evaluate(scale,3,off,gluon_[2*ig],scal,decay[iscal]->mass());
+ outgoingVertexS->evaluate(scale,3,off,gluon_[2*ig],scal,decay[iscal]->mass());
if (scal.particle()->PDGName()!=scalarInter.particle()->PDGName())
throw Exception()
<< scal .particle()->PDGName() << " was changed to "
<< scalarInter.particle()->PDGName() << " in VSSDecayer::threeBodyME"
<< Exception::runerror;
- double gs = abstractOutgoingVertexS->strongCoupling(scale);
- Complex diag =abstractVertex_->evaluate(scale,vector3_[iv],anti,scalarInter)/gs;
+ double gs = outgoingVertexS->strongCoupling(scale);
+ Complex diag =vertex_->evaluate(scale,vector3_[iv],anti,scalarInter)/gs;
for(unsigned int ix=0;ix<colourFlow[1].size();++ix) {
(*ME[colourFlow[1][ix].first])(iv, 0, 0, ig) +=
colourFlow[1][ix].second*diag;
}
}
if(decay[ianti]->dataPtr()->coloured()) {
- assert(abstractOutgoingVertexA);
+ assert(outgoingVertexA);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[ianti]->dataPtr();
if(off->CC()) off = off->CC();
ScalarWaveFunction scalarInter =
- abstractOutgoingVertexA->evaluate(scale,3,off, gluon_[2*ig],anti,decay[ianti]->mass());
+ outgoingVertexA->evaluate(scale,3,off, gluon_[2*ig],anti,decay[ianti]->mass());
if (anti.particle()->PDGName()!=scalarInter.particle()->PDGName())
throw Exception()
<< anti .particle()->PDGName() << " was changed to "
<< scalarInter.particle()->PDGName() << " in VSSDecayer::threeBodyME"
<< Exception::runerror;
- double gs = abstractOutgoingVertexA->strongCoupling(scale);
- Complex diag =abstractVertex_->evaluate(scale,vector3_[iv],scal,scalarInter)/gs;
+ double gs = outgoingVertexA->strongCoupling(scale);
+ Complex diag = vertex_->evaluate(scale,vector3_[iv],scal,scalarInter)/gs;
for(unsigned int ix=0;ix<colourFlow[2].size();++ix) {
(*ME[colourFlow[2][ix].first])(iv, 0, 0, ig) +=
colourFlow[2][ix].second*diag;
}
}
}
if(massless) ++iv;
}
// contract matrices
double output=0.;
for(unsigned int ix=0; ix<nflow; ++ix){
for(unsigned int iy=0; iy<nflow; ++iy){
output+=cfactors[ix][iy]*(ME[ix]->contract(*ME[iy],rho3_)).real();
}
}
output*=(4.*Constants::pi);
// return the answer
return output;
}
void VSSDecayer::identifyVertices(const int iscal, const int ianti,
const Particle & inpart, const ParticleVector & decay,
- AbstractVSSVertexPtr & abstractOutgoingVertexS,
- AbstractVSSVertexPtr & abstractOutgoingVertexA){
+ AbstractVSSVertexPtr & outgoingVertexS,
+ AbstractVSSVertexPtr & outgoingVertexA,
+ ShowerInteraction inter){
// work out which scalar each outgoing vertex corresponds to
// two outgoing vertices
if( inpart.dataPtr() ->iColour()==PDT::Colour0 &&
((decay[iscal]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar) ||
(decay[iscal]->dataPtr()->iColour()==PDT::Colour8 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour8))){
- if(abstractOutgoingVertex1_==abstractOutgoingVertex2_){
- abstractOutgoingVertexS = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){
+ outgoingVertexS = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
- else if (abstractOutgoingVertex1_->isIncoming(getParticleData(decay[iscal]->id()))){
- abstractOutgoingVertexS = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){
+ outgoingVertexS = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
- else if (abstractOutgoingVertex2_->isIncoming(getParticleData(decay[iscal]->id()))){
- abstractOutgoingVertexS = abstractOutgoingVertex2_;
- abstractOutgoingVertexA = abstractOutgoingVertex1_;
+ else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){
+ outgoingVertexS = outgoingVertex2_[inter];
+ outgoingVertexA = outgoingVertex1_[inter];
}
}
else if(inpart.dataPtr() ->iColour()==PDT::Colour8 &&
decay[iscal]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){
- if(abstractOutgoingVertex1_==abstractOutgoingVertex2_){
- abstractOutgoingVertexS = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){
+ outgoingVertexS = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
- else if (abstractOutgoingVertex1_->isIncoming(getParticleData(decay[iscal]->id()))){
- abstractOutgoingVertexS = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){
+ outgoingVertexS = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
- else if (abstractOutgoingVertex2_->isIncoming(getParticleData(decay[iscal]->id()))){
- abstractOutgoingVertexS = abstractOutgoingVertex2_;
- abstractOutgoingVertexA = abstractOutgoingVertex1_;
+ else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){
+ outgoingVertexS = outgoingVertex2_[inter];
+ outgoingVertexA = outgoingVertex1_[inter];
}
}
// one outgoing vertex
else if(inpart.dataPtr()->iColour()==PDT::Colour3){
if(decay[iscal]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour0){
- if (abstractOutgoingVertex1_) abstractOutgoingVertexS = abstractOutgoingVertex1_;
- else if(abstractOutgoingVertex2_) abstractOutgoingVertexS = abstractOutgoingVertex2_;
+ if (outgoingVertex1_[inter]) outgoingVertexS = outgoingVertex1_[inter];
+ else if(outgoingVertex2_[inter]) outgoingVertexS = outgoingVertex2_[inter];
}
else if (decay[iscal]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour8){
- if (abstractOutgoingVertex1_->isIncoming(getParticleData(decay[ianti]->dataPtr()->id()))){
- abstractOutgoingVertexS = abstractOutgoingVertex2_;
- abstractOutgoingVertexA = abstractOutgoingVertex1_;
+ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[ianti]->dataPtr()->id()))){
+ outgoingVertexS = outgoingVertex2_[inter];
+ outgoingVertexA = outgoingVertex1_[inter];
}
else {
- abstractOutgoingVertexS = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ outgoingVertexS = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
}
}
else if(inpart.dataPtr()->iColour()==PDT::Colour3bar){
if(decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar &&
decay[iscal]->dataPtr()->iColour()==PDT::Colour0){
- if (abstractOutgoingVertex1_) abstractOutgoingVertexA = abstractOutgoingVertex1_;
- else if(abstractOutgoingVertex2_) abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ if (outgoingVertex1_[inter]) outgoingVertexA = outgoingVertex1_[inter];
+ else if(outgoingVertex2_[inter]) outgoingVertexA = outgoingVertex2_[inter];
}
else if (decay[iscal]->dataPtr()->iColour()==PDT::Colour8 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){
- if (abstractOutgoingVertex1_->isIncoming(getParticleData(decay[iscal]->dataPtr()->id()))){
- abstractOutgoingVertexS = abstractOutgoingVertex1_;
- abstractOutgoingVertexA = abstractOutgoingVertex2_;
+ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->dataPtr()->id()))){
+ outgoingVertexS = outgoingVertex1_[inter];
+ outgoingVertexA = outgoingVertex2_[inter];
}
else {
- abstractOutgoingVertexS = abstractOutgoingVertex2_;
- abstractOutgoingVertexA = abstractOutgoingVertex1_;
+ outgoingVertexS = outgoingVertex2_[inter];
+ outgoingVertexA = outgoingVertex1_[inter];
}
}
}
- if (! ((abstractIncomingVertex_ && (abstractOutgoingVertexS || abstractOutgoingVertexA)) ||
- ( abstractOutgoingVertexS && abstractOutgoingVertexA)))
+ if (! ((incomingVertex_[inter] && (outgoingVertexS || outgoingVertexA)) ||
+ ( outgoingVertexS && outgoingVertexA)))
throw Exception()
<< "Invalid vertices for QCD radiation in VSS decay in VSSDecayer::identifyVertices"
<< Exception::runerror;
// // prohibit all for now since all unchecked
// if (true)
// throw Exception()
// << "Invalid vertices for QCD radiation in VSS decay in VSSDecayer::identifyVertices"
// << Exception::runerror;
}
diff --git a/Decay/General/VSSDecayer.h b/Decay/General/VSSDecayer.h
--- a/Decay/General/VSSDecayer.h
+++ b/Decay/General/VSSDecayer.h
@@ -1,203 +1,201 @@
// -*- C++ -*-
//
// VSSDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_VSSDecayer_H
#define HERWIG_VSSDecayer_H
//
// This is the declaration of the VSSDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Helicity/Vertex/Scalar/VSSVertex.h"
#include "ThePEG/Helicity/Vertex/Vector/VVVVertex.h"
#include "ThePEG/Repository/EventGenerator.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::VSSVertexPtr;
/** \ingroup Decay
* The VSSDecayer class implements the decay of a vector
* to 2 scalars in a general model. It holds an VSSVertex pointer
* that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class VSSDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
VSSDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* 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 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;
/**
* 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;
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return FSR;}
/**
* Three-body matrix element including additional QCD radiation
*/
virtual double threeBodyME(const int , const Particle & inpart,
- const ParticleVector & decay,MEOption meopt);
+ const ParticleVector & decay,
+ ShowerInteraction inter, MEOption meopt);
/**
* Indentify outgoing vertices for the fermion and antifermion
*/
void identifyVertices(const int iscal, const int ianti,
const Particle & inpart, const ParticleVector & decay,
AbstractVSSVertexPtr & abstractOutgoingVertexS,
- AbstractVSSVertexPtr & abstractOutgoingVertexA);
+ AbstractVSSVertexPtr & abstractOutgoingVertexA,
+ ShowerInteraction inter);
+
+ /**
+ * Set the information on the decay
+ */
+ virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr>);
//@}
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
-protected:
-
- /** @name Standard Interfaced functions. */
- //@{
- /**
- * Initialize this object after the setup phase before saving an
- * EventGenerator to disk.
- * @throws InitException if object could not be initialized properly.
- */
- virtual void doinit();
- //@}
-
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
VSSDecayer & operator=(const VSSDecayer &);
private:
/**
* Abstract pointer to AbstractVSSVertex
*/
- AbstractVSSVertexPtr abstractVertex_;
+ AbstractVSSVertexPtr vertex_;
/**
* Pointer to the perturbative vertex
*/
VSSVertexPtr perturbativeVertex_;
/**
* Abstract pointer to AbstractVVVVertex for QCD radiation from incoming vector
*/
- AbstractVVVVertexPtr abstractIncomingVertex_;
+ map<ShowerInteraction,AbstractVVVVertexPtr> incomingVertex_;
/**
* Abstract pointer to AbstractFFVVertex for QCD radiation from outgoing scalar
*/
- AbstractVSSVertexPtr abstractOutgoingVertex1_;
+ map<ShowerInteraction,AbstractVSSVertexPtr> outgoingVertex1_;
/**
* Abstract pointer to AbstractFFVVertex for QCD radiation from outgoing scalar
*/
- AbstractVSSVertexPtr abstractOutgoingVertex2_;
+ map<ShowerInteraction,AbstractVSSVertexPtr> outgoingVertex2_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Polarization vectors for the decaying particle
*/
mutable vector<Helicity::VectorWaveFunction> vectors_;
/**
* Spin density matrix for 3 body decay
*/
mutable RhoDMatrix rho3_;
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<Helicity::VectorWaveFunction> vector3_;
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<Helicity::VectorWaveFunction> gluon_;
};
}
#endif /* HERWIG_VSSDecayer_H */
diff --git a/Decay/General/VVSDecayer.cc b/Decay/General/VVSDecayer.cc
--- a/Decay/General/VVSDecayer.cc
+++ b/Decay/General/VVSDecayer.cc
@@ -1,123 +1,126 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the VVSDecayer class.
//
#include "VVSDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr VVSDecayer::clone() const {
return new_ptr(*this);
}
IBPtr VVSDecayer::fullclone() const {
return new_ptr(*this);
}
-
-void VVSDecayer::doinit() {
- perturbativeVertex_ = dynamic_ptr_cast<VVSVertexPtr> (vertex());
- abstractVertex_ = dynamic_ptr_cast<AbstractVVSVertexPtr>(vertex());
- GeneralTwoBodyDecayer::doinit();
+void VVSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
+ VertexBasePtr vertex,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr>) {
+ decayInfo(incoming,outgoing);
+ vertex_ = dynamic_ptr_cast<AbstractVVSVertexPtr>(vertex);
+ perturbativeVertex_ = dynamic_ptr_cast<VVSVertexPtr> (vertex);
}
void VVSDecayer::persistentOutput(PersistentOStream & os) const {
- os << abstractVertex_ << perturbativeVertex_;
+ os << vertex_ << perturbativeVertex_;
}
void VVSDecayer::persistentInput(PersistentIStream & is, int) {
- is >> abstractVertex_ >> perturbativeVertex_;
+ is >> vertex_ >> perturbativeVertex_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<VVSDecayer,GeneralTwoBodyDecayer>
describeHerwigVVSDecayer("Herwig::VVSDecayer", "Herwig.so");
void VVSDecayer::Init() {
static ClassDocumentation<VVSDecayer> documentation
("The VVSDecayer class implements the decay of a vector"
" to a vector and a scalar");
}
double VVSDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
bool massless = ( decay[0]->id()==ParticleID::gamma ||
decay[0]->id()==ParticleID::g );
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1,PDT::Spin0)));
if(meopt==Initialize) {
VectorWaveFunction::calculateWaveFunctions(vectors_[0],rho_,
const_ptr_cast<tPPtr>(&inpart),
incoming,false);
}
if(meopt==Terminate) {
VectorWaveFunction::constructSpinInfo(vectors_[0],const_ptr_cast<tPPtr>(&inpart),
incoming,true,false);
VectorWaveFunction::
constructSpinInfo(vectors_[1],decay[0],outgoing,true,massless);
ScalarWaveFunction::
constructSpinInfo(decay[1],outgoing,true);
return 0.;
}
VectorWaveFunction::
calculateWaveFunctions(vectors_[1],decay[0],outgoing,massless);
ScalarWaveFunction sca(decay[1]->momentum(),decay[1]->dataPtr(),outgoing);
Energy2 scale(sqr(inpart.mass()));
for(unsigned int in=0;in<3;++in) {
for(unsigned int out=0;out<3;++out) {
if(massless&&out==1) ++out;
(*ME())(in,out,0) =
- abstractVertex_->evaluate(scale,vectors_[0][in],vectors_[1][out],sca);
+ vertex_->evaluate(scale,vectors_[0][in],vectors_[1][out],sca);
}
}
double output=(ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy VVSDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
if(perturbativeVertex_) {
Energy2 scale(sqr(inpart.second));
double mu1sq = sqr(outa.second/inpart.second);
double mu2sq = sqr(outb.second/inpart.second);
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
if( outb.first->iSpin() == PDT::Spin0 )
perturbativeVertex_->setCoupling(sqr(inpart.second), in,
outa.first, outb.first);
else {
perturbativeVertex_->setCoupling(sqr(inpart.second), in,
outb.first, outa.first);
swap(mu1sq, mu2sq);
}
double vn = norm(perturbativeVertex_->norm());
if(vn == ZERO || mu1sq == ZERO) return ZERO;
double me2 = 2. + 0.25*sqr(1. + mu1sq - mu2sq)/mu1sq;
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second,
outb.second);
Energy output = vn*me2*pcm/(24.*Constants::pi)/scale*UnitRemoval::E2;
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
diff --git a/Decay/General/VVSDecayer.h b/Decay/General/VVSDecayer.h
--- a/Decay/General/VVSDecayer.h
+++ b/Decay/General/VVSDecayer.h
@@ -1,146 +1,142 @@
// -*- C++ -*-
#ifndef THEPEG_VVSDecayer_H
#define THEPEG_VVSDecayer_H
//
// This is the declaration of the VVSDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Helicity/Vertex/Scalar/VVSVertex.h"
#include "ThePEG/Repository/EventGenerator.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::VVSVertexPtr;
/** \ingroup Decay
* The VVSDecayer class implements the decay of a vector to a
* vector and a scalar in a general model. It holds an VVSVertex pointer
* that must be typecast from the VertexBase pointer helid in the
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see \ref VVSDecayerInterfaces "The interfaces"
* defined for VVSDecayer.
*/
class VVSDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
VVSDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* 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;
/**
* 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;
+
+ /**
+ * Set the information on the decay
+ */
+ virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr>);
//@}
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
-protected:
-
- /** @name Standard Interfaced functions. */
- //@{
- /**
- * Initialize this object after the setup phase before saving an
- * EventGenerator to disk.
- * @throws InitException if object could not be initialized properly.
- */
- virtual void doinit();
- //@}
-
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
VVSDecayer & operator=(const VVSDecayer &);
private:
/**
* Abstract pointer to AbstractVVSVertex
*/
- AbstractVVSVertexPtr abstractVertex_;
+ AbstractVVSVertexPtr vertex_;
/**
* Pointer to the perturbative vertex
*/
VVSVertexPtr perturbativeVertex_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Vector wavefunctions
*/
mutable vector<Helicity::VectorWaveFunction> vectors_[2];
};
}
#endif /* THEPEG_VVSDecayer_H */
diff --git a/Decay/General/VVVDecayer.cc b/Decay/General/VVVDecayer.cc
--- a/Decay/General/VVVDecayer.cc
+++ b/Decay/General/VVVDecayer.cc
@@ -1,130 +1,134 @@
// -*- C++ -*-
//
// VVVDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the VVVDecayer class.
//
#include "VVVDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr VVVDecayer::clone() const {
return new_ptr(*this);
}
IBPtr VVVDecayer::fullclone() const {
return new_ptr(*this);
}
-void VVVDecayer::doinit() {
- perturbativeVertex_ = dynamic_ptr_cast<VVVVertexPtr> (vertex());
- abstractVertex_ = dynamic_ptr_cast<AbstractVVVVertexPtr>(vertex());
- GeneralTwoBodyDecayer::doinit();
+void VVVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
+ VertexBasePtr vertex,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr>) {
+ decayInfo(incoming,outgoing);
+ vertex_ = dynamic_ptr_cast<AbstractVVVVertexPtr>(vertex);
+ perturbativeVertex_ = dynamic_ptr_cast<VVVVertexPtr> (vertex);
}
void VVVDecayer::persistentOutput(PersistentOStream & os) const {
- os << abstractVertex_ << perturbativeVertex_;
+ os << vertex_ << perturbativeVertex_;
}
void VVVDecayer::persistentInput(PersistentIStream & is, int) {
- is >> abstractVertex_ >> perturbativeVertex_;
+ is >> vertex_ >> perturbativeVertex_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<VVVDecayer,GeneralTwoBodyDecayer>
describeHerwigVVVDecayer("Herwig::VVVDecayer", "Herwig.so");
void VVVDecayer::Init() {
static ClassDocumentation<VVVDecayer> documentation
("The VVVDecayer class implements the decay of a vector boson "
"into 2 vector bosons");
}
double VVVDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1,PDT::Spin1)));
bool massless[2];
for(unsigned int ix=0;ix<2;++ix)
massless[ix] = (decay[ix]->id()==ParticleID::gamma ||
decay[ix]->id()==ParticleID::g);
if(meopt==Initialize) {
VectorWaveFunction::calculateWaveFunctions(vectors_[0],rho_,
const_ptr_cast<tPPtr>(&inpart),
incoming,false);
}
if(meopt==Terminate) {
VectorWaveFunction::constructSpinInfo(vectors_[0],const_ptr_cast<tPPtr>(&inpart),
incoming,true,false);
for(unsigned int ix=0;ix<2;++ix)
VectorWaveFunction::
constructSpinInfo(vectors_[ix+1],decay[ix],outgoing,true,massless[ix]);
return 0.;
}
for(unsigned int ix=0;ix<2;++ix)
VectorWaveFunction::
calculateWaveFunctions(vectors_[ix+1],decay[ix],outgoing,massless[ix]);
Energy2 scale(sqr(inpart.mass()));
for(unsigned int iv3=0;iv3<3;++iv3) {
for(unsigned int iv2=0;iv2<3;++iv2) {
for(unsigned int iv1=0;iv1<3;++iv1) {
- (*ME())(iv1,iv2,iv3) = abstractVertex_->
+ (*ME())(iv1,iv2,iv3) = vertex_->
evaluate(scale,vectors_[1][iv2],vectors_[2][iv3],vectors_[0][iv1]);
}
}
}
double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy VVVDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
if(perturbativeVertex_) {
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
perturbativeVertex_->setCoupling(sqr(inpart.second), in,
outa.first, outb.first);
double mu1(outa.second/inpart.second), mu1sq(sqr(mu1)),
mu2(outb.second/inpart.second), mu2sq(sqr(mu2));
double vn = norm(perturbativeVertex_->norm());
if(vn == ZERO || mu1sq == ZERO || mu2sq == ZERO) return ZERO;
double me2 =
(mu1 - mu2 - 1.)*(mu1 - mu2 + 1.)*(mu1 + mu2 - 1.)*(mu1 + mu2 + 1.)
* (sqr(mu1sq) + sqr(mu2sq) + 10.*(mu1sq*mu2sq + mu1sq + mu2sq) + 1.)
/4./mu1sq/mu2sq;
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second,
outb.second);
Energy pWidth = vn*me2*pcm/24./Constants::pi;
// colour factor
pWidth *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return pWidth;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
diff --git a/Decay/General/VVVDecayer.h b/Decay/General/VVVDecayer.h
--- a/Decay/General/VVVDecayer.h
+++ b/Decay/General/VVVDecayer.h
@@ -1,152 +1,148 @@
// -*- C++ -*-
//
// VVVDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_VVVDecayer_H
#define HERWIG_VVVDecayer_H
//
// This is the declaration of the VVVDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Vector/VVVVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::VVVVertexPtr;
/** \ingroup Decay
* The VVVDecayer class implements the decay of a vector
* to 2 vectors in a general model. It holds an VVVVertex pointer
* that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class VVVDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
VVVDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* 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;
/**
* 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;
+
+ /**
+ * Set the information on the decay
+ */
+ virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ map<ShowerInteraction,VertexBasePtr> &,
+ const vector<map<ShowerInteraction,VertexBasePtr> > &,
+ map<ShowerInteraction,VertexBasePtr>);
//@}
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 and
- * EventGenerator to disk.
- * @throws InitException if object could not be initialized properly.
- */
- virtual void doinit();
- //@}
-
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
VVVDecayer & operator=(const VVVDecayer &);
private:
/**
* Abstract pointer to AbstractVVVVertex
*/
- AbstractVVVVertexPtr abstractVertex_;
+ AbstractVVVVertexPtr vertex_;
/**
* Pointer to the perturbative vertex
*/
VVVVertexPtr perturbativeVertex_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Vector wavefunctions
*/
mutable vector<Helicity::VectorWaveFunction> vectors_[3];
};
}
#endif /* HERWIG_VVVDecayer_H */
diff --git a/Decay/PerturbativeDecayer.cc b/Decay/PerturbativeDecayer.cc
--- a/Decay/PerturbativeDecayer.cc
+++ b/Decay/PerturbativeDecayer.cc
@@ -1,952 +1,944 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the PerturbativeDecayer class.
//
#include "PerturbativeDecayer.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/EventRecord/Particle.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Utilities/EnumIO.h"
using namespace Herwig;
void PerturbativeDecayer::persistentOutput(PersistentOStream & os) const {
os << ounit(pTmin_,GeV) << oenum(inter_) << alphaS_ << alphaEM_;
}
void PerturbativeDecayer::persistentInput(PersistentIStream & is, int) {
is >> iunit(pTmin_,GeV) >> ienum(inter_) >> alphaS_ >> alphaEM_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeAbstractClass<PerturbativeDecayer,DecayIntegrator>
describeHerwigPerturbativeDecayer("Herwig::PerturbativeDecayer",
"Herwig.so HwPerturbativeDecay.so");
void PerturbativeDecayer::Init() {
static ClassDocumentation<PerturbativeDecayer> documentation
("The PerturbativeDecayer class is the mase class for perturbative decays in Herwig");
static Parameter<PerturbativeDecayer,Energy> interfacepTmin
("pTmin",
"Minimum transverse momentum from gluon radiation",
&PerturbativeDecayer::pTmin_, GeV, 1.0*GeV, 0.0*GeV, 10.0*GeV,
false, false, Interface::limited);
static Switch<PerturbativeDecayer,ShowerInteraction> interfaceInteractions
("Interactions",
"which interactions to include for the hard corrections",
&PerturbativeDecayer::inter_, ShowerInteraction::QCD, false, false);
static SwitchOption interfaceInteractionsQCD
(interfaceInteractions,
"QCD",
"QCD Only",
ShowerInteraction::QCD);
static SwitchOption interfaceInteractionsQED
(interfaceInteractions,
"QED",
"QED only",
ShowerInteraction::QED);
static SwitchOption interfaceInteractionsQCDandQED
(interfaceInteractions,
"QCDandQED",
"Both QCD and QED",
ShowerInteraction::Both);
static Reference<PerturbativeDecayer,ShowerAlpha> interfaceAlphaS
("AlphaS",
"Object for the coupling in the generation of hard QCD radiation",
&PerturbativeDecayer::alphaS_, false, false, true, true, false);
static Reference<PerturbativeDecayer,ShowerAlpha> interfaceAlphaEM
("AlphaEM",
"Object for the coupling in the generation of hard QED radiation",
&PerturbativeDecayer::alphaEM_, false, false, true, true, false);
}
-double PerturbativeDecayer::threeBodyME(const int , const Particle &,
- const ParticleVector &,MEOption) {
- throw Exception() << "Base class PerturbativeDecayer::threeBodyME() "
- << "called, should have an implementation in the inheriting class"
- << Exception::runerror;
- return 0.;
-}
-
double PerturbativeDecayer::matrixElementRatio(const Particle & ,
const ParticleVector & ,
const ParticleVector & ,
MEOption ,
ShowerInteraction ) {
throw Exception() << "Base class PerturbativeDecayer::matrixElementRatio() "
<< "called, should have an implementation in the inheriting class"
<< Exception::runerror;
return 0.;
}
RealEmissionProcessPtr PerturbativeDecayer::generateHardest(RealEmissionProcessPtr born) {
return getHardEvent(born,false,inter_);
}
RealEmissionProcessPtr PerturbativeDecayer::applyHardMatrixElementCorrection(RealEmissionProcessPtr born) {
return getHardEvent(born,true,ShowerInteraction::QCD);
}
RealEmissionProcessPtr PerturbativeDecayer::getHardEvent(RealEmissionProcessPtr born,
bool inDeadZone,
ShowerInteraction inter) {
// check one incoming
assert(born->bornIncoming().size()==1);
// check exactly two outgoing particles
assert(born->bornOutgoing().size()==2); // search for coloured particles
bool colouredParticles=born->bornIncoming()[0]->dataPtr()->coloured();
bool chargedParticles=born->bornIncoming()[0]->dataPtr()->charged();
for(unsigned int ix=0;ix<born->bornOutgoing().size();++ix) {
if(born->bornOutgoing()[ix]->dataPtr()->coloured())
colouredParticles=true;
if(born->bornOutgoing()[ix]->dataPtr()->charged())
chargedParticles=true;
}
// if no coloured/charged particles return
if ( !colouredParticles && !chargedParticles ) return RealEmissionProcessPtr();
if ( !colouredParticles && inter==ShowerInteraction::QCD ) return RealEmissionProcessPtr();
if ( ! chargedParticles && inter==ShowerInteraction::QED ) return RealEmissionProcessPtr();
// for decay b -> a c
// set progenitors
PPtr cProgenitor = born->bornOutgoing()[0];
PPtr aProgenitor = born->bornOutgoing()[1];
// get the decaying particle
PPtr bProgenitor = born->bornIncoming()[0];
// identify which dipoles are required
vector<DipoleType> dipoles;
if(!identifyDipoles(dipoles,aProgenitor,bProgenitor,cProgenitor,inter)) {
return RealEmissionProcessPtr();
}
Energy trialpT = pTmin_;
LorentzRotation eventFrame;
vector<Lorentz5Momentum> momenta;
vector<Lorentz5Momentum> trialMomenta(4);
PPtr finalEmitter, finalSpectator;
PPtr trialEmitter, trialSpectator;
DipoleType finalType(FFa,ShowerInteraction::QCD);
for (int i=0; i<int(dipoles.size()); ++i) {
// assign emitter and spectator based on current dipole
if (dipoles[i].type==FFc || dipoles[i].type==IFc || dipoles[i].type==IFbc){
trialEmitter = cProgenitor;
trialSpectator = aProgenitor;
}
else if (dipoles[i].type==FFa || dipoles[i].type==IFa || dipoles[i].type==IFba){
trialEmitter = aProgenitor;
trialSpectator = cProgenitor;
}
// find rotation from lab to frame with the spectator along -z
LorentzRotation trialEventFrame(bProgenitor->momentum().findBoostToCM());
Lorentz5Momentum pspectator = (trialEventFrame*trialSpectator->momentum());
trialEventFrame.rotateZ( -pspectator.phi() );
trialEventFrame.rotateY( -pspectator.theta() - Constants::pi );
// invert it
trialEventFrame.invert();
// try to generate an emission
pT_ = pTmin_;
vector<Lorentz5Momentum> trialMomenta
= hardMomenta(bProgenitor, trialEmitter, trialSpectator,
dipoles, i, inDeadZone);
// select dipole which gives highest pT emission
if(pT_>trialpT) {
trialpT = pT_;
momenta = trialMomenta;
eventFrame = trialEventFrame;
finalEmitter = trialEmitter;
finalSpectator = trialSpectator;
finalType = dipoles[i];
if (dipoles[i].type==FFc || dipoles[i].type==FFa ) {
if((momenta[3]+momenta[1]).m2()-momenta[1].m2()>
(momenta[3]+momenta[2]).m2()-momenta[2].m2()) {
swap(finalEmitter,finalSpectator);
swap(momenta[1],momenta[2]);
}
}
}
}
pT_ = trialpT;
// if no emission return
if(momenta.empty()) {
if(inter==ShowerInteraction::Both || inter==ShowerInteraction::QCD)
born->pT()[ShowerInteraction::QCD] = pTmin_;
if(inter==ShowerInteraction::Both || inter==ShowerInteraction::QED)
born->pT()[ShowerInteraction::QED] = pTmin_;
return born;
}
// rotate momenta back to the lab
for(unsigned int ix=0;ix<momenta.size();++ix) {
momenta[ix] *= eventFrame;
}
// set maximum pT for subsequent branchings
if(inter==ShowerInteraction::Both || inter==ShowerInteraction::QCD)
born->pT()[ShowerInteraction::QCD] = pT_;
if(inter==ShowerInteraction::Both || inter==ShowerInteraction::QED)
born->pT()[ShowerInteraction::QED] = pT_;
// get ParticleData objects
tcPDPtr b = bProgenitor ->dataPtr();
tcPDPtr e = finalEmitter ->dataPtr();
tcPDPtr s = finalSpectator->dataPtr();
tcPDPtr boson = getParticleData(finalType.interaction==ShowerInteraction::QCD ?
ParticleID::g : ParticleID::gamma);
// create new ShowerParticles
PPtr emitter = e ->produceParticle(momenta[1]);
PPtr spectator = s ->produceParticle(momenta[2]);
PPtr gauge = boson->produceParticle(momenta[3]);
PPtr incoming = b ->produceParticle(bProgenitor->momentum());
// insert the particles
born->incoming().push_back(incoming);
unsigned int iemit(0),ispect(0);
for(unsigned int ix=0;ix<born->bornOutgoing().size();++ix) {
if(born->bornOutgoing()[ix]==finalEmitter) {
born->outgoing().push_back(emitter);
iemit = born->outgoing().size();
}
else if(born->bornOutgoing()[ix]==finalSpectator) {
born->outgoing().push_back(spectator);
ispect = born->outgoing().size();
}
}
born->outgoing().push_back(gauge);
if(!spectator->dataPtr()->coloured() ||
(finalType.type != FFa && finalType.type!=FFc) ) ispect = 0;
born->emitter(iemit);
born->spectator(ispect);
born->emitted(3);
// set the interaction
born->interaction(finalType.interaction);
// set up colour lines
getColourLines(born);
// return the tree
return born;
}
bool PerturbativeDecayer::identifyDipoles(vector<DipoleType> & dipoles,
PPtr & aProgenitor,
PPtr & bProgenitor,
PPtr & cProgenitor,
ShowerInteraction inter) const {
// identify any QCD dipoles
if(inter==ShowerInteraction::QCD ||
inter==ShowerInteraction::Both) {
PDT::Colour bColour = bProgenitor->dataPtr()->iColour();
PDT::Colour cColour = cProgenitor->dataPtr()->iColour();
PDT::Colour aColour = aProgenitor->dataPtr()->iColour();
// decaying colour singlet
if (bColour==PDT::Colour0 ) {
if ((cColour==PDT::Colour3 && aColour==PDT::Colour3bar) ||
(cColour==PDT::Colour3bar && aColour==PDT::Colour3) ||
(cColour==PDT::Colour8 && aColour==PDT::Colour8)){
dipoles.push_back(DipoleType(FFa,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(FFc,ShowerInteraction::QCD));
}
}
// decaying colour triplet
else if (bColour==PDT::Colour3 ) {
if (cColour==PDT::Colour3 && aColour==PDT::Colour0){
dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFc ,ShowerInteraction::QCD));
}
else if (cColour==PDT::Colour0 && aColour==PDT::Colour3){
dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFa ,ShowerInteraction::QCD));
}
else if (cColour==PDT::Colour8 && aColour==PDT::Colour3){
dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFc ,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(FFc ,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(FFa ,ShowerInteraction::QCD));
}
else if (cColour==PDT::Colour3 && aColour==PDT::Colour8){
dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFa ,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(FFc ,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(FFa ,ShowerInteraction::QCD));
}
}
// decaying colour anti-triplet
else if (bColour==PDT::Colour3bar) {
if ((cColour==PDT::Colour3bar && aColour==PDT::Colour0)){
dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFc ,ShowerInteraction::QCD));
}
else if ((cColour==PDT::Colour0 && aColour==PDT::Colour3bar)){
dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFa ,ShowerInteraction::QCD));
}
else if (cColour==PDT::Colour8 && aColour==PDT::Colour3bar){
dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFc ,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(FFc ,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(FFa ,ShowerInteraction::QCD));
}
else if (cColour==PDT::Colour3bar && aColour==PDT::Colour8){
dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFa ,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(FFc ,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(FFa ,ShowerInteraction::QCD));
}
}
// decaying colour octet
else if (bColour==PDT::Colour8){
if ((cColour==PDT::Colour3 && aColour==PDT::Colour3bar) ||
(cColour==PDT::Colour3bar && aColour==PDT::Colour3)){
dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFa,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFc,ShowerInteraction::QCD));
}
else if (cColour==PDT::Colour8 && aColour==PDT::Colour0){
dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFc,ShowerInteraction::QCD));
}
else if (cColour==PDT::Colour0 && aColour==PDT::Colour8){
dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFa,ShowerInteraction::QCD));
}
}
}
// QED dipoles
if(inter==ShowerInteraction::Both ||
inter==ShowerInteraction::QED) {
const bool & bCharged = bProgenitor->dataPtr()->charged();
const bool & cCharged = cProgenitor->dataPtr()->charged();
const bool & aCharged = aProgenitor->dataPtr()->charged();
// initial-final
if(bCharged && aCharged) {
dipoles.push_back(DipoleType(IFba,ShowerInteraction::QED));
dipoles.push_back(DipoleType(IFa ,ShowerInteraction::QED));
}
if(bCharged && cCharged) {
dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QED));
dipoles.push_back(DipoleType(IFc ,ShowerInteraction::QED));
}
// final-state
if(aCharged && cCharged) {
dipoles.push_back(DipoleType(FFa,ShowerInteraction::QED));
dipoles.push_back(DipoleType(FFc,ShowerInteraction::QED));
}
}
// check colour structure is allowed
return !dipoles.empty();
}
vector<Lorentz5Momentum> PerturbativeDecayer::hardMomenta(PPtr in, PPtr emitter,
PPtr spectator,
const vector<DipoleType> &dipoles,
int i, bool inDeadZone) {
double C = 6.3;
double ymax = 10.;
double ymin = -ymax;
// get masses of the particles
mb_ = in ->momentum().mass();
e_ = emitter ->momentum().mass()/mb_;
s_ = spectator->momentum().mass()/mb_;
e2_ = sqr(e_);
s2_ = sqr(s_);
vector<Lorentz5Momentum> particleMomenta (4);
Energy2 lambda = sqr(mb_)*sqrt(1.+sqr(s2_)+sqr(e2_)-2.*s2_-2.*e2_-2.*s2_*e2_);
// calculate A
double A = (ymax-ymin)*C/Constants::twopi;
if(dipoles[i].interaction==ShowerInteraction::QCD)
A *= alphaS() ->overestimateValue();
else
A *= alphaEM()->overestimateValue();
Energy pTmax = mb_*(sqr(1.-s_)-e2_)/(2.*(1.-s_));
// if no possible branching return
if ( pTmax < pTmin_ ) {
particleMomenta.clear();
return particleMomenta;
}
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 xs[2], xe[2], xe_z[2], xg;
for (unsigned int j=0; j<2; j++) {
// check if the momenta are physical
if (!calcMomenta(j, pT, y, phi, xg, xs[j], xe[j], xe_z[j], particleMomenta))
continue;
// check if point lies within phase space
if (!psCheck(xg, xs[j]))
continue;
// check if point lies within the dead-zone (if required)
if(inDeadZone) {
if(!inTotalDeadZone(xg,xs[j],dipoles,i)) continue;
}
// decay products for 3 body decay
PPtr inpart = in ->dataPtr()->produceParticle(particleMomenta[0]);
ParticleVector decay3;
decay3.push_back(emitter ->dataPtr()->produceParticle(particleMomenta[1]));
decay3.push_back(spectator->dataPtr()->produceParticle(particleMomenta[2]));
if(dipoles[i].interaction==ShowerInteraction::QCD)
decay3.push_back(getParticleData(ParticleID::g )->produceParticle(particleMomenta[3]));
else
decay3.push_back(getParticleData(ParticleID::gamma)->produceParticle(particleMomenta[3]));
// decay products for 2 body decay
Lorentz5Momentum p1(ZERO,ZERO, lambda/2./mb_,(mb_/2.)*(1.+e2_-s2_),mb_*e_);
Lorentz5Momentum p2(ZERO,ZERO,-lambda/2./mb_,(mb_/2.)*(1.+s2_-e2_),mb_*s_);
ParticleVector decay2;
decay2.push_back(emitter ->dataPtr()->produceParticle(p1));
decay2.push_back(spectator->dataPtr()->produceParticle(p2));
if (dipoles[i].type==FFc || dipoles[i].type==IFc || dipoles[i].type==IFbc){
swap(decay2[0],decay2[1]);
swap(decay3[0],decay3[1]);
}
// calculate matrix element ratio R/B
double meRatio = matrixElementRatio(*inpart,decay2,decay3,Initialize,dipoles[i].interaction);
// calculate dipole factor
InvEnergy2 dipoleSum = ZERO;
InvEnergy2 numerator = ZERO;
for (int k=0; k<int(dipoles.size()); ++k) {
// skip dipoles which are not of the interaction being considered
if(dipoles[k].interaction!=dipoles[i].interaction) continue;
InvEnergy2 dipole = abs(calculateDipole(dipoles[k],*inpart,decay3));
dipoleSum += dipole;
if (k==i) numerator = dipole;
}
meRatio *= numerator/dipoleSum;
// calculate jacobian
Energy2 denom = (mb_-particleMomenta[3].e())*particleMomenta[2].vect().mag() -
particleMomenta[2].e()*particleMomenta[3].z();
InvEnergy2 J = (particleMomenta[2].vect().mag2())/(lambda*denom);
// calculate weight
weight[j] = meRatio*fabs(sqr(pT)*J)/C/Constants::twopi;
if(dipoles[i].interaction==ShowerInteraction::QCD)
weight[j] *= alphaS() ->ratio(pT*pT);
else
weight[j] *= alphaEM()->ratio(pT*pT);
}
// accept point if weight > R
if (weight[0] + weight[1] > UseRandom::rnd()) {
if (weight[0] > (weight[0] + weight[1])*UseRandom::rnd()) {
particleMomenta[1].setE( (mb_/2.)*xe [0]);
particleMomenta[1].setZ( (mb_/2.)*xe_z[0]);
particleMomenta[2].setE( (mb_/2.)*xs [0]);
particleMomenta[2].setZ(-(mb_/2.)*sqrt(sqr(xs[0])-4.*s2_));
}
else {
particleMomenta[1].setE( (mb_/2.)*xe [1]);
particleMomenta[1].setZ( (mb_/2.)*xe_z[1]);
particleMomenta[2].setE( (mb_/2.)*xs [1]);
particleMomenta[2].setZ(-(mb_/2.)*sqrt(sqr(xs[1])-4.*s2_));
}
pT_ = pT;
break;
}
// if there's no branching lower the pT
pTmax = pT;
}
return particleMomenta;
}
bool PerturbativeDecayer::calcMomenta(int j, Energy pT, double y, double phi,
double& xg, double& xs, double& xe, double& xe_z,
vector<Lorentz5Momentum>& particleMomenta){
// calculate xg
xg = 2.*pT*cosh(y) / mb_;
if (xg>(1. - sqr(e_ + s_)) || xg<0.) return false;
// calculate the two values of xs
double xT = 2.*pT / mb_;
double A = 4.-4.*xg+sqr(xT);
double B = 4.*(3.*xg-2.+2.*e2_-2.*s2_-sqr(xg)-xg*e2_+xg*s2_);
double L = 1.+sqr(s2_)+sqr(e2_)-2.*s2_-2.*e2_-2.*s2_*e2_;
double det = 16.*( -L*sqr(xT)+pow(xT,4)*s2_+2.*xg*sqr(xT)*(1.-s2_-e2_)+
L*sqr(xg)-sqr(xg*xT)*(1.+s2_)+pow(xg,4)+
2.*pow(xg,3)*(-1.+s2_+e2_) );
if (det<0.) return false;
if (j==0) xs = (-B+sqrt(det))/(2.*A);
if (j==1) xs = (-B-sqrt(det))/(2.*A);
// check value of xs is physical
if (xs>(1.+s2_-e2_) || xs<2.*s_) return false;
// calculate xe
xe = 2.-xs-xg;
// check value of xe is physical
if (xe>(1.+e2_-s2_) || xe<2.*e_) return false;
// calculate xe_z
double root1 = sqrt(max(0.,sqr(xs)-4.*s2_)), root2 = sqrt(max(0.,sqr(xe)-4.*e2_-sqr(xT)));
double epsilon_p = -root1+xT*sinh(y)+root2;
double epsilon_m = -root1+xT*sinh(y)-root2;
// find direction of emitter
if (fabs(epsilon_p) < 1.e-10) xe_z = sqrt(sqr(xe)-4.*e2_-sqr(xT));
else if (fabs(epsilon_m) < 1.e-10) xe_z = -sqrt(sqr(xe)-4.*e2_-sqr(xT));
else return false;
// check the emitter is on shell
if (fabs((sqr(xe)-sqr(xT)-sqr(xe_z)-4.*e2_))>1.e-10) return false;
// calculate 4 momenta
particleMomenta[0].setE ( mb_);
particleMomenta[0].setX ( ZERO);
particleMomenta[0].setY ( ZERO);
particleMomenta[0].setZ ( ZERO);
particleMomenta[0].setMass( mb_);
particleMomenta[1].setE ( mb_*xe/2.);
particleMomenta[1].setX (-pT*cos(phi));
particleMomenta[1].setY (-pT*sin(phi));
particleMomenta[1].setZ ( mb_*xe_z/2.);
particleMomenta[1].setMass( mb_*e_);
particleMomenta[2].setE ( mb_*xs/2.);
particleMomenta[2].setX ( ZERO);
particleMomenta[2].setY ( ZERO);
particleMomenta[2].setZ (-mb_*sqrt(sqr(xs)-4.*s2_)/2.);
particleMomenta[2].setMass( mb_*s_);
particleMomenta[3].setE ( pT*cosh(y));
particleMomenta[3].setX ( pT*cos(phi));
particleMomenta[3].setY ( pT*sin(phi));
particleMomenta[3].setZ ( pT*sinh(y));
particleMomenta[3].setMass( ZERO);
return true;
}
bool PerturbativeDecayer::psCheck(const double xg, const double xs) {
// check is point is in allowed region of phase space
double xe_star = (1.-s2_+e2_-xg)/sqrt(1.-xg);
double xg_star = xg/sqrt(1.-xg);
if ((sqr(xe_star)-4.*e2_) < 1e-10) return false;
double xs_max = (4.+4.*s2_-sqr(xe_star+xg_star)+
sqr(sqrt(sqr(xe_star)-4.*e2_)+xg_star))/ 4.;
double xs_min = (4.+4.*s2_-sqr(xe_star+xg_star)+
sqr(sqrt(sqr(xe_star)-4.*e2_)-xg_star))/ 4.;
if (xs < xs_min || xs > xs_max) return false;
return true;
}
InvEnergy2 PerturbativeDecayer::calculateDipole(const DipoleType & dipoleId,
const Particle & inpart,
const ParticleVector & decay3) {
// calculate dipole for decay b->ac
InvEnergy2 dipole = ZERO;
double x1 = 2.*decay3[0]->momentum().e()/mb_;
double x2 = 2.*decay3[1]->momentum().e()/mb_;
double xg = 2.*decay3[2]->momentum().e()/mb_;
double mu12 = sqr(decay3[0]->mass()/mb_);
double mu22 = sqr(decay3[1]->mass()/mb_);
tcPDPtr part[3] = {inpart.dataPtr(),decay3[0]->dataPtr(),decay3[1]->dataPtr()};
if(dipoleId.type==FFc || dipoleId.type == IFc || dipoleId.type == IFbc) {
swap(part[1],part[2]);
swap(x1,x2);
swap(mu12,mu22);
}
// radiation from b with initial-final connection
if (dipoleId.type==IFba || dipoleId.type==IFbc) {
dipole = -2./sqr(mb_*xg);
dipole *= colourCoeff(part[0],part[1],part[2],dipoleId);
}
// radiation from a/c with initial-final connection
else if (dipoleId.type==IFa || dipoleId.type==IFc) {
double z = 1. - xg/(1.-mu22+mu12);
dipole = (-2.*mu12/sqr(1.-x2+mu22-mu12)/sqr(mb_) + (1./(1.-x2+mu22-mu12)/sqr(mb_))*
(2./(1.-z)-dipoleSpinFactor(part[1],z)));
dipole *= colourCoeff(part[1],part[0],part[2],dipoleId);
}
// radiation from a/c with final-final connection
else if (dipoleId.type==FFa || dipoleId.type==FFc) {
double z = 1. + ((x1-1.+mu22-mu12)/(x2-2.*mu22));
double y = (1.-x2-mu12+mu22)/(1.-mu12-mu22);
double vt = sqrt((1.-sqr(e_+s_))*(1.-sqr(e_-s_)))/(1.-mu12-mu22);
double v = sqrt(sqr(2.*mu22+(1.-mu12-mu22)*(1.-y))-4.*mu22)
/(1.-y)/(1.-mu12-mu22);
if(part[1]->iSpin()!=PDT::Spin1) {
dipole = (1./(1.-x2+mu22-mu12)/sqr(mb_))*
((2./(1.-z*(1.-y)))-vt/v*(dipoleSpinFactor(part[1],z)+(2.*mu12/(1.+mu22-mu12-x2))));
}
else {
dipole = (1./(1.-x2+mu22-mu12)/sqr(mb_))*
(1./(1.-z*(1.-y))+1./(1.-(1.-z)*(1.-y))+(z*(1.-z)-2.)/v-vt/v*(2.*mu12/(1.+mu22-mu12-x2)));
}
dipole *= colourCoeff(part[1],part[2],part[0],dipoleId);
}
// coupling prefactors
dipole *= 8.*Constants::pi;
if(dipoleId.interaction==ShowerInteraction::QCD)
dipole *= alphaS() ->value(mb_*mb_);
else
dipole *= alphaEM()->value(mb_*mb_);
// return the answer
return dipole;
}
double PerturbativeDecayer::dipoleSpinFactor(tcPDPtr part, double z){
// calculate the spin dependent component of the dipole
if (part->iSpin()==PDT::Spin0)
return 2.;
else if (part->iSpin()==PDT::Spin1Half)
return (1. + z);
else if (part->iSpin()==PDT::Spin1)
return -(z*(1.-z) - 1./(1.-z) + 1./z -2.);
return 0.;
}
double PerturbativeDecayer::colourCoeff(tcPDPtr emitter,
tcPDPtr spectator,
tcPDPtr other,
DipoleType dipole) {
if(dipole.interaction==ShowerInteraction::QCD) {
// calculate the colour factor of the dipole
double numerator=1.;
double denominator=1.;
if (emitter->iColour()!=PDT::Colour0 &&
spectator->iColour()!=PDT::Colour0 &&
other->iColour()!=PDT::Colour0) {
if (emitter->iColour() ==PDT::Colour3 ||
emitter->iColour() ==PDT::Colour3bar) numerator=-4./3;
else if (emitter->iColour() ==PDT::Colour8) numerator=-3. ;
denominator=-1.*numerator;
if (spectator->iColour()==PDT::Colour3 ||
spectator->iColour()==PDT::Colour3bar) numerator-=4./3;
else if (spectator->iColour()==PDT::Colour8) numerator-=3. ;
if (other->iColour() ==PDT::Colour3 ||
other->iColour() ==PDT::Colour3bar) numerator+=4./3;
else if (other->iColour() ==PDT::Colour8) numerator+=3. ;
numerator*=(-1./2.);
}
if (emitter->iColour()==PDT::Colour3 ||
emitter->iColour()== PDT::Colour3bar) numerator*=4./3.;
else if (emitter->iColour()==PDT::Colour8 &&
spectator->iColour()!=PDT::Colour8) numerator*=3.;
else if (emitter->iColour()==PDT::Colour8 &&
spectator->iColour()==PDT::Colour8) numerator*=6.;
return (numerator/denominator);
}
else {
double val = double(emitter->iCharge()*spectator->iCharge())/9.;
// FF dipoles
if(dipole.type==FFa || dipole.type == FFc) {
return val;
}
else {
return -val;
}
}
}
void PerturbativeDecayer::getColourLines(RealEmissionProcessPtr real) {
// extract the particles
vector<PPtr> branchingPart;
branchingPart.push_back(real->incoming()[0]);
for(unsigned int ix=0;ix<real->outgoing().size();++ix) {
branchingPart.push_back(real->outgoing()[ix]);
}
vector<unsigned int> sing,trip,atrip,oct;
for (size_t ib=0;ib<branchingPart.size()-1;++ib) {
if (branchingPart[ib]->dataPtr()->iColour()==PDT::Colour0 ) sing. push_back(ib);
else if(branchingPart[ib]->dataPtr()->iColour()==PDT::Colour3 ) trip. push_back(ib);
else if(branchingPart[ib]->dataPtr()->iColour()==PDT::Colour3bar) atrip.push_back(ib);
else if(branchingPart[ib]->dataPtr()->iColour()==PDT::Colour8 ) oct. push_back(ib);
}
// decaying colour singlet
if (branchingPart[0]->dataPtr()->iColour()==PDT::Colour0) {
// 0 -> 3 3bar
if (trip.size()==1 && atrip.size()==1) {
if(real->interaction()==ShowerInteraction::QCD) {
branchingPart[atrip[0]]->colourConnect(branchingPart[ 3 ]);
branchingPart[ 3 ]->colourConnect(branchingPart[trip[0]]);
}
else {
branchingPart[atrip[0]]->colourConnect(branchingPart[trip[0]]);
}
}
// 0 -> 8 8
else if (oct.size()==2 ) {
if(real->interaction()==ShowerInteraction::QCD) {
bool col = UseRandom::rndbool();
branchingPart[oct[0]]->colourConnect(branchingPart[ 3 ],col);
branchingPart[ 3 ]->colourConnect(branchingPart[oct[1]],col);
branchingPart[oct[1]]->colourConnect(branchingPart[oct[0]],col);
}
else {
branchingPart[oct[0]]->colourConnect(branchingPart[oct[1]]);
branchingPart[oct[1]]->colourConnect(branchingPart[oct[0]]);
}
}
else
assert(real->interaction()==ShowerInteraction::QED);
}
// decaying colour triplet
else if (branchingPart[0]->dataPtr()->iColour()==PDT::Colour3 ){
// 3 -> 3 0
if (trip.size()==2 && sing.size()==1) {
if(real->interaction()==ShowerInteraction::QCD) {
branchingPart[3]->incomingColour(branchingPart[trip[0]]);
branchingPart[3]-> colourConnect(branchingPart[trip[1]]);
}
else {
branchingPart[trip[1]]->incomingColour(branchingPart[trip[0]]);
}
} // 3 -> 3 8
else if (trip.size()==2 && oct.size()==1) {
if(real->interaction()==ShowerInteraction::QCD) {
// 8 emit incoming partner
if(real->emitter()==oct[0]&&real->spectator()==0) {
branchingPart[ 3 ]->incomingColour(branchingPart[trip[0]]);
branchingPart[ 3 ]-> colourConnect(branchingPart[oct[0] ]);
branchingPart[oct[0]]-> colourConnect(branchingPart[trip[1]]);
}
// 8 emit final spectator or vice veras
else {
branchingPart[oct[0]]->incomingColour(branchingPart[trip[0]]);
branchingPart[oct[0]]-> colourConnect(branchingPart[ 3 ]);
branchingPart[ 3 ]-> colourConnect(branchingPart[trip[1]]);
}
}
else {
branchingPart[oct[0]]->incomingColour(branchingPart[trip[0]]);
branchingPart[oct[0]]-> colourConnect(branchingPart[trip[1]]);
}
}
else
assert(false);
}
// decaying colour anti-triplet
else if (branchingPart[0]->dataPtr()->iColour()==PDT::Colour3bar) {
// 3bar -> 3bar 0
if (atrip.size()==2 && sing.size()==1) {
if(real->interaction()==ShowerInteraction::QCD) {
branchingPart[3]->incomingColour(branchingPart[atrip[0]],true);
branchingPart[3]-> colourConnect(branchingPart[atrip[1]],true);
}
else {
branchingPart[atrip[1]]->incomingColour(branchingPart[atrip[0]],true);
}
}
// 3 -> 3 8
else if (atrip.size()==2 && oct.size()==1){
if(real->interaction()==ShowerInteraction::QCD) {
// 8 emit incoming partner
if(real->emitter()==oct[0]&&real->spectator()==0) {
branchingPart[ 3 ]->incomingColour(branchingPart[atrip[0]],true);
branchingPart[ 3 ]-> colourConnect(branchingPart[oct[0] ],true);
branchingPart[oct[0]]-> colourConnect(branchingPart[atrip[1]],true);
}
// 8 emit final spectator or vice veras
else {
if(real->interaction()==ShowerInteraction::QCD) {
branchingPart[oct[0]]->incomingColour(branchingPart[atrip[0]],true);
branchingPart[oct[0]]-> colourConnect(branchingPart[ 3 ],true);
branchingPart[3]-> colourConnect(branchingPart[atrip[1]] ,true);
}
}
}
else {
branchingPart[oct[0]]->incomingColour(branchingPart[atrip[0]],true);
branchingPart[oct[0]]-> colourConnect(branchingPart[atrip[1]],true);
}
}
else
assert(false);
}
// decaying colour octet
else if(branchingPart[0]->dataPtr()->iColour()==PDT::Colour8 ) {
// 8 -> 3 3bar
if (trip.size()==1 && atrip.size()==1) {
if(real->interaction()==ShowerInteraction::QCD) {
// 3 emits
if(trip[0]==real->emitter()) {
branchingPart[3] ->incomingColour(branchingPart[oct[0]] );
branchingPart[3] -> colourConnect(branchingPart[trip[0]]);
branchingPart[atrip[0]]->incomingColour(branchingPart[oct[0]],true);
}
// 3bar emits
else {
branchingPart[3] ->incomingColour(branchingPart[oct[0]] ,true);
branchingPart[3] -> colourConnect(branchingPart[atrip[0]],true);
branchingPart[trip[0]]->incomingColour(branchingPart[oct[0]] );
}
}
else {
branchingPart[trip[0]]->incomingColour(branchingPart[oct[0]] );
branchingPart[atrip[0]]->incomingColour(branchingPart[oct[0]],true);
}
}
// 8 -> 8 0
else if (sing.size()==1 && oct.size()==2) {
if(real->interaction()==ShowerInteraction::QCD) {
bool col = UseRandom::rndbool();
branchingPart[ 3 ]->colourConnect (branchingPart[oct[1]], col);
branchingPart[ 3 ]->incomingColour(branchingPart[oct[0]], col);
branchingPart[oct[1]]->incomingColour(branchingPart[oct[0]],!col);
}
else {
branchingPart[oct[1]]->incomingColour(branchingPart[oct[0]]);
branchingPart[oct[1]]->incomingColour(branchingPart[oct[0]],true);
}
}
else
assert(false);
}
}
PerturbativeDecayer::phaseSpaceRegion
PerturbativeDecayer::inInitialFinalDeadZone(double xg, double xa,
double a, double c) const {
double lam = sqrt(1.+a*a+c*c-2.*a-2.*c-2.*a*c);
double kappab = 1.+0.5*(1.-a+c+lam);
double kappac = kappab-1.+c;
double kappa(0.);
// check whether or not in the region for emission from c
double r = 0.5;
if(c!=0.) r += 0.5*c/(1.+a-xa);
double pa = sqrt(sqr(xa)-4.*a);
double z = ((2.-xa)*(1.-r)+r*pa-xg)/pa;
if(z<1. && z>0.) {
kappa = (1.+a-c-xa)/(z*(1.-z));
if(kappa<kappac)
return emissionFromC;
}
// check in region for emission from b (T1)
double cq = sqr(1.+a-c)-4*a;
double bq = -2.*kappab*(1.-a-c);
double aq = sqr(kappab)-4.*a*(kappab-1);
double dis = sqr(bq)-4.*aq*cq;
z=1.-(-bq-sqrt(dis))/2./aq;
double w = 1.-(1.-z)*(kappab-1.);
double xgmax = (1.-z)*kappab;
// possibly in T1 region
if(xg<xgmax) {
z = 1.-xg/kappab;
kappa=kappab;
}
// possibly in T2 region
else {
aq = 4.*a;
bq = -4.*a*(2.-xg);
cq = sqr(1.+a-c-xg);
dis = sqr(bq)-4.*aq*cq;
z = (-bq-sqrt(dis))/2./aq;
kappa = xg/(1.-z);
}
// compute limit on xa
double u = 1.+a-c-(1.-z)*kappa;
w = 1.-(1.-z)*(kappa-1.);
double v = sqr(u)-4.*z*a*w;
if(v<0. && v>-1e-10) v= 0.;
v = sqrt(v);
if(xa<0.5*((u+v)/w+(u-v)/z))
return xg<xgmax ? emissionFromA1 : emissionFromA2;
else
return deadZone;
}
PerturbativeDecayer::phaseSpaceRegion
PerturbativeDecayer::inFinalFinalDeadZone(double xb, double xc,
double b, double c) const {
// basic kinematics
double lam = sqrt(1.+b*b+c*c-2.*b-2.*c-2.*b*c);
// check whether or not in the region for emission from b
double r = 0.5;
if(b!=0.) r+=0.5*b/(1.+c-xc);
double pc = sqrt(sqr(xc)-4.*c);
double z = -((2.-xc)*r-r*pc-xb)/pc;
if(z<1. and z>0.) {
if((1.-b+c-xc)/(z*(1.-z))<0.5*(1.+b-c+lam)) return emissionFromB;
}
// check whether or not in the region for emission from c
r = 0.5;
if(c!=0.) r+=0.5*c/(1.+b-xb);
double pb = sqrt(sqr(xb)-4.*b);
z = -((2.-xb)*r-r*pb-xc)/pb;
if(z<1. and z>0.) {
if((1.-c+b-xb)/(z*(1.-z))<0.5*(1.-b+c+lam)) return emissionFromC;
}
return deadZone;
}
bool PerturbativeDecayer::inTotalDeadZone(double xg, double xs,
const vector<DipoleType> & dipoles,
int i) {
double xb,xc,b,c;
if(dipoles[i].type==FFa || dipoles[i].type == IFa || dipoles[i].type == IFba) {
xc = xs;
xb = 2.-xg-xs;
b = e2_;
c = s2_;
}
else {
xb = xs;
xc = 2.-xg-xs;
b = s2_;
c = e2_;
}
for(unsigned int ix=0;ix<dipoles.size();++ix) {
if(dipoles[ix].interaction!=dipoles[i].interaction)
continue;
// should also remove negative QED dipoles but shouldn't be an issue unless we
// support QED ME corrections
switch (dipoles[ix].type) {
case FFa :
if(inFinalFinalDeadZone(xb,xc,b,c)!=deadZone) return false;
break;
case FFc :
if(inFinalFinalDeadZone(xc,xb,c,b)!=deadZone) return false;
break;
case IFa : case IFba:
if(inInitialFinalDeadZone(xg,xc,c,b)!=deadZone) return false;
break;
case IFc : case IFbc:
if(inInitialFinalDeadZone(xg,xb,b,c)!=deadZone) return false;
break;
}
}
return true;
}
diff --git a/Decay/PerturbativeDecayer.h b/Decay/PerturbativeDecayer.h
--- a/Decay/PerturbativeDecayer.h
+++ b/Decay/PerturbativeDecayer.h
@@ -1,315 +1,309 @@
// -*- C++ -*-
#ifndef Herwig_PerturbativeDecayer_H
#define Herwig_PerturbativeDecayer_H
//
// This is the declaration of the PerturbativeDecayer class.
//
#include "Herwig/Decay/DecayIntegrator.h"
#include "Herwig/Shower/Core/Couplings/ShowerAlpha.h"
#include "Herwig/Shower/Core/ShowerInteraction.h"
namespace Herwig {
using namespace ThePEG;
/**
* The PerturbativeDecayer class is the base class for perturbative decays in
* Herwig and implements the functuality for the POWHEG corrections
*
* @see \ref PerturbativeDecayerInterfaces "The interfaces"
* defined for PerturbativeDecayer.
*/
class PerturbativeDecayer: public DecayIntegrator {
protected:
/**
* Type of dipole
*/
enum dipoleType {FFa, FFc, IFa, IFc, IFba, IFbc};
/**
* Phase-space region for an emission (assumes \f$a\to b,c\f$
*/
enum phaseSpaceRegion {emissionFromB,emissionFromC,emissionFromA1,emissionFromA2,deadZone};
/**
* Type of dipole
*/
struct DipoleType {
DipoleType() {}
DipoleType(dipoleType a, ShowerInteraction b)
: type(a), interaction(b)
{}
dipoleType type;
ShowerInteraction interaction;
};
public:
/**
* The default constructor.
*/
PerturbativeDecayer() : inter_(ShowerInteraction::QCD),
pTmin_(GeV), pT_(ZERO), mb_(ZERO),
e_(0.), s_(0.), e2_(0.), s2_(0.)
{}
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {return No;}
/**
* Member to generate the hardest emission in the POWHEG scheme
*/
virtual RealEmissionProcessPtr generateHardest(RealEmissionProcessPtr);
/**
* Apply the hard matrix element correction to a given hard process or decay
*/
virtual RealEmissionProcessPtr applyHardMatrixElementCorrection(RealEmissionProcessPtr);
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:
/**
- * Three-body matrix element including additional QCD radiation
- */
- virtual double threeBodyME(const int , const Particle & inpart,
- const ParticleVector & decay, MEOption meopt);
-
- /**
* Calculate matrix element ratio \f$\frac{M^2}{\alpha_S}\frac{|\overline{\rm{ME}}_3|}{|\overline{\rm{ME}}_2|}\f$
*/
virtual double matrixElementRatio(const Particle & inpart, const ParticleVector & decay2,
const ParticleVector & decay3, MEOption meopt,
ShowerInteraction inter);
/**
* Work out the type of process
*/
bool identifyDipoles(vector<DipoleType> & dipoles,
PPtr & aProgenitor,
PPtr & bProgenitor,
PPtr & cProgenitor,
ShowerInteraction inter) const;
/**
* Coupling for the generation of hard QCD radiation
*/
ShowerAlphaPtr alphaS() {return alphaS_;}
/**
* Coupling for the generation of hard QED radiation
*/
ShowerAlphaPtr alphaEM() {return alphaEM_;}
/**
* Return the momenta including the hard emission
*/
vector<Lorentz5Momentum> hardMomenta(PPtr in, PPtr emitter,
PPtr spectator,
const vector<DipoleType> & dipoles,
int i, bool inDeadZone);
/**
* 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 dipole corresponding to the DipoleType dipoleId
*/
InvEnergy2 calculateDipole(const DipoleType & dipoleId, const Particle & inpart,
const ParticleVector & decay3);
/**
* Return contribution to dipole that depends on the spin of the emitter
*/
double dipoleSpinFactor(tcPDPtr emitter, double z);
/**
* Return the colour coefficient of the dipole
*/
double colourCoeff(tcPDPtr emitter, tcPDPtr spectator,
tcPDPtr other, DipoleType dipole);
/**
* Set up the colour lines
*/
void getColourLines(RealEmissionProcessPtr real);
/**
* Generate a hard emission
*/
RealEmissionProcessPtr getHardEvent(RealEmissionProcessPtr born,
bool inDeadZone,
ShowerInteraction inter);
/**
* Is the \f$x_g,x_s\f$ point in the dead-zone for all the dipoles
*/
bool inTotalDeadZone(double xg, double xs,
const vector<DipoleType> & dipoles,
int i);
/**
* Is the \f$x_g,x_a\f$ point in the dead-zone for an initial-final colour connection
*/
phaseSpaceRegion inInitialFinalDeadZone(double xg, double xa, double a, double c) const;
/**
* Is the \f$x_b,x_c\f$ point in the dead-zone for a final-final colour connection
*/
phaseSpaceRegion inFinalFinalDeadZone(double xb, double xc, double b, double c) const;
protected:
/**
* Access to the kinematics for inheriting classes
*/
//@{
/**
* Transverse momentum of the emission
*/
const Energy & pT() const { return pT_;}
/**
* Mass of decaying particle
*/
const Energy & mb() const {return mb_;}
/**
* Reduced mass of emitter child particle
*/
const double & e() const {return e_;}
/**
* Reduced mass of spectator child particle
*/
const double & s() const {return s_;}
/**
* Reduced mass of emitter child particle squared
*/
const double & e2() const {return e2_;}
/**
* Reduced mass of spectator child particle squared
*/
const double & s2() const {return s2_;}
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
PerturbativeDecayer & operator=(const PerturbativeDecayer &);
private:
/**
* Members for the generation of the hard radiation
*/
//@{
/**
* Which types of radiation to generate
*/
ShowerInteraction inter_;
/**
* Coupling for the generation of hard QCD radiation
*/
ShowerAlphaPtr alphaS_;
/**
* Coupling for the generation of hard QED radiation
*/
ShowerAlphaPtr alphaEM_;
/**
* Minimum \f$p_T\f$
*/
Energy pTmin_;
//@}
private:
/**
* Mmeber variables for the kinematics of the hard emission
*/
//@{
/**
* Transverse momentum of the emission
*/
Energy pT_;
/**
* 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_;
//@}
};
}
#endif /* Herwig_PerturbativeDecayer_H */
diff --git a/Models/General/TwoBodyDecayConstructor.cc b/Models/General/TwoBodyDecayConstructor.cc
--- a/Models/General/TwoBodyDecayConstructor.cc
+++ b/Models/General/TwoBodyDecayConstructor.cc
@@ -1,371 +1,377 @@
// -*- C++ -*-
//
// TwoBodyDecayConstructor.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the TwoBodyDecayConstructor class.
//
#include "TwoBodyDecayConstructor.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "Herwig/Decay/General/GeneralTwoBodyDecayer.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "DecayConstructor.h"
#include "ThePEG/Utilities/Throw.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.fh"
#include "ThePEG/Helicity/Vertex/AbstractFFSVertex.fh"
#include "ThePEG/Helicity/Vertex/AbstractVVSVertex.fh"
#include "ThePEG/Helicity/Vertex/AbstractVSSVertex.fh"
#include "ThePEG/Helicity/Vertex/AbstractVVTVertex.fh"
#include "ThePEG/Helicity/Vertex/AbstractFFTVertex.fh"
#include "ThePEG/Helicity/Vertex/AbstractSSTVertex.fh"
#include "ThePEG/Helicity/Vertex/AbstractSSSVertex.fh"
#include "ThePEG/Helicity/Vertex/AbstractVVVVertex.fh"
#include "ThePEG/Helicity/Vertex/AbstractRFSVertex.fh"
#include "ThePEG/Helicity/Vertex/AbstractRFVVertex.fh"
using namespace Herwig;
using ThePEG::Helicity::VertexBasePtr;
IBPtr TwoBodyDecayConstructor::clone() const {
return new_ptr(*this);
}
IBPtr TwoBodyDecayConstructor::fullclone() const {
return new_ptr(*this);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeNoPIOClass<TwoBodyDecayConstructor,NBodyDecayConstructorBase>
describeHerwigTwoBodyDecayConstructor("Herwig::TwoBodyDecayConstructor", "Herwig.so");
void TwoBodyDecayConstructor::Init() {
static ClassDocumentation<TwoBodyDecayConstructor> documentation
("The TwoBodyDecayConstructor implements to creation of 2 body decaymodes "
"and decayers that do not already exist for the given set of vertices.");
}
void TwoBodyDecayConstructor::DecayList(const set<PDPtr> & particles) {
if( particles.empty() ) return;
tHwSMPtr model = dynamic_ptr_cast<tHwSMPtr>(generator()->standardModel());
unsigned int nv(model->numberOfVertices());
for(set<PDPtr>::const_iterator ip=particles.begin();
ip!=particles.end();++ip) {
tPDPtr parent = *ip;
if ( Debug::level > 0 )
Repository::cout() << "Constructing 2-body decays for "
<< parent->PDGName() << '\n';
for(unsigned int iv = 0; iv < nv; ++iv) {
if(excluded(model->vertex(iv)) ||
model->vertex(iv)->getNpoint()>3) continue;
for(unsigned int il = 0; il < 3; ++il) {
set<TwoBodyDecay> decays =
createModes(parent, model->vertex(iv), il);
if( !decays.empty() ) createDecayMode(decays);
}
}
}
}
set<TwoBodyDecay> TwoBodyDecayConstructor::
createModes(tPDPtr inpart, VertexBasePtr vertex,
unsigned int list) {
if( !vertex->isIncoming(inpart) || vertex->getNpoint() != 3 )
return set<TwoBodyDecay>();
Energy m1(inpart->mass());
tPDPtr ccpart = inpart->CC() ? inpart->CC() : inpart;
long id = ccpart->id();
tPDVector decaylist = vertex->search(list, ccpart);
set<TwoBodyDecay> decays;
tPDVector::size_type nd = decaylist.size();
for( tPDVector::size_type i = 0; i < nd; i += 3 ) {
tPDPtr pa(decaylist[i]), pb(decaylist[i + 1]), pc(decaylist[i + 2]);
if( pb->id() == id ) swap(pa, pb);
if( pc->id() == id ) swap(pa, pc);
//allowed on-shell decay?
if( m1 <= pb->mass() + pc->mass() ) continue;
//vertices are defined with all particles incoming
decays.insert( TwoBodyDecay(inpart,pb, pc, vertex) );
}
return decays;
}
GeneralTwoBodyDecayerPtr TwoBodyDecayConstructor::createDecayer(TwoBodyDecay decay) {
string name;
using namespace Helicity::VertexType;
PDT::Spin in = decay.parent_->iSpin();
// PDT::Spin out1 = decay.children_.first ->iSpin();
PDT::Spin out2 = decay.children_.second->iSpin();
switch(decay.vertex_->getName()) {
case FFV :
if(in == PDT::Spin1Half) {
name = "FFVDecayer";
if(out2==PDT::Spin1Half)
swap(decay.children_.first,decay.children_.second);
}
else {
name = "VFFDecayer";
}
break;
case FFS :
if(in == PDT::Spin1Half) {
name = "FFSDecayer";
if(out2==PDT::Spin1Half)
swap(decay.children_.first,decay.children_.second);
}
else {
name = "SFFDecayer";
}
break;
case VVS :
if(in == PDT::Spin1) {
name = "VVSDecayer";
if(out2==PDT::Spin1)
swap(decay.children_.first,decay.children_.second);
}
else {
name = "SVVDecayer";
}
break;
case VSS :
if(in == PDT::Spin1) {
name = "VSSDecayer";
}
else {
name = "SSVDecayer";
if(out2==PDT::Spin0)
swap(decay.children_.first,decay.children_.second);
}
break;
case VVT :
name = in==PDT::Spin2 ? "TVVDecayer" : "Unknown";
break;
case FFT :
name = in==PDT::Spin2 ? "TFFDecayer" : "Unknown";
break;
case SST :
name = in==PDT::Spin2 ? "TSSDecayer" : "Unknown";
break;
case SSS :
name = "SSSDecayer";
break;
case VVV :
name = "VVVDecayer";
break;
case RFS :
if(in==PDT::Spin1Half) {
name = "FRSDecayer";
if(out2==PDT::Spin3Half)
swap(decay.children_.first,decay.children_.second);
}
else if(in==PDT::Spin0) {
name = "SRFDecayer";
if(out2==PDT::Spin3Half)
swap(decay.children_.first,decay.children_.second);
}
else {
name = "Unknown";
}
break;
case RFV :
if(in==PDT::Spin1Half) {
name = "FRVDecayer";
if(out2==PDT::Spin3Half)
swap(decay.children_.first,decay.children_.second);
}
else
name = "Unknown";
break;
default : Throw<NBodyDecayConstructorError>()
<< "Error: Cannot assign " << decay.vertex_->fullName() << " to a decayer. "
<< "Decay is " << decay.parent_->PDGName() << " -> "
<< decay.children_.first ->PDGName() << " "
<< decay.children_.second->PDGName() << Exception::runerror;
}
if(name=="Unknown")
Throw<NBodyDecayConstructorError>()
<< "Error: Cannot assign " << decay.vertex_->fullName() << " to a decayer. "
<< "Decay is " << decay.parent_->PDGName() << " -> "
<< decay.children_.first ->PDGName() << " "
<< decay.children_.second->PDGName() << Exception::runerror;
ostringstream fullname;
fullname << "/Herwig/Decays/" << name << "_" << decay.parent_->PDGName()
<< "_" << decay.children_.first ->PDGName()
<< "_" << decay.children_.second->PDGName();
string classname = "Herwig::" + name;
GeneralTwoBodyDecayerPtr decayer;
decayer = dynamic_ptr_cast<GeneralTwoBodyDecayerPtr>
(generator()->preinitCreate(classname,fullname.str()));
if(!decayer)
Throw<NBodyDecayConstructorError>()
<< "Error: Cannot assign " << decay.vertex_->fullName() << " to a decayer. "
<< "Decay is " << decay.parent_->PDGName() << " -> "
<< decay.children_.first ->PDGName() << " "
<< decay.children_.second->PDGName() << Exception::runerror;
// set the strong coupling for radiation
generator()->preinitInterface(decayer, "AlphaS", "set", showerAlpha_);
// get the vertices for radiation from the external legs
- VertexBasePtr inRad = radiationVertex(decay.parent_);
- vector<VertexBasePtr> outRad;
- outRad.push_back(radiationVertex(decay.children_.first ));
- outRad.push_back(radiationVertex(decay.children_.second));
- // get any contributing 4 point vertices
- VertexBasePtr fourRad = radiationVertex(decay.parent_, decay.children_);
+ map<ShowerInteraction,VertexBasePtr> inRad,fourRad;
+ vector<map<ShowerInteraction,VertexBasePtr> > outRad(2);
+ vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
+ for(auto & inter : itemp) {
+ inRad[inter] = radiationVertex(decay.parent_,inter);
+ outRad[0][inter] = radiationVertex(decay.children_.first ,inter);
+ outRad[1][inter] = radiationVertex(decay.children_.second,inter);
+ // get any contributing 4 point vertices
+ fourRad[inter] = radiationVertex(decay.parent_,inter, decay.children_);
+ }
// set info on decay
decayer->setDecayInfo(decay.parent_,decay.children_,decay.vertex_,
inRad,outRad,fourRad);
// initialised the decayer
setDecayerInterfaces(fullname.str());
decayer->init();
return decayer;
}
void TwoBodyDecayConstructor::
createDecayMode(set<TwoBodyDecay> & decays) {
tPDPtr inpart = decays.begin()->parent_;
set<TwoBodyDecay>::iterator dend = decays.end();
for( set<TwoBodyDecay>::iterator dit = decays.begin();
dit != dend; ++dit ) {
tPDPtr pb((*dit).children_.first), pc((*dit).children_.second);
string tag = inpart->name() + "->" + pb->name() + "," +
pc->name() + ";";
// Does it exist already ?
tDMPtr dm = generator()->findDecayMode(tag);
// now create DecayMode objects that do not already exist
if( createDecayModes() && (!dm || inpart->id() == ParticleID::h0) ) {
tDMPtr ndm = generator()->preinitCreateDecayMode(tag);
if(ndm) {
inpart->stable(false);
GeneralTwoBodyDecayerPtr decayer=createDecayer(*dit);
if(!decayer) continue;
generator()->preinitInterface(ndm, "Decayer", "set",
decayer->fullName());
generator()->preinitInterface(ndm, "Active", "set", "Yes");
Energy width =
decayer->partialWidth(make_pair(inpart,inpart->mass()),
make_pair(pb,pb->mass()) ,
make_pair(pc,pc->mass()));
setBranchingRatio(ndm, width);
if(width==ZERO || ndm->brat()<decayConstructor()->minimumBR()) {
generator()->preinitInterface(decayer->fullName(),
"Initialize", "set","0");
}
}
else
Throw<NBodyDecayConstructorError>()
<< "TwoBodyDecayConstructor::createDecayMode - Needed to create "
<< "new decaymode but one could not be created for the tag "
<< tag << Exception::warning;
}
else if( dm ) {
if(dm->brat()<decayConstructor()->minimumBR()) {
continue;
}
if((dm->decayer()->fullName()).find("Mambo") != string::npos) {
inpart->stable(false);
GeneralTwoBodyDecayerPtr decayer=createDecayer(*dit);
if(!decayer) continue;
generator()->preinitInterface(dm, "Decayer", "set",
decayer->fullName());
Energy width =
decayer->partialWidth(make_pair(inpart,inpart->mass()),
make_pair(pb,pb->mass()) ,
make_pair(pc,pc->mass()));
if(width/(dm->brat()*inpart->width())<1e-10) {
string message = "Herwig calculation of the partial width for the decay mode "
+ inpart->PDGName() + " -> " + pb->PDGName() + " " + pc->PDGName()
+ " is zero.\n This will cause problems with the calculation of"
+ " spin correlations.\n It is probably due to inconsistent parameters"
+ " and decay modes being passed to Herwig via the SLHA file.\n"
+ " Zeroing the branching ratio for this mode.";
setBranchingRatio(dm,ZERO);
generator()->logWarning(NBodyDecayConstructorError(message,Exception::warning));
}
}
}
}
// update CC mode if it exists
if( inpart->CC() ) inpart->CC()->synchronize();
}
-VertexBasePtr TwoBodyDecayConstructor::radiationVertex(tPDPtr particle, tPDPair children) {
+VertexBasePtr TwoBodyDecayConstructor::radiationVertex(tPDPtr particle,
+ ShowerInteraction inter,
+ tPDPair children) {
tHwSMPtr model = dynamic_ptr_cast<tHwSMPtr>(generator()->standardModel());
map<tPDPtr,VertexBasePtr>::iterator rit = radiationVertices_.find(particle);
tPDPtr cc = particle->CC() ? particle->CC() : particle;
if(children==tPDPair() && rit!=radiationVertices_.end()) return rit->second;
unsigned int nv(model->numberOfVertices());
- tPDPtr gluon = getParticleData(ParticleID::g);
+ tPDPtr gluon = getParticleData(inter==ShowerInteraction::QCD ? ParticleID::g : ParticleID::gamma);
// look for radiation vertices for incoming and outgoing particles
for(unsigned int iv=0;iv<nv;++iv) {
VertexBasePtr vertex = model->vertex(iv);
// look for 3 point vertices
if (children==tPDPair()){
if( !vertex->isIncoming(particle) || vertex->getNpoint() != 3 ||
!vertex->isOutgoing(particle) || !vertex->isOutgoing(gluon)) continue;
for(unsigned int list=0;list<3;++list) {
tPDVector decaylist = vertex->search(list, particle);
for( tPDVector::size_type i = 0; i < decaylist.size(); i += 3 ) {
tPDPtr pa(decaylist[i]), pb(decaylist[i + 1]), pc(decaylist[i + 2]);
if( pb->id() == ParticleID::g ) swap(pa, pb);
if( pc->id() == ParticleID::g ) swap(pa, pc);
if( pb->id() != particle->id()) swap(pb, pc);
if( pa->id() != ParticleID::g) continue;
if( pb != particle) continue;
if( pc != cc) continue;
radiationVertices_[particle] = vertex;
return vertex;
}
}
}
// look for 4 point vertex including a gluon
else {
if( !vertex->isIncoming(particle) || vertex->getNpoint()!=4 ||
!vertex->isOutgoing(children.first) || !vertex->isOutgoing(children.second) ||
!vertex->isOutgoing(gluon)) continue;
for(unsigned int list=0;list<4;++list) {
tPDVector decaylist = vertex->search(list, particle);
for( tPDVector::size_type i = 0; i < decaylist.size(); i += 4 ) {
tPDPtr pa(decaylist[i]), pb(decaylist[i+1]), pc(decaylist[i+2]), pd(decaylist[i+3]);
// order so that a = g, b = parent
if( pb->id() == ParticleID::g ) swap(pa, pb);
if( pc->id() == ParticleID::g ) swap(pa, pc);
if( pd->id() == ParticleID::g ) swap(pa, pd);
if( pc->id() == particle->id()) swap(pb, pc);
if( pd->id() == particle->id()) swap(pb, pd);
if( pa->id() != ParticleID::g) continue;
if( pb->id() != particle->id()) continue;
if( !((abs(pd->id()) == abs(children. first->id()) &&
abs(pc->id()) == abs(children.second->id())) ||
(abs(pc->id()) == abs(children. first->id()) &&
abs(pd->id()) == abs(children.second->id()))))
continue;
return vertex;
}
}
}
}
return VertexBasePtr();
}
diff --git a/Models/General/TwoBodyDecayConstructor.h b/Models/General/TwoBodyDecayConstructor.h
--- a/Models/General/TwoBodyDecayConstructor.h
+++ b/Models/General/TwoBodyDecayConstructor.h
@@ -1,143 +1,144 @@
// -*- C++ -*-
//
// TwoBodyDecayConstructor.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_TwoBodyDecayConstructor_H
#define HERWIG_TwoBodyDecayConstructor_H
//
// This is the declaration of the TwoBodyDecayConstructor class.
//
#include "NBodyDecayConstructorBase.h"
#include "ThePEG/Helicity/Vertex/VertexBase.h"
#include "Herwig/Decay/General/GeneralTwoBodyDecayer.fh"
#include "TwoBodyDecay.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::VertexBasePtr;
using Helicity::tVertexBasePtr;
/**
* The TwoBodyDecayConstructor class inherits from the dummy base class
* NBodyDecayConstructorBase and implements the necessary functions in
* order to create the 2 body decay modes for a given set of vertices
* stored in a Model class.
*
* @see \ref TwoBodyDecayConstructorInterfaces "The interfaces"
* defined for TwoBodyDecayConstructor.
* @see NBodyDecayConstructor
**/
class TwoBodyDecayConstructor: public NBodyDecayConstructorBase {
public:
/**
* The default constructor.
*/
TwoBodyDecayConstructor() : showerAlpha_("/Herwig/Shower/AlphaQCD") {}
/**
* Function used to determine allowed decaymodes
*@param part vector of ParticleData pointers containing particles in model
*/
virtual void DecayList(const set<PDPtr> & part);
/**
* Number of outgoing lines. Required for correct ordering.
*/
virtual unsigned int numBodies() const { return 2; }
public:
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
TwoBodyDecayConstructor & operator=(const TwoBodyDecayConstructor &);
private:
/** @name Functions to create decayers and decaymodes. */
//@{
/**
* Function to create decays
* @param inpart Incoming particle
* @param vert The vertex to create decays for
* @param ilist Which list to search
* @param iv Row number in _theExistingDecayers member
* @return A vector a decay modes
*/
set<TwoBodyDecay> createModes(tPDPtr inpart, VertexBasePtr vert,
unsigned int ilist);
/**
* Function to create decayer for specific vertex
* @param decay decay mode for this decay
* member variable
*/
GeneralTwoBodyDecayerPtr createDecayer(TwoBodyDecay decay);
/**
* Create decay mode(s) from given part and decay modes
* @param decays The vector of decay modes
* @param decayer The decayer responsible for this decay
*/
void createDecayMode(set<TwoBodyDecay> & decays);
//@}
/**
* Get the vertex for QCD radiation
*/
- VertexBasePtr radiationVertex(tPDPtr particle,tPDPair children = tPDPair ());
+ VertexBasePtr radiationVertex(tPDPtr particle,ShowerInteraction inter,
+ tPDPair children = tPDPair ());
private:
/**
* Map of particles and the vertices which generate their QCD
* radiation
*/
map<tPDPtr,VertexBasePtr> radiationVertices_;
/**
* Default choice for the strong coupling object for hard radiation
*/
string showerAlpha_;
};
}
#endif /* HERWIG_TwoBodyDecayConstructor_H */

File Metadata

Mime Type
text/x-diff
Expires
Mon, Jan 20, 9:04 PM (1 d, 1 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4242375
Default Alt Text
(393 KB)

Event Timeline