Page MenuHomeHEPForge

No OneTemporary

diff --git a/Decay/General/FtoFFFDecayer.cc b/Decay/General/FtoFFFDecayer.cc
--- a/Decay/General/FtoFFFDecayer.cc
+++ b/Decay/General/FtoFFFDecayer.cc
@@ -1,311 +1,313 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FtoFFFDecayer class.
//
#include "FtoFFFDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Decay/DecayPhaseSpaceMode.h"
#include "Herwig/PDT/ThreeBodyAllOnCalculator.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
#include <numeric>
using namespace Herwig;
IBPtr FtoFFFDecayer::clone() const {
return new_ptr(*this);
}
IBPtr FtoFFFDecayer::fullclone() const {
return new_ptr(*this);
}
void FtoFFFDecayer::persistentOutput(PersistentOStream & os) const {
os << sca_ << vec_ << ten_;
}
void FtoFFFDecayer::persistentInput(PersistentIStream & is, int) {
is >> sca_ >> vec_ >> ten_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<FtoFFFDecayer,GeneralThreeBodyDecayer>
describeHerwigFtoFFFDecayer("Herwig::FtoFFFDecayer", "Herwig.so");
void FtoFFFDecayer::Init() {
static ClassDocumentation<FtoFFFDecayer> documentation
("The FtoFFFDecayer class implements the general decay of a fermion to "
"three fermions.");
}
void FtoFFFDecayer::doinit() {
GeneralThreeBodyDecayer::doinit();
if(outgoing().empty()) return;
unsigned int ndiags = getProcessInfo().size();
sca_.resize(ndiags);
vec_.resize(ndiags);
ten_.resize(ndiags);
for(unsigned int ix = 0;ix < ndiags; ++ix) {
TBDiagram current = getProcessInfo()[ix];
tcPDPtr offshell = current.intermediate;
if( offshell->CC() ) offshell = offshell->CC();
if(offshell->iSpin() == PDT::Spin0) {
AbstractFFSVertexPtr vert1 = dynamic_ptr_cast<AbstractFFSVertexPtr>
(current.vertices.first);
AbstractFFSVertexPtr vert2 = dynamic_ptr_cast<AbstractFFSVertexPtr>
(current.vertices.second);
if(!vert1||!vert2) throw Exception()
<< "Invalid vertices for a scalar diagram in FtoFFFDecayer::doinit()"
<< Exception::runerror;
sca_[ix] = make_pair(vert1, vert2);
}
else if(offshell->iSpin() == PDT::Spin1) {
AbstractFFVVertexPtr vert1 = dynamic_ptr_cast<AbstractFFVVertexPtr>
(current.vertices.first);
AbstractFFVVertexPtr vert2 = dynamic_ptr_cast<AbstractFFVVertexPtr>
(current.vertices.second);
if(!vert1||!vert2) throw Exception()
<< "Invalid vertices for a vector diagram in FtoFFFDecayer::doinit()"
<< Exception::runerror;
vec_[ix] = make_pair(vert1, vert2);
}
else if(offshell->iSpin() == PDT::Spin2) {
AbstractFFTVertexPtr vert1 = dynamic_ptr_cast<AbstractFFTVertexPtr>
(current.vertices.first);
AbstractFFTVertexPtr vert2 = dynamic_ptr_cast<AbstractFFTVertexPtr>
(current.vertices.second);
if(!vert1||!vert2) throw Exception()
<< "Invalid vertices for a tensor diagram in FtoFFFDecayer::doinit()"
<< Exception::runerror;
ten_[ix] = make_pair(vert1, vert2);
}
}
}
-double FtoFFFDecayer::me2(const int ichan, const Particle & inpart,
- const ParticleVector & decay,
+void FtoFFFDecayer::
+constructSpinInfo(const Particle & part, ParticleVector decay) const {
+ // for the decaying particle
+ if(part.id()<0)
+ SpinorWaveFunction::constructSpinInfo(inwave_.first,
+ const_ptr_cast<tPPtr>(&part),
+ Helicity::incoming,true);
+ else
+ SpinorBarWaveFunction::constructSpinInfo(inwave_.second,
+ const_ptr_cast<tPPtr>(&part),
+ Helicity::incoming,true);
+ // outgoing particles
+ for(unsigned int ix = 0; ix < 3; ++ix) {
+ SpinorWaveFunction::
+ constructSpinInfo(outwave_[ix].first,decay[ix],Helicity::outgoing,true);
+ }
+}
+
+double FtoFFFDecayer::me2(const int ichan,const Particle & part,
+ const tPDVector & outgoing,
+ const vector<Lorentz5Momentum> & momenta,
MEOption meopt) const {
// particle or CC of particle
- bool cc = (*getProcessInfo().begin()).incoming != inpart.id();
+ bool cc = (*getProcessInfo().begin()).incoming != part.id();
// special handling or first/last call
const vector<vector<double> > cfactors(getColourFactors());
const vector<vector<double> > nfactors(getLargeNcColourFactors());
const size_t ncf(numberOfFlows());
- Energy2 scale(sqr(inpart.mass()));
+ Energy2 scale(sqr(part.mass()));
if(meopt==Initialize) {
SpinorWaveFunction::
- calculateWaveFunctions(inwave_.first,rho_,const_ptr_cast<tPPtr>(&inpart),
+ calculateWaveFunctions(inwave_.first,rho_,const_ptr_cast<tPPtr>(&part),
Helicity::incoming);
inwave_.second.resize(2);
if(inwave_.first[0].wave().Type() == SpinorType::u) {
for(unsigned int ix = 0; ix < 2; ++ix) {
inwave_.second[ix] = inwave_.first[ix].bar();
inwave_.second[ix].conjugate();
}
}
else {
for(unsigned int ix = 0; ix < 2; ++ix) {
inwave_.second[ix] = inwave_.first[ix].bar();
inwave_.first[ix].conjugate();
}
}
// fix rho if no correlations
fixRho(rho_);
}
- // setup spin info when needed
- if(meopt==Terminate) {
- // for the decaying particle
- if(inpart.id()<0)
- SpinorWaveFunction::constructSpinInfo(inwave_.first,
- const_ptr_cast<tPPtr>(&inpart),
- Helicity::incoming,true);
- else
- SpinorBarWaveFunction::constructSpinInfo(inwave_.second,
- const_ptr_cast<tPPtr>(&inpart),
- Helicity::incoming,true);
- // outgoing particles
- for(unsigned int ix = 0; ix < 3; ++ix) {
- SpinorWaveFunction::
- constructSpinInfo(outwave_[ix].first,decay[ix],Helicity::outgoing,true);
- }
- }
// outgoing particles
for(unsigned int ix = 0; ix < 3; ++ix) {
SpinorWaveFunction::
- calculateWaveFunctions(outwave_[ix].first,decay[ix],Helicity::outgoing);
+ calculateWaveFunctions(outwave_[ix].first,momenta[ix],outgoing[ix],Helicity::outgoing);
outwave_[ix].second.resize(2);
if(outwave_[ix].first[0].wave().Type() == SpinorType::u) {
for(unsigned int iy = 0; iy < 2; ++iy) {
outwave_[ix].second[iy] = outwave_[ix].first[iy].bar();
outwave_[ix].first[iy].conjugate();
}
}
else {
for(unsigned int iy = 0; iy < 2; ++iy) {
outwave_[ix].second[iy] = outwave_[ix].first[iy].bar();
outwave_[ix].second[iy].conjugate();
}
}
}
- bool ferm = inpart.id()>0;
+ bool ferm = part.id()>0;
vector<Complex> flows(ncf, Complex(0.)),largeflows(ncf, Complex(0.));
static const unsigned int out2[3]={1,0,0},out3[3]={2,2,1};
vector<GeneralDecayMEPtr> mes(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half)));
vector<GeneralDecayMEPtr> mel(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half)));
unsigned int ihel[4];
for(ihel[0] = 0; ihel[0] < 2; ++ihel[0]) {
for(ihel[1] = 0; ihel[1] < 2; ++ihel[1]) {
for(ihel[2] = 0; ihel[2] < 2; ++ihel[2]) {
for(ihel[3] = 0; ihel[3] < 2; ++ihel[3]) {
flows = vector<Complex>(ncf, Complex(0.));
largeflows = vector<Complex>(ncf, Complex(0.));
unsigned int idiag=0;
for(vector<TBDiagram>::const_iterator dit=getProcessInfo().begin();
dit!=getProcessInfo().end();++dit) {
if(ichan>=0&&diagramMap()[ichan]!=idiag) {
++idiag;
continue;
}
// the sign from normal ordering
double sign = ferm ? 1. : -1;
// outgoing wavefunction and NO sign
if (dit->channelType==TBDiagram::channel23) sign *= -1.;
else if(dit->channelType==TBDiagram::channel13) sign *= 1.;
else if(dit->channelType==TBDiagram::channel12) sign *= -1.;
else throw Exception()
<< "Unknown diagram type in FtoFFFDecayer::me2()" << Exception::runerror;
// wavefunctions
SpinorWaveFunction w0,w3;
SpinorBarWaveFunction w1,w2;
// incoming wavefunction
if(ferm) {
w0 = inwave_.first [ihel[0]];
w1 = outwave_[dit->channelType].second[ihel[dit->channelType+1]];
}
else {
w0 = outwave_[dit->channelType].first [ihel[dit->channelType+1]];
w1 = inwave_.second[ihel[0]];
}
- if(decay[out2[dit->channelType]]->id()<0&&
- decay[out3[dit->channelType]]->id()>0) {
+ if(outgoing[out2[dit->channelType]]->id()<0&&
+ outgoing[out3[dit->channelType]]->id()>0) {
w2 = outwave_[out3[dit->channelType]].second[ihel[out3[dit->channelType]+1]];
w3 = outwave_[out2[dit->channelType]].first [ihel[out2[dit->channelType]+1]];
sign *= -1.;
}
else {
w2 = outwave_[out2[dit->channelType]].second[ihel[out2[dit->channelType]+1]];
w3 = outwave_[out3[dit->channelType]].first [ihel[out3[dit->channelType]+1]];
}
tcPDPtr offshell = dit->intermediate;
if(cc&&offshell->CC()) offshell=offshell->CC();
Complex diag(0.);
// intermediate scalar
if (offshell->iSpin() == PDT::Spin0) {
ScalarWaveFunction inters = sca_[idiag].first->
evaluate(scale, widthOption(), offshell, w0, w1);
diag = sca_[idiag].second->evaluate(scale,w3,w2,inters);
}
// intermediate vector
else if(offshell->iSpin() == PDT::Spin1) {
VectorWaveFunction interv = vec_[idiag].first->
evaluate(scale, widthOption(), offshell, w0, w1);
diag = vec_[idiag].second->evaluate(scale,w3,w2,interv);
}
// intermediate tensor
else if(offshell->iSpin() == PDT::Spin2) {
TensorWaveFunction intert = ten_[idiag].first->
evaluate(scale, widthOption(), offshell, w0, w1);
diag = ten_[idiag].second->evaluate(scale,w3,w2,intert);
}
// unknown
else throw Exception()
<< "Unknown intermediate in FtoFFFDecayer::me2()"
<< Exception::runerror;
// apply NO sign
diag *= sign;
// matrix element for the different colour flows
if(ichan<0) {
for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) {
flows[dit->colourFlow[iy].first - 1] +=
dit->colourFlow[iy].second * diag;
}
for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) {
largeflows[dit->largeNcColourFlow[iy].first - 1] +=
dit->largeNcColourFlow[iy].second * diag;
}
}
else {
for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) {
if(dit->colourFlow[iy].first - 1!=colourFlow()) continue;
flows[dit->colourFlow[iy].first - 1] +=
dit->colourFlow[iy].second * diag;
}
for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) {
if(dit->colourFlow[iy].first - 1!=colourFlow()) continue;
largeflows[dit->largeNcColourFlow[iy].first - 1] +=
dit->largeNcColourFlow[iy].second * diag;
}
}
++idiag;
}
// now add the flows to the me2 with appropriate colour factors
for(unsigned int ix = 0; ix < ncf; ++ix) {
(*mes[ix])(ihel[0],ihel[1],ihel[2],ihel[3]) = flows[ix];
(*mel[ix])(ihel[0],ihel[1],ihel[2],ihel[3]) = largeflows[ix];
}
}
}
}
}
double me2(0.);
if(ichan<0) {
vector<double> pflows(ncf,0.);
for(unsigned int ix = 0; ix < ncf; ++ix) {
for(unsigned int iy = 0; iy < ncf; ++ iy) {
double con = cfactors[ix][iy]*(mes[ix]->contract(*mes[iy],rho_)).real();
me2 += con;
if(ix==iy) {
con = nfactors[ix][iy]*(mel[ix]->contract(*mel[iy],rho_)).real();
pflows[ix] += con;
}
}
}
double ptotal(std::accumulate(pflows.begin(),pflows.end(),0.));
ptotal *=UseRandom::rnd();
for(unsigned int ix=0;ix<pflows.size();++ix) {
if(ptotal<=pflows[ix]) {
colourFlow(ix);
ME(mes[ix]);
break;
}
ptotal-=pflows[ix];
}
}
else {
unsigned int iflow = colourFlow();
me2 = nfactors[iflow][iflow]*(mel[iflow]->contract(*mel[iflow],rho_)).real();
}
// return the matrix element squared
return me2;
}
WidthCalculatorBasePtr FtoFFFDecayer::
threeBodyMEIntegrator(const DecayMode & ) const {
vector<int> intype;
vector<Energy> inmass,inwidth;
vector<double> inpow,inweights;
constructIntegratorChannels(intype,inmass,inwidth,inpow,inweights);
return new_ptr(ThreeBodyAllOnCalculator<FtoFFFDecayer>
(inweights,intype,inmass,inwidth,inpow,*this,0,
outgoing()[0]->mass(),outgoing()[1]->mass(),outgoing()[2]->mass(),
relativeError()));
}
diff --git a/Decay/General/FtoFFFDecayer.h b/Decay/General/FtoFFFDecayer.h
--- a/Decay/General/FtoFFFDecayer.h
+++ b/Decay/General/FtoFFFDecayer.h
@@ -1,142 +1,151 @@
// -*- C++ -*-
#ifndef HERWIG_FtoFFFDecayer_H
#define HERWIG_FtoFFFDecayer_H
//
// This is the declaration of the FtoFFFDecayer class.
//
#include "GeneralThreeBodyDecayer.h"
#include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFTVertex.h"
namespace Herwig {
using namespace ThePEG;
/**
* The FtoFFFDecayer class provides the general matrix elements for the
* decay of a (anti)fermion to three (anti)fermions.
*
* @see \ref FtoFFFDecayerInterfaces "The interfaces"
* defined for FtoFFFDecayer.
*/
class FtoFFFDecayer: public GeneralThreeBodyDecayer {
public:
+
+ /**
+ * 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 outgoing The particles produced in the decay
+ * @param momenta The momenta of 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.
+ */
+ double me2(const int ichan,const Particle & part,
+ const tPDVector & outgoing,
+ const vector<Lorentz5Momentum> & momenta,
+ MEOption meopt) 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 matrix element
- * @return The matrix element squared for the phase-space configuration.
+ * Construct the SpinInfos for the particles produced in the decay
*/
- virtual double me2(const int ichan, const Particle & part,
- const ParticleVector & decay, MEOption meopt) const;
+ virtual void constructSpinInfo(const Particle & part,
+ ParticleVector outgoing) const;
/**
* Method to return an object to calculate the 3 (or higher body) partial width
* @param dm The DecayMode
* @return A pointer to a WidthCalculatorBase object capable of calculating the width
*/
virtual WidthCalculatorBasePtr threeBodyMEIntegrator(const DecayMode & dm) const;
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.
*/
FtoFFFDecayer & operator=(const FtoFFFDecayer &);
private:
/**
* Store the vector of FFSVertex pairs
*/
vector<pair<AbstractFFSVertexPtr, AbstractFFSVertexPtr> > sca_;
/**
* Store the vector of FFVVertex pairs
*/
vector<pair<AbstractFFVVertexPtr, AbstractFFVVertexPtr> > vec_;
/**
* Store the vector of FFTVertex pairs
*/
vector<pair<AbstractFFTVertexPtr, AbstractFFTVertexPtr> > ten_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Spinors for incoming particle
*/
mutable pair<vector<SpinorWaveFunction>,vector<SpinorBarWaveFunction> > inwave_;
/**
* Spinors for outgoing particles
*/
mutable pair<vector<SpinorWaveFunction>,vector<SpinorBarWaveFunction> > outwave_[3];
};
}
#endif /* HERWIG_FtoFFFDecayer_H */
diff --git a/Decay/General/FtoFVVDecayer.cc b/Decay/General/FtoFVVDecayer.cc
--- a/Decay/General/FtoFVVDecayer.cc
+++ b/Decay/General/FtoFVVDecayer.cc
@@ -1,403 +1,403 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FtoFVVDecayer class.
//
#include "FtoFVVDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Decay/DecayPhaseSpaceMode.h"
#include "Herwig/PDT/ThreeBodyAllOnCalculator.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
#include <numeric>
using namespace Herwig;
IBPtr FtoFVVDecayer::clone() const {
return new_ptr(*this);
}
IBPtr FtoFVVDecayer::fullclone() const {
return new_ptr(*this);
}
void FtoFVVDecayer::persistentOutput(PersistentOStream & os) const {
os << sca_ << fer_ << vec_ << ten_;
}
void FtoFVVDecayer::persistentInput(PersistentIStream & is, int) {
is >> sca_ >> fer_ >> vec_ >> ten_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<FtoFVVDecayer,GeneralThreeBodyDecayer>
describeHerwigFtoFVVDecayer("Herwig::FtoFVVDecayer", "Herwig.so");
void FtoFVVDecayer::Init() {
static ClassDocumentation<FtoFVVDecayer> documentation
("The FtoFVVDecayer class implements the general decay of a fermion to "
"a fermion and a pair of vectors.");
}
void FtoFVVDecayer::doinit() {
GeneralThreeBodyDecayer::doinit();
if(outgoing().empty()) return;
unsigned int ndiags = getProcessInfo().size();
sca_.resize(ndiags);
fer_.resize(ndiags);
vec_.resize(ndiags);
ten_.resize(ndiags);
for(unsigned int ix = 0;ix < ndiags; ++ix) {
TBDiagram current = getProcessInfo()[ix];
tcPDPtr offshell = current.intermediate;
if(offshell->iSpin() == PDT::Spin0) {
AbstractFFSVertexPtr vert1 = dynamic_ptr_cast<AbstractFFSVertexPtr>
(current.vertices.first);
AbstractVVSVertexPtr vert2 = dynamic_ptr_cast<AbstractVVSVertexPtr>
(current.vertices.second);
if(!vert1||!vert2) throw Exception()
<< "Invalid vertices for a scalar diagram in FtoFVVDecayer::doinit()"
<< Exception::runerror;
sca_[ix] = make_pair(vert1, vert2);
}
else if(offshell->iSpin() == PDT::Spin1Half) {
AbstractFFVVertexPtr vert1 = dynamic_ptr_cast<AbstractFFVVertexPtr>
(current.vertices.first);
AbstractFFVVertexPtr vert2 = dynamic_ptr_cast<AbstractFFVVertexPtr>
(current.vertices.second);
if(!vert1||!vert2) throw Exception()
<< "Invalid vertices for a scalar diagram in FtoFVVDecayer::doinit()"
<< Exception::runerror;
fer_[ix] = make_pair(vert1, vert2);
}
else if(offshell->iSpin() == PDT::Spin1) {
AbstractFFVVertexPtr vert1 = dynamic_ptr_cast<AbstractFFVVertexPtr>
(current.vertices.first);
AbstractVVVVertexPtr vert2 = dynamic_ptr_cast<AbstractVVVVertexPtr>
(current.vertices.second);
if(!vert1||!vert2) throw Exception()
<< "Invalid vertices for a vector diagram in FtoFVVDecayer::doinit()"
<< Exception::runerror;
vec_[ix] = make_pair(vert1, vert2);
}
else if(offshell->iSpin() == PDT::Spin2) {
AbstractFFTVertexPtr vert1 = dynamic_ptr_cast<AbstractFFTVertexPtr>
(current.vertices.first);
AbstractVVTVertexPtr vert2 = dynamic_ptr_cast<AbstractVVTVertexPtr>
(current.vertices.second);
if(!vert1||!vert2) throw Exception()
<< "Invalid vertices for a tensor diagram in FtoFVVDecayer::doinit()"
<< Exception::runerror;
ten_[ix] = make_pair(vert1, vert2);
}
}
}
+void FtoFVVDecayer::
+constructSpinInfo(const Particle & part, ParticleVector decay) const {
+ bool ferm( part.id() > 0 );
+ // for the decaying particle
+ if(ferm)
+ SpinorWaveFunction::constructSpinInfo(fwave_,
+ const_ptr_cast<tPPtr>(&part),
+ Helicity::incoming,true);
+ else
+ SpinorBarWaveFunction::constructSpinInfo(fbwave_,
+ const_ptr_cast<tPPtr>(&part),
+ Helicity::incoming,true);
+ int ivec(-1);
+ // outgoing particles
+ for(int ix = 0; ix < 3; ++ix) {
+ tPPtr p = decay[ix];
+ if( p->dataPtr()->iSpin() == PDT::Spin1Half ) {
+ if( ferm ) {
+ SpinorBarWaveFunction::
+ constructSpinInfo(fbwave_, p, Helicity::outgoing,true);
+ }
+ else {
+ SpinorWaveFunction::
+ constructSpinInfo(fwave_ , p, Helicity::outgoing,true);
+ }
+ }
+ else if( p->dataPtr()->iSpin() == PDT::Spin1 ) {
+ if( ivec < 0 ) {
+ ivec = ix;
+ VectorWaveFunction::
+ constructSpinInfo(vwave_.first , p, Helicity::outgoing, true, false);
+ }
+ else {
+ VectorWaveFunction::
+ constructSpinInfo(vwave_.second, p, Helicity::outgoing, true, false);
+ }
+ }
+ }
+}
-double FtoFVVDecayer::me2(const int ichan, const Particle & inpart,
- const ParticleVector & decay,
+double FtoFVVDecayer::me2(const int ichan,const Particle & part,
+ const tPDVector & outgoing,
+ const vector<Lorentz5Momentum> & momenta,
MEOption meopt) const {
// particle or CC of particle
- bool cc = (*getProcessInfo().begin()).incoming != inpart.id();
+ bool cc = (*getProcessInfo().begin()).incoming != part.id();
// special handling or first/last call
//Set up wave-functions
- bool ferm( inpart.id() > 0 );
+ bool ferm( part.id() > 0 );
if(meopt==Initialize) {
if( ferm ) {
SpinorWaveFunction::
- calculateWaveFunctions(fwave_,rho_,const_ptr_cast<tPPtr>(&inpart),
+ calculateWaveFunctions(fwave_,rho_,const_ptr_cast<tPPtr>(&part),
Helicity::incoming);
if( fwave_[0].wave().Type() != SpinorType::u )
fwave_[0].conjugate();
if( fwave_[1].wave().Type() != SpinorType::u )
fwave_[1].conjugate();
}
else {
SpinorBarWaveFunction::
- calculateWaveFunctions(fbwave_, rho_, const_ptr_cast<tPPtr>(&inpart),
+ calculateWaveFunctions(fbwave_, rho_, const_ptr_cast<tPPtr>(&part),
Helicity::incoming);
if( fbwave_[0].wave().Type() != SpinorType::v )
fbwave_[0].conjugate();
if( fbwave_[1].wave().Type() != SpinorType::v )
fbwave_[1].conjugate();
}
// fix rho if no correlations
fixRho(rho_);
}
- // setup spin info when needed
- if(meopt==Terminate) {
- // for the decaying particle
- if(ferm)
- SpinorWaveFunction::constructSpinInfo(fwave_,
- const_ptr_cast<tPPtr>(&inpart),
- Helicity::incoming,true);
- else
- SpinorBarWaveFunction::constructSpinInfo(fbwave_,
- const_ptr_cast<tPPtr>(&inpart),
- Helicity::incoming,true);
- int ivec(-1);
- // outgoing particles
- for(int ix = 0; ix < 3; ++ix) {
- tPPtr p = decay[ix];
- if( p->dataPtr()->iSpin() == PDT::Spin1Half ) {
- if( ferm ) {
- SpinorBarWaveFunction::
- constructSpinInfo(fbwave_, p, Helicity::outgoing,true);
- }
- else {
- SpinorWaveFunction::
- constructSpinInfo(fwave_ , p, Helicity::outgoing,true);
- }
- }
- else if( p->dataPtr()->iSpin() == PDT::Spin1 ) {
- if( ivec < 0 ) {
- ivec = ix;
- VectorWaveFunction::
- constructSpinInfo(vwave_.first , p, Helicity::outgoing, true, false);
- }
- else {
- VectorWaveFunction::
- constructSpinInfo(vwave_.second, p, Helicity::outgoing, true, false);
- }
- }
- }
- return 0.;
- }
// outgoing, keep track of fermion and first occurrence of vector positions
int isp(-1), ivec(-1);
// outgoing particles
pair<bool,bool> mass = make_pair(false,false);
for(int ix = 0; ix < 3; ++ix) {
- tPPtr p = decay[ix];
- if( p->dataPtr()->iSpin() == PDT::Spin1Half ) {
+ if( outgoing[ix]->iSpin() == PDT::Spin1Half ) {
isp = ix;
if( ferm ) {
SpinorBarWaveFunction::
- calculateWaveFunctions(fbwave_, p, Helicity::outgoing);
+ calculateWaveFunctions(fbwave_, momenta[ix],outgoing[ix], Helicity::outgoing);
if( fbwave_[0].wave().Type() != SpinorType::u )
fbwave_[0].conjugate();
if( fbwave_[1].wave().Type() != SpinorType::u )
fbwave_[1].conjugate();
}
else {
SpinorWaveFunction::
- calculateWaveFunctions(fwave_, p, Helicity::outgoing);
+ calculateWaveFunctions(fwave_, momenta[ix],outgoing[ix], Helicity::outgoing);
if( fwave_[0].wave().Type() != SpinorType::v )
fwave_[0].conjugate();
if( fwave_[1].wave().Type() != SpinorType::v )
fwave_[1].conjugate();
}
}
- else if( p->dataPtr()->iSpin() == PDT::Spin1 ) {
- bool massless = p->id() == ParticleID::gamma || p->id() == ParticleID::g;
+ else if( outgoing[ix]->iSpin() == PDT::Spin1 ) {
+ bool massless = outgoing[ix]->id() == ParticleID::gamma || outgoing[ix]->id() == ParticleID::g;
if( ivec < 0 ) {
ivec = ix;
VectorWaveFunction::
- calculateWaveFunctions(vwave_.first , p, Helicity::outgoing, massless);
+ calculateWaveFunctions(vwave_.first , momenta[ix],outgoing[ix], Helicity::outgoing, massless);
mass.first = massless;
}
else {
VectorWaveFunction::
- calculateWaveFunctions(vwave_.second, p, Helicity::outgoing, massless);
+ calculateWaveFunctions(vwave_.second, momenta[ix],outgoing[ix], Helicity::outgoing, massless);
mass.second = massless;
}
}
}
assert(isp >= 0 && ivec >= 0);
- Energy2 scale(sqr(inpart.mass()));
+ Energy2 scale(sqr(part.mass()));
const vector<vector<double> > cfactors(getColourFactors());
const vector<vector<double> > nfactors(getLargeNcColourFactors());
const size_t ncf(numberOfFlows());
vector<Complex> flows(ncf, Complex(0.)), largeflows(ncf, Complex(0.));
vector<GeneralDecayMEPtr>
mes(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,
(isp == 0) ? PDT::Spin1Half : PDT::Spin1,
(isp == 1) ? PDT::Spin1Half : PDT::Spin1,
(isp == 2) ? PDT::Spin1Half : PDT::Spin1)));
vector<GeneralDecayMEPtr>
mel(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,
(isp == 0) ? PDT::Spin1Half : PDT::Spin1,
(isp == 1) ? PDT::Spin1Half : PDT::Spin1,
(isp == 2) ? PDT::Spin1Half : PDT::Spin1)));
//Helicity calculation
for( unsigned int if1 = 0; if1 < 2; ++if1 ) {
for( unsigned int if2 = 0; if2 < 2; ++if2 ) {
for( unsigned int iv1 = 0; iv1 < 3; ++iv1 ) {
if ( mass.first && iv1 == 1 ) continue;
for( unsigned int iv2 = 0; iv2 < 3; ++iv2 ) {
if ( mass.second && iv2 == 1 ) continue;
flows = vector<Complex>(ncf, Complex(0.));
largeflows = vector<Complex>(ncf, Complex(0.));
unsigned int idiag(0);
for(vector<TBDiagram>::const_iterator dit = getProcessInfo().begin();
dit != getProcessInfo().end(); ++dit) {
// If we are selecting a particular channel
if( ichan >= 0 && diagramMap()[ichan] != idiag ) {
++idiag;
continue;
}
tcPDPtr offshell = (*dit).intermediate;
if(cc&&offshell->CC()) offshell=offshell->CC();
Complex diag;
if( offshell->iSpin() == PDT::Spin1Half ) {
// Make sure we connect the correct particles
VectorWaveFunction vw1, vw2;
if( (*dit).channelType == TBDiagram::channel23 ) {
vw1 = vwave_.first[iv1];
vw2 = vwave_.second[iv2];
}
else if( (*dit).channelType == TBDiagram::channel12 ) {
vw1 = vwave_.second[iv2];
vw2 = vwave_.first[iv1];
}
else {
if( ivec < isp ) {
vw1 = vwave_.second[iv2];
vw2 = vwave_.first[iv1];
}
else {
vw1 = vwave_.first[iv1];
vw2 = vwave_.second[iv2];
}
}
if( ferm ) {
SpinorWaveFunction inters =
fer_[idiag].first->evaluate(scale, widthOption(), offshell,
fwave_[if1], vw1);
diag = fer_[idiag].second->evaluate(scale, inters, fbwave_[if2],
vw2);
}
else {
SpinorBarWaveFunction inters =
fer_[idiag].first->evaluate(scale, widthOption(), offshell,
fbwave_[if2], vw1);
diag = fer_[idiag].second->evaluate(scale, fwave_[if1], inters,
vw2);
}
}
else if( offshell->iSpin() == PDT::Spin0 ) {
ScalarWaveFunction inters =
sca_[idiag].first->evaluate(scale, widthOption(), offshell,
fwave_[if1], fbwave_[if2]);
diag = sca_[idiag].second->evaluate(scale, vwave_.first[iv1],
vwave_.second[iv2], inters);
}
else if( offshell->iSpin() == PDT::Spin1 ) {
VectorWaveFunction interv =
vec_[idiag].first->evaluate(scale, widthOption(), offshell,
fwave_[if1], fbwave_[if2]);
diag = vec_[idiag].second->evaluate(scale, vwave_.first[iv1],
vwave_.second[iv2], interv);
}
else if( offshell->iSpin() == PDT::Spin2 ) {
TensorWaveFunction intert =
ten_[idiag].first->evaluate(scale, widthOption(), offshell,
fwave_[if1], fbwave_[if2]);
diag = ten_[idiag].second->evaluate(scale, vwave_.first[iv1],
vwave_.second[iv2], intert);
}
else
throw Exception()
<< "Unknown intermediate in FtoFVVDecayer::me2()"
<< Exception::runerror;
//NO sign
if( !ferm ) diag *= -1;
if(ichan<0) {
for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) {
flows[dit->colourFlow[iy].first - 1] +=
dit->colourFlow[iy].second * diag;
}
for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) {
largeflows[dit->largeNcColourFlow[iy].first - 1] +=
dit->largeNcColourFlow[iy].second * diag;
}
}
else {
for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) {
if(dit->colourFlow[iy].first - 1!=colourFlow()) continue;
flows[dit->colourFlow[iy].first - 1] +=
dit->colourFlow[iy].second * diag;
}
for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) {
if(dit->colourFlow[iy].first - 1!=colourFlow()) continue;
largeflows[dit->largeNcColourFlow[iy].first - 1] +=
dit->largeNcColourFlow[iy].second * diag;
}
}
++idiag;
}// end diagram loop
// now add the flows to the me2
unsigned int h1(if1), h2(if2);
if( !ferm ) swap(h1,h2);
for(unsigned int ix = 0; ix < ncf; ++ix) {
if(isp == 0) {
(*mes[ix])(h1, h2, iv1, iv2) = flows[ix];
(*mel[ix])(h1, h2, iv1, iv2) = largeflows[ix];
}
else if(isp == 1) {
(*mes[ix])(h1, iv1, h2, iv2) = flows[ix];
(*mel[ix])(h1, iv1, h2, iv2) = largeflows[ix];
}
else if(isp == 2) {
(*mes[ix])(h1, iv1, iv2, h2) = flows[ix];
(*mel[ix])(h1, iv1, h2, iv2) = largeflows[ix];
}
}
}//v2
}//v1
}//f2
}//f1
//Finally, work out me2. This depends on whether we are selecting channels
//or not
double me2(0.);
if(ichan<0) {
vector<double> pflows(ncf,0.);
for(unsigned int ix = 0; ix < ncf; ++ix) {
for(unsigned int iy = 0; iy < ncf; ++ iy) {
double con = cfactors[ix][iy]*(mes[ix]->contract(*mes[iy],rho_)).real();
me2 += con;
if(ix==iy) {
con = nfactors[ix][iy]*(mel[ix]->contract(*mel[iy],rho_)).real();
pflows[ix] += con;
}
}
}
double ptotal(std::accumulate(pflows.begin(),pflows.end(),0.));
ptotal *= UseRandom::rnd();
for(unsigned int ix=0;ix<pflows.size();++ix) {
if(ptotal<=pflows[ix]) {
colourFlow(ix);
ME(mes[ix]);
break;
}
ptotal-=pflows[ix];
}
}
else {
unsigned int iflow = colourFlow();
me2 = nfactors[iflow][iflow]*(mel[iflow]->contract(*mel[iflow],rho_)).real();
}
// return the matrix element squared
return me2;
}
WidthCalculatorBasePtr FtoFVVDecayer::
threeBodyMEIntegrator(const DecayMode & ) const {
vector<int> intype;
vector<Energy> inmass,inwidth;
vector<double> inpow,inweights;
constructIntegratorChannels(intype,inmass,inwidth,inpow,inweights);
return new_ptr(ThreeBodyAllOnCalculator<FtoFVVDecayer>
(inweights,intype,inmass,inwidth,inpow,*this,0,
outgoing()[0]->mass(),outgoing()[1]->mass(),
outgoing()[2]->mass(),relativeError()));
}
diff --git a/Decay/General/FtoFVVDecayer.h b/Decay/General/FtoFVVDecayer.h
--- a/Decay/General/FtoFVVDecayer.h
+++ b/Decay/General/FtoFVVDecayer.h
@@ -1,156 +1,165 @@
// -*- C++ -*-
#ifndef HERWIG_FtoFVVDecayer_H
#define HERWIG_FtoFVVDecayer_H
//
// This is the declaration of the FtoFVVDecayer class.
//
#include "GeneralThreeBodyDecayer.h"
#include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFTVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVTVertex.h"
namespace Herwig {
using namespace ThePEG;
/**
* The FtoFVVDecayer class provides the general matrix elements for the
* decay of a fermion to a fermion and two vector bosons.
*
* @see \ref FtoFVVDecayerInterfaces "The interfaces"
* defined for FtoFVVDecayer.
*/
class FtoFVVDecayer: public GeneralThreeBodyDecayer {
public:
-
+
/**
- * Return the matrix element squared for a given mode and phase-space channel
- * @param ichan The channel we are calculating the matrix element for.
+ * 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 outgoing The particles produced in the decay
+ * @param momenta The momenta of 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;
+ double me2(const int ichan,const Particle & part,
+ const tPDVector & outgoing,
+ const vector<Lorentz5Momentum> & momenta,
+ MEOption meopt) const;
+
+ /**
+ * Construct the SpinInfos for the particles produced in the decay
+ */
+ virtual void constructSpinInfo(const Particle & part,
+ ParticleVector outgoing) const;
/**
* Method to return an object to calculate the 3 (or higher body) partial width
* @param dm The DecayMode
* @return A pointer to a WidthCalculatorBase object capable of calculating the width
*/
virtual WidthCalculatorBasePtr threeBodyMEIntegrator(const DecayMode & dm) const;
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.
*/
FtoFVVDecayer & operator=(const FtoFVVDecayer &);
private:
/**
* Store the vector of scalar intermediates
*/
vector<pair<AbstractFFSVertexPtr, AbstractVVSVertexPtr> > sca_;
/**
* Store the vector for fermion intermediates
*/
vector<pair<AbstractFFVVertexPtr, AbstractFFVVertexPtr> > fer_;
/**
* Store the vector for gauge boson intermediates
*/
vector<pair<AbstractFFVVertexPtr, AbstractVVVVertexPtr> > vec_;
/**
* Store the vector of tensor intermediates
*/
vector<pair<AbstractFFTVertexPtr, AbstractVVTVertexPtr> > ten_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Spinor wavefunctions
*/
mutable vector<SpinorWaveFunction> fwave_;
/**
* Barred spinor wavefunctions
*/
mutable vector<SpinorBarWaveFunction> fbwave_;
/**
* Vector wavefunctions
*/
mutable pair<vector<VectorWaveFunction>, vector<VectorWaveFunction> > vwave_;
};
}
#endif /* HERWIG_FtoFVVDecayer_H */
diff --git a/Decay/General/GeneralThreeBodyDecayer.cc b/Decay/General/GeneralThreeBodyDecayer.cc
--- a/Decay/General/GeneralThreeBodyDecayer.cc
+++ b/Decay/General/GeneralThreeBodyDecayer.cc
@@ -1,1028 +1,1016 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the GeneralThreeBodyDecayer class.
//
#include "GeneralThreeBodyDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
-#include "Herwig/Decay/DecayPhaseSpaceMode.h"
+#include "Herwig/Decay/PhaseSpaceMode.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/PDT/ThreeBodyAllOnCalculator.h"
using namespace Herwig;
void GeneralThreeBodyDecayer::persistentOutput(PersistentOStream & os) const {
os << incoming_ << outgoing_ << diagrams_ << diagmap_ << colour_ << colourLargeNC_
<< nflow_ << widthOpt_ << refTag_ << refTagCC_ << intOpt_ << relerr_;
}
void GeneralThreeBodyDecayer::persistentInput(PersistentIStream & is, int) {
is >> incoming_ >> outgoing_ >> diagrams_ >> diagmap_ >> colour_ >> colourLargeNC_
>> nflow_ >> widthOpt_ >> refTag_ >> refTagCC_ >> intOpt_ >> relerr_;
}
// The following static variable is needed for the type
// description system in ThePEG.
-DescribeAbstractClass<GeneralThreeBodyDecayer,DecayIntegrator>
+DescribeAbstractClass<GeneralThreeBodyDecayer,DecayIntegrator2>
describeHerwigGeneralThreeBodyDecayer("Herwig::GeneralThreeBodyDecayer", "Herwig.so");
void GeneralThreeBodyDecayer::Init() {
static ClassDocumentation<GeneralThreeBodyDecayer> documentation
("The GeneralThreeBodyDecayer class is the base class for the implementation of"
" all three body decays based on spin structures in Herwig.");
static Switch<GeneralThreeBodyDecayer,unsigned int> interfaceWidthOption
("WidthOption",
"Option for the treatment of the widths of the intermediates",
&GeneralThreeBodyDecayer::widthOpt_, 1, false, false);
static SwitchOption interfaceWidthOptionFixed
(interfaceWidthOption,
"Fixed",
"Use fixed widths",
1);
static SwitchOption interfaceWidthOptionRunning
(interfaceWidthOption,
"Running",
"Use running widths",
2);
static SwitchOption interfaceWidthOptionZero
(interfaceWidthOption,
"Zero",
"Set the widths to zero",
3);
static Switch<GeneralThreeBodyDecayer,unsigned int> interfacePartialWidthIntegration
("PartialWidthIntegration",
"Switch to control the partial width integration",
&GeneralThreeBodyDecayer::intOpt_, 0, false, false);
static SwitchOption interfacePartialWidthIntegrationAllPoles
(interfacePartialWidthIntegration,
"AllPoles",
"Include all potential poles",
0);
static SwitchOption interfacePartialWidthIntegrationShallowestPole
(interfacePartialWidthIntegration,
"ShallowestPole",
"Only include the shallowest pole",
1);
static Parameter<GeneralThreeBodyDecayer,double> interfaceRelativeError
("RelativeError",
"The relative error for the GQ integration of the partial width",
&GeneralThreeBodyDecayer::relerr_, 1e-2, 1e-10, 1.,
false, false, Interface::limited);
}
ParticleVector GeneralThreeBodyDecayer::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;
}
int GeneralThreeBodyDecayer::
modeNumber(bool & cc, tcPDPtr in, const tPDVector & outin) const {
assert( !refTag_.empty() && !refTagCC_.empty() );
// check number of outgoing particles
if( outin.size() != 3 || abs(in->id()) != abs(incoming_->id()) ) return -1;
OrderedParticles testmode(outin.begin(), outin.end());
OrderedParticles::const_iterator dit = testmode.begin();
string testtag(in->name() + "->");
for( unsigned int i = 1; dit != testmode.end(); ++dit, ++i) {
testtag += (**dit).name();
if( i != 3 ) testtag += string(",");
}
if( testtag == refTag_ ) {
cc = false;
return 0;
}
else if ( testtag == refTagCC_ ) {
cc = true;
return 0;
}
else return -1;
}
bool GeneralThreeBodyDecayer::setDecayInfo(PDPtr incoming,
vector<PDPtr> outgoing,
const vector<TBDiagram> & process,
double symfac) {
// set the member variables from the info supplied
incoming_ = incoming;
- outgoing_ = outgoing;
+ outgoing_ = {outgoing[0],outgoing[1],outgoing[2]};
diagrams_ = process;
assert( outgoing_.size() == 3 );
// Construct reference tags for testing in modeNumber function
OrderedParticles refmode(outgoing_.begin(), outgoing_.end());
OrderedParticles::const_iterator dit = refmode.begin();
refTag_ = incoming_->name() + "->";
for( unsigned int i = 1; dit != refmode.end(); ++dit, ++i) {
refTag_ += (**dit).name();
if( i != 3 ) refTag_ += string(",");
}
//CC-mode
refmode.clear();
refTagCC_ = incoming_->CC() ? incoming_->CC()->name() :
incoming_->name();
refTagCC_ += "->";
for( unsigned int i = 0; i < 3; ++i ) {
if( outgoing_[i]->CC() ) refmode.insert( outgoing_[i]->CC() );
else refmode.insert( outgoing_[i] );
}
dit = refmode.begin();
for( unsigned int i = 1; dit != refmode.end(); ++dit , ++i) {
refTagCC_ += (**dit).name();
if( i != 3 ) refTagCC_ += string(",");
}
// check if intermeidates or only four point diagrams
bool intermediates(false);
for(auto diagram : diagrams_) {
if(diagram.intermediate) {
intermediates=true;
break;
}
}
if(!intermediates) {
incoming_= PDPtr();
outgoing_.clear();
generator()->log() << "Only four body diagrams for decay "
<< refTag_ << " in GeneralThreeBodyDecayer::"
<< "setDecayInfo(), omitting decay\n";
return false;
}
// set the colour factors and return the answer
if(setColourFactors(symfac)) return true;
incoming_= PDPtr();
outgoing_.clear();
return false;
}
void GeneralThreeBodyDecayer::doinit() {
- DecayIntegrator::doinit();
+ DecayIntegrator2::doinit();
if(outgoing_.empty()) return;
// create the phase space integrator
- tPDVector extpart(1,incoming_);
- extpart.insert(extpart.end(),outgoing_.begin(),outgoing_.end());
// create the integration channels for the decay
- DecayPhaseSpaceModePtr mode(new_ptr(DecayPhaseSpaceMode(extpart,this,true)));
- DecayPhaseSpaceChannelPtr newchannel;
+ PhaseSpaceModePtr mode(new_ptr(PhaseSpaceMode(incoming_,outgoing_,1.)));
// create the phase-space channels for the integration
unsigned int nmode(0);
for(unsigned int ix=0;ix<diagrams_.size();++ix) {
if(diagrams_[ix].channelType==TBDiagram::fourPoint||
diagrams_[ix].channelType==TBDiagram::UNDEFINED) continue;
// create the new channel
- newchannel=new_ptr(DecayPhaseSpaceChannel(mode));
+ PhaseSpaceChannel newChannel(mode);
int jac = 0;
double power = 0.0;
if ( diagrams_[ix].intermediate->mass() == ZERO ||
diagrams_[ix].intermediate->width() == ZERO ) {
jac = 1;
power = -2.0;
}
- if(diagrams_[ix].channelType==TBDiagram::channel23) {
- newchannel->addIntermediate(extpart[0],0,0.0,-1,1);
- newchannel->addIntermediate(diagrams_[ix].intermediate,jac,power, 2,3);
- }
- else if(diagrams_[ix].channelType==TBDiagram::channel13) {
- newchannel->addIntermediate(extpart[0],0,0.0,-1,2);
- newchannel->addIntermediate(diagrams_[ix].intermediate,jac,power, 1,3);
- }
- else if(diagrams_[ix].channelType==TBDiagram::channel12) {
- newchannel->addIntermediate(extpart[0],0,0.0,-1,3);
- newchannel->addIntermediate(diagrams_[ix].intermediate,jac,power, 1,2);
- }
+ if(diagrams_[ix].channelType==TBDiagram::channel23)
+ newChannel = (newChannel,0,diagrams_[ix].intermediate,0,1,1,2,1,3);
+ else if(diagrams_[ix].channelType==TBDiagram::channel13)
+ newChannel = (newChannel,0,diagrams_[ix].intermediate,0,2,1,1,1,3);
+ else if(diagrams_[ix].channelType==TBDiagram::channel12)
+ newChannel = (newChannel,0,diagrams_[ix].intermediate,0,3,1,1,1,2);
+ if(jac==1)
+ newChannel.setJacobian(1,PhaseSpaceChannel::PhaseSpaceResonance::Power,power);
diagmap_.push_back(ix);
- mode->addChannel(newchannel);
+ mode->addChannel(newChannel);
++nmode;
}
if(nmode==0) {
- string mode = extpart[0]->PDGName() + "->";
- for(unsigned int ix=1;ix<extpart.size();++ix) mode += extpart[ix]->PDGName() + " ";
+ string mode = incoming_->PDGName() + "->";
+ for(unsigned int ix=0;ix<outgoing_.size();++ix) mode += outgoing_[ix]->PDGName() + " ";
throw Exception() << "No decay channels in GeneralThreeBodyDecayer::"
<< "doinit() for " << mode << "\n" << Exception::runerror;
}
// add the mode
- vector<double> wgt(nmode,1./double(nmode));
- addMode(mode,1.,wgt);
+ addMode(mode);
}
double GeneralThreeBodyDecayer::
threeBodyMatrixElement(const int imode, const Energy2 q2,
const Energy2 s3, const Energy2 s2,
const Energy2 s1, const Energy m1,
const Energy m2, const Energy m3) const {
// calculate the momenta of the outgoing particles
Energy m0=sqrt(q2);
// energies
Energy eout[3] = {0.5*(q2+sqr(m1)-s1)/m0,
0.5*(q2+sqr(m2)-s2)/m0,
0.5*(q2+sqr(m3)-s3)/m0};
// magnitudes of the momenta
Energy pout[3] = {sqrt(sqr(eout[0])-sqr(m1)),
sqrt(sqr(eout[1])-sqr(m2)),
sqrt(sqr(eout[2])-sqr(m3))};
double cos2 = 0.5*(sqr(pout[0])+sqr(pout[1])-sqr(pout[2]))/pout[0]/pout[1];
double cos3 = 0.5*(sqr(pout[0])-sqr(pout[1])+sqr(pout[2]))/pout[0]/pout[2];
double sin2 = sqrt(1.-sqr(cos2)), sin3 = sqrt(1.-sqr(cos3));
- Lorentz5Momentum out[3]=
+ vector<Lorentz5Momentum> out =
{Lorentz5Momentum( ZERO , ZERO , pout[0] , eout[0] , m1),
Lorentz5Momentum( pout[1]*sin2 , ZERO , -pout[1]*cos2 , eout[1] , m2),
Lorentz5Momentum( -pout[2]*sin3 , ZERO , -pout[2]*cos3 , eout[2] , m3)};
- // create the incoming
- PPtr inpart=mode(imode)->externalParticles(0)->
+ // create the incoming particle
+ PPtr inpart=mode(imode)->incoming().first->
produceParticle(Lorentz5Momentum(sqrt(q2)));
- // and outgoing particles
- ParticleVector decay;
- for(unsigned int ix=1;ix<4;++ix)
- decay.push_back(mode(imode)->externalParticles(ix)->produceParticle(out[ix-1]));
// return the matrix element
- return me2(-1,*inpart,decay,Initialize);
+ return me2(-1,*inpart,outgoing_,out,Initialize);
}
double GeneralThreeBodyDecayer::brat(const DecayMode &, const Particle & p,
double oldbrat) const {
ParticleVector children = p.children();
if( children.size() != 3 || !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()),
make_pair(children[2]->dataPtr(), children[2]->mass()) );
Energy width = p.data().widthGenerator()->width(p.data(), scale);
return pwidth/width;
}
Energy GeneralThreeBodyDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb, PMPair outc) const {
if(inpart.second<outa.second+outb.second+outc.second) return ZERO;
// create the object to calculate the width if it doesn't all ready exist
if(!widthCalc_) {
string tag = incoming_->name() + "->";
tag += outgoing_[0]->name() + "," + outgoing_[1]->name() + ","
+ outgoing_[2]->name() + ";";
DMPtr dm = generator()->findDecayMode(tag);
widthCalc_ = threeBodyMEIntegrator(*dm);
}
return widthCalc_->partialWidth(sqr(inpart.second));
}
void GeneralThreeBodyDecayer::
colourConnections(const Particle & parent,
const ParticleVector & out) const {
// first extract the outgoing particles and intermediate
PPtr inter;
ParticleVector outgoing;
if(!generateIntermediates()) {
outgoing=out;
}
else {
// find the diagram
unsigned int idiag = diagramMap()[mode(imode())->selectedChannel()];
PPtr child;
for(unsigned int ix=0;ix<out.size();++ix) {
if(out[ix]->children().empty()) child = out[ix];
else inter = out[ix];
}
outgoing.resize(3);
switch(diagrams_[idiag].channelType) {
case TBDiagram::channel23:
outgoing[0] = child;
outgoing[1] = inter->children()[0];
outgoing[2] = inter->children()[1];
break;
case TBDiagram::channel13:
outgoing[0] = inter->children()[0];
outgoing[1] = child;
outgoing[2] = inter->children()[1];
break;
case TBDiagram::channel12:
outgoing[0] = inter->children()[0];
outgoing[1] = inter->children()[1];
outgoing[2] = child;
break;
default:
throw Exception() << "unknown diagram type in GeneralThreeBodyDecayer::"
<< "colourConnections()" << Exception::runerror;
}
}
// extract colour of the incoming and outgoing particles
PDT::Colour inColour(parent.data().iColour());
vector<PDT::Colour> outColour;
vector<int> singlet,octet,triplet,antitriplet;
for(unsigned int ix=0;ix<outgoing.size();++ix) {
outColour.push_back(outgoing[ix]->data().iColour());
switch(outColour.back()) {
case PDT::Colour0 :
singlet.push_back(ix);
break;
case PDT::Colour3 :
triplet.push_back(ix);
break;
case PDT::Colour3bar:
antitriplet.push_back(ix);
break;
case PDT::Colour8 :
octet.push_back(ix);
break;
default:
throw Exception() << "Unknown colour for particle in GeneralThreeBodyDecayer::"
<< "colourConnections()" << Exception::runerror;
}
}
// colour neutral decaying particle
if ( inColour == PDT::Colour0) {
// options are all neutral or triplet/antitriplet+ neutral
if(singlet.size()==3) return;
else if(singlet.size()==1&&triplet.size()==1&&antitriplet.size()==1) {
outgoing[triplet[0]]->antiColourNeighbour(outgoing[antitriplet[0]]);
// add intermediate if needed
if(inter&&inter->coloured()) {
if(inter->dataPtr()->iColour()==PDT::Colour3)
outgoing[triplet[0]]->colourLine()->addColoured(inter);
else if(inter->dataPtr()->iColour()==PDT::Colour3bar)
outgoing[triplet[0]]->colourLine()->addAntiColoured(inter);
}
}
else if(octet.size()==1&&triplet.size()==1&&antitriplet.size()==1) {
outgoing[ triplet[0]]->antiColourNeighbour(outgoing[octet[0]]);
outgoing[antitriplet[0]]-> colourNeighbour(outgoing[octet[0]]);
if(inter&&inter->coloured()) {
if(inter->dataPtr()->iColour()==PDT::Colour3)
outgoing[antitriplet[0]]->antiColourLine()->addColoured(inter);
else if(inter->dataPtr()->iColour()==PDT::Colour3bar)
outgoing[ triplet[0]]-> colourLine()->addAntiColoured(inter);
else if(inter->dataPtr()->iColour()==PDT::Colour8) {
outgoing[antitriplet[0]]->antiColourLine()->addAntiColoured(inter);
outgoing[ triplet[0]]-> colourLine()->addColoured(inter);
}
}
}
else if(triplet.size()==3) {
tColinePtr col[3] = {ColourLine::create(outgoing[0]),
ColourLine::create(outgoing[1]),
ColourLine::create(outgoing[2])};
col[0]->setSourceNeighbours(col[1],col[2]);
}
else if(antitriplet.size()==3) {
tColinePtr col[3] = {ColourLine::create(outgoing[0],true),
ColourLine::create(outgoing[1],true),
ColourLine::create(outgoing[2],true)};
col[0]->setSinkNeighbours(col[1],col[2]);
}
else {
string mode = parent.PDGName() + " -> " + out[0]->PDGName() + " "
+ out[1]->PDGName() + " " + out[2]->PDGName();
throw Exception()
<< "Unknown colour structure in GeneralThreeBodyDecayer::"
<< "colourConnections() for singlet decaying particle "
<< mode << Exception::runerror;
}
}
// colour triplet decaying particle
else if( inColour == PDT::Colour3) {
if(singlet.size()==2&&triplet.size()==1) {
outgoing[triplet[0]]->incomingColour(const_ptr_cast<tPPtr>(&parent));
if(inter&&inter->coloured())
outgoing[triplet[0]]->colourLine()->addColoured(inter);
}
else if(antitriplet.size()==1&&triplet.size()==2) {
if(colourFlow()==0) {
outgoing[triplet[0]]->incomingColour(const_ptr_cast<tPPtr>(&parent));
outgoing[antitriplet[0]]->colourNeighbour(outgoing[triplet[1]]);
if(inter&&inter->coloured()) {
switch (inter->dataPtr()->iColour()) {
case PDT::Colour8:
inter->incomingColour(const_ptr_cast<tPPtr>(&parent));
outgoing[triplet[1]]->colourLine()->addAntiColoured(inter);
break;
default:
string mode = parent.PDGName() + " -> " + out[0]->PDGName() + " "
+ out[1]->PDGName() + " " + out[2]->PDGName();
throw Exception() << "Unknown colour for intermediate in "
<< "GeneralThreeBodyDecayer::"
<< "colourConnections() for "
<< "decaying colour triplet "
<< mode << Exception::runerror;
}
}
}
else {
outgoing[triplet[1]]->incomingColour(const_ptr_cast<tPPtr>(&parent));
outgoing[antitriplet[0]]->colourNeighbour(outgoing[triplet[0]]);
if(inter&&inter->coloured()) {
switch (inter->dataPtr()->iColour()) {
case PDT::Colour8:
inter->incomingColour(const_ptr_cast<tPPtr>(&parent));
outgoing[triplet[0]]->colourLine()->addAntiColoured(inter);
break;
default:
string mode = parent.PDGName() + " -> " + out[0]->PDGName() + " "
+ out[1]->PDGName() + " " + out[2]->PDGName();
throw Exception() << "Unknown colour for intermediate in "
<< "GeneralThreeBodyDecayer::"
<< "colourConnections() for "
<< "decaying colour triplet "
<< mode << Exception::runerror;
}
}
}
}
else if (singlet.size()==1&&triplet.size()==1&&octet.size()==1) {
if(inter) {
if(inter->children()[0]->dataPtr()->iColour()==PDT::Colour8 ||
inter->children()[1]->dataPtr()->iColour()==PDT::Colour8) {
inter->incomingColour(const_ptr_cast<tPPtr>(&parent));
outgoing[octet[0]]->incomingColour(inter);
outgoing[octet[0]]->colourNeighbour(outgoing[triplet[0]]);
}
else {
outgoing[octet[0]]->incomingColour(inter);
outgoing[octet[0]]->colourNeighbour(inter);
outgoing[triplet[0]]->incomingColour(inter);
}
}
else {
outgoing[octet[0]]->incomingColour(const_ptr_cast<tPPtr>(&parent));
outgoing[octet[0]]->colourNeighbour(outgoing[triplet[0]]);
}
}
else if (singlet.size()==1&&antitriplet.size()==2) {
tColinePtr col[2] = {ColourLine::create(outgoing[antitriplet[0]],true),
ColourLine::create(outgoing[antitriplet[1]],true)};
parent.colourLine()->setSinkNeighbours(col[0],col[1]);
}
else {
string mode = parent.PDGName() + " -> " + out[0]->PDGName() + " "
+ out[1]->PDGName() + " " + out[2]->PDGName();
throw Exception()
<< "Unknown colour structure in GeneralThreeBodyDecayer::"
<< "colourConnections() for triplet decaying particle "
<< mode << Exception::runerror;
}
}
else if( inColour == PDT::Colour3bar) {
if(singlet.size()==2&&antitriplet.size()==1) {
outgoing[antitriplet[0]]->incomingAntiColour(const_ptr_cast<tPPtr>(&parent));
}
else if(antitriplet.size()==2&&triplet.size()==1) {
if(colourFlow()==0) {
outgoing[antitriplet[0]]->incomingAntiColour(const_ptr_cast<tPPtr>(&parent));
outgoing[triplet[0]]->antiColourNeighbour(outgoing[antitriplet[1]]);
if(inter&&inter->coloured()) {
switch (inter->dataPtr()->iColour()) {
case PDT::Colour8:
inter->incomingAntiColour(const_ptr_cast<tPPtr>(&parent));
outgoing[antitriplet[1]]->antiColourLine()->addAntiColoured(inter);
break;
default:
string mode = parent.PDGName() + " -> " + out[0]->PDGName() + " "
+ out[1]->PDGName() + " " + out[2]->PDGName();
throw Exception() << "Unknown colour for intermediate in"
<< " GeneralThreeBodyDecayer::"
<< "colourConnections() for "
<< "decaying colour antitriplet "
<< mode << Exception::runerror;
}
}
}
else {
outgoing[antitriplet[1]]->incomingAntiColour(const_ptr_cast<tPPtr>(&parent));
outgoing[triplet[0]]->antiColourNeighbour(outgoing[antitriplet[0]]);
if(inter&&inter->coloured()) {
switch (inter->dataPtr()->iColour()) {
case PDT::Colour8:
inter->incomingAntiColour(const_ptr_cast<tPPtr>(&parent));
outgoing[antitriplet[0]]->antiColourLine()->addAntiColoured(inter);
break;
default:
string mode = parent.PDGName() + " -> " + out[0]->PDGName() + " "
+ out[1]->PDGName() + " " + out[2]->PDGName();
throw Exception() << "Unknown colour for intermediate in "
<< "GeneralThreeBodyDecayer::"
<< "colourConnections() for "
<< "decaying colour antitriplet "
<< mode << Exception::runerror;
}
}
}
}
else if (singlet.size()==1&&antitriplet.size()==1&&octet.size()==1) {
if(inter) {
if(inter->children()[0]->dataPtr()->iColour()==PDT::Colour8 ||
inter->children()[1]->dataPtr()->iColour()==PDT::Colour8) {
inter->incomingColour(const_ptr_cast<tPPtr>(&parent));
outgoing[octet[0]]->incomingAntiColour(inter);
outgoing[octet[0]]->antiColourNeighbour(outgoing[antitriplet[0]]);
}
else {
outgoing[octet[0]]->incomingAntiColour(inter);
outgoing[octet[0]]->antiColourNeighbour(inter);
outgoing[antitriplet[0]]->incomingAntiColour(inter);
}
}
else {
outgoing[octet[0]]->incomingAntiColour(const_ptr_cast<tPPtr>(&parent));
outgoing[octet[0]]->antiColourNeighbour(outgoing[antitriplet[0]]);
}
}
else if (singlet.size()==1&&triplet.size()==2) {
tColinePtr col[2] = {ColourLine::create(outgoing[triplet[0]]),
ColourLine::create(outgoing[triplet[1]])};
parent.antiColourLine()->setSourceNeighbours(col[0],col[1]);
}
else {
string mode = parent.PDGName() + " -> " + out[0]->PDGName() + " "
+ out[1]->PDGName() + " " + out[2]->PDGName();
throw Exception()
<< "Unknown colour structure in GeneralThreeBodyDecayer::"
<< "colourConnections() for anti-triplet decaying particle"
<< mode << Exception::runerror;
}
}
else if( inColour == PDT::Colour8) {
if(triplet.size()==1&&antitriplet.size()==1&&singlet.size()==1) {
outgoing[ triplet[0]]->incomingColour (const_ptr_cast<tPPtr>(&parent));
outgoing[antitriplet[0]]->incomingAntiColour(const_ptr_cast<tPPtr>(&parent));
if(inter&&inter->coloured()) {
switch (inter->dataPtr()->iColour()) {
case PDT::Colour3:
outgoing[triplet[0]]->colourLine()->addColoured(inter);
break;
case PDT::Colour3bar:
outgoing[antitriplet[0]]->antiColourLine()->addAntiColoured(inter);
break;
default:
string mode = parent.PDGName() + " -> " + out[0]->PDGName() + " "
+ out[1]->PDGName() + " " + out[2]->PDGName();
throw Exception() << "Unknown colour for intermediate"
<< " in GeneralThreeBodyDecayer::"
<< "colourConnections() for "
<< "decaying colour octet "
<< mode << Exception::runerror;
}
}
}
else if(triplet.size()==3) {
tColinePtr col[2];
if(colourFlow()==0) {
outgoing[0]->incomingColour (const_ptr_cast<tPPtr>(&parent));
col[0] = ColourLine::create(outgoing[1]);
col[1] = ColourLine::create(outgoing[2]);
}
else if(colourFlow()==1) {
outgoing[1]->incomingColour (const_ptr_cast<tPPtr>(&parent));
col[0] = ColourLine::create(outgoing[0]);
col[1] = ColourLine::create(outgoing[2]);
}
else if(colourFlow()==2) {
outgoing[2]->incomingColour (const_ptr_cast<tPPtr>(&parent));
col[0] = ColourLine::create(outgoing[0]);
col[1] = ColourLine::create(outgoing[1]);
}
else
assert(false);
parent.antiColourLine()->setSourceNeighbours(col[0],col[1]);
}
else if(antitriplet.size()==3) {
tColinePtr col[2];
if(colourFlow()==0) {
outgoing[0]->incomingAntiColour(const_ptr_cast<tPPtr>(&parent));
col[0] = ColourLine::create(outgoing[1],true);
col[1] = ColourLine::create(outgoing[2],true);
}
else if(colourFlow()==1) {
outgoing[1]->incomingAntiColour(const_ptr_cast<tPPtr>(&parent));
col[0] = ColourLine::create(outgoing[0],true);
col[1] = ColourLine::create(outgoing[2],true);
}
else if(colourFlow()==2) {
outgoing[2]->incomingAntiColour(const_ptr_cast<tPPtr>(&parent));
col[0] = ColourLine::create(outgoing[0],true);
col[1] = ColourLine::create(outgoing[1],true);
}
else
assert(false);
parent.colourLine()->setSinkNeighbours(col[0],col[1]);
}
else {
string mode = parent.PDGName() + " -> " + out[0]->PDGName() + " "
+ out[1]->PDGName() + " " + out[2]->PDGName();
throw Exception()
<< "Unknown colour structure in GeneralThreeBodyDecayer::"
<< "colourConnections() for octet decaying particle"
<< mode << Exception::runerror;
}
}
}
void GeneralThreeBodyDecayer::
constructIntegratorChannels(vector<int> & intype, vector<Energy> & inmass,
vector<Energy> & inwidth, vector<double> & inpow,
vector<double> & inweights) const {
// check if any intermediate photons
bool hasPhoton=false;
for(unsigned int iy=0;iy<diagmap_.size();++iy) {
unsigned int ix=diagmap_[iy];
if(getProcessInfo()[ix].intermediate->id()==ParticleID::gamma)
hasPhoton = true;
}
// loop over channels
Energy min = incoming()->mass();
int nchannel(0);
pair<int,Energy> imin[4]={make_pair(-1,-1.*GeV),make_pair(-1,-1.*GeV),
make_pair(-1,-1.*GeV),make_pair(-1,-1.*GeV)};
Energy absmin = -1e20*GeV;
int minType = -1;
for(unsigned int iy=0;iy<diagmap_.size();++iy) {
unsigned int ix=diagmap_[iy];
if(getProcessInfo()[ix].channelType==TBDiagram::fourPoint) continue;
Energy dm1(min-getProcessInfo()[ix].intermediate->mass());
Energy dm2(getProcessInfo()[ix].intermediate->mass());
int itype(0);
if (getProcessInfo()[ix].channelType==TBDiagram::channel23) {
dm1 -= outgoing()[0]->mass();
dm2 -= outgoing()[1]->mass()+outgoing()[2]->mass();
itype = 3;
}
else if(getProcessInfo()[ix].channelType==TBDiagram::channel13) {
dm1 -= outgoing()[1]->mass();
dm2 -= outgoing()[0]->mass()+outgoing()[2]->mass();
itype = 2;
}
else if(getProcessInfo()[ix].channelType==TBDiagram::channel12) {
dm1 -= outgoing()[2]->mass();
dm2 -= outgoing()[0]->mass()+outgoing()[1]->mass();
itype = 1;
}
if((dm1<ZERO||dm2<ZERO)&&!hasPhoton) {
if (imin[itype].first < 0 ||
(dm1<ZERO && imin[itype].second < dm1) ) {
imin[itype] = make_pair(ix,dm1);
if(dm1<ZERO&&absmin<dm1) {
absmin = dm1;
minType = itype;
}
}
continue;
}
if(getProcessInfo()[ix].intermediate->id()!=ParticleID::gamma) {
intype.push_back(itype);
inpow.push_back(0.);
inmass.push_back(getProcessInfo()[ix].intermediate->mass());
inwidth.push_back(widthOption() ==3 ? ZERO : getProcessInfo()[ix].intermediate->width());
++nchannel;
}
else if(getProcessInfo()[ix].intermediate->id()==ParticleID::gamma) {
intype.push_back(itype);
inpow.push_back(-2.);
inmass.push_back(-1.*GeV);
inwidth.push_back(-1.*GeV);
++nchannel;
}
}
// physical poles, use them and return
if(nchannel>0) {
inweights = vector<double>(nchannel,1./double(nchannel));
return;
}
// use shallowest pole
else if(intOpt_==1&&minType>0&&getProcessInfo()[imin[minType].first].intermediate->id()!=ParticleID::gamma) {
intype.push_back(minType);
inpow.push_back(0.);
inmass.push_back(getProcessInfo()[imin[minType].first].intermediate->mass());
inwidth.push_back(widthOption() ==3 ? ZERO : getProcessInfo()[imin[minType].first].intermediate->width());
inweights = vector<double>(1,1.);
return;
}
for(unsigned int ix=1;ix<4;++ix) {
if(imin[ix].first>=0) {
intype.push_back(ix);
if(getProcessInfo()[imin[ix].first].intermediate->id()!=ParticleID::gamma) {
inpow.push_back(0.);
inmass.push_back(getProcessInfo()[imin[ix].first].intermediate->mass());
inwidth.push_back(widthOption() ==3 ? ZERO : getProcessInfo()[imin[ix].first].intermediate->width());
}
else {
inpow.push_back(-2.);
inmass.push_back(-1.*GeV);
inwidth.push_back(-1.*GeV);
}
++nchannel;
}
}
inweights = vector<double>(nchannel,1./double(nchannel));
}
bool GeneralThreeBodyDecayer::setColourFactors(double symfac) {
string name = incoming_->PDGName() + "->";
vector<int> sng,trip,atrip,oct;
unsigned int iloc(0);
- for(vector<PDPtr>::const_iterator it = outgoing_.begin();
+ for(tPDVector::const_iterator it = outgoing_.begin();
it != outgoing_.end();++it) {
name += (**it).PDGName() + " ";
if ((**it).iColour() == PDT::Colour0 ) sng.push_back(iloc) ;
else if((**it).iColour() == PDT::Colour3 ) trip.push_back(iloc) ;
else if((**it).iColour() == PDT::Colour3bar ) atrip.push_back(iloc);
else if((**it).iColour() == PDT::Colour8 ) oct.push_back(iloc) ;
++iloc;
}
// colour neutral decaying particle
if ( incoming_->iColour() == PDT::Colour0) {
// options are all neutral or triplet/antitriplet+ neutral
if(sng.size()==3) {
nflow_ = 1;
colour_ = vector<DVector>(1,DVector(1,1.));
colourLargeNC_ = vector<DVector>(1,DVector(1,1.));
}
else if(sng.size()==1&&trip.size()==1&&atrip.size()==1) {
nflow_ = 1;
colour_ = vector<DVector>(1,DVector(1,3.));
colourLargeNC_ = vector<DVector>(1,DVector(1,3.));
}
else if(trip.size()==1&&atrip.size()==1&&oct.size()==1) {
nflow_ = 1;
colour_ = vector<DVector>(1,DVector(1,4.));
colourLargeNC_ = vector<DVector>(1,DVector(1,4.));
}
else if( trip.size() == 3 || atrip.size() == 3 ) {
nflow_ = 1;
colour_ = vector<DVector>(1,DVector(1,6.));
colourLargeNC_ = vector<DVector>(1,DVector(1,6.));
for(unsigned int ix=0;ix<diagrams_.size();++ix) {
double sign = diagrams_[ix].channelType == TBDiagram::channel13 ? -1. : 1.;
diagrams_[ix]. colourFlow = vector<CFPair>(1,make_pair(1,sign));
diagrams_[ix].largeNcColourFlow = vector<CFPair>(1,make_pair(1,sign));
}
}
else {
generator()->log() << "Unknown colour flow structure for "
<< "colour neutral decay "
<< name << " in GeneralThreeBodyDecayer::"
<< "setColourFactors(), omitting decay\n";
return false;
}
}
// colour triplet decaying particle
else if( incoming_->iColour() == PDT::Colour3) {
if(sng.size()==2&&trip.size()==1) {
nflow_ = 1;
colour_ = vector<DVector>(1,DVector(1,1.));
colourLargeNC_ = vector<DVector>(1,DVector(1,1.));
}
else if(trip.size()==2&&atrip.size()==1) {
nflow_ = 2;
colour_.clear();
colour_.resize(2,DVector(2,0.));
colour_[0][0] = 3.; colour_[0][1] = 1.;
colour_[1][0] = 1.; colour_[1][1] = 3.;
colourLargeNC_.clear();
colourLargeNC_.resize(2,DVector(2,0.));
colourLargeNC_[0][0] = 3.; colourLargeNC_[1][1] = 3.;
// sort out the contribution of the different diagrams to the colour
// flows
for(unsigned int ix=0;ix<diagrams_.size();++ix) {
// colour singlet intermediate
if(diagrams_[ix].intermediate->iColour()==PDT::Colour0) {
if(diagrams_[ix].channelType==trip[0]) {
diagrams_[ix]. colourFlow = vector<CFPair>(1,make_pair(1,1.));
diagrams_[ix].largeNcColourFlow = vector<CFPair>(1,make_pair(1,1.));
}
else {
diagrams_[ix].colourFlow = vector<CFPair>(1,make_pair(2,1.));
diagrams_[ix].largeNcColourFlow = vector<CFPair>(1,make_pair(2,1.));
}
}
// colour octet intermediate
else if(diagrams_[ix].intermediate->iColour()==PDT::Colour8) {
if(diagrams_[ix].channelType==trip[0]) {
vector<CFPair> flow(1,make_pair(2, 0.5 ));
diagrams_[ix].largeNcColourFlow = flow;
flow.push_back( make_pair(1,-1./6.));
diagrams_[ix].colourFlow=flow;
}
else {
vector<CFPair> flow(1,make_pair(1, 0.5 ));
diagrams_[ix].largeNcColourFlow = flow;
flow.push_back( make_pair(2,-1./6.));
diagrams_[ix].colourFlow=flow;
}
}
else {
generator()->log() << "Unknown colour for the intermediate in "
<< "triplet -> triplet triplet antitriplet in "
<< "GeneralThreeBodyDecayer::setColourFactors()"
<< " for " << name << " omitting decay\n";
return false;
}
}
}
else if(trip.size()==1&&oct.size()==1&&sng.size()==1) {
nflow_ = 1;
colour_ = vector<DVector>(1,DVector(1,4./3.));
colourLargeNC_ = vector<DVector>(1,DVector(1,4./3.));
}
else if(sng.size()==1&&atrip.size()==2) {
nflow_ = 1;
colour_ = vector<DVector>(1,DVector(1,2.));
colourLargeNC_ = vector<DVector>(1,DVector(1,2.));
}
else {
generator()->log() << "Unknown colour structure for "
<< "triplet decay in "
<< "GeneralThreeBodyDecayer::setColourFactors()"
<< " for " << name << " omitting decay\n";
return false;
}
}
// colour antitriplet decaying particle
else if( incoming_->iColour() == PDT::Colour3bar) {
if(sng.size()==2&&atrip.size()==1) {
nflow_ = 1;
colour_ = vector<DVector>(1,DVector(1,1.));
colourLargeNC_ = vector<DVector>(1,DVector(1,1.));
}
else if(atrip.size()==2&&trip.size()==1) {
nflow_ = 2;
colour_.clear();
colour_.resize(2,DVector(2,0.));
colour_[0][0] = 3.; colour_[0][1] = 1.;
colour_[1][0] = 1.; colour_[1][1] = 3.;
colourLargeNC_.clear();
colourLargeNC_.resize(2,DVector(2,0.));
colourLargeNC_[0][0] = 3.; colourLargeNC_[1][1] = 3.;
// sort out the contribution of the different diagrams to the colour
// flows
for(unsigned int ix=0;ix<diagrams_.size();++ix) {
// colour singlet intermediate
if(diagrams_[ix].intermediate->iColour()==PDT::Colour0) {
if(diagrams_[ix].channelType==atrip[0]) {
diagrams_[ix]. colourFlow = vector<CFPair>(1,make_pair(1,1.));
diagrams_[ix].largeNcColourFlow = vector<CFPair>(1,make_pair(1,1.));
}
else {
diagrams_[ix].colourFlow = vector<CFPair>(1,make_pair(2,1.));
diagrams_[ix].largeNcColourFlow = vector<CFPair>(1,make_pair(2,1.));
}
}
// colour octet intermediate
else if(diagrams_[ix].intermediate->iColour()==PDT::Colour8) {
if(diagrams_[ix].channelType==atrip[0]) {
vector<CFPair> flow(1,make_pair(2, 0.5 ));
diagrams_[ix].largeNcColourFlow = flow;
flow.push_back( make_pair(1,-1./6.));
diagrams_[ix].colourFlow=flow;
}
else {
vector<CFPair> flow(1,make_pair(1, 0.5 ));
diagrams_[ix].largeNcColourFlow = flow;
flow.push_back( make_pair(2,-1./6.));
diagrams_[ix].colourFlow=flow;
}
}
else {
generator()->log() << "Unknown colour for the intermediate in "
<< "antitriplet -> antitriplet antitriplet triplet in "
<< "GeneralThreeBodyDecayer::setColourFactors()"
<< " for " << name << " omitting decay\n";
return false;
}
}
}
else if(atrip.size()==1&&oct.size()==1&&sng.size()==1) {
nflow_ = 1;
colour_ = vector<DVector>(1,DVector(1,4./3.));
colourLargeNC_ = vector<DVector>(1,DVector(1,4./3.));
}
else if(sng.size()==1&&trip.size()==2) {
nflow_ = 1;
colour_ = vector<DVector>(1,DVector(1,2.));
colourLargeNC_ = vector<DVector>(1,DVector(1,2.));
}
else {
generator()->log() << "Unknown colour antitriplet decay in "
<< "GeneralThreeBodyDecayer::setColourFactors()"
<< " for " << name << " omitting decay\n";
return false;
}
}
// colour octet particle
else if( incoming_->iColour() == PDT::Colour8) {
// triplet antitriplet
if(trip.size() == 1 && atrip.size() == 1 && sng.size() == 1) {
nflow_ = 1;
colour_ = vector<DVector>(1,DVector(1,0.5));
colourLargeNC_ = vector<DVector>(1,DVector(1,0.5));
}
// three (anti)triplets
else if(trip.size()==3||atrip.size()==3) {
nflow_ = 3;
colour_ = vector<DVector>(3,DVector(3,0.));
colourLargeNC_ = vector<DVector>(3,DVector(3,0.));
colour_[0][0] = 1.; colour_[1][1] = 1.; colour_[2][2] = 1.;
colour_[0][1] = -0.5; colour_[1][0] = -0.5;
colour_[0][2] = -0.5; colour_[2][0] = -0.5;
colour_[1][2] = -0.5; colour_[2][1] = -0.5;
colourLargeNC_ = vector<DVector>(3,DVector(3,0.));
colourLargeNC_[0][0] = 1.; colourLargeNC_[1][1] = 1.; colourLargeNC_[2][2] = 1.;
// sett the factors for the diagrams
for(unsigned int ix=0;ix<diagrams_.size();++ix) {
tPDPtr inter = diagrams_[ix].intermediate;
if(inter->CC()) inter = inter->CC();
unsigned int io[2]={1,2};
double sign = diagrams_[ix].channelType == TBDiagram::channel13 ? -1. : 1.;
for(unsigned int iy=0;iy<3;++iy) {
if (iy==1) io[0]=0;
else if(iy==2) io[1]=1;
tPDVector decaylist = diagrams_[ix].vertices.second->search(iy, inter);
if(decaylist.empty()) continue;
bool found=false;
for(unsigned int iz=0;iz<decaylist.size();iz+=3) {
if(decaylist[iz+io[0]]->id()==diagrams_[ix].outgoingPair.first &&
decaylist[iz+io[1]]->id()==diagrams_[ix].outgoingPair.second) {
sign *= 1.;
found = true;
}
else if(decaylist[iz+io[0]]->id()==diagrams_[ix].outgoingPair.second &&
decaylist[iz+io[1]]->id()==diagrams_[ix].outgoingPair.first ) {
sign *= -1.;
found = true;
}
}
if(found) {
if(iy==1) sign *=-1.;
break;
}
}
diagrams_[ix]. colourFlow = vector<CFPair>(1,make_pair(diagrams_[ix].channelType+1,sign));
diagrams_[ix].largeNcColourFlow = vector<CFPair>(1,make_pair(diagrams_[ix].channelType+1,sign));
}
}
// unknown
else {
generator()->log() << "Unknown colour octet decay in "
<< "GeneralThreeBodyDecayer::setColourFactors()"
<< " for " << name << " omitting decay\n";
return false;
}
}
else if (incoming_->iColour() == PDT::Colour6 ) {
generator()->log() << "Unknown colour sextet decay in "
<< "GeneralThreeBodyDecayer::setColourFactors()"
<< " for " << name << " omitting decay\n";
return false;
}
else if (incoming_->iColour() == PDT::Colour6bar ) {
generator()->log() << "Unknown colour anti-sextet decay in "
<< "GeneralThreeBodyDecayer::setColourFactors()"
<< " for " << name << " omitting decay\n";
return false;
}
assert(nflow_ != 999);
for(unsigned int ix=0;ix<nflow_;++ix) {
for(unsigned int iy=0;iy<nflow_;++iy) {
colour_ [ix][iy] /= symfac;
colourLargeNC_[ix][iy] /= symfac;
}
}
if( Debug::level > 1 ) {
generator()->log() << "Mode: " << name << " has colour factors\n";
for(unsigned int ix=0;ix<nflow_;++ix) {
for(unsigned int iy=0;iy<nflow_;++iy) {
generator()->log() << colour_[ix][iy] << " ";
}
generator()->log() << "\n";
}
for(unsigned int ix=0;ix<diagrams_.size();++ix) {
generator()->log() << "colour flow for diagram : " << ix;
for(unsigned int iy=0;iy<diagrams_[ix].colourFlow.size();++iy)
generator()->log() << "(" << diagrams_[ix].colourFlow[iy].first << ","
<< diagrams_[ix].colourFlow[iy].second << "); ";
generator()->log() << "\n";
}
}
return true;
}
diff --git a/Decay/General/GeneralThreeBodyDecayer.h b/Decay/General/GeneralThreeBodyDecayer.h
--- a/Decay/General/GeneralThreeBodyDecayer.h
+++ b/Decay/General/GeneralThreeBodyDecayer.h
@@ -1,321 +1,321 @@
// -*- C++ -*-
#ifndef HERWIG_GeneralThreeBodyDecayer_H
#define HERWIG_GeneralThreeBodyDecayer_H
//
// This is the declaration of the GeneralThreeBodyDecayer class.
//
-#include "Herwig/Decay/DecayIntegrator.h"
+#include "Herwig/Decay/DecayIntegrator2.h"
#include "Herwig/Models/General/TBDiagram.h"
#include "GeneralThreeBodyDecayer.fh"
namespace Herwig {
using namespace ThePEG;
/**
* Here is the documentation of the GeneralThreeBodyDecayer class.
*
* @see \ref GeneralThreeBodyDecayerInterfaces "The interfaces"
* defined for GeneralThreeBodyDecayer.
*/
-class GeneralThreeBodyDecayer: public DecayIntegrator {
+class GeneralThreeBodyDecayer: public DecayIntegrator2 {
public:
/** A ParticleData ptr and (possible) mass pair.*/
typedef pair<tcPDPtr, Energy> PMPair;
public:
/**
* The default constructor.
*/
GeneralThreeBodyDecayer() : nflow_(999), widthOpt_(1),
refTag_(), refTagCC_(), iflow_(999),
intOpt_(0), relerr_(1e-2)
{}
/** @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;
/**
* The matrix element to be integrated for the three-body decays as a function
* of the invariant masses of pairs of the outgoing particles.
* @param imode The mode for which the matrix element is needed.
* @param q2 The scale, \e i.e. the mass squared of the decaying particle.
* @param s3 The invariant mass squared of particles 1 and 2, \f$s_3=m^2_{12}\f$.
* @param s2 The invariant mass squared of particles 1 and 3, \f$s_2=m^2_{13}\f$.
* @param s1 The invariant mass squared of particles 2 and 3, \f$s_1=m^2_{23}\f$.
* @param m1 The mass of the first outgoing particle.
* @param m2 The mass of the second outgoing particle.
* @param m3 The mass of the third outgoing particle.
* @return The matrix element
*/
virtual double threeBodyMatrixElement(const int imode, const Energy2 q2,
const Energy2 s3, const Energy2 s2,
const Energy2 s1, const Energy m1,
const Energy m2, const Energy m3) const;
/**
* Function to return partial Width
* @param inpart The decaying particle.
* @param outa First decay product.
* @param outb Second decay product.
* @param outc Third decay product.
*/
virtual Energy partialWidth(PMPair inpart, PMPair outa,
PMPair outb, PMPair outc) 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 diagrams
*/
bool setDecayInfo(PDPtr incoming,vector<PDPtr> outgoing,
const vector<TBDiagram> & process,
double symfac);
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
//@}
protected:
/**
* Access the TBDiagrams that store the required information
* to create the diagrams
*/
const vector<TBDiagram> & getProcessInfo() const {
return diagrams_;
}
/**
* Incoming particle
*/
PDPtr incoming() const { return incoming_; }
/**
* Outgoing particles
*/
- const vector<PDPtr> & outgoing() const { return outgoing_; }
+ const vector<tPDPtr> & outgoing() const { return outgoing_; }
/**
* Number of colour flows
*/
unsigned int numberOfFlows() const { return nflow_; }
/**
* Set up the colour factors
*/
bool setColourFactors(double symfac);
/**
* Return the matrix of colour factors
*/
const vector<DVector> & getColourFactors() const { return colour_; }
/**
* Return the matrix of colour factors
*/
const vector<DVector> & getLargeNcColourFactors() const {
return colourLargeNC_;
}
/**
* Get the mapping between the phase-space channel and the diagram
*/
const vector<unsigned int> & diagramMap() const {
return diagmap_;
}
/**
* Option for the handling of the widths of the intermediate particles
*/
unsigned int widthOption() const { return widthOpt_; }
/**
* 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;
/**
* Method to construct the channels for the integrator to give the partial width
* @param intype Types of the channels
* @param inmass Mass for the channels
* @param inwidth Width for the channels
* @param inpow Power for the channels
* @param inweights Weights for the channels
*/
void constructIntegratorChannels(vector<int> & intype, vector<Energy> & inmass,
vector<Energy> & inwidth, vector<double> & inpow,
vector<double> & inweights) const;
/**
* Set the colour flow
* @param flow The value for the colour flow
*/
void colourFlow(unsigned int flow) const { iflow_ = flow; }
/**
* Set the colour flow
*/
unsigned int const & colourFlow() const { return iflow_; }
/**
* Relative error for GQ integration
*/
double relativeError() const {return relerr_;}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
GeneralThreeBodyDecayer & operator=(const GeneralThreeBodyDecayer &);
private:
/**
* Store the incoming particle
*/
PDPtr incoming_;
/**
* Outgoing particles
*/
- vector<PDPtr> outgoing_;
+ vector<tPDPtr> outgoing_;
/**
* Store the diagrams for the decay
*/
vector<TBDiagram> diagrams_;
/**
* Map between the diagrams and the phase-space channels
*/
vector<unsigned int> diagmap_;
/**
* Store colour factors for ME calc.
*/
vector<DVector> colour_;
/**
* Store cololur factors for ME calc at large N_c
*/
vector<DVector> colourLargeNC_;
/**
* The number of colourflows.
*/
unsigned int nflow_;
/**
* Reference to object to calculate the partial width
*/
mutable WidthCalculatorBasePtr widthCalc_;
/**
* Option for the treatment of the widths
*/
unsigned int widthOpt_;
/**
* Store a decay tag for this mode that can be tested when
* trying to determine whether it can be generated by
* this Decayer
*/
string refTag_;
/**
* Store a decay tag for the cc-mode that can be tested when
* trying to determine whether it can be generated by
* this Decayer
*/
string refTagCC_;
/**
* The colour flow
*/
mutable unsigned int iflow_;
/**
* Option for the construction of the gaussian integrator
*/
unsigned int intOpt_;
/**
* Relative error for GQ integration of partial width
*/
double relerr_;
};
}
#endif /* HERWIG_GeneralThreeBodyDecayer_H */
diff --git a/Decay/General/SFFDecayer.h b/Decay/General/SFFDecayer.h
--- a/Decay/General/SFFDecayer.h
+++ b/Decay/General/SFFDecayer.h
@@ -1,241 +1,236 @@
// -*- 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() {}
/**
* 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 outgoing The particles produced in the decay
* @param momenta The momenta of 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.
*/
double me2(const int ichan,const Particle & part,
const tPDVector & outgoing,
const vector<Lorentz5Momentum> & momenta,
MEOption meopt) const;
/**
* Construct the SpinInfos for the particles produced in the decay
*/
virtual void constructSpinInfo(const Particle & part,
ParticleVector outgoing) 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() {
POWHEGType output = FSR;
for(auto vertex : vertex_) {
if(vertex->orderInAllCouplings()!=1) {
output = No;
break;
}
}
return output;
}
/**
* Three-body matrix element including additional QCD radiation
*/
virtual double threeBodyME(const int , const Particle & inpart,
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 & outgoingVertexF,
AbstractFFVVertexPtr & outgoingVertexA,
ShowerInteraction inter);
/**
* Set the information on the decay
*/
virtual void setDecayInfo(PDPtr incoming, PDPair outgoing,
vector<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;
//@}
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
*/
vector<AbstractFFSVertexPtr> vertex_;
/**
* Pointer to the perturbative vertex
*/
vector<FFSVertexPtr> perturbativeVertex_;
/**
* Abstract pointer to AbstractVSSVertex for QCD radiation from incoming scalar
*/
map<ShowerInteraction,AbstractVSSVertexPtr> incomingVertex_;
/**
* Abstract pointer to AbstractFFVVertex for QCD radiation from outgoing (anti)fermion
*/
map<ShowerInteraction,AbstractFFVVertexPtr> outgoingVertex1_;
/**
* Abstract pointer to AbstractFFVVertex for QCD radiation from outgoing (anti)fermion
*/
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/StoFFVDecayer.cc b/Decay/General/StoFFVDecayer.cc
--- a/Decay/General/StoFFVDecayer.cc
+++ b/Decay/General/StoFFVDecayer.cc
@@ -1,389 +1,393 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the StoFFVDecayer class.
//
#include "StoFFVDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/PDT/ThreeBodyAllOnCalculator.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
#include <numeric>
using namespace Herwig;
using namespace ThePEG;
using namespace ThePEG::Helicity;
IBPtr StoFFVDecayer::clone() const {
return new_ptr(*this);
}
IBPtr StoFFVDecayer::fullclone() const {
return new_ptr(*this);
}
void StoFFVDecayer::persistentOutput(PersistentOStream & os) const {
os << sca_ << fer_ << vec_ << RSfer_ << four_;
}
void StoFFVDecayer::persistentInput(PersistentIStream & is, int) {
is >> sca_ >> fer_ >> vec_ >> RSfer_ >> four_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<StoFFVDecayer,GeneralThreeBodyDecayer>
describeHerwigStoFFVDecayer("Herwig::StoFFVDecayer", "Herwig.so");
void StoFFVDecayer::Init() {
static ClassDocumentation<StoFFVDecayer> documentation
("The StoFFVDecayer class implements the general decay of a scalar to "
"a two fermions and a vector.");
}
WidthCalculatorBasePtr StoFFVDecayer::
threeBodyMEIntegrator(const DecayMode & ) const {
vector<int> intype;
vector<Energy> inmass,inwidth;
vector<double> inpow,inweights;
constructIntegratorChannels(intype,inmass,inwidth,inpow,inweights);
return new_ptr(ThreeBodyAllOnCalculator<StoFFVDecayer>
(inweights,intype,inmass,inwidth,inpow,*this,0,
outgoing()[0]->mass(),outgoing()[1]->mass(),
outgoing()[2]->mass(),relativeError()));
}
void StoFFVDecayer::doinit() {
GeneralThreeBodyDecayer::doinit();
if(outgoing().empty()) return;
unsigned int ndiags = getProcessInfo().size();
sca_.resize(ndiags);
fer_.resize(ndiags);
RSfer_.resize(ndiags);
vec_.resize(ndiags);
four_.resize(ndiags);
for(unsigned int ix = 0;ix < ndiags; ++ix) {
TBDiagram current = getProcessInfo()[ix];
tcPDPtr offshell = current.intermediate;
// four point vertex
if(!offshell) {
four_[ix] = dynamic_ptr_cast<AbstractFFVSVertexPtr>(current.vertices.first);
continue;
}
if( offshell->CC() ) offshell = offshell->CC();
if(offshell->iSpin() == PDT::Spin0) {
AbstractVSSVertexPtr vert1 = dynamic_ptr_cast<AbstractVSSVertexPtr>
(current.vertices.first);
AbstractFFSVertexPtr vert2 = dynamic_ptr_cast<AbstractFFSVertexPtr>
(current.vertices.second);
if(!vert1||!vert2) throw Exception()
<< "Invalid vertices for a scalar diagram in StoFFVDecayer::doinit()"
<< Exception::runerror;
sca_[ix] = make_pair(vert1, vert2);
}
else if(offshell->iSpin() == PDT::Spin1Half) {
AbstractFFSVertexPtr vert1 = dynamic_ptr_cast<AbstractFFSVertexPtr>
(current.vertices.first);
AbstractFFVVertexPtr vert2 = dynamic_ptr_cast<AbstractFFVVertexPtr>
(current.vertices.second);
if(!vert1||!vert2) throw Exception()
<< "Invalid vertices for a fermion diagram in StoFFVDecayer::doinit()"
<< Exception::runerror;
fer_[ix] = make_pair(vert1, vert2);
}
else if(offshell->iSpin() == PDT::Spin1) {
AbstractVVSVertexPtr vert1 = dynamic_ptr_cast<AbstractVVSVertexPtr>
(current.vertices.first);
AbstractFFVVertexPtr vert2 = dynamic_ptr_cast<AbstractFFVVertexPtr>
(current.vertices.second);
if(!vert1||!vert2) throw Exception()
<< "Invalid vertices for a vector diagram in StoFFVDecayer::doinit()"
<< Exception::runerror;
vec_[ix] = make_pair(vert1, vert2);
}
else if(offshell->iSpin() == PDT::Spin3Half) {
AbstractRFSVertexPtr vert1 = dynamic_ptr_cast<AbstractRFSVertexPtr>
(current.vertices.first);
AbstractRFVVertexPtr vert2 = dynamic_ptr_cast<AbstractRFVVertexPtr>
(current.vertices.second);
if(!vert1||!vert2) throw Exception()
<< "Invalid vertices for a RS fermion diagram in StoFFVDecayer::doinit()"
<< Exception::runerror;
RSfer_[ix] = make_pair(vert1, vert2);
}
}
}
-double StoFFVDecayer::me2(const int ichan, const Particle & inpart,
- const ParticleVector & decay, MEOption meopt) const {
+void StoFFVDecayer::
+constructSpinInfo(const Particle & part, ParticleVector decay) const {
+ ScalarWaveFunction::
+ constructSpinInfo(const_ptr_cast<tPPtr>(&part),
+ Helicity::incoming,true);
+ for(unsigned int ix=0;ix<decay.size();++ix) {
+ if(decay[ix]->dataPtr()->iSpin()==PDT::Spin1) {
+ VectorWaveFunction::constructSpinInfo(outVector_,decay[ix],
+ Helicity::outgoing,true,false);
+ }
+ else {
+ SpinorWaveFunction::
+ constructSpinInfo(outspin_[ix].first,decay[ix],Helicity::outgoing,true);
+ }
+ }
+}
+
+double StoFFVDecayer::me2(const int ichan, const Particle & part,
+ const tPDVector & outgoing,
+ const vector<Lorentz5Momentum> & momenta,
+ MEOption meopt) const {
// particle or CC of particle
- bool cc = (*getProcessInfo().begin()).incoming != inpart.id();
+ bool cc = (*getProcessInfo().begin()).incoming != part.id();
// special handling or first/last call
if(meopt==Initialize) {
ScalarWaveFunction::
- calculateWaveFunctions(rho_,const_ptr_cast<tPPtr>(&inpart),
+ calculateWaveFunctions(rho_,const_ptr_cast<tPPtr>(&part),
Helicity::incoming);
- swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),
+ swave_ = ScalarWaveFunction(part.momentum(),part.dataPtr(),
Helicity::incoming);
// fix rho if no correlations
fixRho(rho_);
}
- if(meopt==Terminate) {
- ScalarWaveFunction::
- constructSpinInfo(const_ptr_cast<tPPtr>(&inpart),
- Helicity::incoming,true);
- for(unsigned int ix=0;ix<decay.size();++ix) {
- if(decay[ix]->dataPtr()->iSpin()==PDT::Spin1) {
- VectorWaveFunction::constructSpinInfo(outVector_,decay[ix],
- Helicity::outgoing,true,false);
- }
- else {
- SpinorWaveFunction::
- constructSpinInfo(outspin_[ix].first,decay[ix],Helicity::outgoing,true);
- }
- }
- }
unsigned int ivec(0);
bool massless(false);
- for(unsigned int ix = 0; ix < decay.size();++ix) {
- if(decay[ix]->dataPtr()->iSpin() == PDT::Spin1) {
+ for(unsigned int ix = 0; ix < outgoing.size();++ix) {
+ if(outgoing[ix]->iSpin() == PDT::Spin1) {
ivec = ix;
- massless = decay[ivec]->mass()==ZERO;
+ massless = outgoing[ivec]->mass()==ZERO;
VectorWaveFunction::
- calculateWaveFunctions(outVector_, decay[ix], Helicity::outgoing,massless);
+ calculateWaveFunctions(outVector_, momenta[ix],outgoing[ix], Helicity::outgoing,massless);
}
else {
SpinorWaveFunction::
- calculateWaveFunctions(outspin_[ix].first,decay[ix],Helicity::outgoing);
+ calculateWaveFunctions(outspin_[ix].first,momenta[ix],outgoing[ix],Helicity::outgoing);
outspin_[ix].second.resize(2);
// Need a ubar and a v spinor
if(outspin_[ix].first[0].wave().Type() == SpinorType::u) {
for(unsigned int iy = 0; iy < 2; ++iy) {
outspin_[ix].second[iy] = outspin_[ix].first[iy].bar();
outspin_[ix].first[iy].conjugate();
}
}
else {
for(unsigned int iy = 0; iy < 2; ++iy) {
outspin_[ix].second[iy] = outspin_[ix].first[iy].bar();
outspin_[ix].second[iy].conjugate();
}
}
}
}
const vector<vector<double> > cfactors(getColourFactors());
const vector<vector<double> > nfactors(getLargeNcColourFactors());
- Energy2 scale(sqr(inpart.mass()));
+ Energy2 scale(sqr(part.mass()));
const size_t ncf(numberOfFlows());
vector<Complex> flows(ncf, Complex(0.)), largeflows(ncf, Complex(0.));
// setup the DecayMatrixElement
vector<GeneralDecayMEPtr>
mes(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin0,
ivec == 0 ? PDT::Spin1 : PDT::Spin1Half,
ivec == 1 ? PDT::Spin1 : PDT::Spin1Half,
ivec == 2 ? PDT::Spin1 : PDT::Spin1Half)));
vector<GeneralDecayMEPtr>
mel(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin0,
ivec == 0 ? PDT::Spin1 : PDT::Spin1Half,
ivec == 1 ? PDT::Spin1 : PDT::Spin1Half,
ivec == 2 ? PDT::Spin1 : PDT::Spin1Half)));
//the channel possiblities
static const unsigned int out2[3] = {1,0,0}, out3[3] = {2,2,1};
for(unsigned int s1 = 0; s1 < 2; ++s1) {
for(unsigned int s2 = 0; s2 < 2; ++s2) {
for(unsigned int v1 = 0; v1 < 3; ++v1) {
if(massless&&v1==1) ++v1;
flows = vector<Complex>(ncf, Complex(0.));
largeflows = vector<Complex>(ncf, Complex(0.));
unsigned int idiag(0);
Complex diag;
for(vector<TBDiagram>::const_iterator dit=getProcessInfo().begin();
dit!=getProcessInfo().end();++dit) {
// channels if selecting
if( ichan >= 0 && diagramMap()[ichan] != idiag ) {
++idiag;
continue;
}
tcPDPtr offshell = dit->intermediate;
if(offshell) {
if(cc&&offshell->CC()) offshell=offshell->CC();
unsigned int o2(out2[dit->channelType]), o3(out3[dit->channelType]);
double sign = (o3 < o2) ? 1. : -1.;
// intermediate scalar
if(offshell->iSpin() == PDT::Spin0) {
ScalarWaveFunction inters = sca_[idiag].first->
evaluate(scale, widthOption(), offshell, outVector_[v1], swave_);
unsigned int h1(s1),h2(s2);
if(o2 > o3) swap(h1, h2);
- if(decay[o2]->id() < 0 && decay[o3]->id() > 0) {
+ if(outgoing[o2]->id() < 0 && outgoing[o3]->id() > 0) {
diag = -sign*sca_[idiag].second->
evaluate(scale,outspin_[o2].first[h1],
outspin_[o3].second[h2],inters);
}
else {
diag = sign*sca_[idiag].second->
evaluate(scale, outspin_[o3].first [h2],
outspin_[o2].second[h1],inters);
}
}
// intermediate fermion
else if(offshell->iSpin() == PDT::Spin1Half) {
- int iferm = (decay[o2]->dataPtr()->iSpin() == PDT::Spin1Half)
+ int iferm = (outgoing[o2]->iSpin() == PDT::Spin1Half)
? o2 : o3;
unsigned int h1(s1),h2(s2);
if(dit->channelType > iferm) swap(h1, h2);
sign = iferm < dit->channelType ? 1. : -1.;
- if((decay[dit->channelType]->id() < 0 && decay[iferm]->id() > 0 ) ||
- (decay[dit->channelType]->id()*offshell->id()>0)) {
+ if((outgoing[dit->channelType]->id() < 0 && outgoing[iferm]->id() > 0 ) ||
+ (outgoing[dit->channelType]->id()*offshell->id()>0)) {
SpinorWaveFunction inters = fer_[idiag].first->
evaluate(scale,widthOption(),offshell,
outspin_[dit->channelType].first[h1], swave_);
diag = -sign*fer_[idiag].second->
evaluate(scale,inters,outspin_[iferm].second[h2], outVector_[v1]);
}
else {
SpinorBarWaveFunction inters = fer_[idiag].first->
evaluate(scale,widthOption(),offshell,
outspin_[dit->channelType].second[h1],swave_);
diag = sign*fer_[idiag].second->
evaluate(scale,outspin_[iferm].first [h2],inters, outVector_[v1]);
}
}
// intermediate vector
else if(offshell->iSpin() == PDT::Spin1) {
VectorWaveFunction interv = vec_[idiag].first->
evaluate(scale, widthOption(), offshell, outVector_[v1], swave_);
unsigned int h1(s1),h2(s2);
if(o2 > o3) swap(h1,h2);
- if(decay[o2]->id() < 0 && decay[o3]->id() > 0) {
+ if(outgoing[o2]->id() < 0 && outgoing[o3]->id() > 0) {
diag =-sign*vec_[idiag].second->
evaluate(scale, outspin_[o2].first[h1],
outspin_[o3].second[h2], interv);
}
else {
diag = sign*vec_[idiag].second->
evaluate(scale, outspin_[o3].first[h2],
outspin_[o2].second[h1], interv);
}
}
// intermediate RS fermion
else if(offshell->iSpin() == PDT::Spin3Half) {
- int iferm = (decay[o2]->dataPtr()->iSpin() == PDT::Spin1Half)
+ int iferm = (outgoing[o2]->iSpin() == PDT::Spin1Half)
? o2 : o3;
unsigned int h1(s1),h2(s2);
if(dit->channelType > iferm) swap(h1, h2);
sign = iferm < dit->channelType ? 1. : -1.;
- if((decay[dit->channelType]->id() < 0 && decay[iferm]->id() > 0 ) ||
- (decay[dit->channelType]->id()*offshell->id()>0)) {
+ if((outgoing[dit->channelType]->id() < 0 && outgoing[iferm]->id() > 0 ) ||
+ (outgoing[dit->channelType]->id()*offshell->id()>0)) {
RSSpinorWaveFunction inters = RSfer_[idiag].first->
evaluate(scale,widthOption(),offshell,
outspin_[dit->channelType].first[h1], swave_);
diag = -sign*RSfer_[idiag].second->
evaluate(scale,inters,outspin_[iferm].second[h2], outVector_[v1]);
}
else {
RSSpinorBarWaveFunction inters = RSfer_[idiag].first->
evaluate(scale,widthOption(),offshell,
outspin_[dit->channelType].second[h1],swave_);
diag = sign*RSfer_[idiag].second->
evaluate(scale,outspin_[iferm].first [h2],inters, outVector_[v1]);
}
}
// unknown
else throw Exception()
<< "Unknown intermediate in StoFFVDecayer::me2()"
<< Exception::runerror;
}
else {
unsigned int o2 = ivec > 0 ? 0 : 1;
unsigned int o3 = ivec < 2 ? 2 : 1;
- if(decay[o2]->id() < 0 && decay[o3]->id() > 0) {
+ if(outgoing[o2]->id() < 0 && outgoing[o3]->id() > 0) {
diag =-four_[idiag]->
evaluate(scale, outspin_[o2].first[s1],
outspin_[o3].second[s2], outVector_[v1], swave_);
}
else {
diag = four_[idiag]->
evaluate(scale, outspin_[o3].first[s2],
outspin_[o2].second[s1], outVector_[v1], swave_);
}
}
// matrix element for the different colour flows
if(ichan < 0) {
for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) {
flows[dit->colourFlow[iy].first - 1] +=
dit->colourFlow[iy].second * diag;
}
for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) {
largeflows[dit->largeNcColourFlow[iy].first - 1] +=
dit->largeNcColourFlow[iy].second * diag;
}
}
else {
for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) {
if(dit->colourFlow[iy].first - 1 != colourFlow()) continue;
flows[dit->colourFlow[iy].first - 1] +=
dit->colourFlow[iy].second * diag;
}
for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) {
if(dit->colourFlow[iy].first - 1!=colourFlow()) continue;
largeflows[dit->largeNcColourFlow[iy].first - 1] +=
dit->largeNcColourFlow[iy].second * diag;
}
}
++idiag;
} //end of diagrams
// now add the flows to the me2 with appropriate colour factors
for(unsigned int ix = 0; ix < ncf; ++ix) {
if ( ivec == 0 ) {
(*mes[ix])(0, v1, s1, s2) = flows[ix];
(*mel[ix])(0, v1, s1, s2) = largeflows[ix];
}
else if( ivec == 1 ) {
(*mes[ix])(0, s1, v1, s2) = flows[ix];
(*mel[ix])(0, s1, v1, s2) = largeflows[ix];
}
else if( ivec == 2 ) {
(*mes[ix])(0, s1, s2, v1) = flows[ix];
(*mel[ix])(0, s1, s2, v1) = largeflows[ix];
}
}
}
}
}
double me2(0.);
if(ichan < 0) {
vector<double> pflows(ncf,0.);
for(unsigned int ix = 0; ix < ncf; ++ix) {
for(unsigned int iy = 0; iy < ncf; ++ iy) {
double con = cfactors[ix][iy]*(mes[ix]->contract(*mes[iy],rho_)).real();
me2 += con;
if(ix == iy) {
con = nfactors[ix][iy]*(mel[ix]->contract(*mel[iy],rho_)).real();
pflows[ix] += con;
}
}
}
double ptotal(std::accumulate(pflows.begin(),pflows.end(),0.));
ptotal *= UseRandom::rnd();
for(unsigned int ix = 0;ix < pflows.size(); ++ix) {
if(ptotal <= pflows[ix]) {
colourFlow(ix);
ME(mes[ix]);
break;
}
ptotal -= pflows[ix];
}
}
else {
unsigned int iflow = colourFlow();
me2 = nfactors[iflow][iflow]*(mel[iflow]->contract(*mel[iflow],rho_)).real();
}
// return the matrix element squared
return me2;
}
diff --git a/Decay/General/StoFFVDecayer.h b/Decay/General/StoFFVDecayer.h
--- a/Decay/General/StoFFVDecayer.h
+++ b/Decay/General/StoFFVDecayer.h
@@ -1,162 +1,171 @@
// -*- C++ -*-
#ifndef THEPEG_StoFFVDecayer_H
#define THEPEG_StoFFVDecayer_H
//
// This is the declaration of the StoFFVDecayer class.
//
#include "GeneralThreeBodyDecayer.h"
#include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVSSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractRFVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractRFSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVSVertex.h"
namespace Herwig {
using namespace ThePEG;
/**
* Here is the documentation of the StoFFVDecayer class.
*
* @see \ref StoFFVDecayerInterfaces "The interfaces"
* defined for StoFFVDecayer.
*/
class StoFFVDecayer: public GeneralThreeBodyDecayer {
public:
-
+
/**
- * Return the matrix element squared for a given mode and phase-space channel
- * @param ichan The channel we are calculating the matrix element for.
+ * 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 outgoing The particles produced in the decay
+ * @param momenta The momenta of 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;
+ double me2(const int ichan,const Particle & part,
+ const tPDVector & outgoing,
+ const vector<Lorentz5Momentum> & momenta,
+ MEOption meopt) const;
+
+ /**
+ * Construct the SpinInfos for the particles produced in the decay
+ */
+ virtual void constructSpinInfo(const Particle & part,
+ ParticleVector outgoing) const;
/**
* Method to return an object to calculate the 3 (or higher body) partial width
* @param dm The DecayMode
* @return A pointer to a WidthCalculatorBase object capable of
* calculating the width
*/
virtual WidthCalculatorBasePtr threeBodyMEIntegrator(const DecayMode & dm) const;
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.
*/
StoFFVDecayer & operator=(const StoFFVDecayer &);
private:
/**
* Store the vertices for fermion intrermediate
*/
vector<pair<AbstractFFSVertexPtr, AbstractFFVVertexPtr> > fer_;
/**
* Store the vertices for fermion intrermediate
*/
vector<pair<AbstractRFSVertexPtr, AbstractRFVVertexPtr> > RSfer_;
/**
* Store the vertices for scalar intrermediate
*/
vector<pair<AbstractVSSVertexPtr, AbstractFFSVertexPtr> > sca_;
/**
* Store the vertices for vector intrermediate
*/
vector<pair<AbstractVVSVertexPtr, AbstractFFVVertexPtr> > vec_;
/**
* Store the vertices for 4-point diagrams
*/
vector<AbstractFFVSVertexPtr> four_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Scalar wavefunction
*/
mutable ScalarWaveFunction swave_;
/**
* Vector wavefunction
*/
mutable vector<VectorWaveFunction> outVector_;
/**
* Spinor wavefunctions
*/
mutable pair<vector<SpinorWaveFunction>,vector<SpinorBarWaveFunction> > outspin_[3];
};
}
#endif /* THEPEG_StoFFVDecayer_H */
diff --git a/Decay/General/StoSFFDecayer.cc b/Decay/General/StoSFFDecayer.cc
--- a/Decay/General/StoSFFDecayer.cc
+++ b/Decay/General/StoSFFDecayer.cc
@@ -1,424 +1,425 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the StoSFFDecayer class.
//
#include "StoSFFDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/PDT/ThreeBodyAllOnCalculator.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
#include <numeric>
using namespace Herwig;
using namespace ThePEG;
using namespace ThePEG::Helicity;
IBPtr StoSFFDecayer::clone() const {
return new_ptr(*this);
}
IBPtr StoSFFDecayer::fullclone() const {
return new_ptr(*this);
}
void StoSFFDecayer::persistentOutput(PersistentOStream & os) const {
os << sca_ << fer_ << vec_ << ten_ << RSfer_ << four_;
}
void StoSFFDecayer::persistentInput(PersistentIStream & is, int) {
is >> sca_ >> fer_ >> vec_ >> ten_ >> RSfer_ >> four_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<StoSFFDecayer,GeneralThreeBodyDecayer>
describeHerwigStoSFFDecayer("Herwig::StoSFFDecayer", "Herwig.so");
void StoSFFDecayer::Init() {
static ClassDocumentation<StoSFFDecayer> documentation
("The StoSFFDecayer class implements the general decay of a scalar to "
"a scalar and two fermions.");
}
WidthCalculatorBasePtr StoSFFDecayer::
threeBodyMEIntegrator(const DecayMode & ) const {
vector<int> intype;
vector<Energy> inmass,inwidth;
vector<double> inpow,inweights;
constructIntegratorChannels(intype,inmass,inwidth,inpow,inweights);
return new_ptr(ThreeBodyAllOnCalculator<StoSFFDecayer>
(inweights,intype,inmass,inwidth,inpow,*this,0,
outgoing()[0]->mass(),outgoing()[1]->mass(),outgoing()[2]->mass(),
relativeError()));
}
void StoSFFDecayer::doinit() {
GeneralThreeBodyDecayer::doinit();
if(outgoing().empty()) return;
unsigned int ndiags = getProcessInfo().size();
sca_.resize(ndiags);
fer_.resize(ndiags);
RSfer_.resize(ndiags);
vec_.resize(ndiags);
ten_.resize(ndiags);
four_.resize(ndiags);
for(unsigned int ix = 0;ix < ndiags; ++ix) {
TBDiagram current = getProcessInfo()[ix];
tcPDPtr offshell = current.intermediate;
// four point vertex
if(!offshell) {
four_[ix] = dynamic_ptr_cast<AbstractFFSSVertexPtr>(current.vertices.first);
continue;
}
if( offshell->CC() ) offshell = offshell->CC();
if(offshell->iSpin() == PDT::Spin0) {
AbstractSSSVertexPtr vert1 = dynamic_ptr_cast<AbstractSSSVertexPtr>
(current.vertices.first);
AbstractFFSVertexPtr vert2 = dynamic_ptr_cast<AbstractFFSVertexPtr>
(current.vertices.second);
if(!vert1||!vert2) throw Exception()
<< "Invalid vertices for a scalar diagram in StoSFFDecayer::doinit()"
<< Exception::runerror;
sca_[ix] = make_pair(vert1, vert2);
}
else if(offshell->iSpin() == PDT::Spin1Half) {
AbstractFFSVertexPtr vert1 = dynamic_ptr_cast<AbstractFFSVertexPtr>
(current.vertices.first);
AbstractFFSVertexPtr vert2 = dynamic_ptr_cast<AbstractFFSVertexPtr>
(current.vertices.second);
if(!vert1||!vert2) throw Exception()
<< "Invalid vertices for a fermion diagram in StoSFFDecayer::doinit()"
<< Exception::runerror;
fer_[ix] = make_pair(vert1, vert2);
}
else if(offshell->iSpin() == PDT::Spin1) {
AbstractVSSVertexPtr vert1 = dynamic_ptr_cast<AbstractVSSVertexPtr>
(current.vertices.first);
AbstractFFVVertexPtr vert2 = dynamic_ptr_cast<AbstractFFVVertexPtr>
(current.vertices.second);
if(!vert1||!vert2) throw Exception()
<< "Invalid vertices for a vector diagram in StoSFFDecayer::doinit()"
<< Exception::runerror;
vec_[ix] = make_pair(vert1, vert2);
}
else if(offshell->iSpin() == PDT::Spin2) {
AbstractSSTVertexPtr vert1 = dynamic_ptr_cast<AbstractSSTVertexPtr>
(current.vertices.first);
AbstractFFTVertexPtr vert2 = dynamic_ptr_cast<AbstractFFTVertexPtr>
(current.vertices.second);
if(!vert1||!vert2) throw Exception()
<< "Invalid vertices for a tensor diagram in StoSFFDecayer::doinit()"
<< Exception::runerror;
ten_[ix] = make_pair(vert1, vert2);
}
else if(offshell->iSpin() == PDT::Spin3Half) {
AbstractRFSVertexPtr vert1 = dynamic_ptr_cast<AbstractRFSVertexPtr>
(current.vertices.first);
AbstractRFSVertexPtr vert2 = dynamic_ptr_cast<AbstractRFSVertexPtr>
(current.vertices.second);
if(!vert1||!vert2) throw Exception()
<< "Invalid vertices for a RS fermion diagram in StoSFFDecayer::doinit()"
<< Exception::runerror;
RSfer_[ix] = make_pair(vert1, vert2);
}
}
}
-double StoSFFDecayer::me2(const int ichan, const Particle & inpart,
- const ParticleVector & decay,
+void StoSFFDecayer::
+constructSpinInfo(const Particle & part, ParticleVector decay) const {
+ ScalarWaveFunction::
+ constructSpinInfo(const_ptr_cast<tPPtr>(&part),
+ Helicity::incoming,true);
+ for(unsigned int ix=0;ix<decay.size();++ix) {
+ if(decay[ix]->dataPtr()->iSpin()==PDT::Spin0) {
+ ScalarWaveFunction::constructSpinInfo(decay[ix],Helicity::outgoing,true);
+ }
+ else {
+ SpinorWaveFunction::
+ constructSpinInfo(outspin_[ix].first,decay[ix],Helicity::outgoing,true);
+ }
+ }
+}
+
+double StoSFFDecayer::me2(const int ichan, const Particle & part,
+ const tPDVector & outgoing,
+ const vector<Lorentz5Momentum> & momenta,
MEOption meopt) const {
// particle or CC of particle
- bool cc = (*getProcessInfo().begin()).incoming != inpart.id();
+ bool cc = (*getProcessInfo().begin()).incoming != part.id();
// special handling or first/last call
if(meopt==Initialize) {
ScalarWaveFunction::
- calculateWaveFunctions(rho_,const_ptr_cast<tPPtr>(&inpart),
+ calculateWaveFunctions(rho_,const_ptr_cast<tPPtr>(&part),
Helicity::incoming);
- swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),
+ swave_ = ScalarWaveFunction(part.momentum(),part.dataPtr(),
Helicity::incoming);
// fix rho if no correlations
fixRho(rho_);
}
- if(meopt==Terminate) {
- ScalarWaveFunction::
- constructSpinInfo(const_ptr_cast<tPPtr>(&inpart),
- Helicity::incoming,true);
- for(unsigned int ix=0;ix<decay.size();++ix) {
- if(decay[ix]->dataPtr()->iSpin()==PDT::Spin0) {
- ScalarWaveFunction::constructSpinInfo(decay[ix],Helicity::outgoing,true);
- }
- else {
- SpinorWaveFunction::
- constructSpinInfo(outspin_[ix].first,decay[ix],Helicity::outgoing,true);
- }
- }
- return 0.;
- }
// get the wavefunctions for all the particles
ScalarWaveFunction outScalar;
unsigned int isca(0);
- for(unsigned int ix=0;ix<decay.size();++ix) {
- if(decay[ix]->dataPtr()->iSpin()==PDT::Spin0) {
+ for(unsigned int ix=0;ix<outgoing.size();++ix) {
+ if(outgoing[ix]->iSpin()==PDT::Spin0) {
isca = ix;
- outScalar = ScalarWaveFunction(decay[ix]->momentum(),
- decay[ix]->dataPtr(),Helicity::outgoing);
+ outScalar = ScalarWaveFunction(momenta[ix],outgoing[ix],Helicity::outgoing);
}
else {
SpinorWaveFunction::
- calculateWaveFunctions(outspin_[ix].first,decay[ix],Helicity::outgoing);
+ calculateWaveFunctions(outspin_[ix].first,momenta[ix],outgoing[ix],Helicity::outgoing);
outspin_[ix].second.resize(2);
if(outspin_[ix].first[0].wave().Type() == SpinorType::u) {
for(unsigned int iy = 0; iy < 2; ++iy) {
outspin_[ix].second[iy] = outspin_[ix].first[iy].bar();
outspin_[ix].first[iy].conjugate();
}
}
else {
for(unsigned int iy = 0; iy < 2; ++iy) {
outspin_[ix].second[iy] = outspin_[ix].first[iy].bar();
outspin_[ix].second[iy].conjugate();
}
}
}
}
const vector<vector<double> > cfactors(getColourFactors());
const vector<vector<double> > nfactors(getLargeNcColourFactors());
- Energy2 scale(sqr(inpart.mass()));
+ Energy2 scale(sqr(part.mass()));
const size_t ncf(numberOfFlows());
vector<Complex> flows(ncf, Complex(0.)), largeflows(ncf, Complex(0.));
vector<GeneralDecayMEPtr>
mes(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin0,
isca==0 ? PDT::Spin0 : PDT::Spin1Half,
isca==1 ? PDT::Spin0 : PDT::Spin1Half,
isca==2 ? PDT::Spin0 : PDT::Spin1Half)));
vector<GeneralDecayMEPtr>
mel(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin0,
isca == 0 ? PDT::Spin0 : PDT::Spin1Half,
isca == 1 ? PDT::Spin0 : PDT::Spin1Half,
isca == 2 ? PDT::Spin0 : PDT::Spin1Half)));
static const unsigned int out2[3]={1,0,0},out3[3]={2,2,1};
for(unsigned int s1 = 0;s1 < 2; ++s1) {
for(unsigned int s2 = 0;s2 < 2; ++s2) {
flows = vector<Complex>(ncf, Complex(0.));
largeflows = vector<Complex>(ncf, Complex(0.));
unsigned int idiag(0);
for(vector<TBDiagram>::const_iterator dit = getProcessInfo().begin();
dit != getProcessInfo().end(); ++dit) {
// channels if selecting
if( ichan >= 0 && diagramMap()[ichan] != idiag ) {
++idiag;
continue;
}
tcPDPtr offshell = dit->intermediate;
Complex diag;
if(offshell) {
if(cc&&offshell->CC()) offshell=offshell->CC();
double sign = out3[dit->channelType] < out2[dit->channelType] ? 1. : -1.;
// intermediate scalar
if (offshell->iSpin() == PDT::Spin0) {
ScalarWaveFunction inters = sca_[idiag].first->
evaluate(scale, widthOption(), offshell, swave_, outScalar);
unsigned int h1(s1),h2(s2);
if(out2[dit->channelType]>out3[dit->channelType]) swap(h1,h2);
- if(decay[out2[dit->channelType]]->id()<0&&
- decay[out3[dit->channelType]]->id()>0) {
+ if(outgoing[out2[dit->channelType]]->id()<0&&
+ outgoing[out3[dit->channelType]]->id()>0) {
diag =-sign*sca_[idiag].second->
evaluate(scale,
outspin_[out2[dit->channelType]].first [h1],
outspin_[out3[dit->channelType]].second[h2],inters);
}
else {
diag = sign*sca_[idiag].second->
evaluate(scale,
outspin_[out3[dit->channelType]].first [h2],
outspin_[out2[dit->channelType]].second[h1],inters);
}
}
// intermediate fermion
else if(offshell->iSpin() == PDT::Spin1Half) {
int iferm =
- decay[out2[dit->channelType]]->dataPtr()->iSpin()==PDT::Spin1Half
+ outgoing[out2[dit->channelType]]->iSpin()==PDT::Spin1Half
? out2[dit->channelType] : out3[dit->channelType];
unsigned int h1(s1),h2(s2);
if(dit->channelType>iferm) swap(h1,h2);
sign = iferm<dit->channelType ? 1. : -1.;
- if((decay[dit->channelType]->id() < 0 &&decay[iferm]->id() > 0 ) ||
- (decay[dit->channelType]->id()*offshell->id()>0)) {
+ if((outgoing[dit->channelType]->id() < 0 &&outgoing[iferm]->id() > 0 ) ||
+ (outgoing[dit->channelType]->id()*offshell->id()>0)) {
SpinorWaveFunction inters = fer_[idiag].first->
evaluate(scale,widthOption(),offshell,
outspin_[dit->channelType].first [h1],swave_);
diag = -sign*fer_[idiag].second->
evaluate(scale,inters,outspin_[iferm].second[h2],outScalar);
}
else {
SpinorBarWaveFunction inters = fer_[idiag].first->
evaluate(scale,widthOption(),offshell,
outspin_[dit->channelType].second[h1],swave_);
diag = sign*fer_[idiag].second->
evaluate(scale,outspin_[iferm].first [h2],inters,outScalar);
}
}
// intermediate vector
else if(offshell->iSpin() == PDT::Spin1) {
VectorWaveFunction interv = vec_[idiag].first->
evaluate(scale, widthOption(), offshell, swave_, outScalar);
unsigned int h1(s1),h2(s2);
if(out2[dit->channelType]>out3[dit->channelType]) swap(h1,h2);
- if(decay[out2[dit->channelType]]->id()<0&&
- decay[out3[dit->channelType]]->id()>0) {
+ if(outgoing[out2[dit->channelType]]->id()<0&&
+ outgoing[out3[dit->channelType]]->id()>0) {
diag =-sign*vec_[idiag].second->
evaluate(scale,
outspin_[out2[dit->channelType]].first [h1],
outspin_[out3[dit->channelType]].second[h2],interv);
}
else {
diag = sign*vec_[idiag].second->
evaluate(scale,
outspin_[out3[dit->channelType]].first [h2],
outspin_[out2[dit->channelType]].second[h1],interv);
}
}
// intermediate tensor
else if(offshell->iSpin() == PDT::Spin2) {
TensorWaveFunction intert = ten_[idiag].first->
evaluate(scale, widthOption(), offshell, swave_, outScalar);
unsigned int h1(s1),h2(s2);
if(out2[dit->channelType]>out3[dit->channelType]) swap(h1,h2);
- if(decay[out2[dit->channelType]]->id()<0&&
- decay[out3[dit->channelType]]->id()>0) {
+ if(outgoing[out2[dit->channelType]]->id()<0&&
+ outgoing[out3[dit->channelType]]->id()>0) {
diag =-sign*ten_[idiag].second->
evaluate(scale,
outspin_[out2[dit->channelType]].first [h1],
outspin_[out3[dit->channelType]].second[h2],intert);
}
else {
diag = sign*ten_[idiag].second->
evaluate(scale,
outspin_[out3[dit->channelType]].first [h2],
outspin_[out2[dit->channelType]].second[h1],intert);
}
}
// intermediate RS fermion
else if(offshell->iSpin() == PDT::Spin3Half) {
int iferm =
- decay[out2[dit->channelType]]->dataPtr()->iSpin()==PDT::Spin1Half
+ outgoing[out2[dit->channelType]]->iSpin()==PDT::Spin1Half
? out2[dit->channelType] : out3[dit->channelType];
unsigned int h1(s1),h2(s2);
if(dit->channelType>iferm) swap(h1,h2);
sign = iferm<dit->channelType ? 1. : -1.;
- if((decay[dit->channelType]->id() < 0 &&decay[iferm]->id() > 0 ) ||
- (decay[dit->channelType]->id()*offshell->id()>0)) {
+ if((outgoing[dit->channelType]->id() < 0 &&outgoing[iferm]->id() > 0 ) ||
+ (outgoing[dit->channelType]->id()*offshell->id()>0)) {
RSSpinorWaveFunction inters = RSfer_[idiag].first->
evaluate(scale,widthOption(),offshell,
outspin_[dit->channelType].first [h1],swave_);
diag = -sign*RSfer_[idiag].second->
evaluate(scale,inters,outspin_[iferm].second[h2],outScalar);
}
else {
RSSpinorBarWaveFunction inters = RSfer_[idiag].first->
evaluate(scale,widthOption(),offshell,
outspin_[dit->channelType].second[h1],swave_);
diag = sign*RSfer_[idiag].second->
evaluate(scale,outspin_[iferm].first [h2],inters,outScalar);
}
}
// unknown
else throw Exception()
<< "Unknown intermediate in StoSFFDecayer::me2()"
<< Exception::runerror;
}
// four point diagram
else {
unsigned int o2 = isca > 0 ? 0 : 1;
unsigned int o3 = isca < 2 ? 2 : 1;
- if(decay[o2]->id() < 0 && decay[o3]->id() > 0) {
+ if(outgoing[o2]->id() < 0 && outgoing[o3]->id() > 0) {
diag =-four_[idiag]->
evaluate(scale, outspin_[o2].first[s1],
outspin_[o3].second[s2], outScalar, swave_);
}
else {
diag = four_[idiag]->
evaluate(scale, outspin_[o3].first[s2],
outspin_[o2].second[s1], outScalar, swave_);
}
}
// matrix element for the different colour flows
if(ichan < 0) {
for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) {
flows[dit->colourFlow[iy].first - 1] +=
dit->colourFlow[iy].second * diag;
}
for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) {
largeflows[dit->largeNcColourFlow[iy].first - 1] +=
dit->largeNcColourFlow[iy].second * diag;
}
}
else {
for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) {
if(dit->colourFlow[iy].first - 1 != colourFlow()) continue;
flows[dit->colourFlow[iy].first - 1] +=
dit->colourFlow[iy].second * diag;
}
for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) {
if(dit->colourFlow[iy].first - 1!=colourFlow()) continue;
largeflows[dit->largeNcColourFlow[iy].first - 1] +=
dit->largeNcColourFlow[iy].second * diag;
}
}
++idiag;
}
for(unsigned int ix = 0; ix < ncf; ++ix) {
if(isca == 0) {
(*mes[ix])(0, 0, s1, s2) = flows[ix];
(*mel[ix])(0, 0, s1, s2) = largeflows[ix];
}
else if(isca == 1 ) {
(*mes[ix])(0, s1, 0, s2) = flows[ix];
(*mel[ix])(0, s1, 0, s2) = largeflows[ix];
}
else if(isca == 2) {
(*mes[ix])(0, s1,s2, 0) = flows[ix];
(*mel[ix])(0, s1,s2, 0) = largeflows[ix] ;
}
}
}
}
double me2(0.);
if(ichan < 0) {
vector<double> pflows(ncf,0.);
for(unsigned int ix = 0; ix < ncf; ++ix) {
for(unsigned int iy = 0; iy < ncf; ++ iy) {
double con = cfactors[ix][iy]*(mes[ix]->contract(*mes[iy],rho_)).real();
me2 += con;
if(ix == iy) {
con = nfactors[ix][iy]*(mel[ix]->contract(*mel[iy],rho_)).real();
pflows[ix] += con;
}
}
}
double ptotal(std::accumulate(pflows.begin(),pflows.end(),0.));
ptotal *= UseRandom::rnd();
for(unsigned int ix = 0;ix < pflows.size(); ++ix) {
if(ptotal <= pflows[ix]) {
colourFlow(ix);
ME(mes[ix]);
break;
}
ptotal -= pflows[ix];
}
}
else {
unsigned int iflow = colourFlow();
me2 = nfactors[iflow][iflow]*(mel[iflow]->contract(*mel[iflow],rho_)).real();
}
// return the matrix element squared
return me2;
}
diff --git a/Decay/General/StoSFFDecayer.h b/Decay/General/StoSFFDecayer.h
--- a/Decay/General/StoSFFDecayer.h
+++ b/Decay/General/StoSFFDecayer.h
@@ -1,163 +1,172 @@
// -*- C++ -*-
#ifndef THEPEG_StoSFFDecayer_H
#define THEPEG_StoSFFDecayer_H
//
// This is the declaration of the StoSFFDecayer class.
//
#include "GeneralThreeBodyDecayer.h"
#include "ThePEG/Helicity/Vertex/AbstractSSSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractRFSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVSSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractSSTVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFTVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFSSVertex.h"
namespace Herwig {
using namespace ThePEG;
/**
* The StoSFFDecayer class provides the general matrix element for
* scalar decays into another scalar and a fermion-antifermion pair.
*
* @see \ref StoSFFDecayerInterfaces "The interfaces"
* defined for StoSFFDecayer.
*/
class StoSFFDecayer: public GeneralThreeBodyDecayer {
public:
-
+
/**
- * Return the matrix element squared for a given mode and phase-space channel
- * @param ichan The channel we are calculating the matrix element for.
+ * 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 outgoing The particles produced in the decay
+ * @param momenta The momenta of 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;
+ double me2(const int ichan,const Particle & part,
+ const tPDVector & outgoing,
+ const vector<Lorentz5Momentum> & momenta,
+ MEOption meopt) const;
+
+ /**
+ * Construct the SpinInfos for the particles produced in the decay
+ */
+ virtual void constructSpinInfo(const Particle & part,
+ ParticleVector outgoing) const;
/**
* Method to return an object to calculate the 3 (or higher body) partial width
* @param dm The DecayMode
* @return A pointer to a WidthCalculatorBase object capable of calculating the width
*/
virtual WidthCalculatorBasePtr threeBodyMEIntegrator(const DecayMode & dm) const;
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.
*/
StoSFFDecayer & operator=(const StoSFFDecayer &);
private:
/**
* Store the vertices for scalar intermediate
*/
vector<pair<AbstractSSSVertexPtr, AbstractFFSVertexPtr> > sca_;
/**
* Store the vertices for spin-\f$\frac12\f$ fermion intermediate
*/
vector<pair<AbstractFFSVertexPtr, AbstractFFSVertexPtr> > fer_;
/**
* Store the vertices for spin-\f$\frac32\f$ fermion intermediate
*/
vector<pair<AbstractRFSVertexPtr, AbstractRFSVertexPtr> > RSfer_;
/**
* Store the vertices for vector intermediate
*/
vector<pair<AbstractVSSVertexPtr, AbstractFFVVertexPtr> > vec_;
/**
* Store the vertices for tensor intermediate
*/
vector<pair<AbstractSSTVertexPtr, AbstractFFTVertexPtr> > ten_;
/**
* Store the vertices for four point diagrams
*/
vector<AbstractFFSSVertexPtr> four_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Scalar wavefunction
*/
mutable ScalarWaveFunction swave_;
/**
* Spinor wavefunctions
*/
mutable pair<vector<SpinorWaveFunction>,vector<SpinorBarWaveFunction> > outspin_[3];
};
}
#endif /* THEPEG_StoSFFDecayer_H */
diff --git a/Decay/General/VtoFFVDecayer.cc b/Decay/General/VtoFFVDecayer.cc
--- a/Decay/General/VtoFFVDecayer.cc
+++ b/Decay/General/VtoFFVDecayer.cc
@@ -1,371 +1,372 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the VtoFFVDecayer class.
//
#include "VtoFFVDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/PDT/ThreeBodyAllOnCalculator.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
#include <numeric>
using namespace Herwig;
using namespace ThePEG;
using namespace ThePEG::Helicity;
IBPtr VtoFFVDecayer::clone() const {
return new_ptr(*this);
}
IBPtr VtoFFVDecayer::fullclone() const {
return new_ptr(*this);
}
void VtoFFVDecayer::persistentOutput(PersistentOStream & os) const {
os << sca_ << fer_ << vec_ << ten_;
}
void VtoFFVDecayer::persistentInput(PersistentIStream & is, int) {
is >> sca_ >> fer_ >> vec_ >> ten_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<VtoFFVDecayer,GeneralThreeBodyDecayer>
describeHerwigVtoFFVDecayer("Herwig::VtoFFVDecayer", "Herwig.so");
void VtoFFVDecayer::Init() {
static ClassDocumentation<VtoFFVDecayer> documentation
("The VtoFFVDecayer class implements the general three-body "
"decay of a vector to a two fermions and a vector.");
}
WidthCalculatorBasePtr VtoFFVDecayer::
threeBodyMEIntegrator(const DecayMode & ) const {
vector<int> intype;
vector<Energy> inmass,inwidth;
vector<double> inpow,inweights;
constructIntegratorChannels(intype,inmass,inwidth,inpow,inweights);
return new_ptr(ThreeBodyAllOnCalculator<VtoFFVDecayer>
(inweights,intype,inmass,inwidth,inpow,*this,0,
outgoing()[0]->mass(),outgoing()[1]->mass(),
outgoing()[2]->mass(),relativeError()));
}
void VtoFFVDecayer::doinit() {
GeneralThreeBodyDecayer::doinit();
if(outgoing().empty()) return;
unsigned int ndiags = getProcessInfo().size();
sca_.resize(ndiags);
fer_.resize(ndiags);
vec_.resize(ndiags);
ten_.resize(ndiags);
for(unsigned int ix = 0;ix < ndiags; ++ix) {
TBDiagram current = getProcessInfo()[ix];
tcPDPtr offshell = current.intermediate;
if( offshell->CC() ) offshell = offshell->CC();
if(offshell->iSpin() == PDT::Spin0) {
AbstractVVSVertexPtr vert1 = dynamic_ptr_cast<AbstractVVSVertexPtr>
(current.vertices.first);
AbstractFFSVertexPtr vert2 = dynamic_ptr_cast<AbstractFFSVertexPtr>
(current.vertices.second);
if(!vert1||!vert2) throw Exception()
<< "Invalid vertices for a scalar diagram in VtoFFVDecayer::doinit()"
<< Exception::runerror;
sca_[ix] = make_pair(vert1, vert2);
}
else if(offshell->iSpin() == PDT::Spin1Half) {
AbstractFFVVertexPtr vert1 = dynamic_ptr_cast<AbstractFFVVertexPtr>
(current.vertices.first);
AbstractFFVVertexPtr vert2 = dynamic_ptr_cast<AbstractFFVVertexPtr>
(current.vertices.second);
if(!vert1||!vert2) throw Exception()
<< "Invalid vertices for a fermion diagram in VtoFFVDecayer::doinit()"
<< Exception::runerror;
fer_[ix] = make_pair(vert1, vert2);
}
else if(offshell->iSpin() == PDT::Spin1) {
AbstractVVVVertexPtr vert1 = dynamic_ptr_cast<AbstractVVVVertexPtr>
(current.vertices.first);
AbstractFFVVertexPtr vert2 = dynamic_ptr_cast<AbstractFFVVertexPtr>
(current.vertices.second);
if(!vert1||!vert2) throw Exception()
<< "Invalid vertices for a vector diagram in VtoFFVDecayer::doinit()"
<< Exception::runerror;
vec_[ix] = make_pair(vert1, vert2);
}
else if(offshell->iSpin() == PDT::Spin2) {
AbstractVVTVertexPtr vert1 = dynamic_ptr_cast<AbstractVVTVertexPtr>
(current.vertices.first);
AbstractFFTVertexPtr vert2 = dynamic_ptr_cast<AbstractFFTVertexPtr>
(current.vertices.second);
if(!vert1||!vert2) throw Exception()
<< "Invalid vertices for a tensor diagram in VtoFFVDecayer::doinit()"
<< Exception::runerror;
ten_[ix] = make_pair(vert1, vert2);
}
}
}
+void VtoFFVDecayer::
+constructSpinInfo(const Particle & part, ParticleVector decay) const {
+ VectorWaveFunction::
+ constructSpinInfo(inVector_,const_ptr_cast<tPPtr>(&part),
+ Helicity::incoming,true,false);
+ for(unsigned int ix=0;ix<decay.size();++ix) {
+ if(decay[ix]->dataPtr()->iSpin()==PDT::Spin1) {
+ VectorWaveFunction::constructSpinInfo(outVector_,decay[ix],
+ Helicity::outgoing,true,false);
+ }
+ else {
+ SpinorWaveFunction::
+ constructSpinInfo(outspin_[ix].first,decay[ix],Helicity::outgoing,true);
+ }
+ }
+}
-double VtoFFVDecayer::me2(const int ichan, const Particle & inpart,
- const ParticleVector & decay,
+double VtoFFVDecayer::me2(const int ichan,const Particle & part,
+ const tPDVector & outgoing,
+ const vector<Lorentz5Momentum> & momenta,
MEOption meopt) const {
// particle or CC of particle
- bool cc = (*getProcessInfo().begin()).incoming != inpart.id();
+ bool cc = (*getProcessInfo().begin()).incoming != part.id();
// special handling or first/last call
if(meopt==Initialize) {
VectorWaveFunction::
- calculateWaveFunctions(inVector_,rho_,const_ptr_cast<tPPtr>(&inpart),
+ calculateWaveFunctions(inVector_,rho_,const_ptr_cast<tPPtr>(&part),
Helicity::incoming,false);
// fix rho if no correlations
fixRho(rho_);
}
-
- if(meopt==Terminate) {
- VectorWaveFunction::
- constructSpinInfo(inVector_,const_ptr_cast<tPPtr>(&inpart),
- Helicity::incoming,true,false);
- for(unsigned int ix=0;ix<decay.size();++ix) {
- if(decay[ix]->dataPtr()->iSpin()==PDT::Spin1) {
- VectorWaveFunction::constructSpinInfo(outVector_,decay[ix],
- Helicity::outgoing,true,false);
- }
- else {
- SpinorWaveFunction::
- constructSpinInfo(outspin_[ix].first,decay[ix],Helicity::outgoing,true);
- }
- }
- }
unsigned int ivec(0);
bool massless = false;
- for(unsigned int ix = 0; ix < decay.size();++ix) {
- if(decay[ix]->dataPtr()->iSpin() == PDT::Spin1) {
- massless = decay[ix]->id()==ParticleID::g || decay[ix]->id()==ParticleID::gamma;
+ for(unsigned int ix = 0; ix < outgoing.size();++ix) {
+ if(outgoing[ix]->iSpin() == PDT::Spin1) {
+ massless = outgoing[ix]->id()==ParticleID::g || outgoing[ix]->id()==ParticleID::gamma;
ivec = ix;
VectorWaveFunction::
- calculateWaveFunctions(outVector_, decay[ix], Helicity::outgoing, massless );
+ calculateWaveFunctions(outVector_, momenta[ix], outgoing[ix], Helicity::outgoing, massless );
}
else {
SpinorWaveFunction::
- calculateWaveFunctions(outspin_[ix].first,decay[ix],Helicity::outgoing);
+ calculateWaveFunctions(outspin_[ix].first,momenta[ix], outgoing[ix],Helicity::outgoing);
outspin_[ix].second.resize(2);
// Need a ubar and a v spinor
if(outspin_[ix].first[0].wave().Type() == SpinorType::u) {
for(unsigned int iy = 0; iy < 2; ++iy) {
outspin_[ix].second[iy] = outspin_[ix].first[iy].bar();
outspin_[ix].first[iy].conjugate();
}
}
else {
for(unsigned int iy = 0; iy < 2; ++iy) {
outspin_[ix].second[iy] = outspin_[ix].first[iy].bar();
outspin_[ix].second[iy].conjugate();
}
}
}
}
const vector<vector<double> > cfactors(getColourFactors());
const vector<vector<double> > nfactors(getLargeNcColourFactors());
- Energy2 scale(sqr(inpart.mass()));
+ Energy2 scale(sqr(part.mass()));
const size_t ncf(numberOfFlows());
vector<Complex> flows(ncf, Complex(0.)), largeflows(ncf, Complex(0.));
// setup the DecayMatrixElement
vector<GeneralDecayMEPtr>
mes(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin1,
ivec == 0 ? PDT::Spin1 : PDT::Spin1Half,
ivec == 1 ? PDT::Spin1 : PDT::Spin1Half,
ivec == 2 ? PDT::Spin1 : PDT::Spin1Half)));
vector<GeneralDecayMEPtr>
mel(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin1,
ivec == 0 ? PDT::Spin1 : PDT::Spin1Half,
ivec == 1 ? PDT::Spin1 : PDT::Spin1Half,
ivec == 2 ? PDT::Spin1 : PDT::Spin1Half)));
//the channel possiblities
static const unsigned int out2[3] = {1,0,0}, out3[3] = {2,2,1};
for(unsigned int vi = 0; vi < 3; ++vi) {
for(unsigned int s1 = 0; s1 < 2; ++s1) {
for(unsigned int s2 = 0; s2 < 2; ++s2) {
for(unsigned int v1 = 0; v1 < 3; ++v1) {
if ( massless && v1 == 1 ) continue;
flows = vector<Complex>(ncf, Complex(0.));
largeflows = vector<Complex>(ncf, Complex(0.));
unsigned int idiag(0);
for(vector<TBDiagram>::const_iterator dit=getProcessInfo().begin();
dit!=getProcessInfo().end();++dit) {
// channels if selecting
if( ichan >=0 && diagramMap()[ichan] != idiag ) {
++idiag;
continue;
}
tcPDPtr offshell = dit->intermediate;
if(cc&&offshell->CC()) offshell=offshell->CC();
Complex diag;
unsigned int o2(out2[dit->channelType]), o3(out3[dit->channelType]);
double sign = (o3 < o2) ? 1. : -1.;
// intermediate scalar
if(offshell->iSpin() == PDT::Spin0) {
ScalarWaveFunction inters = sca_[idiag].first->
evaluate(scale, widthOption(), offshell, outVector_[v1],
inVector_[vi]);
unsigned int h1(s1),h2(s2);
if(o2 > o3) swap(h1, h2);
- if(decay[o2]->id() < 0 && decay[o3]->id() > 0) {
+ if(outgoing[o2]->id() < 0 && outgoing[o3]->id() > 0) {
diag = -sign*sca_[idiag].second->
evaluate(scale,outspin_[o2].first[h1],
outspin_[o3].second[h2],inters);
}
else {
diag = sign*sca_[idiag].second->
evaluate(scale, outspin_[o3].first [h2],
outspin_[o2].second[h1],inters);
}
}
// intermediate fermion
else if(offshell->iSpin() == PDT::Spin1Half) {
- int iferm = (decay[o2]->dataPtr()->iSpin() == PDT::Spin1Half)
+ int iferm = (outgoing[o2]->iSpin() == PDT::Spin1Half)
? o2 : o3;
unsigned int h1(s1),h2(s2);
if(dit->channelType > iferm) swap(h1, h2);
sign = iferm < dit->channelType ? 1. : -1.;
- if(decay[dit->channelType]->id() < 0 && decay[iferm]->id() > 0 ) {
+ if(outgoing[dit->channelType]->id() < 0 && outgoing[iferm]->id() > 0 ) {
SpinorWaveFunction inters = fer_[idiag].first->
evaluate(scale,widthOption(),offshell,
outspin_[dit->channelType].first[h1], inVector_[vi]);
diag = -sign*fer_[idiag].second->
evaluate(scale,inters,outspin_[iferm].second[h2], outVector_[v1]);
}
else {
SpinorBarWaveFunction inters = fer_[idiag].first->
evaluate(scale,widthOption(),offshell,
outspin_[dit->channelType].second[h1],inVector_[vi]);
diag = sign*fer_[idiag].second->
evaluate(scale,outspin_[iferm].first [h2],inters, outVector_[v1]);
}
}
// intermediate vector
else if(offshell->iSpin() == PDT::Spin1) {
VectorWaveFunction interv = vec_[idiag].first->
evaluate(scale, widthOption(), offshell, outVector_[v1],
inVector_[vi]);
unsigned int h1(s1),h2(s2);
if(o2 > o3) swap(h1,h2);
- if(decay[o2]->id() < 0 && decay[o3]->id() > 0) {
+ if(outgoing[o2]->id() < 0 && outgoing[o3]->id() > 0) {
diag =-sign*vec_[idiag].second->
evaluate(scale, outspin_[o2].first[h1],
outspin_[o3].second[h2], interv);
}
else {
diag = sign*vec_[idiag].second->
evaluate(scale, outspin_[o3].first[h2],
outspin_[o2].second[h1], interv);
}
}
else if(offshell->iSpin() == PDT::Spin2) {
TensorWaveFunction intert = ten_[idiag].first->
evaluate(scale, widthOption(), offshell, inVector_[vi],
outVector_[v1]);
unsigned int h1(s1),h2(s2);
if(out2[dit->channelType]>out3[dit->channelType]) swap(h1,h2);
- if(decay[out2[dit->channelType]]->id()<0&&
- decay[out3[dit->channelType]]->id()>0) {
+ if(outgoing[out2[dit->channelType]]->id()<0&&
+ outgoing[out3[dit->channelType]]->id()>0) {
diag =-sign*ten_[idiag].second->
evaluate(scale,
outspin_[out2[dit->channelType]].first [h1],
outspin_[out3[dit->channelType]].second[h2],intert);
}
else {
diag = sign*ten_[idiag].second->
evaluate(scale,
outspin_[out3[dit->channelType]].first [h2],
outspin_[out2[dit->channelType]].second[h1],intert);
}
}
// unknown
else throw Exception()
<< "Unknown intermediate in VtoFFVDecayer::me2()"
<< Exception::runerror;
// matrix element for the different colour flows
if(ichan < 0) {
for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) {
flows[dit->colourFlow[iy].first - 1] +=
dit->colourFlow[iy].second * diag;
}
for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) {
largeflows[dit->largeNcColourFlow[iy].first - 1] +=
dit->largeNcColourFlow[iy].second * diag;
}
}
else {
for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) {
if(dit->colourFlow[iy].first - 1 != colourFlow()) continue;
flows[dit->colourFlow[iy].first - 1] +=
dit->colourFlow[iy].second * diag;
}
for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) {
if(dit->colourFlow[iy].first - 1!=colourFlow()) continue;
largeflows[dit->largeNcColourFlow[iy].first - 1] +=
dit->largeNcColourFlow[iy].second * diag;
}
}
++idiag;
} //end of diagrams
// now add the flows to the me2 with appropriate colour factors
for(unsigned int ix = 0; ix < ncf; ++ix) {
if (ivec == 0) {
(*mes[ix])(vi, v1, s1, s2) = flows[ix];
(*mel[ix])(vi, v1, s1, s2) = largeflows[ix];
}
else if(ivec == 1) {
(*mes[ix])(vi, s1, v1, s2) = flows[ix];
(*mel[ix])(vi, s1, v1, s2) = largeflows[ix];
}
else if(ivec == 2) {
(*mes[ix])(vi, s1, s2, v1) = flows[ix];
(*mel[ix])(vi, s1, s2, v1) = largeflows[ix];
}
}
}
}
}
}
double me2(0.);
if(ichan < 0) {
vector<double> pflows(ncf,0.);
for(unsigned int ix = 0; ix < ncf; ++ix) {
for(unsigned int iy = 0; iy < ncf; ++ iy) {
double con = cfactors[ix][iy]*(mes[ix]->contract(*mes[iy],rho_)).real();
me2 += con;
if(ix == iy) {
con = nfactors[ix][iy]*(mel[ix]->contract(*mel[iy],rho_)).real();
pflows[ix] += con;
}
}
}
double ptotal(std::accumulate(pflows.begin(),pflows.end(),0.));
ptotal *= UseRandom::rnd();
for(unsigned int ix = 0;ix < pflows.size(); ++ix) {
if(ptotal <= pflows[ix]) {
colourFlow(ix);
ME(mes[ix]);
break;
}
ptotal -= pflows[ix];
}
}
else {
unsigned int iflow = colourFlow();
me2 = nfactors[iflow][iflow]*(mel[iflow]->contract(*mel[iflow],rho_)).real();
}
// return the matrix element squared
return me2;
}
diff --git a/Decay/General/VtoFFVDecayer.h b/Decay/General/VtoFFVDecayer.h
--- a/Decay/General/VtoFFVDecayer.h
+++ b/Decay/General/VtoFFVDecayer.h
@@ -1,161 +1,170 @@
// -*- C++ -*-
#ifndef THEPEG_VtoFFVDecayer_H
#define THEPEG_VtoFFVDecayer_H
//
// This is the declaration of the VtoFFVDecayer class.
//
#include "GeneralThreeBodyDecayer.h"
#include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFTVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVTVertex.h"
namespace Herwig {
using namespace ThePEG;
/**
* Here is the documentation of the VtoFFVDecayer class.
*
* @see \ref VtoFFVDecayerInterfaces "The interfaces"
* defined for VtoFFVDecayer.
*/
class VtoFFVDecayer: public GeneralThreeBodyDecayer {
public:
+
+ /**
+ * 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 outgoing The particles produced in the decay
+ * @param momenta The momenta of 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.
+ */
+ double me2(const int ichan,const Particle & part,
+ const tPDVector & outgoing,
+ const vector<Lorentz5Momentum> & momenta,
+ MEOption meopt) 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 matrix element
- * @return The matrix element squared for the phase-space configuration.
+ * Construct the SpinInfos for the particles produced in the decay
*/
- virtual double me2(const int ichan, const Particle & part,
- const ParticleVector & decay, MEOption meopt) const;
+ virtual void constructSpinInfo(const Particle & part,
+ ParticleVector outgoing) const;
/**
* Method to return an object to calculate the 3 (or higher body) partial width
* @param dm The DecayMode
* @return A pointer to a WidthCalculatorBase object capable of
* calculating the width
*/
virtual WidthCalculatorBasePtr threeBodyMEIntegrator(const DecayMode & dm) const;
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.
*/
VtoFFVDecayer & operator=(const VtoFFVDecayer &);
private:
/**
* Store the vertices for scalar intrermediate
*/
vector<pair<AbstractVVSVertexPtr, AbstractFFSVertexPtr> > sca_;
/**
* Store the vertices for fermion intrermediate
*/
vector<pair<AbstractFFVVertexPtr, AbstractFFVVertexPtr> > fer_;
/**
* Store the vertices for vector intrermediate
*/
vector<pair<AbstractVVVVertexPtr, AbstractFFVVertexPtr> > vec_;
/**
* Store the vertices for vector intrermediate
*/
vector<pair<AbstractVVTVertexPtr, AbstractFFTVertexPtr> > ten_;
/**
* Spinr density matrix
*/
mutable RhoDMatrix rho_;
/**
* Polarization vectors for the decaying particle
*/
mutable vector<VectorWaveFunction> inVector_;
/**
* Scalar wavefunction for the decay products
*/
mutable ScalarWaveFunction swave_;
/**
* Polarization vectors for the decay products
*/
mutable vector<VectorWaveFunction> outVector_;
/**
* Spinors for the decay products
*/
mutable pair<vector<SpinorWaveFunction>,vector<SpinorBarWaveFunction> > outspin_[3];
};
}
#endif /* THEPEG_VtoFFVDecayer_H */
diff --git a/Decay/PhaseSpaceMode.cc b/Decay/PhaseSpaceMode.cc
--- a/Decay/PhaseSpaceMode.cc
+++ b/Decay/PhaseSpaceMode.cc
@@ -1,491 +1,492 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the PhaseSpaceMode class.
//
#include "PhaseSpaceMode.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 "Herwig/Utilities/Kinematics.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
void PhaseSpaceMode::persistentOutput(PersistentOStream & os) const {
os << incoming_ << channels_ << maxWeight_ << outgoing_ << outgoingCC_
<< partial_ << widthGen_ << massGen_ << testOnShell_
<< ounit(eMax_,GeV) << nRand_;
}
void PhaseSpaceMode::persistentInput(PersistentIStream & is, int) {
is >> incoming_ >> channels_ >> maxWeight_ >> outgoing_ >> outgoingCC_
>> partial_ >> widthGen_ >> massGen_ >> testOnShell_
>> iunit(eMax_,GeV) >> nRand_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<PhaseSpaceMode,Base>
describeHerwigPhaseSpaceMode("Herwig::PhaseSpaceMode", "PhaseSpaceMode.so");
void PhaseSpaceMode::Init() {
static ClassDocumentation<PhaseSpaceMode> documentation
("The PhaseSpaceMode classs contains a number of phase space"
" channels for the integration of a particular decay mode");
}
ParticleVector
PhaseSpaceMode::generateDecay(const Particle & inpart,
tcDecayIntegrator2Ptr decayer,
bool intermediates,bool cc) {
decayer->ME(DecayMEPtr());
eps_=decayer->eps_;
// compute the prefactor
Energy prewid = (widthGen_&&partial_>=0) ?
widthGen_->partialWidth(partial_,inpart.mass()) :
incoming_.first->width();
InvEnergy pre = prewid>ZERO ? 1./prewid : 1./MeV;
// boosts to/from rest
Boost bv =-inpart.momentum().boostVector();
double gammarest = inpart.momentum().e()/inpart.momentum().mass();
LorentzRotation boostToRest( bv,gammarest);
LorentzRotation boostFromRest(-bv,gammarest);
// construct a new particle which is at rest
Particle inrest(inpart);
inrest.transform(boostToRest);
double wgt(0.);
vector<Lorentz5Momentum> momenta(outgoing_.size());
int ichan;
unsigned int ncount(0);
try {
do {
// phase-space pieces of the weight
fillStack();
wgt = pre*weight(ichan,inrest.momentum(),momenta);
// matrix element piece
wgt *= decayer->me2(-1,inrest,!cc ? outgoing_ : outgoingCC_,
momenta,
ncount ==0 ? DecayIntegrator2::Initialize : DecayIntegrator2::Calculate);
++ncount;
if(wgt>maxWeight_) {
CurrentGenerator::log() << "Resetting max weight for decay "
<< inrest.PDGName() << " -> ";
for(tcPDPtr part : outgoing_)
CurrentGenerator::log() << " " << part->PDGName();
CurrentGenerator::log() << " " << maxWeight_ << " " << wgt
<< " " << inrest.mass()/MeV << "\n";
maxWeight_=wgt;
}
}
while(maxWeight_*UseRandom::rnd()>wgt&&ncount<decayer->nTry_);
}
catch (Veto) {
// restore the incoming particle to its original state
inrest.transform(boostFromRest);
throw Veto();
}
if(ncount>=decayer->nTry_) {
CurrentGenerator::log() << "The decay " << inrest.PDGName() << " -> ";
for(tcPDPtr part : outgoing_)
CurrentGenerator::log() << " " << part->PDGName();
CurrentGenerator::log() << " " << maxWeight_ << " " << decayer->nTry_
<< " is too inefficient for the particle "
<< inpart << "vetoing the decay \n";
momenta.clear();
throw Veto();
}
// construct the particles
ParticleVector output(outgoing_.size());
for(unsigned int ix=0;ix<outgoing_.size();++ix)
output[ix] = (!cc ? outgoing_[ix] : outgoingCC_[ix] )->produceParticle(momenta[ix]);
// set up the spin correlations
decayer->constructSpinInfo(inrest,output);
const_ptr_cast<tPPtr>(&inpart)->spinInfo(inrest.spinInfo());
constructVertex(inpart,output,decayer);
// return if intermediate particles not required
if(channels_.empty()||!intermediates) {
for(tPPtr part : output) part->transform(boostFromRest);
}
// find the intermediate particles
else {
// select the channel
vector<double> mewgts(channels_.size(),0.0);
double total=0.;
for(unsigned int ix=0,N=channels_.size();ix<N;++ix) {
mewgts[ix]=decayer->me2(ix,inrest,!cc ? outgoing_ : outgoingCC_,
momenta,DecayIntegrator2::Calculate);
total+=mewgts[ix];
}
// randomly pick a channel
total *= UseRandom::rnd();
int iChannel = -1;
do {
++iChannel;
total-=mewgts[iChannel];
}
while(iChannel<int(channels_.size()) && total>0.);
+ iChannel_ = iChannel;
// apply boost
for(tPPtr part : output) part->transform(boostFromRest);
channels_[iChannel].generateIntermediates(cc,inpart,output);
}
decayer->ME(DecayMEPtr());
// return particles;
return output;
}
// flat phase space generation and weight
Energy PhaseSpaceMode::flatPhaseSpace(const Lorentz5Momentum & in,
vector<Lorentz5Momentum> & momenta,
bool onShell) const {
double wgt(1.);
// masses of the particles
vector<Energy> mass = externalMasses(in.mass(),wgt,onShell);
// two body decay
double ctheta = 2.*rStack_.top() - 1.;
rStack_.pop();
double phi = Constants::twopi*rStack_.top();
rStack_.pop();
if(! Kinematics::twoBodyDecay(in, mass[0], mass[1],
ctheta, phi, momenta[0],momenta[1]))
throw Exception() << "Incoming mass - Outgoing mass negative in "
<< "PhaseSpaceMode::flatPhaseSpace()"
<< Exception::eventerror;
wgt *= Kinematics::pstarTwoBodyDecay(in.mass(),mass[0],mass[1])
/8./Constants::pi/in.mass();
return wgt*in.mass();
}
// generate the masses of the external particles
vector<Energy> PhaseSpaceMode::externalMasses(Energy inmass,double & wgt,
bool onShell) const {
vector<Energy> mass(outgoing_.size());
vector<int> notdone;
Energy mlow(ZERO);
// set masses of stable particles and limits
for(unsigned int ix=0;ix<outgoing_.size();++ix) {
// get the mass of the particle if can't use weight
if(onShell)
mass[ix] = outgoing_[ix]->mass();
else if(!massGen_[ix] || outgoing_[ix]->stable()) {
mass[ix] = outgoing_[ix]->generateMass();
mlow += mass[ix];
}
else {
mass[ix] = ZERO;
notdone.push_back(ix);
mlow+=max(outgoing_[ix]->mass()-outgoing_[ix]->widthLoCut(),ZERO);
}
}
if(mlow>inmass) throw Veto();
// now we need to generate the masses for the particles we haven't
for( ;!notdone.empty();) {
unsigned int iloc=long(UseRandom::rnd()*(notdone.size()-1));
Energy low = max(outgoing_[notdone[iloc]]->mass()-outgoing_[notdone[iloc]]->widthLoCut(),ZERO);
mlow-=low;
double wgttemp;
mass[notdone[iloc]]= massGen_[notdone[iloc]]->mass(wgttemp,*outgoing_[notdone[iloc]],low,inmass-mlow,rStack_.top());
rStack_.pop();
assert(mass[notdone[iloc]]>=low&&mass[notdone[iloc]]<=inmass-mlow);
wgt *= wgttemp;
mlow += mass[notdone[iloc]];
notdone.erase(notdone.begin()+iloc);
}
return mass;
}
// construct the vertex for spin corrections
void PhaseSpaceMode::constructVertex(const Particle & inpart,
const ParticleVector & decay,
tcDecayIntegrator2Ptr decayer) const {
// construct the decay vertex
VertexPtr vertex(new_ptr(DecayVertex()));
DVertexPtr Dvertex(dynamic_ptr_cast<DVertexPtr>(vertex));
// set the incoming particle for the decay vertex
(inpart.spinInfo())->decayVertex(vertex);
for(unsigned int ix=0;ix<decay.size();++ix) {
decay[ix]->spinInfo()->productionVertex(vertex);
}
// set the matrix element
Dvertex->ME(decayer->ME());
decayer->ME(DecayMEPtr());
}
// initialise the phase space
Energy PhaseSpaceMode::initializePhaseSpace(bool init, tcDecayIntegrator2Ptr decayer,
bool onShell) {
decayer->ME(DecayMEPtr());
eps_=decayer->eps_;
Energy output(ZERO);
// ensure that the weights add up to one
if(!channels_.empty()) {
double temp=0.;
for(const PhaseSpaceChannel & channel : channels_) temp+= channel.weight();
for(PhaseSpaceChannel & channel : channels_) channel.weight(channel.weight()/temp);
}
if(!init) return ZERO;
ThePEG::PPtr inpart=incoming_.first->produceParticle();
// now if using flat phase space
maxWeight_=0.;
if(channels_.empty()) {
vector<Lorentz5Momentum> momenta(outgoing_.size());
double wsum=0.,wsqsum=0.;
Energy m0,mmin(ZERO);
for(tcPDPtr part : outgoing_) mmin += part->massMin();
for(unsigned int ix=0;ix<decayer->nPoint_;++ix) {
// set the mass of the decaying particle
m0 = !onShell ? inpart->dataPtr()->generateMass() : inpart->dataPtr()->mass();
double wgt=0.;
if(m0<=mmin) continue;
inpart->set5Momentum(Lorentz5Momentum(m0));
// compute the prefactor
Energy prewid = (widthGen_&&partial_>=0) ?
widthGen_->partialWidth(partial_,inpart->mass()) :
incoming_.first->width();
InvEnergy pre = prewid>ZERO ? 1./prewid : 1./MeV;
// generate the weight for this point
try {
int dummy;
// phase-space piece
fillStack();
wgt = pre*weight(dummy,inpart->momentum(),momenta,onShell);
// matrix element piece
wgt *= decayer->me2(-1,*inpart,outgoing_,momenta,DecayIntegrator2::Initialize);
}
catch (Veto) {
wgt=0.;
}
if(wgt>maxWeight_) maxWeight_ = wgt;
wsum += wgt;
wsqsum += sqr(wgt);
}
wsum /= decayer->nPoint_;
wsqsum=wsqsum/decayer->nPoint_-sqr(wsum);
if(wsqsum<0.) wsqsum=0.;
wsqsum=sqrt(wsqsum/decayer->nPoint_);
Energy fact = (widthGen_&&partial_>=0) ?
widthGen_->partialWidth(partial_,inpart->nominalMass()) :
inpart->dataPtr()->width();
if(fact==ZERO) fact=MeV;
// factor for the weight with spin correlations
maxWeight_ *= inpart->dataPtr()->iSpin()==1 ? 1.1 : 1.6;
if ( Debug::level > 1 ) {
// ouptut the information on the initialisation
CurrentGenerator::log() << "Initialized the phase space for the decay "
<< incoming_.first->PDGName() << " -> ";
for(tPDPtr part : outgoing_)
CurrentGenerator::log() << part->PDGName() << " ";
CurrentGenerator::log() << "\n";
if(fact!=MeV) CurrentGenerator::log() << "The branching ratio is " << wsum
<< " +/- " << wsqsum << "\n";
CurrentGenerator::log() << "The partial width is " << wsum*fact/MeV
<< " +/- " << wsqsum*fact/MeV << " MeV\n";
CurrentGenerator::log() << "The partial width is "
<< wsum*fact/6.58212E-22/MeV
<< " +/- " << wsqsum*fact/6.58212E-22/MeV<< " s-1\n";
CurrentGenerator::log() << "The maximum weight is "
<< maxWeight_ << endl;
}
output=wsum*fact;
}
else {
vector<Lorentz5Momentum> momenta(outgoing_.size());
double totsum(0.),totsq(0.);
for(unsigned int iy=0;iy<decayer->nIter_;++iy) {
// zero the maximum weight
maxWeight_=0.;
vector<double> wsum(channels_.size(),0.),wsqsum(channels_.size(),0.);
vector<int> nchan(channels_.size(),0);
totsum = 0.;
totsq = 0.;
Energy m0,mmin(ZERO);
for(tcPDPtr part : outgoing_) mmin += part->massMin();
for(unsigned int ix=0;ix<decayer->nPoint_;++ix) {
m0 = !onShell ? incoming_.first->generateMass() : incoming_.first->mass();
double wgt=0.;
int ichan(-1);
if(m0>mmin) {
inpart->set5Momentum(Lorentz5Momentum(m0));
// compute the prefactor
Energy prewid= (widthGen_&&partial_>=0) ?
widthGen_->partialWidth(partial_,inpart->mass()) :
inpart->dataPtr()->width();
InvEnergy pre = prewid>ZERO ? 1./prewid : 1./MeV;
// generate the weight for this point
try {
fillStack();
wgt = pre*weight(ichan,inpart->momentum(),momenta,onShell);
// matrix element piece
wgt *= decayer->me2(-1,*inpart,outgoing_,momenta,DecayIntegrator2::Initialize);
}
catch (Veto) {
wgt=0.;
}
}
if(wgt>maxWeight_) maxWeight_=wgt;
if(ichan>=0) {
wsum[ichan] += wgt;
wsqsum[ichan] += sqr(wgt);
++nchan[ichan];
}
totsum+=wgt;
totsq+=wgt*wgt;
}
totsum=totsum/decayer->nPoint_;
totsq=totsq/decayer->nPoint_-sqr(totsum);
if(totsq<0.) totsq=0.;
totsq=sqrt(totsq/decayer->nPoint_);
if ( Debug::level > 1 )
CurrentGenerator::log() << "The branching ratio is " << iy << " "
<< totsum << " +/- " << totsq
<< maxWeight_ << "\n";
// compute the individual terms
double total(0.);
for(unsigned int ix=0;ix<channels_.size();++ix) {
if(nchan[ix]!=0) {
wsum[ix]=wsum[ix]/nchan[ix];
wsqsum[ix]=wsqsum[ix]/nchan[ix];
if(wsqsum[ix]<0.) wsqsum[ix]=0.;
wsqsum[ix]=sqrt(wsqsum[ix]/nchan[ix]);
}
else {
wsum[ix]=0;
wsqsum[ix]=0;
}
total+=sqrt(wsqsum[ix])*channels_[ix].weight();
}
if(total>0.) {
for(unsigned int ix=0;ix<channels_.size();++ix) {
channels_[ix].weight(sqrt(wsqsum[ix])*channels_[ix].weight()/total);
}
}
}
// factor for the weight with spin correlations
maxWeight_*= inpart->dataPtr()->iSpin()==1 ? 1.1 : 1.6;
// output the information on the initialisation
Energy fact = (widthGen_&&partial_>=0) ?
widthGen_->partialWidth(partial_,inpart->nominalMass()) :
inpart->dataPtr()->width();
output=totsum*fact;
if(fact==ZERO) fact=MeV;
if ( Debug::level > 1 ) {
CurrentGenerator::log() << "Initialized the phase space for the decay "
<< incoming_.first->PDGName() << " -> ";
for(tcPDPtr part : outgoing_)
CurrentGenerator::log() << part->PDGName() << " ";
CurrentGenerator::log() << "\n";
if(fact!=MeV) CurrentGenerator::log() << "The branching ratio is " << totsum
<< " +/- " << totsq << "\n";
CurrentGenerator::log() << "The partial width is " << totsum*fact/MeV
<< " +/- " << totsq*fact/MeV << " MeV\n";
CurrentGenerator::log() << "The partial width is "
<< totsum*fact/6.58212E-22/MeV
<< " +/- " << totsq*fact/6.58212E-22/MeV
<< " s-1\n";
CurrentGenerator::log() << "The maximum weight is "
<< maxWeight_ << "\n";
CurrentGenerator::log() << "The weights for the different phase"
<< " space channels are \n";
for(unsigned int ix=0,N=channels_.size();ix<N;++ix) {
CurrentGenerator::log() << "Channel " << ix
<< " had weight " << channels_[ix].weight()
<< "\n";
}
}
CurrentGenerator::log() << flush;
}
decayer->ME(DecayMEPtr());
return output;
}
// generate a phase-space point using multichannel phase space
Energy PhaseSpaceMode::channelPhaseSpace(int & ichan, const Lorentz5Momentum & in,
vector<Lorentz5Momentum> & momenta,
bool onShell) const {
double wgt(rStack_.top());
rStack_.pop();
// select a channel
ichan=-1;
do {
++ichan;
wgt-=channels_[ichan].weight();
}
while(ichan<int(channels_.size())&&wgt>0.);
// generate the momenta
if(ichan==int(channels_.size())) {
throw DecayIntegratorError() << "PhaseSpaceMode::channelPhaseSpace()"
<< " failed to select a channel"
<< Exception::abortnow;
}
// generate the masses of the external particles
double masswgt(1.);
vector<Energy> mass(externalMasses(in.mass(),masswgt,onShell));
momenta=channels_[ichan].generateMomenta(in,mass);
// compute the denominator of the weight
wgt=0.;
for(const PhaseSpaceChannel & channel : channels_)
wgt += channel.generateWeight(momenta);
// return the weight
return wgt!=0. ? in.mass()*masswgt/wgt : ZERO;
}
void PhaseSpaceMode::init() {
// get mass and width generators
outgoingCC_.clear();
for(tPDPtr part : outgoing_) {
outgoingCC_.push_back(part->CC() ? part->CC() : part);
}
massGen_.resize(outgoing_.size());
widthGen_ = dynamic_ptr_cast<cGenericWidthGeneratorPtr>(incoming_.first->widthGenerator());
for(unsigned int ix=0;ix<outgoing_.size();++ix) {
assert(outgoing_[ix]);
massGen_[ix]= dynamic_ptr_cast<cGenericMassGeneratorPtr>(outgoing_[ix]->massGenerator());
}
// get max energy for decays
if(!incoming_.second)
eMax_ = testOnShell_ ? incoming_.first->mass() : incoming_.first->massMax();
// work out how many random numbers we need
nRand_ = 3*outgoing_.size()-4;
for(unsigned int ix=0;ix<outgoing_.size();++ix) {
if(massGen_[ix]) ++nRand_;
}
if(channels_.empty()) return;
++nRand_;
// ensure weights sum to one
double sum(0.);
for(const PhaseSpaceChannel & channel : channels_)
sum+=channel.weight();
for(PhaseSpaceChannel & channel : channels_)
channel.weight(channel.weight()/sum);
}
void PhaseSpaceMode::initrun() {
// update the mass and width generators
if(incoming_.first->widthGenerator()!=widthGen_)
widthGen_ = dynamic_ptr_cast<cGenericWidthGeneratorPtr>(incoming_.first->widthGenerator());
for(unsigned int ix=0;ix<outgoing_.size();++ix) {
if(massGen_[ix]!=outgoing_[ix]->massGenerator())
massGen_[ix] = dynamic_ptr_cast<cGenericMassGeneratorPtr>(outgoing_[ix]->massGenerator());
}
for(PhaseSpaceChannel & channel : channels_) channel.initrun(this);
if(widthGen_) const_ptr_cast<GenericWidthGeneratorPtr>(widthGen_)->initrun();
tcGenericWidthGeneratorPtr wtemp;
for(unsigned int ix=0;ix<outgoing_.size();++ix) {
wtemp=
dynamic_ptr_cast<tcGenericWidthGeneratorPtr>(outgoing_[ix]->widthGenerator());
if(wtemp) const_ptr_cast<tGenericWidthGeneratorPtr>(wtemp)->initrun();
}
// ensure weights sum to one
double sum(0.);
for(const PhaseSpaceChannel & channel : channels_)
sum+=channel.weight();
for(PhaseSpaceChannel & channel : channels_)
channel.weight(channel.weight()/sum);
}
diff --git a/Decay/PhaseSpaceMode.h b/Decay/PhaseSpaceMode.h
--- a/Decay/PhaseSpaceMode.h
+++ b/Decay/PhaseSpaceMode.h
@@ -1,388 +1,398 @@
// -*- C++ -*-
#ifndef Herwig_PhaseSpaceMode_H
#define Herwig_PhaseSpaceMode_H
//
// This is the declaration of the PhaseSpaceMode class.
//
#include "ThePEG/Config/ThePEG.h"
#include "PhaseSpaceMode.fh"
#include "PhaseSpaceChannel.h"
#include "Herwig/PDT/GenericWidthGenerator.h"
#include "Herwig/PDT/GenericMassGenerator.h"
namespace Herwig {
using namespace ThePEG;
/** \ingroup Decay
*
* The <code>PhaseSpaceMode</code> class is designed to store a group
* of phase-space channels for use by the DecayIntegrator class to
* generate the phase-space for a given decay mode.
*
* Additional phase-space channels can be added using the addChannel member.
*
* In practice the modes are usually constructed together with the a number of
* <code>PhaseSpaceChannel</code> objects. In classes inheriting from the
* DecayIntegrator class.
*
* @see DecayIntegrator
* @see PhaseSpaceChannel
*
* @author Peter Richardson
*
*/
class PhaseSpaceMode: public Base {
friend class PhaseSpaceChannel;
public:
/** @name Standard constructors and destructors. */
//@{
/**
* The default constructor.
*/
PhaseSpaceMode() : maxWeight_(0.), partial_(-1),
testOnShell_(false), eMax_(ZERO),
eps_(ZERO), nRand_(0)
{};
/**
* The default constructor.
*/
PhaseSpaceMode(tPDPtr in1, tPDVector out,
double wMax, tPDPtr in2=tPDPtr(),
Energy eMax=ZERO) : incoming_(make_pair(in1,in2)),
maxWeight_(wMax),
outgoing_(out), partial_(-1),
testOnShell_(false), eMax_(eMax),
eps_(ZERO), nRand_(0)
{};
//@}
public:
/**
* Generate the decay.
* @param intermediates Whether or not to generate the intermediate particle
* in the decay channel.
* @param cc Whether we are generating the mode specified or the charge
* conjugate mode.
* @param inpart The incoming particle.
* @return The outgoing particles.
*/
ParticleVector generateDecay(const Particle & inpart,
tcDecayIntegrator2Ptr decayer,
bool intermediates,bool cc);
/**
* Add a new channel.
* @param channel A pointer to the new PhaseChannel
*/
void addChannel(PhaseSpaceChannel channel) {
channel.init(this);
channels_.push_back(channel);
}
/**
* Reset the properties of one of the intermediate particles. Only a specific channel
* is reset.
* @param ichan The channel to reset.
* @param part The ParticleData object of the particle to reset
* @param mass The mass of the intermediate.
* @param width The width of gthe intermediate.
*/
void resetIntermediate(int ichan, tcPDPtr part, Energy mass, Energy width) {
if(!part) return;
channels_[ichan].resetIntermediate(part,mass,width);
}
/**
* Reset the properties of one of the intermediate particles. All the channels
* are reset.
* @param part The ParticleData object of the particle to reset
* @param mass The mass of the intermediate.
* @param width The width of gthe intermediate.
*/
void resetIntermediate(tcPDPtr part, Energy mass, Energy width) {
for(PhaseSpaceChannel & channel : channels_)
channel.resetIntermediate(part,mass,width);
}
/**
* The phase-space channels
*/
const vector<PhaseSpaceChannel> & channels() const {return channels_;}
/**
* Set the weights
*/
void setWeights(const vector<double> & wgts) {
assert(wgts.size()==channels_.size());
for(unsigned int ix=0;ix<channels_.size();++ix)
channels_[ix].weight(wgts[ix]);
}
/**
+ * Access to the selected channel
+ */
+ unsigned int selectedChannel() const {return iChannel_;}
+
+ /**
* Number of rnadom numbers needed
*/
unsigned int nRand() const {return nRand_;}
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
public :
/**
* Initialize the phase space
*/
void init();
/**
* Initialisation before the run stage
*/
void initrun();
/**
* Get the maximum weight for the decay.
* @return The maximum weight.
*/
double maxWeight() const {return maxWeight_;}
/**
* Set the maximum weight for the decay.
* @return The maximum weight.
*/
void maxWeight(double wgt) const {maxWeight_=wgt;}
/**
* Initialise the phase space.
* @param init Perform the initialization.
*/
Energy initializePhaseSpace(bool init, tcDecayIntegrator2Ptr decayer,
bool onShell=false);
/**
* The incoming particles
*/
pair<PDPtr,PDPtr> incoming() const {return incoming_;}
/**
* Access to the outging particles.
* @return A pointer to the ParticleData object.
*/
tPDVector outgoing() const {return outgoing_;}
/**
* Number of outgoing particles.
* @return The number of outgoing particles.
*/
unsigned int numberOfParticles() const {return outgoing_.size();}
/**
* Set the partial width to use for normalization. This is the partial width
* in the WidthGenerator object.
* @param in The partial width to use.
*/
void setPartialWidth(int in) {partial_=in;}
/**
* Access to the epsilon parameter
*/
Energy epsilonPS() const {return eps_;}
/**
* Fill the stack
*/
void fillStack(const double * r) {
assert(rStack_.empty());
for(unsigned int ix=nRand_;ix>0;--ix)
rStack_.push(r[nRand_-1]);
}
/**
* Fill the stack
*/
void fillStack() {
assert(rStack_.empty());
for(unsigned int ix=0;ix<nRand_;++ix) rStack_.push(UseRandom::rnd());
}
/**
* Return the weight for a given phase-space point.
* @param in The momentum of the incoming particle
* @param momenta The momenta of the outgoing particles
* @param onShell Whether or not to force the intermediates to be on-shell
* @return The weight.
*/
Energy weight(int & ichan, const Lorentz5Momentum & in,
vector<Lorentz5Momentum> & momenta,
bool onShell=false) const {
ichan=0;
// flat phase-space
if(channels_.empty())
return flatPhaseSpace(in,momenta,onShell);
// multi-channel
else
return channelPhaseSpace(ichan,in,momenta,onShell);
}
public :
/**
* A friend operator to allow the mode to be outputted for debugging purposes.
*/
friend ostream & operator<<(ostream & os, const PhaseSpaceMode & mode) {
os << "The mode has " << mode.channels_.size() << " channels\n";
if(mode.incoming_.second==PDPtr())
os << "This is a mode for the decay of " << mode.incoming_.first->PDGName() << " to ";
else
os << "This is a mode for " << mode.incoming_.first->PDGName() << ", "
<< mode.incoming_.second->PDGName() << " to ";
for(tPDPtr out : mode.outgoing_) os << out->PDGName() << " ";
os << "\n";
for(const PhaseSpaceChannel & channel : mode.channels_) os << channel;
return os;
}
private:
/**
* Return the weight and momenta for a flat phase-space decay.
* @param in The momentum of the incoming particle
* @param momenta The momenta of the outgoing particles
* @param onShell Whether or not to force the intermediates to be on-shell
* @return The weight.
*/
Energy flatPhaseSpace(const Lorentz5Momentum & in,
vector<Lorentz5Momentum> & momenta,
bool onShell=false) const;
/**
* Generate a phase-space point using multichannel phase space.
* @param ichan The channel to use
* @param in The momentum of the incoming particle
* @param momenta The momenta of the outgoing particles
* @param onShell Whether or not to force the intermediates to be on-shell
* @return The weight.
*/
Energy channelPhaseSpace(int & ichan, const Lorentz5Momentum & in,
vector<Lorentz5Momentum> & momenta,
bool onShell=false) const;
/**
* Generate the masses of the external particles.
* @param inmass The mass of the decaying particle.
* @param wgt The weight for the masses.
* @return The masses.
*/
vector<Energy> externalMasses(Energy inmass,double & wgt, bool onShell) const;
/**
* Construct the vertex for spin corrections
* @param in The incoming particle.
* @param out The outgoing particles.
*/
void constructVertex(const Particle & in, const ParticleVector & out,
tcDecayIntegrator2Ptr decayer) const;
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
PhaseSpaceMode & operator=(const PhaseSpaceMode &);
private:
/**
* The incoming particles
*/
pair<PDPtr,PDPtr> incoming_;
/**
* The phase-space channels
*/
vector<PhaseSpaceChannel> channels_;
/**
* The maximum weight
*/
mutable double maxWeight_;
/**
* The external particles
*/
tPDVector outgoing_;
tPDVector outgoingCC_;
/**
* Which of the partial widths of the incoming particle to use
*/
int partial_;
/**
* The width generator for the incoming particle.
*/
cGenericWidthGeneratorPtr widthGen_;
/**
* The mass generators for the outgoing particles.
*/
vector<cGenericMassGeneratorPtr> massGen_;
/**
* Whether to check on-shell or off-shell kinematics
* in doinit, if on-shell off-shell is tested in initrun
*/
bool testOnShell_;
/**
* The maximum energy for the mode
*/
Energy eMax_;
/**
+ * The selected channel
+ */
+ mutable unsigned int iChannel_;
+
+ /**
* Cut-off
*/
Energy eps_;
/**
* Number of random numbers required
*/
unsigned int nRand_;
/**
* Stack for the random numbers
*/
mutable stack<double> rStack_;
};
}
#endif /* Herwig_PhaseSpaceMode_H */

File Metadata

Mime Type
text/x-diff
Expires
Tue, Nov 19, 3:54 PM (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3753976
Default Alt Text
(185 KB)

Event Timeline